@pattern-stack/codegen 0.22.0 → 0.24.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.
Files changed (104) hide show
  1. package/CHANGELOG.md +56 -1
  2. package/consumer-skills/integration/SKILL.md +11 -3
  3. package/dist/{chunk-XKWOJZZ4.js → chunk-37PILMIT.js} +4 -4
  4. package/dist/{chunk-NR7QQ6ZI.js → chunk-6M6LZEP6.js} +3 -3
  5. package/dist/{chunk-VDL5CJ5C.js → chunk-7B7MMDOJ.js} +54 -1
  6. package/dist/chunk-7B7MMDOJ.js.map +1 -0
  7. package/dist/{chunk-NXHL5YII.js → chunk-7LKAMLV4.js} +4 -4
  8. package/dist/{chunk-6DQEIXYU.js → chunk-CKLM57IE.js} +10 -10
  9. package/dist/chunk-CKLM57IE.js.map +1 -0
  10. package/dist/{chunk-QXVCRA23.js → chunk-ENAR3F5S.js} +9 -4
  11. package/dist/chunk-ENAR3F5S.js.map +1 -0
  12. package/dist/{chunk-FFUDEIFF.js → chunk-HN5HT5WL.js} +2 -2
  13. package/dist/{chunk-6ECCJVYW.js → chunk-K4BQQ2NN.js} +46 -2
  14. package/dist/chunk-K4BQQ2NN.js.map +1 -0
  15. package/dist/{chunk-QFUIE37H.js → chunk-KFXXOFDC.js} +4 -4
  16. package/dist/{chunk-O2A6XHGD.js → chunk-LLDJS7PJ.js} +2 -2
  17. package/dist/{chunk-JOBQ6RUU.js → chunk-LQZESSM3.js} +28 -1
  18. package/dist/chunk-LQZESSM3.js.map +1 -0
  19. package/dist/{chunk-JRQO2IOF.js → chunk-MU54DZCC.js} +27 -1
  20. package/dist/chunk-MU54DZCC.js.map +1 -0
  21. package/dist/{chunk-INO47JXD.js → chunk-PBENHIN2.js} +3 -3
  22. package/dist/{chunk-CLWBNXKF.js → chunk-PLUJEQLU.js} +2 -2
  23. package/dist/{chunk-DB5UXJC3.js → chunk-PNCOUFFI.js} +4 -2
  24. package/dist/chunk-PNCOUFFI.js.map +1 -0
  25. package/dist/{chunk-S7C6TIIF.js → chunk-S5G3HO7N.js} +3 -1
  26. package/dist/chunk-S5G3HO7N.js.map +1 -0
  27. package/dist/{chunk-FNHNSFIJ.js → chunk-WZOPWQN2.js} +2 -2
  28. package/dist/{chunk-TDEHU73T.js → chunk-YIVQ7KLS.js} +46 -5
  29. package/dist/chunk-YIVQ7KLS.js.map +1 -0
  30. package/dist/runtime/subsystems/auth/auth.module.js +2 -2
  31. package/dist/runtime/subsystems/auth/index.js +4 -4
  32. package/dist/runtime/subsystems/bridge/bridge.module.js +7 -7
  33. package/dist/runtime/subsystems/bridge/index.js +7 -7
  34. package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js +1 -1
  35. package/dist/runtime/subsystems/events/events.module.js +5 -5
  36. package/dist/runtime/subsystems/events/generated/bus.js +3 -3
  37. package/dist/runtime/subsystems/events/generated/index.d.ts +2 -2
  38. package/dist/runtime/subsystems/events/generated/index.js +9 -3
  39. package/dist/runtime/subsystems/events/generated/registry.d.ts +36 -0
  40. package/dist/runtime/subsystems/events/generated/registry.js +1 -1
  41. package/dist/runtime/subsystems/events/generated/schemas.d.ts +109 -1
  42. package/dist/runtime/subsystems/events/generated/schemas.js +7 -1
  43. package/dist/runtime/subsystems/events/generated/types.d.ts +48 -2
  44. package/dist/runtime/subsystems/events/index.js +5 -5
  45. package/dist/runtime/subsystems/index.d.ts +3 -2
  46. package/dist/runtime/subsystems/index.js +29 -25
  47. package/dist/runtime/subsystems/integration/execute-integration.use-case.d.ts +11 -1
  48. package/dist/runtime/subsystems/integration/execute-integration.use-case.js +2 -2
  49. package/dist/runtime/subsystems/integration/index.d.ts +2 -1
  50. package/dist/runtime/subsystems/integration/index.js +10 -8
  51. package/dist/runtime/subsystems/integration/integration-change-emitter.protocol.d.ts +106 -0
  52. package/dist/runtime/subsystems/integration/integration-change-emitter.protocol.js +1 -0
  53. package/dist/runtime/subsystems/integration/integration-change-emitter.protocol.js.map +1 -0
  54. package/dist/runtime/subsystems/integration/integration-cursor-store.drizzle-backend.js +2 -2
  55. package/dist/runtime/subsystems/integration/integration-run-recorder.drizzle-backend.js +2 -2
  56. package/dist/runtime/subsystems/integration/integration.module.js +4 -4
  57. package/dist/runtime/subsystems/integration/integration.tokens.d.ts +11 -1
  58. package/dist/runtime/subsystems/integration/integration.tokens.js +3 -1
  59. package/dist/runtime/subsystems/jobs/index.js +12 -12
  60. package/dist/runtime/subsystems/jobs/job-worker.d.ts +592 -4
  61. package/dist/runtime/subsystems/jobs/job-worker.js +3 -1
  62. package/dist/runtime/subsystems/jobs/job-worker.module.js +6 -6
  63. package/dist/runtime/subsystems/jobs/jobs-domain.module.d.ts +19 -0
  64. package/dist/runtime/subsystems/jobs/jobs-domain.module.js +4 -4
  65. package/dist/runtime/subsystems/observability/index.js +3 -3
  66. package/dist/runtime/subsystems/observability/observability.module.js +3 -3
  67. package/dist/runtime/subsystems/observability/observability.service.js +2 -2
  68. package/dist/src/cli/index.js +413 -85
  69. package/dist/src/cli/index.js.map +1 -1
  70. package/dist/src/index.d.ts +490 -1
  71. package/dist/src/index.js +7 -7
  72. package/package.json +1 -1
  73. package/runtime/subsystems/events/event-bus.drizzle-backend.ts +23 -7
  74. package/runtime/subsystems/events/generated/registry.ts +27 -0
  75. package/runtime/subsystems/events/generated/schemas.ts +26 -0
  76. package/runtime/subsystems/events/generated/types.ts +52 -0
  77. package/runtime/subsystems/index.ts +23 -0
  78. package/runtime/subsystems/integration/execute-integration.use-case.ts +69 -1
  79. package/runtime/subsystems/integration/index.ts +6 -0
  80. package/runtime/subsystems/integration/integration-change-emitter.protocol.ts +107 -0
  81. package/runtime/subsystems/integration/integration.tokens.ts +11 -0
  82. package/runtime/subsystems/jobs/job-worker.module.ts +5 -0
  83. package/runtime/subsystems/jobs/job-worker.ts +126 -12
  84. package/runtime/subsystems/jobs/jobs-domain.module.ts +19 -0
  85. package/templates/entity/new/clean-lite-ps/prompt-extension.js +59 -10
  86. package/templates/subsystem/jobs-config/codegen-config-jobs-block.ejs.t +11 -0
  87. package/dist/chunk-6DQEIXYU.js.map +0 -1
  88. package/dist/chunk-6ECCJVYW.js.map +0 -1
  89. package/dist/chunk-DB5UXJC3.js.map +0 -1
  90. package/dist/chunk-JOBQ6RUU.js.map +0 -1
  91. package/dist/chunk-JRQO2IOF.js.map +0 -1
  92. package/dist/chunk-QXVCRA23.js.map +0 -1
  93. package/dist/chunk-S7C6TIIF.js.map +0 -1
  94. package/dist/chunk-TDEHU73T.js.map +0 -1
  95. package/dist/chunk-VDL5CJ5C.js.map +0 -1
  96. /package/dist/{chunk-XKWOJZZ4.js.map → chunk-37PILMIT.js.map} +0 -0
  97. /package/dist/{chunk-NR7QQ6ZI.js.map → chunk-6M6LZEP6.js.map} +0 -0
  98. /package/dist/{chunk-NXHL5YII.js.map → chunk-7LKAMLV4.js.map} +0 -0
  99. /package/dist/{chunk-FFUDEIFF.js.map → chunk-HN5HT5WL.js.map} +0 -0
  100. /package/dist/{chunk-QFUIE37H.js.map → chunk-KFXXOFDC.js.map} +0 -0
  101. /package/dist/{chunk-O2A6XHGD.js.map → chunk-LLDJS7PJ.js.map} +0 -0
  102. /package/dist/{chunk-INO47JXD.js.map → chunk-PBENHIN2.js.map} +0 -0
  103. /package/dist/{chunk-CLWBNXKF.js.map → chunk-PLUJEQLU.js.map} +0 -0
  104. /package/dist/{chunk-FNHNSFIJ.js.map → chunk-WZOPWQN2.js.map} +0 -0
@@ -852,6 +852,29 @@ function processSearchQueries(queriesBlock, processedFields, belongsTo, entityNa
852
852
  // Integration write-surface derivation (#374)
853
853
  // ============================================================================
854
854
 
855
+ /**
856
+ * Shared delete-knob → softDelete boolean mapping rule (#490).
857
+ *
858
+ * Applied at BOTH derivations (repo config + sink body) so the two always agree:
859
+ * soft → true (set deletedAt)
860
+ * tombstone → false (null externalId/provider)
861
+ * absent → !!hasSoftDelete (preserve today's default)
862
+ * noop → !!hasSoftDelete (repo config irrelevant for noop — sink short-circuits)
863
+ *
864
+ * The sink only needs 'delegate' | 'noop' for its body decision; this helper
865
+ * is for the REPO config boolean. Mirrored verbatim in buildSinkInput caller
866
+ * (adapter-emission-generator.ts) for the contract test (spec Tests §3d).
867
+ *
868
+ * @param {'soft'|'tombstone'|'noop'|undefined} deleteKnob
869
+ * @param {boolean} hasSoftDelete
870
+ * @returns {boolean}
871
+ */
872
+ export function resolveSoftDeleteBoolean(deleteKnob, hasSoftDelete) {
873
+ if (deleteKnob === 'soft') return true;
874
+ if (deleteKnob === 'tombstone') return false;
875
+ return !!hasSoftDelete; // absent OR noop → preserve current default
876
+ }
877
+
855
878
  /**
856
879
  * Pre-compute the inbound-integration write surface for a `pattern: Integrated` entity.
857
880
  * Keeps the EJS thin + unit-testable: the template hand-emits the integrationConfig
@@ -866,14 +889,27 @@ function processSearchQueries(queriesBlock, processedFields, belongsTo, entityNa
866
889
  * @param {boolean} hasTimestamps
867
890
  * @param {boolean} eavEnabled
868
891
  * @param {boolean} hasSoftDelete
892
+ * @param {object} [fields] raw entity fields (for FK strict detection)
893
+ * @param {object} [sinkPolicy] integration.sink knobs {delete?, exclude_fields?}
869
894
  */
870
- export function buildIntegrationSurface(patternName, processedFields, belongsTo, hasTimestamps, eavEnabled, hasSoftDelete, fields) {
895
+ export function buildIntegrationSurface(patternName, processedFields, belongsTo, hasTimestamps, eavEnabled, hasSoftDelete, fields, sinkPolicy) {
871
896
  if (patternName !== 'Integrated') return null;
872
897
 
898
+ // Per-field exclusion (#490): drop declared-excluded fields from copy-through.
899
+ // Exclusion targets copy-through scalars only (FK columns and user_id are
900
+ // rejected at schema validation — the schema superRefine guards both).
901
+ // Match on snake_case `name` (how processedFields.name is keyed) so a
902
+ // multi-word field like `conversation_external_id` matches correctly.
903
+ const excludeSet = new Set(sinkPolicy?.exclude_fields ?? []);
904
+
873
905
  // Copy-through columns: every non-FK declared field. external_id_tracking
874
906
  // columns (external_id/provider/provider_metadata) are injected by the
875
907
  // behavior, NOT present in processedFields, so they're already excluded.
876
- const writeColumns = processedFields.map((f) => f.camelName);
908
+ // Excluded fields (#490) are also dropped here — they are removed from the
909
+ // copy-through write surface so integrationUpsertOne never clobbers them.
910
+ const writeColumns = processedFields
911
+ .filter((f) => !excludeSet.has(f.name))
912
+ .map((f) => f.camelName);
877
913
 
878
914
  // FK resolvers — one per belongs_to. writeKey = `${relationKey}ExternalId`
879
915
  // (Decision 4). refTable is the string 'self' for self-FKs, else the parent
@@ -896,12 +932,15 @@ export function buildIntegrationSurface(patternName, processedFields, belongsTo,
896
932
  importPath: rel.importPath,
897
933
  }));
898
934
 
899
- // Projection columns: id + externalId + copy-through + local FK columns +
900
- // timestamps. Omits provider/provider_metadata.
935
+ // Projection columns: id + externalId + ALL copy-through columns + local FK
936
+ // columns + timestamps. Omits provider/provider_metadata.
937
+ // Projection keeps excluded fields (#490) — exclusion is write-surface only.
938
+ // The find VIEW also keeps them (bare passthroughs); diff-soundness holds via
939
+ // the differ's `key in incoming` guard, not by omitting them from the view.
901
940
  const projectionColumns = [
902
941
  'id',
903
942
  'externalId',
904
- ...writeColumns,
943
+ ...processedFields.map((f) => f.camelName),
905
944
  ...belongsTo.map((rel) => rel.camelField),
906
945
  ...(hasTimestamps ? ['createdAt', 'updatedAt'] : []),
907
946
  ];
@@ -909,20 +948,26 @@ export function buildIntegrationSurface(patternName, processedFields, belongsTo,
909
948
  // The integrationConfig object literal the template hand-emits. fkResolvers carry a
910
949
  // sentinel so the template can swap `refTable` to either 'self' or the live
911
950
  // table identifier.
951
+ // softDelete: use resolveSoftDeleteBoolean (delete knob takes precedence over
952
+ // !!hasSoftDelete default; noop/absent both preserve !!hasSoftDelete, spec §Delete).
912
953
  const integrationConfig = {
913
954
  conflictTarget: ['provider', 'externalId'],
914
955
  writeColumns,
915
956
  projectionColumns,
916
957
  eav: !!eavEnabled,
917
- softDelete: !!hasSoftDelete,
958
+ softDelete: resolveSoftDeleteBoolean(sinkPolicy?.delete, hasSoftDelete),
918
959
  };
919
960
 
920
961
  // TIntegrationWrite fields: externalId:string, copy-through (typed, nullable-aware),
921
962
  // one `<writeKey>?: string | null` per FK, fields?: Record<string, unknown>.
922
- const writeFields = processedFields.map((f) => ({
923
- camelName: f.camelName,
924
- tsType: f.nullable ? `${f.tsType} | null` : f.tsType,
925
- }));
963
+ // Excluded fields (#490) are dropped from writeFields too — same exclusion set
964
+ // as writeColumns. The projection keeps them (projectionFields below).
965
+ const writeFields = processedFields
966
+ .filter((f) => !excludeSet.has(f.name))
967
+ .map((f) => ({
968
+ camelName: f.camelName,
969
+ tsType: f.nullable ? `${f.tsType} | null` : f.tsType,
970
+ }));
926
971
  const writeFkFields = fkResolvers.map((fk) => ({
927
972
  name: fk.writeKey,
928
973
  tsType: 'string | null',
@@ -1336,6 +1381,9 @@ export function buildCleanLitePsLocals(definition, baseLocals) {
1336
1381
  }));
1337
1382
 
1338
1383
  // Integration write-surface derivation (#374) — null unless pattern: Integrated.
1384
+ // Pass sinkPolicy (#490) so the delete knob and exclude_fields knob are applied
1385
+ // at this derivation (repo config) as well as buildSinkInput (sink derivation).
1386
+ const sinkPolicy = definition.integration?.sink ?? null;
1339
1387
  const integrationSurface = buildIntegrationSurface(
1340
1388
  patternName,
1341
1389
  nonFkFields,
@@ -1344,6 +1392,7 @@ export function buildCleanLitePsLocals(definition, baseLocals) {
1344
1392
  eavEnabled,
1345
1393
  hasSoftDelete,
1346
1394
  fields,
1395
+ sinkPolicy,
1347
1396
  );
1348
1397
 
1349
1398
  // EVT-7: emits locals flow through from baseLocals (prompt.js computed them
@@ -30,6 +30,17 @@ jobs:
30
30
  # # are simply never received and the worker
31
31
  # # degrades to polling.
32
32
  poll_interval_ms: 1000 # interval-poll heartbeat (the wake fallback)
33
+ # ── Claim lease / heartbeat (CLAIM-HB-1) ──
34
+ # A live worker renews `claimed_at` for its in-flight runs every
35
+ # `claim_heartbeat_interval_ms`, so a legitimately long-running handler is
36
+ # NEVER swept; only a row whose worker died ages past
37
+ # `stale_threshold_ms` and is reset to `pending` by the sweeper. Raise the
38
+ # threshold only if you expect worker-crash recovery to wait longer; the
39
+ # heartbeat (not the threshold) is what protects long handlers.
40
+ # stale_threshold_ms: 300000 # dead-worker recovery window (5 min)
41
+ # stale_sweeper_interval_ms: 60000 # how often the sweeper scans
42
+ # claim_heartbeat_interval_ms: 100000 # lease renewal cadence
43
+ # # (default = stale_threshold_ms / 3)
33
44
  # bullmq: # Example shape for Phase 6+ BullMQ backend.
34
45
  # bull_board: # Mount Bull Board admin UI.
35
46
  # enabled: true
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../runtime/subsystems/jobs/jobs-domain.module.ts"],"sourcesContent":["/**\n * JobsDomainModule — `DynamicModule.forRoot({ backend })` factory wiring\n * the three jobs-domain protocol tokens to a backend implementation\n * (ADR-022, JOB-5).\n *\n * Mirrors `EventsModule.forRoot()` exactly:\n * - `global: true` so consumer entity modules don't have to import this\n * individually — `JOB_ORCHESTRATOR` / `JOB_RUN_SERVICE` /\n * `JOB_STEP_SERVICE` are available project-wide.\n * - One backend at a time (Drizzle for production, Memory for tests).\n *\n * Backend swappability follows the core/extension protocol from CLAUDE.md:\n * the three tokens are the **core contract**; backend-specific tunables\n * live under `extensions.<backend>` so opting into a feature is explicit\n * and the type system reserves the slot.\n */\nimport { Module, type DynamicModule, type Provider } from '@nestjs/common';\nimport { DRIZZLE } from '../../constants/tokens';\nimport {\n JOB_ORCHESTRATOR,\n JOB_RUN_SERVICE,\n JOB_STEP_SERVICE,\n JOBS_MULTI_TENANT,\n JOBS_LISTEN_NOTIFY,\n} from './jobs-domain.tokens';\nimport { DrizzleJobOrchestrator } from './job-orchestrator.drizzle-backend';\nimport { DrizzleJobRunService } from './job-run-service.drizzle-backend';\nimport { DrizzleJobStepService } from './job-step-service.drizzle-backend';\n// #6 — `BullMQJobOrchestrator` is lazy-loaded only when `backend: 'bullmq'`\n// is selected. The backend file is filtered out of drizzle/memory installs\n// (see `backendFileFilter`); a non-literal dynamic import below sidesteps\n// consumer-side tsc resolution of an absent file.\nimport { MemoryJobOrchestrator } from './job-orchestrator.memory-backend';\nimport { MemoryJobRunService } from './job-run-service.memory-backend';\nimport { MemoryJobStepService } from './job-step-service.memory-backend';\nimport { MemoryJobStore } from './memory-job-store';\nimport {\n BULLMQ_CONNECTION,\n BULLMQ_RESOLVED_CONFIG,\n resolveBullMqConfig,\n type BullMqExtensionsConfig,\n} from './bullmq.config';\n\n/**\n * Drizzle backend extensions surface (LISTEN-NOTIFY-1 wires both fields).\n *\n * - `listenNotify` → provided as `JOBS_LISTEN_NOTIFY` so the orchestrator emits\n * in-tx `pg_notify` on enqueue, and threaded into each spawned `JobWorker`\n * (which holds the listener connection). Off by default.\n * - `pollIntervalMs` → threaded into the spawned `JobWorker`'s\n * `JobWorkerOptions.pollIntervalMs` (the worker already honored this; it just\n * never received a config value). Default 1000.\n *\n * Both run ALONGSIDE interval polling — `listenNotify` only adds an early wake;\n * polling remains the durability heartbeat.\n */\nexport interface DrizzleBackendExtensions {\n /** Use Postgres LISTEN/NOTIFY to wake the polling loop. Default false. */\n listenNotify?: boolean;\n /** Polling interval (ms). Default 1000. */\n pollIntervalMs?: number;\n}\n\nexport interface JobsDomainModuleOptions {\n backend: 'drizzle' | 'memory' | 'bullmq';\n /**\n * Backend-specific extensions. Only the matching backend's extensions\n * are read at boot; non-matching keys are ignored. This is the\n * core/extension protocol surface — see CLAUDE.md.\n */\n extensions?: {\n drizzle?: DrizzleBackendExtensions;\n /**\n * BullMQ backend extensions (BULLMQ-1). Snake_case mirrors the YAML\n * under `jobs.extensions.bullmq`. `redis_url` falls back to\n * `process.env.REDIS_URL` then `redis://localhost:6379`.\n */\n bullmq?: BullMqExtensionsConfig;\n };\n /** Multi-tenancy opt-in. Wired by JOB-8; module signature stays stable. */\n multiTenant?: boolean;\n}\n\n@Module({})\nexport class JobsDomainModule {\n static forRoot(opts: JobsDomainModuleOptions): DynamicModule {\n const multiTenant = opts.multiTenant ?? false;\n // LISTEN-NOTIFY-1 — drizzle-only extension. `listen_notify` is meaningless\n // for memory (no DB) and redundant for bullmq (native wakeups); only the\n // drizzle backend's orchestrator reads it.\n const listenNotify =\n opts.backend === 'drizzle' && Boolean(opts.extensions?.drizzle?.listenNotify);\n\n const providers: Provider[] = [\n // JOB-8 — boolean provider consumed by the four service-layer backends.\n // Always provided (even when `multiTenant === false`) so `@Inject`\n // always resolves; backends short-circuit the enforcement path when\n // the value is `false`. See `jobs-domain.tokens.ts` for the claim-loop\n // cross-tenant-by-design decision.\n { provide: JOBS_MULTI_TENANT, useValue: multiTenant },\n // LISTEN-NOTIFY-1 — always provided so the orchestrator's `@Inject`\n // resolves; the orchestrator skips the `pg_notify` emit when `false`.\n { provide: JOBS_LISTEN_NOTIFY, useValue: listenNotify },\n ];\n\n if (opts.backend === 'memory') {\n // The store is a plain class — wired as a singleton `useValue` so\n // unit tests can pull it out via `.get(MemoryJobStore)` for direct\n // assertions (matches the access pattern in JOB-4 specs).\n const store = new MemoryJobStore();\n providers.push({ provide: MemoryJobStore, useValue: store });\n providers.push(MemoryJobStepService);\n providers.push({ provide: JOB_STEP_SERVICE, useExisting: MemoryJobStepService });\n providers.push(MemoryJobOrchestrator);\n providers.push({ provide: JOB_ORCHESTRATOR, useExisting: MemoryJobOrchestrator });\n providers.push(MemoryJobRunService);\n providers.push({ provide: JOB_RUN_SERVICE, useExisting: MemoryJobRunService });\n } else if (opts.backend === 'bullmq') {\n // BULLMQ-1 — BullMQ orchestrator over a Postgres source of truth. The\n // run/step services stay Drizzle (domain reads + `listForScope` are\n // Postgres queries, unchanged per spec). Only the orchestrator's\n // claim/dispatch half swaps to BullMQ.\n //\n // #6 — the bullmq backend module is filtered out of drizzle/memory\n // installs (no `bullmq` peer dep, no consumer-side tsc compile of an\n // unused file). The factory below dynamic-imports it via a non-literal\n // specifier so TS treats the module type as `any` and never tries to\n // resolve the absent file on a drizzle/memory consumer.\n const resolved = resolveBullMqConfig(opts.extensions?.bullmq);\n providers.push({ provide: BULLMQ_CONNECTION, useValue: resolved.connection });\n providers.push({ provide: BULLMQ_RESOLVED_CONFIG, useValue: resolved });\n providers.push({\n provide: JOB_ORCHESTRATOR,\n useFactory: async (...args: unknown[]): Promise<object> => {\n const specifier = './job-orchestrator.bullmq-backend';\n const mod = (await import(specifier)) as {\n BullMQJobOrchestrator: new (...args: unknown[]) => object;\n };\n return new mod.BullMQJobOrchestrator(...args);\n },\n // The bullmq orchestrator constructor mirrors DrizzleJobOrchestrator's\n // injection list: DRIZZLE + JOBS_MULTI_TENANT + the resolved BullMQ\n // tokens. Importing token references would force a static dep on the\n // tokens file in this module's import graph; using the existing\n // symbols already in scope is sufficient.\n inject: [DRIZZLE, JOBS_MULTI_TENANT, BULLMQ_CONNECTION, BULLMQ_RESOLVED_CONFIG],\n });\n providers.push({ provide: JOB_RUN_SERVICE, useClass: DrizzleJobRunService });\n providers.push({ provide: JOB_STEP_SERVICE, useClass: DrizzleJobStepService });\n } else {\n providers.push({ provide: JOB_ORCHESTRATOR, useClass: DrizzleJobOrchestrator });\n providers.push({ provide: JOB_RUN_SERVICE, useClass: DrizzleJobRunService });\n providers.push({ provide: JOB_STEP_SERVICE, useClass: DrizzleJobStepService });\n }\n\n const exports = [\n JOB_ORCHESTRATOR,\n JOB_RUN_SERVICE,\n JOB_STEP_SERVICE,\n JOBS_MULTI_TENANT,\n JOBS_LISTEN_NOTIFY,\n ];\n // BULLMQ-1 — only export the BullMQ tokens when they were actually\n // provided. Nest throws \"exported but not provided\" otherwise. Exported so\n // JobWorkerModule (which imports this module) can read the resolved\n // connection/config to spawn BullMQ workers.\n if (opts.backend === 'bullmq') {\n exports.push(BULLMQ_CONNECTION, BULLMQ_RESOLVED_CONFIG);\n }\n\n return {\n module: JobsDomainModule,\n global: true,\n providers,\n exports,\n };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBA,SAAS,cAAiD;AAoEnD,IAAM,mBAAN,MAAuB;AAAA,EAC5B,OAAO,QAAQ,MAA8C;AAC3D,UAAM,cAAc,KAAK,eAAe;AAIxC,UAAM,eACJ,KAAK,YAAY,aAAa,QAAQ,KAAK,YAAY,SAAS,YAAY;AAE9E,UAAM,YAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAM5B,EAAE,SAAS,mBAAmB,UAAU,YAAY;AAAA;AAAA;AAAA,MAGpD,EAAE,SAAS,oBAAoB,UAAU,aAAa;AAAA,IACxD;AAEA,QAAI,KAAK,YAAY,UAAU;AAI7B,YAAM,QAAQ,IAAI,eAAe;AACjC,gBAAU,KAAK,EAAE,SAAS,gBAAgB,UAAU,MAAM,CAAC;AAC3D,gBAAU,KAAK,oBAAoB;AACnC,gBAAU,KAAK,EAAE,SAAS,kBAAkB,aAAa,qBAAqB,CAAC;AAC/E,gBAAU,KAAK,qBAAqB;AACpC,gBAAU,KAAK,EAAE,SAAS,kBAAkB,aAAa,sBAAsB,CAAC;AAChF,gBAAU,KAAK,mBAAmB;AAClC,gBAAU,KAAK,EAAE,SAAS,iBAAiB,aAAa,oBAAoB,CAAC;AAAA,IAC/E,WAAW,KAAK,YAAY,UAAU;AAWpC,YAAM,WAAW,oBAAoB,KAAK,YAAY,MAAM;AAC5D,gBAAU,KAAK,EAAE,SAAS,mBAAmB,UAAU,SAAS,WAAW,CAAC;AAC5E,gBAAU,KAAK,EAAE,SAAS,wBAAwB,UAAU,SAAS,CAAC;AACtE,gBAAU,KAAK;AAAA,QACb,SAAS;AAAA,QACT,YAAY,UAAU,SAAqC;AACzD,gBAAM,YAAY;AAClB,gBAAM,MAAO,MAAM,OAAO;AAG1B,iBAAO,IAAI,IAAI,sBAAsB,GAAG,IAAI;AAAA,QAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMA,QAAQ,CAAC,SAAS,mBAAmB,mBAAmB,sBAAsB;AAAA,MAChF,CAAC;AACD,gBAAU,KAAK,EAAE,SAAS,iBAAiB,UAAU,qBAAqB,CAAC;AAC3E,gBAAU,KAAK,EAAE,SAAS,kBAAkB,UAAU,sBAAsB,CAAC;AAAA,IAC/E,OAAO;AACL,gBAAU,KAAK,EAAE,SAAS,kBAAkB,UAAU,uBAAuB,CAAC;AAC9E,gBAAU,KAAK,EAAE,SAAS,iBAAiB,UAAU,qBAAqB,CAAC;AAC3E,gBAAU,KAAK,EAAE,SAAS,kBAAkB,UAAU,sBAAsB,CAAC;AAAA,IAC/E;AAEA,UAAM,UAAU;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAKA,QAAI,KAAK,YAAY,UAAU;AAC7B,cAAQ,KAAK,mBAAmB,sBAAsB;AAAA,IACxD;AAEA,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AA7Fa,mBAAN;AAAA,EADN,OAAO,CAAC,CAAC;AAAA,GACG;","names":[]}