fix(server): boot-time settings read runs inside an explicit ORM request context

This commit is contained in:
jubnl
2026-09-22 12:32:17 +02:00
parent 7908914345
commit b8e7dbccc6
2 changed files with 8 additions and 3 deletions
+5 -1
View File
@@ -13,6 +13,7 @@ import { TrekWsAdapter } from './nest/realtime/trek-ws.adapter';
import { SettingsService } from './nest/settings/settings.service';
import { StorageService } from './nest/storage/storage.service';
import { MikroORM } from '@mikro-orm/core';
import { withRequestContext } from './nest/database/request-context';
import type { INestApplication } from '@nestjs/common';
import type { ConfigType } from '@nestjs/config';
import { NestFactory } from '@nestjs/core';
@@ -101,7 +102,10 @@ export async function buildApp(): Promise<INestApplication> {
// engines go through the same door — the second one answers the avoidance questions
// the first cannot, and is blocked just as silently when the policy leaves it out.
const settings = app.get(SettingsService, { strict: false });
const defaults = await settings?.getAdminUserDefaults();
// Boot runs outside any HTTP request, so there is no per-request EntityManager
// yet and `allowGlobalContext` is off in production: every repository-backed
// read at boot goes through D6's explicit context (see request-context.ts).
const defaults = await withRequestContext(orm, () => settings?.getAdminUserDefaults());
const asUrl = (value: unknown) => (typeof value === 'string' ? value : null);
applyGlobalMiddleware(instance, {
http,
+3 -2
View File
@@ -1,4 +1,4 @@
import { RequestContext, type MikroORM } from '@mikro-orm/core';
import { RequestContext, type EntityManager } from '@mikro-orm/core';
/**
* A request-scoped EntityManager for work that no HTTP request wraps.
@@ -11,6 +11,7 @@ import { RequestContext, type MikroORM } from '@mikro-orm/core';
* call. It is deliberately a function and not a decorator so a call site can
* pass the ORM it was given rather than reach for a global.
*/
export function withRequestContext<T>(orm: MikroORM, fn: () => T): T {
/** Accepts anything carrying the ORM's global EntityManager (MikroORM itself, or a narrower handle); `app.get(MikroORM)`'s readonly-entities generic would otherwise not assign to `MikroORM`. */
export function withRequestContext<T>(orm: { em: EntityManager }, fn: () => T): T {
return RequestContext.create(orm.em, fn);
}