import { createServiceApp, registerOptionalJwtContext, startService } from '@bytelyst/fastify-core'; import { jwtVerify } from 'jose'; import { noteAgentActionRoutes } from './modules/note-agent-actions/routes.js'; import { noteArtifactRoutes } from './modules/note-artifacts/routes.js'; import { noteRoutes } from './modules/notes/routes.js'; import { noteRelationshipRoutes } from './modules/note-relationships/routes.js'; import { noteTaskRoutes } from './modules/note-tasks/routes.js'; import { savedViewRoutes } from './modules/saved-views/routes.js'; import { workspaceRoutes } from './modules/workspaces/routes.js'; import { initCosmosIfNeeded } from './lib/cosmos-init.js'; import { initEncryption } from './lib/field-encrypt.js'; import { initDatastore } from './lib/datastore.js'; import { config } from './lib/config.js'; import { getAllFlags } from './lib/feature-flags.js'; import { getBufferedEvents, flushEvents } from './lib/telemetry.js'; import { DISPLAY_NAME, PRODUCT_ID, productConfig } from './lib/product-config.js'; import type { JwtPayload } from './lib/request-context.js'; const jwtSecret = new TextEncoder().encode(config.JWT_SECRET); await initCosmosIfNeeded(); initDatastore(); const app = await createServiceApp({ name: config.SERVICE_NAME, version: '0.1.0', description: `${DISPLAY_NAME} product-specific backend — notes and workspaces`, corsOrigin: config.CORS_ORIGIN, swagger: { title: `${DISPLAY_NAME} Backend`, description: 'Notes and workspaces API', port: config.PORT, }, metrics: true, readiness: true, }); await registerOptionalJwtContext(app, { verifyToken: async (token: string) => { const { payload } = await jwtVerify(token, jwtSecret, { issuer: 'bytelyst-platform' }); return payload as unknown as JwtPayload; }, }); type RegisterablePlugin = Parameters[0]; async function registerApiPlugin(plugin: unknown) { await app.register(plugin as RegisterablePlugin, { prefix: '/api' }); } await registerApiPlugin(noteAgentActionRoutes); await registerApiPlugin(noteArtifactRoutes); await registerApiPlugin(noteRoutes); await registerApiPlugin(noteRelationshipRoutes); await registerApiPlugin(noteTaskRoutes); await registerApiPlugin(savedViewRoutes); await registerApiPlugin(workspaceRoutes); // ── Bootstrap (no auth) ────────────────────────────────────────── app.get('/api/bootstrap', async () => ({ productId: productConfig.productId, displayName: productConfig.displayName, backendPort: config.PORT, })); // ── Diagnostics routes (no auth) ──────────────────────────────── app.get('/api/diagnostics/flags', async () => getAllFlags()); app.get('/api/diagnostics/telemetry', async () => ({ events: getBufferedEvents() })); app.post('/api/diagnostics/telemetry/flush', async () => ({ flushed: flushEvents().length })); app.get('/api/diagnostics/config', async () => ({ productId: PRODUCT_ID, serviceName: config.SERVICE_NAME, port: config.PORT, nodeEnv: config.NODE_ENV, dbProvider: config.DB_PROVIDER, telemetryEnabled: config.TELEMETRY_ENABLED, featureFlagsEnabled: config.FEATURE_FLAGS_ENABLED, })); await initEncryption(PRODUCT_ID, app.log); await startService(app, { port: config.PORT, host: config.HOST });