@pattern-stack/codegen 0.23.0 → 0.25.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 (109) hide show
  1. package/CHANGELOG.md +51 -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-2VHZ7EKC.js → chunk-5AAA4LTE.js} +2 -2
  5. package/dist/{chunk-42763UEE.js → chunk-6M6LZEP6.js} +2 -2
  6. package/dist/{chunk-AS3NAZB6.js → chunk-B7SC2V45.js} +2 -2
  7. package/dist/{chunk-W72PRNJY.js → chunk-BPYZCEHS.js} +2 -2
  8. package/dist/{chunk-FIUC6QB5.js → chunk-CKLM57IE.js} +10 -10
  9. package/dist/{chunk-KYR3B3OW.js → chunk-DAHWN63L.js} +26 -5
  10. package/dist/chunk-DAHWN63L.js.map +1 -0
  11. package/dist/{chunk-SH76CFAY.js → chunk-ENAR3F5S.js} +2 -2
  12. package/dist/{chunk-RFH7N6EP.js → chunk-FCPTHS42.js} +2 -2
  13. package/dist/{chunk-FFUDEIFF.js → chunk-HN5HT5WL.js} +2 -2
  14. package/dist/{chunk-4M66MQYA.js → chunk-K4BQQ2NN.js} +4 -2
  15. package/dist/chunk-K4BQQ2NN.js.map +1 -0
  16. package/dist/{chunk-QFUIE37H.js → chunk-KFXXOFDC.js} +4 -4
  17. package/dist/{chunk-O2A6XHGD.js → chunk-LLDJS7PJ.js} +2 -2
  18. package/dist/{chunk-JOBQ6RUU.js → chunk-LQZESSM3.js} +28 -1
  19. package/dist/chunk-LQZESSM3.js.map +1 -0
  20. package/dist/{chunk-JRQO2IOF.js → chunk-MU54DZCC.js} +27 -1
  21. package/dist/chunk-MU54DZCC.js.map +1 -0
  22. package/dist/{chunk-INO47JXD.js → chunk-PBENHIN2.js} +3 -3
  23. package/dist/{chunk-CLWBNXKF.js → chunk-PLUJEQLU.js} +2 -2
  24. package/dist/{chunk-S7C6TIIF.js → chunk-S5G3HO7N.js} +3 -1
  25. package/dist/chunk-S5G3HO7N.js.map +1 -0
  26. package/dist/{chunk-JYBFPNBJ.js → chunk-SJGEBMJT.js} +2 -2
  27. package/dist/{chunk-6XP2Q5SS.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/base-classes/activity-entity-service.js +3 -3
  31. package/dist/runtime/base-classes/base-service.js +2 -2
  32. package/dist/runtime/base-classes/index.js +20 -20
  33. package/dist/runtime/base-classes/integrated-entity-service.js +3 -3
  34. package/dist/runtime/base-classes/knowledge-entity-service.js +3 -3
  35. package/dist/runtime/base-classes/lifecycle-events.js +1 -1
  36. package/dist/runtime/base-classes/metadata-entity-service.js +3 -3
  37. package/dist/runtime/subsystems/auth/auth.module.js +1 -1
  38. package/dist/runtime/subsystems/auth/index.js +3 -3
  39. package/dist/runtime/subsystems/bridge/bridge.module.js +6 -6
  40. package/dist/runtime/subsystems/bridge/index.js +6 -6
  41. package/dist/runtime/subsystems/events/events.module.js +4 -4
  42. package/dist/runtime/subsystems/events/generated/bus.js +3 -3
  43. package/dist/runtime/subsystems/events/generated/index.d.ts +2 -2
  44. package/dist/runtime/subsystems/events/generated/index.js +9 -3
  45. package/dist/runtime/subsystems/events/generated/registry.d.ts +36 -0
  46. package/dist/runtime/subsystems/events/generated/registry.js +1 -1
  47. package/dist/runtime/subsystems/events/generated/schemas.d.ts +109 -1
  48. package/dist/runtime/subsystems/events/generated/schemas.js +7 -1
  49. package/dist/runtime/subsystems/events/generated/types.d.ts +48 -2
  50. package/dist/runtime/subsystems/events/index.js +4 -4
  51. package/dist/runtime/subsystems/index.d.ts +3 -2
  52. package/dist/runtime/subsystems/index.js +25 -21
  53. package/dist/runtime/subsystems/integration/execute-integration.use-case.d.ts +11 -1
  54. package/dist/runtime/subsystems/integration/execute-integration.use-case.js +2 -2
  55. package/dist/runtime/subsystems/integration/index.d.ts +2 -1
  56. package/dist/runtime/subsystems/integration/index.js +10 -8
  57. package/dist/runtime/subsystems/integration/integration-change-emitter.protocol.d.ts +106 -0
  58. package/dist/runtime/subsystems/integration/integration-change-emitter.protocol.js +1 -0
  59. package/dist/runtime/subsystems/integration/integration-change-emitter.protocol.js.map +1 -0
  60. package/dist/runtime/subsystems/integration/integration-cursor-store.drizzle-backend.js +2 -2
  61. package/dist/runtime/subsystems/integration/integration-run-recorder.drizzle-backend.js +2 -2
  62. package/dist/runtime/subsystems/integration/integration.module.js +4 -4
  63. package/dist/runtime/subsystems/integration/integration.tokens.d.ts +11 -1
  64. package/dist/runtime/subsystems/integration/integration.tokens.js +3 -1
  65. package/dist/runtime/subsystems/jobs/index.js +11 -11
  66. package/dist/runtime/subsystems/jobs/job-worker.module.js +5 -5
  67. package/dist/runtime/subsystems/jobs/jobs-domain.module.js +4 -4
  68. package/dist/runtime/subsystems/observability/index.js +3 -3
  69. package/dist/runtime/subsystems/observability/observability.module.js +3 -3
  70. package/dist/runtime/subsystems/observability/observability.service.js +2 -2
  71. package/dist/src/cli/index.js +300 -53
  72. package/dist/src/cli/index.js.map +1 -1
  73. package/dist/src/index.d.ts +13 -0
  74. package/dist/src/index.js +7 -7
  75. package/package.json +1 -1
  76. package/runtime/base-classes/lifecycle-events.ts +39 -6
  77. package/runtime/subsystems/events/generated/registry.ts +27 -0
  78. package/runtime/subsystems/events/generated/schemas.ts +26 -0
  79. package/runtime/subsystems/events/generated/types.ts +52 -0
  80. package/runtime/subsystems/index.ts +23 -0
  81. package/runtime/subsystems/integration/execute-integration.use-case.ts +69 -1
  82. package/runtime/subsystems/integration/index.ts +6 -0
  83. package/runtime/subsystems/integration/integration-change-emitter.protocol.ts +107 -0
  84. package/runtime/subsystems/integration/integration.tokens.ts +11 -0
  85. package/templates/subsystem/jobs/job-orchestration.schema.ejs.t +1 -0
  86. package/templates/subsystem/jobs/main-hook.ejs.t +1 -1
  87. package/templates/subsystem/jobs/prompt.js +40 -2
  88. package/templates/subsystem/jobs/worker.ejs.t +47 -35
  89. package/dist/chunk-4M66MQYA.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-KYR3B3OW.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-XKWOJZZ4.js.map → chunk-37PILMIT.js.map} +0 -0
  96. /package/dist/{chunk-2VHZ7EKC.js.map → chunk-5AAA4LTE.js.map} +0 -0
  97. /package/dist/{chunk-42763UEE.js.map → chunk-6M6LZEP6.js.map} +0 -0
  98. /package/dist/{chunk-AS3NAZB6.js.map → chunk-B7SC2V45.js.map} +0 -0
  99. /package/dist/{chunk-W72PRNJY.js.map → chunk-BPYZCEHS.js.map} +0 -0
  100. /package/dist/{chunk-FIUC6QB5.js.map → chunk-CKLM57IE.js.map} +0 -0
  101. /package/dist/{chunk-SH76CFAY.js.map → chunk-ENAR3F5S.js.map} +0 -0
  102. /package/dist/{chunk-RFH7N6EP.js.map → chunk-FCPTHS42.js.map} +0 -0
  103. /package/dist/{chunk-FFUDEIFF.js.map → chunk-HN5HT5WL.js.map} +0 -0
  104. /package/dist/{chunk-QFUIE37H.js.map → chunk-KFXXOFDC.js.map} +0 -0
  105. /package/dist/{chunk-O2A6XHGD.js.map → chunk-LLDJS7PJ.js.map} +0 -0
  106. /package/dist/{chunk-INO47JXD.js.map → chunk-PBENHIN2.js.map} +0 -0
  107. /package/dist/{chunk-CLWBNXKF.js.map → chunk-PLUJEQLU.js.map} +0 -0
  108. /package/dist/{chunk-JYBFPNBJ.js.map → chunk-SJGEBMJT.js.map} +0 -0
  109. /package/dist/{chunk-6XP2Q5SS.js.map → chunk-WZOPWQN2.js.map} +0 -0
@@ -9,9 +9,10 @@
9
9
  * Invoked via:
10
10
  * bunx hygen subsystem jobs \
11
11
  * --workerPath <abs> --workerExists <'true'|''> \
12
+ * --jobWorkerModuleImport <specifier> --workerForRootOpts <ts-literal> \
12
13
  * --mainTsPath <abs> --configPath <abs> --schemaPath <abs> \
13
14
  * --multiTenant <'true'|'false'> --workerMode <embedded|standalone> \
14
- * --appName <string>
15
+ * --skipSchema <'true'|''> --appName <string>
15
16
  */
16
17
 
17
18
  import { renderGeneratedBanner } from "../../_shared/generated-banner.mjs";
@@ -23,6 +24,28 @@ function coerceBool(raw) {
23
24
  return false;
24
25
  }
25
26
 
27
+ // #513: the CLI base64-encodes --workerForRootOpts because Hygen's yargs parser
28
+ // mangles a raw `{ mode: 'standalone', … }` TS literal (the braces/colons are
29
+ // read as nested object syntax). Decode it back to the source string here. A
30
+ // direct hygen invocation that passes a non-encoded value (or omits it) falls
31
+ // back to the plain default below.
32
+ function decodeWorkerForRootOpts(raw) {
33
+ if (typeof raw !== "string" || raw.length === 0) {
34
+ return "{ mode: 'standalone', allPools: true }";
35
+ }
36
+ try {
37
+ const decoded = Buffer.from(raw, "base64").toString("utf-8");
38
+ // Re-encoding round-trips iff `raw` was valid base64 of the decoded bytes;
39
+ // guards against a hand-passed plain literal being treated as base64.
40
+ if (Buffer.from(decoded, "utf-8").toString("base64") === raw) {
41
+ return decoded;
42
+ }
43
+ } catch {
44
+ /* fall through to raw */
45
+ }
46
+ return raw;
47
+ }
48
+
26
49
  export default {
27
50
  prompt: async ({ args }) => {
28
51
  return {
@@ -34,9 +57,24 @@ export default {
34
57
  // Hygen's skip_if treats any non-empty string as truthy, so we send an
35
58
  // empty string when the file doesn't exist (CLI already does this).
36
59
  workerExists: args.workerExists ?? "",
37
- workerPath: args.workerPath ?? "worker.ts",
60
+ // #513: the worker lands at `src/worker.ts` (inside the default tsconfig
61
+ // include, next to `app.module.ts`); the CLI always passes an absolute
62
+ // --workerPath, this fallback only guards a direct hygen invocation.
63
+ workerPath: args.workerPath ?? "src/worker.ts",
64
+ // #513: mode-aware JobWorkerModule import + the pre-serialised
65
+ // forRoot(<opts>) literal (the only mode-dependent import the worker
66
+ // carries — AppModule is imported relatively).
67
+ jobWorkerModuleImport:
68
+ args.jobWorkerModuleImport ??
69
+ "@pattern-stack/codegen/runtime/subsystems/jobs/index",
70
+ workerForRootOpts: decodeWorkerForRootOpts(args.workerForRootOpts),
38
71
  schemaPath:
39
72
  args.schemaPath ?? "shared/subsystems/jobs/job-orchestration.schema.ts",
73
+ // #517: package mode skips the schema template (the schema ships in the
74
+ // package, re-exported via the schema barrel). Hygen's skip_if treats any
75
+ // non-empty string as truthy, so the CLI sends '' in vendored mode and
76
+ // 'true' in package mode. Default '' so a direct hygen invocation renders.
77
+ skipSchema: args.skipSchema ?? "",
40
78
  // @generated DO-NOT-EDIT banner — the jobs subsystem schema is
41
79
  // force-overwritten on every `subsystem install`.
42
80
  generatedBanner: renderGeneratedBanner({
@@ -5,31 +5,42 @@ unless_exists: true
5
5
  /**
6
6
  * Standalone job worker entrypoint — emitted by `codegen subsystem install jobs`.
7
7
  *
8
- * Boots a Nest application context (NO HTTP listener) wiring the full
9
- * subsystem barrel (`SUBSYSTEM_MODULES` events + jobs + bridge + integration, in
10
- * dependency order) plus `JobWorkerModule.forRoot({ mode: 'standalone',
11
- * allPools: true })`. Run with:
8
+ * Boots a Nest application context (NO HTTP listener) that composes the
9
+ * consumer's root `AppModule` plus `JobWorkerModule.forRoot({ mode:
10
+ * 'standalone', allPools: true, … })`. Run with:
12
11
  *
13
- * bun worker.ts
12
+ * bun src/worker.ts
14
13
  *
15
- * Why the barrel + `allPools`:
16
- * - The events subsystem's outbox drain and the bridge's fanout wrappers
17
- * run as `job_run` rows in the RESERVED `events_*` pools. A worker that
18
- * only polls the non-reserved pools (`interactive`, `batch`, …) leaves
19
- * those lanes stranded `BridgeDeliveryHandler` never fires and durable
20
- * event→job fanout silently stops.
14
+ * Why import `AppModule` whole:
15
+ * - Job handlers are Nest providers registered by the consumer's handler
16
+ * modules (and the subsystem barrel). Composing around `AppModule` gives
17
+ * this worker the SAME DI graph as the HTTP process — every `@JobHandler`
18
+ * resolves its dependencies here exactly as it would in the API. A bare
19
+ * `SUBSYSTEM_MODULES`-only worker boots with an empty handler surface.
20
+ * - `AppModule` already wires `DatabaseModule` + `SUBSYSTEM_MODULES` (events +
21
+ * jobs + bridge + integration, dependency-ordered), so the worker needs no
22
+ * mode-aware barrel import — only `JobWorkerModule` itself.
23
+ *
24
+ * Why `allPools: true`:
25
+ * - The events subsystem's outbox drain and the bridge's fanout wrappers run
26
+ * as `job_run` rows in the RESERVED `events_*` pools. A worker that only
27
+ * polls the non-reserved pools (`interactive`, `batch`, …) strands those
28
+ * lanes — `BridgeDeliveryHandler` never fires and durable event→job fanout
29
+ * silently stops.
21
30
  * - `allPools: true` activates every pool in the resolved config, reserved
22
31
  * lanes included, so this single standalone process drains both user work
23
32
  * and the framework's reserved lanes.
24
- * - Importing `SUBSYSTEM_MODULES` (rather than `JobsDomainModule` alone)
25
- * registers `EVENT_BUS` / `JOB_ORCHESTRATOR` / `BRIDGE_*` so the
26
- * framework `@framework/bridge_delivery` handler resolves its DI deps.
27
- * `BridgeModule`'s reserved-pool guard short-circuits to pass because
28
- * `allPools` is set.
29
33
  *
30
- * Embedded mode (single-process) is configured by importing
31
- * `JobWorkerModule.forRoot({ mode: 'embedded' })` inside AppModule instead
32
- * see the commented guidance injected into `src/main.ts`.
34
+ * STANDALONE ONLY: this entrypoint is for `jobs.worker_mode: standalone`. In
35
+ * embedded mode the worker already runs inside `AppModule` (via the
36
+ * `JobWorkerModule.forRoot({ mode: 'embedded' })` the barrel composes), so
37
+ * booting this file too would double-spawn the worker against the same pools.
38
+ *
39
+ * DO NOT boot `AppModule` twice in one process: a consumer `AppModule`
40
+ * registers an OpenAPI document against the per-process `OpenApiRegistry`
41
+ * singleton, which throws `DuplicateSchemaError` on the second registration.
42
+ * Multi-rung boot validation (e.g. "does the worker boot AND does the API
43
+ * boot?") must spawn CHILD PROCESSES, not import both modules into one.
33
44
  *
34
45
  * SIGTERM triggers graceful shutdown bounded by SHUTDOWN_TIMEOUT_MS; after the
35
46
  * timeout the process exits hard so orchestrators (systemd, Kubernetes) can
@@ -39,26 +50,23 @@ import 'reflect-metadata';
39
50
  import { Logger, Module } from '@nestjs/common';
40
51
  import { NestFactory } from '@nestjs/core';
41
52
 
42
- import { DatabaseModule } from '@shared/database/database.module';
43
- import { JobWorkerModule } from '@shared/subsystems/jobs/job-worker.module';
44
- import { SUBSYSTEM_MODULES } from '@generated/subsystems';
53
+ import { AppModule } from './app.module';
54
+ import { JobWorkerModule } from '<%= jobWorkerModuleImport %>';
45
55
 
46
56
  const SHUTDOWN_TIMEOUT_MS = 30_000;
47
57
 
48
58
  @Module({
49
59
  imports: [
50
- DatabaseModule,
51
- // Events + Jobs + Bridge + Integration (dependency-ordered) from the generated
52
- // barrel. This is the same composition AppModule imports — keeping the
53
- // worker's DI graph identical to the HTTP app's so handlers resolve the
54
- // same way in both processes.
55
- ...SUBSYSTEM_MODULES,
60
+ // Consumer root — DatabaseModule + SUBSYSTEM_MODULES + handler modules.
61
+ // Importing it whole keeps the worker's DI graph identical to the HTTP app's
62
+ // so every `@JobHandler` resolves the same way in both processes.
63
+ AppModule,
56
64
  // `allPools: true` drains the reserved `events_*` lanes (events outbox +
57
65
  // bridge wrappers) alongside the user pools.
58
- JobWorkerModule.forRoot({ mode: 'standalone', allPools: true }),
66
+ JobWorkerModule.forRoot(<%- workerForRootOpts %>),
59
67
  ],
60
68
  })
61
- class WorkerAppModule {}
69
+ export class WorkerAppModule {}
62
70
 
63
71
  async function bootstrap(): Promise<void> {
64
72
  const logger = new Logger('JobWorker');
@@ -98,8 +106,12 @@ async function bootstrap(): Promise<void> {
98
106
  logger.log('job worker started (standalone mode, all pools)');
99
107
  }
100
108
 
101
- bootstrap().catch((err) => {
102
- // eslint-disable-next-line no-console
103
- console.error('failed to bootstrap job worker', err);
104
- process.exit(1);
105
- });
109
+ // Gated so the module can be imported by boot-checks / e2e without spawning a
110
+ // worker; `bun src/worker.ts` runs it as the entrypoint.
111
+ if (import.meta.main) {
112
+ bootstrap().catch((err) => {
113
+ // eslint-disable-next-line no-console
114
+ console.error('failed to bootstrap job worker', err);
115
+ process.exit(1);
116
+ });
117
+ }