@xemahq/xema-service-nest 0.2.7 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -5,4 +5,5 @@ export { applyXemaServiceMiddleware } from './lib/apply-xema-service-middleware'
5
5
  export { type ConfigureAuthMiddlewareOptions } from '@xemahq/platform-common';
6
6
  export { validateBiomeServiceDescriptor, BiomeServiceDescriptorError, type BiomeServiceDescriptor, } from './lib/biome-service-descriptor';
7
7
  export { ServiceKind } from '@xemahq/xema-decorators';
8
+ export { IdentityBootstrapModule, IdentityBootstrapService, type IdentityBootstrapModuleAsyncOptions, type IdentityBootstrapConfig, } from '@xemahq/identity-client';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,iBAAiB,EACjB,KAAK,wBAAwB,GAC9B,MAAM,2BAA2B,CAAC;AAKnC,OAAO,EACL,oBAAoB,EACpB,KAAK,2BAA2B,GACjC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,YAAY,EACZ,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,KAAK,8BAA8B,EAAE,MAAM,yBAAyB,CAAC;AAG9E,OAAO,EACL,8BAA8B,EAC9B,2BAA2B,EAC3B,KAAK,sBAAsB,GAC5B,MAAM,gCAAgC,CAAC;AAIxC,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,iBAAiB,EACjB,KAAK,wBAAwB,GAC9B,MAAM,2BAA2B,CAAC;AAKnC,OAAO,EACL,oBAAoB,EACpB,KAAK,2BAA2B,GACjC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,YAAY,EACZ,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,KAAK,8BAA8B,EAAE,MAAM,yBAAyB,CAAC;AAG9E,OAAO,EACL,8BAA8B,EAC9B,2BAA2B,EAC3B,KAAK,sBAAsB,GAC5B,MAAM,gCAAgC,CAAC;AAIxC,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAStD,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,KAAK,mCAAmC,EACxC,KAAK,uBAAuB,GAC7B,MAAM,yBAAyB,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ServiceKind = exports.BiomeServiceDescriptorError = exports.validateBiomeServiceDescriptor = exports.applyXemaServiceMiddleware = exports.DEFAULT_SWAGGER_JSON_PATH = exports.DEFAULT_SWAGGER_DOCS_PATH = exports.DEFAULT_PORT = exports.bootstrapXemaService = exports.XemaServiceModule = void 0;
3
+ exports.IdentityBootstrapService = exports.IdentityBootstrapModule = exports.ServiceKind = exports.BiomeServiceDescriptorError = exports.validateBiomeServiceDescriptor = exports.applyXemaServiceMiddleware = exports.DEFAULT_SWAGGER_JSON_PATH = exports.DEFAULT_SWAGGER_DOCS_PATH = exports.DEFAULT_PORT = exports.bootstrapXemaService = exports.XemaServiceModule = void 0;
4
4
  var xema_service_module_1 = require("./lib/xema-service-module");
5
5
  Object.defineProperty(exports, "XemaServiceModule", { enumerable: true, get: function () { return xema_service_module_1.XemaServiceModule; } });
6
6
  var bootstrap_xema_service_1 = require("./lib/bootstrap-xema-service");
@@ -16,4 +16,7 @@ Object.defineProperty(exports, "validateBiomeServiceDescriptor", { enumerable: t
16
16
  Object.defineProperty(exports, "BiomeServiceDescriptorError", { enumerable: true, get: function () { return biome_service_descriptor_1.BiomeServiceDescriptorError; } });
17
17
  var xema_decorators_1 = require("@xemahq/xema-decorators");
18
18
  Object.defineProperty(exports, "ServiceKind", { enumerable: true, get: function () { return xema_decorators_1.ServiceKind; } });
19
+ var identity_client_1 = require("@xemahq/identity-client");
20
+ Object.defineProperty(exports, "IdentityBootstrapModule", { enumerable: true, get: function () { return identity_client_1.IdentityBootstrapModule; } });
21
+ Object.defineProperty(exports, "IdentityBootstrapService", { enumerable: true, get: function () { return identity_client_1.IdentityBootstrapService; } });
19
22
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,iEAGmC;AAFjC,wHAAA,iBAAiB,OAAA;AAOnB,uEAGsC;AAFpC,8HAAA,oBAAoB,OAAA;AAGtB,iEAMmC;AAHjC,mHAAA,YAAY,OAAA;AACZ,gIAAA,yBAAyB,OAAA;AACzB,gIAAA,yBAAyB,OAAA;AAI3B,qFAAiF;AAAxE,2IAAA,0BAA0B,OAAA;AAInC,2EAIwC;AAHtC,0IAAA,8BAA8B,OAAA;AAC9B,uIAAA,2BAA2B,OAAA;AAM7B,2DAAsD;AAA7C,8GAAA,WAAW,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,iEAGmC;AAFjC,wHAAA,iBAAiB,OAAA;AAOnB,uEAGsC;AAFpC,8HAAA,oBAAoB,OAAA;AAGtB,iEAMmC;AAHjC,mHAAA,YAAY,OAAA;AACZ,gIAAA,yBAAyB,OAAA;AACzB,gIAAA,yBAAyB,OAAA;AAI3B,qFAAiF;AAAxE,2IAAA,0BAA0B,OAAA;AAInC,2EAIwC;AAHtC,0IAAA,8BAA8B,OAAA;AAC9B,uIAAA,2BAA2B,OAAA;AAM7B,2DAAsD;AAA7C,8GAAA,WAAW,OAAA;AASpB,2DAKiC;AAJ/B,0HAAA,uBAAuB,OAAA;AACvB,2HAAA,wBAAwB,OAAA"}
@@ -10,6 +10,7 @@ export interface BootstrapXemaServiceOptions {
10
10
  readonly swaggerVersion?: string;
11
11
  readonly port?: number | string;
12
12
  readonly swagger?: boolean | BootstrapSwaggerOptions;
13
+ readonly composeDatabaseUrlFromEnv?: boolean;
13
14
  readonly registerGlobalExceptionFilter?: boolean;
14
15
  readonly registerResponseEnvelopeInterceptor?: boolean;
15
16
  readonly configureApp?: (app: NestExpressApplication) => void | Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrap-xema-service.d.ts","sourceRoot":"","sources":["../../src/lib/bootstrap-xema-service.ts"],"names":[],"mappings":"AAUA,OAAO,EAML,KAAK,uBAAuB,EAC7B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAOvE,MAAM,WAAW,2BAA2B;IAE1C,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAMlC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAE9B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IAOpC,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAK7C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAKjC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAOhC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,CAAC;IAOrD,QAAQ,CAAC,6BAA6B,CAAC,EAAE,OAAO,CAAC;IAQjD,QAAQ,CAAC,mCAAmC,CAAC,EAAE,OAAO,CAAC;IAQvD,QAAQ,CAAC,YAAY,CAAC,EAAE,CACtB,GAAG,EAAE,sBAAsB,KACxB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAsCD,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,gBAAgB,CAAC,CA+D3B"}
1
+ {"version":3,"file":"bootstrap-xema-service.d.ts","sourceRoot":"","sources":["../../src/lib/bootstrap-xema-service.ts"],"names":[],"mappings":"AAWA,OAAO,EAML,KAAK,uBAAuB,EAC7B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAOvE,MAAM,WAAW,2BAA2B;IAE1C,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAMlC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAE9B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IAOpC,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAK7C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAKjC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAOhC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,CAAC;IAYrD,QAAQ,CAAC,yBAAyB,CAAC,EAAE,OAAO,CAAC;IAO7C,QAAQ,CAAC,6BAA6B,CAAC,EAAE,OAAO,CAAC;IAQjD,QAAQ,CAAC,mCAAmC,CAAC,EAAE,OAAO,CAAC;IAQvD,QAAQ,CAAC,YAAY,CAAC,EAAE,CACtB,GAAG,EAAE,sBAAsB,KACxB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAsCD,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,gBAAgB,CAAC,CA2E3B"}
@@ -8,6 +8,12 @@ const bootstrap_swagger_1 = require("./bootstrap-swagger");
8
8
  const bootstrap_internals_1 = require("./bootstrap-internals");
9
9
  async function bootstrapXemaService(options) {
10
10
  const logger = new common_1.Logger('bootstrapXemaService');
11
+ if (options.composeDatabaseUrlFromEnv !== false && !process.env.DATABASE_URL) {
12
+ const composed = (0, platform_common_1.composeBiomeDatabaseUrlFromEnv)();
13
+ if (composed) {
14
+ process.env.DATABASE_URL = composed;
15
+ }
16
+ }
11
17
  (0, bootstrap_internals_1.validateRequiredEnv)(options.requiredEnvVars ?? []);
12
18
  const app = await core_1.NestFactory.create(options.appModule, { cors: (0, platform_common_1.getCorsConfig)(process.env.CORS_ALLOWED_ORIGINS) });
13
19
  (0, platform_common_1.applyStandardBodyParsers)(app);
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrap-xema-service.js","sourceRoot":"","sources":["../../src/lib/bootstrap-xema-service.ts"],"names":[],"mappings":";;AA+HA,oDAiEC;AAhMD,2CAAwD;AACxD,uCAA2C;AAC3C,6DAKiC;AAEjC,2DAA2D;AAC3D,+DAO+B;AA8GxB,KAAK,UAAU,oBAAoB,CACxC,OAAoC;IAEpC,MAAM,MAAM,GAAG,IAAI,eAAM,CAAC,sBAAsB,CAAC,CAAC;IAGlD,IAAA,yCAAmB,EAAC,OAAO,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC;IAGnD,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAClC,OAAO,CAAC,SAAS,EACjB,EAAE,IAAI,EAAE,IAAA,+BAAa,EAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE,CAC1D,CAAC;IAGF,IAAA,0CAAwB,EAAC,GAAG,CAAC,CAAC;IAG9B,GAAG,CAAC,cAAc,CAChB,IAAI,uBAAc,CAAC;QACjB,SAAS,EAAE,IAAI;QACf,oBAAoB,EAAE,IAAI;QAC1B,SAAS,EAAE,IAAI;KAChB,CAAC,CACH,CAAC;IAGF,IAAI,OAAO,CAAC,6BAA6B,KAAK,KAAK,EAAE,CAAC;QACpD,GAAG,CAAC,gBAAgB,CAAC,IAAI,uCAAqB,EAAE,CAAC,CAAC;IACpD,CAAC;IAID,IAAI,OAAO,CAAC,mCAAmC,KAAK,IAAI,EAAE,CAAC;QACzD,GAAG,CAAC,qBAAqB,CAAC,IAAI,6CAA2B,EAAE,CAAC,CAAC;IAC/D,CAAC;IAGD,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACzB,MAAM,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAGD,MAAM,aAAa,GAAG,IAAA,0CAAoB,EAAC;QACzC,OAAO,EAAE,IAAA,sCAAgB,EAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,yCAAmB,CAAC,CAAC;QAC5E,KAAK,EAAE,OAAO,CAAC,YAAY;QAC3B,WAAW,EAAE,OAAO,CAAC,kBAAkB;QACvC,OAAO,EAAE,OAAO,CAAC,cAAc,IAAI,OAAO;QAC1C,aAAa,EAAE,OAAO,CAAC,OAAO;QAC9B,GAAG,EAAE;YACH,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,uBAAuB;YAClD,iBAAiB,EAAE,OAAO,CAAC,GAAG,CAAC,2BAA2B;YAC1D,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;SAC9C;KACF,CAAC,CAAC;IACH,IAAI,aAAa,EAAE,CAAC;QAClB,IAAA,wCAAoB,EAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IAC3C,CAAC;IAGD,MAAM,IAAI,GAAG,IAAA,iCAAW,EAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzD,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACvB,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,WAAW,sBAAsB,IAAI,EAAE,CAAC,CAAC;IAE/D,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"bootstrap-xema-service.js","sourceRoot":"","sources":["../../src/lib/bootstrap-xema-service.ts"],"names":[],"mappings":";;AA4IA,oDA6EC;AAzND,2CAAwD;AACxD,uCAA2C;AAC3C,6DAMiC;AAEjC,2DAA2D;AAC3D,+DAO+B;AA0HxB,KAAK,UAAU,oBAAoB,CACxC,OAAoC;IAEpC,MAAM,MAAM,GAAG,IAAI,eAAM,CAAC,sBAAsB,CAAC,CAAC;IAOlD,IAAI,OAAO,CAAC,yBAAyB,KAAK,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAC7E,MAAM,QAAQ,GAAG,IAAA,gDAA8B,GAAE,CAAC;QAClD,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,QAAQ,CAAC;QACtC,CAAC;IACH,CAAC;IAGD,IAAA,yCAAmB,EAAC,OAAO,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC;IAGnD,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAClC,OAAO,CAAC,SAAS,EACjB,EAAE,IAAI,EAAE,IAAA,+BAAa,EAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE,CAC1D,CAAC;IAGF,IAAA,0CAAwB,EAAC,GAAG,CAAC,CAAC;IAG9B,GAAG,CAAC,cAAc,CAChB,IAAI,uBAAc,CAAC;QACjB,SAAS,EAAE,IAAI;QACf,oBAAoB,EAAE,IAAI;QAC1B,SAAS,EAAE,IAAI;KAChB,CAAC,CACH,CAAC;IAGF,IAAI,OAAO,CAAC,6BAA6B,KAAK,KAAK,EAAE,CAAC;QACpD,GAAG,CAAC,gBAAgB,CAAC,IAAI,uCAAqB,EAAE,CAAC,CAAC;IACpD,CAAC;IAID,IAAI,OAAO,CAAC,mCAAmC,KAAK,IAAI,EAAE,CAAC;QACzD,GAAG,CAAC,qBAAqB,CAAC,IAAI,6CAA2B,EAAE,CAAC,CAAC;IAC/D,CAAC;IAGD,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACzB,MAAM,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAGD,MAAM,aAAa,GAAG,IAAA,0CAAoB,EAAC;QACzC,OAAO,EAAE,IAAA,sCAAgB,EAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,yCAAmB,CAAC,CAAC;QAC5E,KAAK,EAAE,OAAO,CAAC,YAAY;QAC3B,WAAW,EAAE,OAAO,CAAC,kBAAkB;QACvC,OAAO,EAAE,OAAO,CAAC,cAAc,IAAI,OAAO;QAC1C,aAAa,EAAE,OAAO,CAAC,OAAO;QAC9B,GAAG,EAAE;YACH,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,uBAAuB;YAClD,iBAAiB,EAAE,OAAO,CAAC,GAAG,CAAC,2BAA2B;YAC1D,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;SAC9C;KACF,CAAC,CAAC;IACH,IAAI,aAAa,EAAE,CAAC;QAClB,IAAA,wCAAoB,EAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IAC3C,CAAC;IAGD,MAAM,IAAI,GAAG,IAAA,iCAAW,EAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzD,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACvB,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,WAAW,sBAAsB,IAAI,EAAE,CAAC,CAAC;IAE/D,OAAO,GAAG,CAAC;AACb,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xemahq/xema-service-nest",
3
- "version": "0.2.7",
3
+ "version": "0.3.0",
4
4
  "description": "Xema platform service-bootstrap SDK. `XemaServiceModule.forBiome(descriptor)` composes the full platform service stack — Service Registry, Identity bootstrap, Auth (JWT verification + request context), and the Xema runtime route/capability scanner — behind a single call, so a biome API is auth-correct in ~5 lines and never re-wires authentication.",
5
5
  "keywords": [
6
6
  "xema",
package/src/index.ts CHANGED
@@ -33,3 +33,17 @@ export {
33
33
  // Re-export `ServiceKind` so a generated bootstrap constant can name its kind
34
34
  // without a second import from `@xemahq/xema-decorators`.
35
35
  export { ServiceKind } from '@xemahq/xema-decorators';
36
+
37
+ // Re-export the identity-bootstrap module + service from the one-call bootstrap
38
+ // surface. `XemaServiceModule.forBiome` already wires `IdentityBootstrapModule`
39
+ // internally, but a biome that needs to reference the module (e.g. to wire it
40
+ // into a feature sub-module) or inject `IdentityBootstrapService` (to mint a
41
+ // service bearer for a bespoke client) would otherwise reach into the deeper
42
+ // `@xemahq/identity-client` path. Surfacing them here keeps the bootstrap SDK
43
+ // the single import a platform-correct biome service needs.
44
+ export {
45
+ IdentityBootstrapModule,
46
+ IdentityBootstrapService,
47
+ type IdentityBootstrapModuleAsyncOptions,
48
+ type IdentityBootstrapConfig,
49
+ } from '@xemahq/identity-client';
@@ -2,6 +2,7 @@ import { Logger, ValidationPipe } from '@nestjs/common';
2
2
  import { NestFactory } from '@nestjs/core';
3
3
  import {
4
4
  applyStandardBodyParsers,
5
+ composeBiomeDatabaseUrlFromEnv,
5
6
  getCorsConfig,
6
7
  GlobalExceptionFilter,
7
8
  ResponseEnvelopeInterceptor,
@@ -62,6 +63,18 @@ export interface BootstrapXemaServiceOptions {
62
63
  * `SWAGGER_ENABLED=false` env kill-switch.
63
64
  */
64
65
  readonly swagger?: boolean | BootstrapSwaggerOptions;
66
+ /**
67
+ * Compose `process.env.DATABASE_URL` from the standard `DB_*` env contract
68
+ * (via `composeBiomeDatabaseUrlFromEnv`) before the app is created, when
69
+ * `DATABASE_URL` is not already set. Defaults to `true` — this inlines the
70
+ * local `ensureDatabaseUrl()` shim ~36 DB-using services hand-roll in their
71
+ * `main.ts`. It is behavior-preserving:
72
+ * • if `DATABASE_URL` is already set, it is a no-op (explicit URL wins);
73
+ * • if the `DB_*` parts are incomplete it composes nothing (returns null),
74
+ * so a non-DB service or one with an explicit URL is unaffected.
75
+ * Set `false` only for a service that must NOT derive its URL from `DB_*`.
76
+ */
77
+ readonly composeDatabaseUrlFromEnv?: boolean;
65
78
  /**
66
79
  * Auto-register the platform `GlobalExceptionFilter` as a global filter.
67
80
  * Defaults to `true` — adopting `bootstrapXemaService` fixes the audit gap
@@ -130,6 +143,18 @@ export async function bootstrapXemaService(
130
143
  ): Promise<INestApplication> {
131
144
  const logger = new Logger('bootstrapXemaService');
132
145
 
146
+ // 0. Compose DATABASE_URL from the DB_* env contract when not already set.
147
+ // Replaces the per-service local `ensureDatabaseUrl()` shim. Must run BEFORE
148
+ // env validation + app creation so a service that lists DATABASE_URL in
149
+ // `requiredEnvVars` (and supplies only DB_* parts) still passes, and Prisma
150
+ // sees the composed URL at module construction.
151
+ if (options.composeDatabaseUrlFromEnv !== false && !process.env.DATABASE_URL) {
152
+ const composed = composeBiomeDatabaseUrlFromEnv();
153
+ if (composed) {
154
+ process.env.DATABASE_URL = composed;
155
+ }
156
+ }
157
+
133
158
  // 1. Fail-fast env validation BEFORE any framework work.
134
159
  validateRequiredEnv(options.requiredEnvVars ?? []);
135
160