// ── module-uo · server entry point ───────────────────────────────────────── // // SPIKE SCOPE. Phase 1 carries only /api/v1/public/atlas/* out of core // (MODULE_SYSTEM.md §2.7): six routes, DB-backed, no sidecar, no SSE, one boot // hook. Phase 3 brings the rest — the other 12 router/controller files, the 7 // remaining model directories, the notification-stream catalog and the // town-crier announce leg. // // Called ONCE, synchronously, during the website's app.js require. Everything // here must therefore be synchronous and must not touch the database: the route // manifest generator and the OpenAPI generator both require app.js with the // pool pointed at a dead port, and a module that queried here would hang both // (MODULE_API.md §2.2). Anything needing a live database goes in onBoot. const core = require('./core') module.exports = function register(ctx, api) { // Park ctx before requiring anything that reads it. The requires below pull in // the model layer, whose files resolve core lazily — but the ORDER still // matters for the router, which is constructed at require time. core.init(ctx) /* eslint-disable global-require */ const atlasRouter = require('./router/atlas.router') const atlas = require('./model/shardAtlas/shardAtlas.model') /* eslint-enable global-require */ const log = ctx.log('boot') // The URL is unchanged from when this router lived in core's // router/v1/public/index.js — that is the point, and routes.manifest.json is // the proof (MODULE_API.md §5.3). api.registerRoutes({ public: { '/atlas': atlasRouter }, }) // Was server.js:92, an explicit call in core's start(). Re-derive the spawn // atlas from the shard's own ServUO tree: the shard's maps change over its // lifetime — facets get added, replaced or renamed — so the atlas is rebuilt // on every boot rather than shipped as a snapshot that would silently go // stale. Hash-gated, so an unchanged tree costs one read pass and no write. // // Best-effort by contract: no configured path, an unreadable mount or a // malformed file must never stop the site coming up, and a refresh that would // REMOVE a facet is staged for admin approval instead of being applied. So it // is caught HERE rather than left to the loader — the loader's catch would be // correct about the failure but wrong about the severity, marking the module // startup_failed and 503-ing six routes that serve perfectly good stale data. api.onBoot(async () => { try { const result = await atlas.refreshOnBoot() log.info('spawn atlas refreshed', { status: result && result.status }) } catch (err) { log.warn('spawn atlas refresh failed — serving whatever was last imported', { error: err.message, }) } }) }