102 lines
2.5 KiB
TypeScript
102 lines
2.5 KiB
TypeScript
/**
|
|
* API 服务器
|
|
*/
|
|
|
|
import express, {
|
|
type Request,
|
|
type Response,
|
|
type NextFunction,
|
|
} from 'express'
|
|
import cors from 'cors'
|
|
import dotenv from 'dotenv'
|
|
import filesRoutes from './core/files/routes.js'
|
|
import eventsRoutes from './core/events/routes.js'
|
|
import settingsRoutes from './core/settings/routes.js'
|
|
import uploadRoutes from './core/upload/routes.js'
|
|
import searchRoutes from './core/search/routes.js'
|
|
import type { ApiResponse } from '../shared/types.js'
|
|
import { errorHandler } from './middlewares/errorHandler.js'
|
|
import { NOTEBOOK_ROOT } from './config/paths.js'
|
|
import { ModuleManager } from './infra/moduleManager.js'
|
|
import { ServiceContainer } from './infra/container.js'
|
|
import { apiModules } from './modules/index.js'
|
|
import { validateModuleConsistency } from './infra/moduleValidator.js'
|
|
import path from 'path'
|
|
import fs from 'fs'
|
|
|
|
dotenv.config()
|
|
|
|
const app: express.Application = express()
|
|
export const container = new ServiceContainer()
|
|
export const moduleManager = new ModuleManager(container)
|
|
|
|
app.use(cors())
|
|
app.use(express.json({ limit: '200mb' }))
|
|
app.use(express.urlencoded({ extended: true, limit: '200mb' }))
|
|
|
|
/**
|
|
* Core Routes
|
|
*/
|
|
app.use('/api/files', filesRoutes)
|
|
app.use('/api/events', eventsRoutes)
|
|
app.use('/api/settings', settingsRoutes)
|
|
app.use('/api/upload', uploadRoutes)
|
|
app.use('/api/search', searchRoutes)
|
|
|
|
/**
|
|
* Module Routes (loaded dynamically via ModuleManager)
|
|
*/
|
|
for (const module of apiModules) {
|
|
await moduleManager.register(module)
|
|
}
|
|
|
|
await validateModuleConsistency(apiModules)
|
|
|
|
for (const module of moduleManager.getAllModules()) {
|
|
await moduleManager.activate(module.metadata.id)
|
|
const router = await module.createRouter(container)
|
|
app.use('/api' + module.metadata.basePath, router)
|
|
}
|
|
|
|
app.get('/background.png', (req, res, next) => {
|
|
const customBgPath = path.join(NOTEBOOK_ROOT, '.config', 'background.png')
|
|
if (fs.existsSync(customBgPath)) {
|
|
res.sendFile(customBgPath)
|
|
} else {
|
|
next()
|
|
}
|
|
})
|
|
|
|
/**
|
|
* health
|
|
*/
|
|
app.use(
|
|
'/api/health',
|
|
(_req: Request, res: Response): void => {
|
|
const response: ApiResponse<{ message: string }> = {
|
|
success: true,
|
|
data: { message: 'ok' },
|
|
}
|
|
res.status(200).json(response)
|
|
},
|
|
)
|
|
|
|
/**
|
|
* 404 handler
|
|
*/
|
|
app.use((req: Request, res: Response, next: NextFunction) => {
|
|
if (req.path.startsWith('/api')) {
|
|
const response: ApiResponse<null> = {
|
|
success: false,
|
|
error: { code: 'NOT_FOUND', message: 'API不存在' },
|
|
}
|
|
res.status(404).json(response)
|
|
} else {
|
|
next()
|
|
}
|
|
})
|
|
|
|
app.use(errorHandler)
|
|
|
|
export default app
|