69 lines
1.9 KiB
TypeScript
69 lines
1.9 KiB
TypeScript
import { readdirSync, statSync } from 'fs'
|
|
import { join, dirname } from 'path'
|
|
import { fileURLToPath } from 'url'
|
|
import type { ApiModule } from '../infra/types.js'
|
|
|
|
const __filename = fileURLToPath(import.meta.url)
|
|
const __dirname = dirname(__filename)
|
|
|
|
const moduleFactoryPattern = /^create\w+Module$/
|
|
|
|
async function discoverModules(): Promise<ApiModule[]> {
|
|
const modules: ApiModule[] = []
|
|
const entries = readdirSync(__dirname)
|
|
|
|
for (const entry of entries) {
|
|
const entryPath = join(__dirname, entry)
|
|
|
|
try {
|
|
const stats = statSync(entryPath)
|
|
if (!stats.isDirectory()) {
|
|
continue
|
|
}
|
|
|
|
const moduleIndexPath = join(entryPath, 'index.ts')
|
|
let moduleIndexStats: ReturnType<typeof statSync>
|
|
try {
|
|
moduleIndexStats = statSync(moduleIndexPath)
|
|
} catch {
|
|
continue
|
|
}
|
|
if (!moduleIndexStats.isFile()) {
|
|
continue
|
|
}
|
|
|
|
const moduleExports = await import(`./${entry}/index.js`)
|
|
|
|
for (const exportName of Object.keys(moduleExports)) {
|
|
if (moduleFactoryPattern.test(exportName)) {
|
|
const factory = moduleExports[exportName]
|
|
if (typeof factory === 'function') {
|
|
const module = factory() as ApiModule
|
|
modules.push(module)
|
|
}
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.warn(`[ModuleLoader] Failed to load module '${entry}':`, error)
|
|
}
|
|
}
|
|
|
|
modules.sort((a, b) => {
|
|
const orderA = a.metadata.order ?? 0
|
|
const orderB = b.metadata.order ?? 0
|
|
return orderA - orderB
|
|
})
|
|
|
|
return modules
|
|
}
|
|
|
|
export const apiModules: ApiModule[] = await discoverModules()
|
|
|
|
export * from './todo/index.js'
|
|
export * from './time-tracking/index.js'
|
|
export * from './recycle-bin/index.js'
|
|
export * from './pydemos/index.js'
|
|
export * from './document-parser/index.js'
|
|
export * from './ai/index.js'
|
|
export * from './remote/index.js'
|