@pattern-stack/codegen 0.24.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 (30) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/{chunk-2VHZ7EKC.js → chunk-5AAA4LTE.js} +2 -2
  3. package/dist/{chunk-AS3NAZB6.js → chunk-B7SC2V45.js} +2 -2
  4. package/dist/{chunk-W72PRNJY.js → chunk-BPYZCEHS.js} +2 -2
  5. package/dist/{chunk-KYR3B3OW.js → chunk-DAHWN63L.js} +26 -5
  6. package/dist/chunk-DAHWN63L.js.map +1 -0
  7. package/dist/{chunk-RFH7N6EP.js → chunk-FCPTHS42.js} +2 -2
  8. package/dist/{chunk-JYBFPNBJ.js → chunk-SJGEBMJT.js} +2 -2
  9. package/dist/runtime/base-classes/activity-entity-service.js +3 -3
  10. package/dist/runtime/base-classes/base-service.js +2 -2
  11. package/dist/runtime/base-classes/index.js +26 -26
  12. package/dist/runtime/base-classes/integrated-entity-service.js +3 -3
  13. package/dist/runtime/base-classes/knowledge-entity-service.js +3 -3
  14. package/dist/runtime/base-classes/lifecycle-events.js +1 -1
  15. package/dist/runtime/base-classes/metadata-entity-service.js +3 -3
  16. package/dist/runtime/subsystems/index.js +1 -1
  17. package/dist/src/cli/index.js +97 -27
  18. package/dist/src/cli/index.js.map +1 -1
  19. package/package.json +1 -1
  20. package/runtime/base-classes/lifecycle-events.ts +39 -6
  21. package/templates/subsystem/jobs/job-orchestration.schema.ejs.t +1 -0
  22. package/templates/subsystem/jobs/main-hook.ejs.t +1 -1
  23. package/templates/subsystem/jobs/prompt.js +40 -2
  24. package/templates/subsystem/jobs/worker.ejs.t +47 -35
  25. package/dist/chunk-KYR3B3OW.js.map +0 -1
  26. /package/dist/{chunk-2VHZ7EKC.js.map → chunk-5AAA4LTE.js.map} +0 -0
  27. /package/dist/{chunk-AS3NAZB6.js.map → chunk-B7SC2V45.js.map} +0 -0
  28. /package/dist/{chunk-W72PRNJY.js.map → chunk-BPYZCEHS.js.map} +0 -0
  29. /package/dist/{chunk-RFH7N6EP.js.map → chunk-FCPTHS42.js.map} +0 -0
  30. /package/dist/{chunk-JYBFPNBJ.js.map → chunk-SJGEBMJT.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,34 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.25.0] — 2026-06-07
6
+
7
+ ### Fixed
8
+
9
+ - **Lifecycle events: revive the audit trail + diagnosable emit failures.** The
10
+ `BaseService` lifecycle/change event path (`runtime/base-classes/lifecycle-events.ts`)
11
+ predates the AUDIT tier + routing schema (ADR-039) and was never migrated:
12
+ `buildLifecycleEvent` / `buildChangeEvents` stamped no `tier`, so
13
+ `toInsertValues` defaulted the row to `tier='domain'` with NULL `pool` /
14
+ `direction` — which violates the `domain_events_tier_routing_check` CHECK
15
+ (`tier='audit' ⇔ pool IS NULL AND direction IS NULL`). Result: **every**
16
+ `BaseService` create/update/delete in every consumer paid a rejected INSERT and
17
+ silently lost its lifecycle audit trail. The builders now stamp `tier: 'audit'`
18
+ (lifecycle/change events are exactly audit-tier semantics — untyped audit
19
+ records, never bridge-routed); the rows land and surface under the
20
+ observability viewer's audit-tier toggle, and the bridge guard keeps them out
21
+ of job routing. Discovered by the swe-brain dogfood (2× `failed to emit 3
22
+ event(s)` per dispatcher fire — the 3 being the `[updated, field_changed,
23
+ field_changed]` `publishMany` batch from `BaseService.update`).
24
+ - **Lifecycle events: `emitSafely` logs the cause via the Nest Logger.** The
25
+ fire-and-forget catch was a bare `catch {}` that swallowed the error and
26
+ printed `failed to emit N event(s)` via raw `console.warn` — bypassing the Nest
27
+ `Logger` (so consumers configuring `app.useLogger` / factory `logger:` could
28
+ neither format nor filter it) with zero diagnosability. Now logs via a
29
+ module-level `Logger('LifecycleEvents')` at `warn` level including the event
30
+ count, the distinct event types, and the error message; the stack follows at
31
+ `debug`. Never-throw semantics preserved.
32
+
5
33
  ## [0.24.0] — 2026-06-06
6
34
 
7
35
  ### Added
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BaseService
3
- } from "./chunk-W72PRNJY.js";
3
+ } from "./chunk-BPYZCEHS.js";
4
4
 
5
5
  // runtime/base-classes/integrated-entity-service.ts
6
6
  var IntegratedEntityService = class extends BaseService {
@@ -34,4 +34,4 @@ var IntegratedEntityService = class extends BaseService {
34
34
  export {
35
35
  IntegratedEntityService
36
36
  };
37
- //# sourceMappingURL=chunk-2VHZ7EKC.js.map
37
+ //# sourceMappingURL=chunk-5AAA4LTE.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BaseService
3
- } from "./chunk-W72PRNJY.js";
3
+ } from "./chunk-BPYZCEHS.js";
4
4
 
5
5
  // runtime/base-classes/knowledge-entity-service.ts
6
6
  var KnowledgeEntityService = class extends BaseService {
@@ -11,4 +11,4 @@ var KnowledgeEntityService = class extends BaseService {
11
11
  export {
12
12
  KnowledgeEntityService
13
13
  };
14
- //# sourceMappingURL=chunk-AS3NAZB6.js.map
14
+ //# sourceMappingURL=chunk-B7SC2V45.js.map
@@ -4,7 +4,7 @@ import {
4
4
  diffSnapshots,
5
5
  emitSafely,
6
6
  entitySnapshot
7
- } from "./chunk-KYR3B3OW.js";
7
+ } from "./chunk-DAHWN63L.js";
8
8
 
9
9
  // runtime/base-classes/base-service.ts
10
10
  var BaseService = class {
@@ -123,4 +123,4 @@ var BaseService = class {
123
123
  export {
124
124
  BaseService
125
125
  };
126
- //# sourceMappingURL=chunk-W72PRNJY.js.map
126
+ //# sourceMappingURL=chunk-BPYZCEHS.js.map
@@ -1,5 +1,7 @@
1
1
  // runtime/base-classes/lifecycle-events.ts
2
2
  import { randomUUID } from "crypto";
3
+ import { Logger } from "@nestjs/common";
4
+ var logger = new Logger("LifecycleEvents");
3
5
  var SYSTEM_FIELDS = /* @__PURE__ */ new Set([
4
6
  "id",
5
7
  "createdAt",
@@ -36,7 +38,17 @@ function buildLifecycleEvent(entityName, action, entityId, snapshot) {
36
38
  aggregateType: entityName,
37
39
  payload: snapshot ? { snapshot } : {},
38
40
  occurredAt: /* @__PURE__ */ new Date(),
39
- metadata: { category: "lifecycle" }
41
+ // AUDIT tier: lifecycle/change events are untyped audit-trail records —
42
+ // never bridge-routed, no pool/direction. The `domain_events`
43
+ // `domain_events_tier_routing_check` CHECK requires `tier='audit' ⇔
44
+ // (pool IS NULL AND direction IS NULL)`; the DEFAULT `tier='domain'`
45
+ // (applied by toInsertValues when absent) requires non-null routing
46
+ // fields, so an un-tiered lifecycle row violates the constraint and the
47
+ // INSERT is rejected — silently, pre-fix, by emitSafely's catch. Stamp
48
+ // `tier:'audit'` so these rows land (and surface under the
49
+ // observability viewer's audit-tier toggle). The bridge guard keeps
50
+ // audit-tier events out of job routing.
51
+ metadata: { category: "lifecycle", tier: "audit" }
40
52
  };
41
53
  }
42
54
  function buildChangeEvents(entityName, entityId, changes) {
@@ -51,7 +63,9 @@ function buildChangeEvents(entityName, entityId, changes) {
51
63
  newValue: c.newValue
52
64
  },
53
65
  occurredAt: /* @__PURE__ */ new Date(),
54
- metadata: { category: "change" }
66
+ // AUDIT tier see buildLifecycleEvent. Change events are audit-trail
67
+ // records; tier:'audit' satisfies the tier-routing CHECK constraint.
68
+ metadata: { category: "change", tier: "audit" }
55
69
  }));
56
70
  }
57
71
  async function emitSafely(eventBus, events) {
@@ -64,8 +78,15 @@ async function emitSafely(eventBus, events) {
64
78
  } else {
65
79
  await eventBus.publishMany(events);
66
80
  }
67
- } catch {
68
- console.warn(`[lifecycle-events] failed to emit ${events.length} event(s)`);
81
+ } catch (err) {
82
+ const message = err instanceof Error ? err.message : String(err);
83
+ const types = [...new Set(events.map((e) => e.type))].join(", ");
84
+ logger.warn(
85
+ `failed to emit ${events.length} event(s) [${types}]: ${message}`
86
+ );
87
+ if (err instanceof Error && err.stack) {
88
+ logger.debug(err.stack);
89
+ }
69
90
  }
70
91
  }
71
92
 
@@ -76,4 +97,4 @@ export {
76
97
  buildChangeEvents,
77
98
  emitSafely
78
99
  };
79
- //# sourceMappingURL=chunk-KYR3B3OW.js.map
100
+ //# sourceMappingURL=chunk-DAHWN63L.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../runtime/base-classes/lifecycle-events.ts"],"sourcesContent":["/**\n * Lifecycle event emission for BaseService.\n *\n * Ported from pattern-stack/atoms/patterns/services/base.py — the Python\n * BaseService emits LIFECYCLE and CHANGE events on every CRUD operation.\n * This module provides the same capability for the TypeScript codegen stack.\n *\n * Design:\n * - Fire-and-forget: event emission never fails the CRUD operation.\n * - IEventBus is optional: if no EVENT_BUS is injected, emission is silently\n * skipped. This means base classes work in projects that haven't installed\n * the events subsystem.\n * - LIFECYCLE events carry an entity snapshot in payload.\n * - CHANGE events carry per-field old/new diffs.\n * - Controlled per-entity via `emitLifecycleEvents` flag (default: true).\n *\n * @deprecated EVT-7 — Lifecycle events are untyped and emit outside of the\n * CRUD transaction. New work should declare an `emits:` block on the entity\n * and publish typed domain events from use-cases via TYPED_EVENT_BUS inside\n * the same Drizzle transaction. See `docs/specs/EVT-7.md`. This helper is\n * retained for BaseService backward compatibility until all entities have\n * migrated to typed emits.\n */\n\nimport { randomUUID } from 'crypto';\nimport { Logger } from '@nestjs/common';\nimport type { IEventBus, DomainEvent } from '../subsystems/events/event-bus.protocol';\n\n/**\n * Module-level logger for fire-and-forget emission failures. Routed through the\n * Nest `Logger` (not bare `console`) so consumers configuring `app.useLogger`\n * or the factory `logger:` option can format and filter it like any other\n * framework log line.\n */\nconst logger = new Logger('LifecycleEvents');\n\n// ============================================================================\n// Event categories (subset of pattern-stack's EventCategory)\n// ============================================================================\n\nexport type EventCategory = 'lifecycle' | 'change';\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/** System fields excluded from entity snapshots and change diffs. */\nconst SYSTEM_FIELDS = new Set([\n\t'id',\n\t'createdAt',\n\t'updatedAt',\n\t'deletedAt',\n]);\n\n/**\n * Snapshot an entity's field values, excluding system fields.\n * Mirrors pattern-stack's `_get_entity_snapshot()`.\n */\nexport function entitySnapshot(entity: Record<string, unknown>): Record<string, unknown> {\n\tconst snap: Record<string, unknown> = {};\n\tfor (const [key, value] of Object.entries(entity)) {\n\t\tif (!SYSTEM_FIELDS.has(key)) {\n\t\t\tsnap[key] = value;\n\t\t}\n\t}\n\treturn snap;\n}\n\n/**\n * Diff two entity snapshots, returning per-field old/new pairs.\n * Only includes fields that actually changed.\n */\nexport function diffSnapshots(\n\tbefore: Record<string, unknown>,\n\tafter: Record<string, unknown>,\n): Array<{ field: string; oldValue: unknown; newValue: unknown }> {\n\tconst changes: Array<{ field: string; oldValue: unknown; newValue: unknown }> = [];\n\tconst allKeys = new Set([...Object.keys(before), ...Object.keys(after)]);\n\n\tfor (const key of allKeys) {\n\t\tif (SYSTEM_FIELDS.has(key)) continue;\n\t\tconst oldVal = before[key];\n\t\tconst newVal = after[key];\n\t\t// Simple equality — good enough for primitives and nulls.\n\t\t// For deep objects, JSON.stringify comparison.\n\t\tif (oldVal !== newVal && JSON.stringify(oldVal) !== JSON.stringify(newVal)) {\n\t\t\tchanges.push({ field: key, oldValue: oldVal, newValue: newVal });\n\t\t}\n\t}\n\n\treturn changes;\n}\n\n// ============================================================================\n// Event builders\n// ============================================================================\n\nexport function buildLifecycleEvent(\n\tentityName: string,\n\taction: 'created' | 'updated' | 'deleted',\n\tentityId: string,\n\tsnapshot?: Record<string, unknown>,\n): DomainEvent {\n\treturn {\n\t\tid: randomUUID(),\n\t\ttype: `${entityName}.${action}`,\n\t\taggregateId: entityId,\n\t\taggregateType: entityName,\n\t\tpayload: snapshot ? { snapshot } : {},\n\t\toccurredAt: new Date(),\n\t\t// AUDIT tier: lifecycle/change events are untyped audit-trail records —\n\t\t// never bridge-routed, no pool/direction. The `domain_events`\n\t\t// `domain_events_tier_routing_check` CHECK requires `tier='audit' ⇔\n\t\t// (pool IS NULL AND direction IS NULL)`; the DEFAULT `tier='domain'`\n\t\t// (applied by toInsertValues when absent) requires non-null routing\n\t\t// fields, so an un-tiered lifecycle row violates the constraint and the\n\t\t// INSERT is rejected — silently, pre-fix, by emitSafely's catch. Stamp\n\t\t// `tier:'audit'` so these rows land (and surface under the\n\t\t// observability viewer's audit-tier toggle). The bridge guard keeps\n\t\t// audit-tier events out of job routing.\n\t\tmetadata: { category: 'lifecycle' as EventCategory, tier: 'audit' },\n\t};\n}\n\nexport function buildChangeEvents(\n\tentityName: string,\n\tentityId: string,\n\tchanges: Array<{ field: string; oldValue: unknown; newValue: unknown }>,\n): DomainEvent[] {\n\treturn changes.map((c) => ({\n\t\tid: randomUUID(),\n\t\ttype: `${entityName}.field_changed`,\n\t\taggregateId: entityId,\n\t\taggregateType: entityName,\n\t\tpayload: {\n\t\t\tfieldName: c.field,\n\t\t\toldValue: c.oldValue,\n\t\t\tnewValue: c.newValue,\n\t\t},\n\t\toccurredAt: new Date(),\n\t\t// AUDIT tier — see buildLifecycleEvent. Change events are audit-trail\n\t\t// records; tier:'audit' satisfies the tier-routing CHECK constraint.\n\t\tmetadata: { category: 'change' as EventCategory, tier: 'audit' },\n\t}));\n}\n\n// ============================================================================\n// Emission helper (fire-and-forget)\n// ============================================================================\n\n/**\n * Emit events to the bus, swallowing errors.\n * Mirrors pattern-stack's `_emit_lifecycle_event()` try/except.\n */\nexport async function emitSafely(\n\teventBus: IEventBus | undefined,\n\tevents: DomainEvent[],\n): Promise<void> {\n\tif (!eventBus || events.length === 0) return;\n\ttry {\n\t\tif (events.length === 1) {\n\t\t\tconst only = events[0];\n\t\t\tif (!only) return;\n\t\t\tawait eventBus.publish(only);\n\t\t} else {\n\t\t\tawait eventBus.publishMany(events);\n\t\t}\n\t} catch (err) {\n\t\t// Never fail the CRUD operation — but surface the cause. The bare\n\t\t// `catch` that used to live here swallowed the error entirely, so a\n\t\t// failing bus printed `failed to emit N event(s)` with zero\n\t\t// diagnosability. Route through the Nest Logger (not bare console) at\n\t\t// warn level, including the distinct event types and the error message;\n\t\t// the stack follows at debug so it's available without noising the\n\t\t// default-threshold output.\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tconst types = [...new Set(events.map((e) => e.type))].join(', ');\n\t\tlogger.warn(\n\t\t\t`failed to emit ${events.length} event(s) [${types}]: ${message}`,\n\t\t);\n\t\tif (err instanceof Error && err.stack) {\n\t\t\tlogger.debug(err.stack);\n\t\t}\n\t}\n}\n"],"mappings":";AAwBA,SAAS,kBAAkB;AAC3B,SAAS,cAAc;AASvB,IAAM,SAAS,IAAI,OAAO,iBAAiB;AAa3C,IAAM,gBAAgB,oBAAI,IAAI;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAC;AAMM,SAAS,eAAe,QAA0D;AACxF,QAAM,OAAgC,CAAC;AACvC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AAClD,QAAI,CAAC,cAAc,IAAI,GAAG,GAAG;AAC5B,WAAK,GAAG,IAAI;AAAA,IACb;AAAA,EACD;AACA,SAAO;AACR;AAMO,SAAS,cACf,QACA,OACiE;AACjE,QAAM,UAA0E,CAAC;AACjF,QAAM,UAAU,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,CAAC,CAAC;AAEvE,aAAW,OAAO,SAAS;AAC1B,QAAI,cAAc,IAAI,GAAG,EAAG;AAC5B,UAAM,SAAS,OAAO,GAAG;AACzB,UAAM,SAAS,MAAM,GAAG;AAGxB,QAAI,WAAW,UAAU,KAAK,UAAU,MAAM,MAAM,KAAK,UAAU,MAAM,GAAG;AAC3E,cAAQ,KAAK,EAAE,OAAO,KAAK,UAAU,QAAQ,UAAU,OAAO,CAAC;AAAA,IAChE;AAAA,EACD;AAEA,SAAO;AACR;AAMO,SAAS,oBACf,YACA,QACA,UACA,UACc;AACd,SAAO;AAAA,IACN,IAAI,WAAW;AAAA,IACf,MAAM,GAAG,UAAU,IAAI,MAAM;AAAA,IAC7B,aAAa;AAAA,IACb,eAAe;AAAA,IACf,SAAS,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,IACpC,YAAY,oBAAI,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAWrB,UAAU,EAAE,UAAU,aAA8B,MAAM,QAAQ;AAAA,EACnE;AACD;AAEO,SAAS,kBACf,YACA,UACA,SACgB;AAChB,SAAO,QAAQ,IAAI,CAAC,OAAO;AAAA,IAC1B,IAAI,WAAW;AAAA,IACf,MAAM,GAAG,UAAU;AAAA,IACnB,aAAa;AAAA,IACb,eAAe;AAAA,IACf,SAAS;AAAA,MACR,WAAW,EAAE;AAAA,MACb,UAAU,EAAE;AAAA,MACZ,UAAU,EAAE;AAAA,IACb;AAAA,IACA,YAAY,oBAAI,KAAK;AAAA;AAAA;AAAA,IAGrB,UAAU,EAAE,UAAU,UAA2B,MAAM,QAAQ;AAAA,EAChE,EAAE;AACH;AAUA,eAAsB,WACrB,UACA,QACgB;AAChB,MAAI,CAAC,YAAY,OAAO,WAAW,EAAG;AACtC,MAAI;AACH,QAAI,OAAO,WAAW,GAAG;AACxB,YAAM,OAAO,OAAO,CAAC;AACrB,UAAI,CAAC,KAAM;AACX,YAAM,SAAS,QAAQ,IAAI;AAAA,IAC5B,OAAO;AACN,YAAM,SAAS,YAAY,MAAM;AAAA,IAClC;AAAA,EACD,SAAS,KAAK;AAQb,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,UAAM,QAAQ,CAAC,GAAG,IAAI,IAAI,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,EAAE,KAAK,IAAI;AAC/D,WAAO;AAAA,MACN,kBAAkB,OAAO,MAAM,cAAc,KAAK,MAAM,OAAO;AAAA,IAChE;AACA,QAAI,eAAe,SAAS,IAAI,OAAO;AACtC,aAAO,MAAM,IAAI,KAAK;AAAA,IACvB;AAAA,EACD;AACD;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BaseService
3
- } from "./chunk-W72PRNJY.js";
3
+ } from "./chunk-BPYZCEHS.js";
4
4
 
5
5
  // runtime/base-classes/metadata-entity-service.ts
6
6
  var MetadataEntityService = class extends BaseService {
@@ -33,4 +33,4 @@ var MetadataEntityService = class extends BaseService {
33
33
  export {
34
34
  MetadataEntityService
35
35
  };
36
- //# sourceMappingURL=chunk-RFH7N6EP.js.map
36
+ //# sourceMappingURL=chunk-FCPTHS42.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BaseService
3
- } from "./chunk-W72PRNJY.js";
3
+ } from "./chunk-BPYZCEHS.js";
4
4
 
5
5
  // runtime/base-classes/activity-entity-service.ts
6
6
  var ActivityEntityService = class extends BaseService {
@@ -33,4 +33,4 @@ var ActivityEntityService = class extends BaseService {
33
33
  export {
34
34
  ActivityEntityService
35
35
  };
36
- //# sourceMappingURL=chunk-JYBFPNBJ.js.map
36
+ //# sourceMappingURL=chunk-SJGEBMJT.js.map
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  ActivityEntityService
3
- } from "../../chunk-JYBFPNBJ.js";
4
- import "../../chunk-W72PRNJY.js";
5
- import "../../chunk-KYR3B3OW.js";
3
+ } from "../../chunk-SJGEBMJT.js";
4
+ import "../../chunk-BPYZCEHS.js";
5
+ import "../../chunk-DAHWN63L.js";
6
6
  import "../../chunk-2E224ZSN.js";
7
7
  export {
8
8
  ActivityEntityService
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  BaseService
3
- } from "../../chunk-W72PRNJY.js";
4
- import "../../chunk-KYR3B3OW.js";
3
+ } from "../../chunk-BPYZCEHS.js";
4
+ import "../../chunk-DAHWN63L.js";
5
5
  import "../../chunk-2E224ZSN.js";
6
6
  export {
7
7
  BaseService
@@ -1,3 +1,15 @@
1
+ import {
2
+ MetadataEntityService
3
+ } from "../../chunk-FCPTHS42.js";
4
+ import {
5
+ WithAnalytics
6
+ } from "../../chunk-IBGER4YK.js";
7
+ import {
8
+ IntegratedEntityRepository
9
+ } from "../../chunk-OTDN3OUQ.js";
10
+ import {
11
+ IntegratedEntityService
12
+ } from "../../chunk-5AAA4LTE.js";
1
13
  import {
2
14
  JunctionIntegrationRepository,
3
15
  buildCompositeExternalId,
@@ -8,42 +20,20 @@ import {
8
20
  } from "../../chunk-NN7XZEGF.js";
9
21
  import {
10
22
  KnowledgeEntityService
11
- } from "../../chunk-AS3NAZB6.js";
23
+ } from "../../chunk-B7SC2V45.js";
12
24
  import {
13
25
  MetadataEntityRepository
14
26
  } from "../../chunk-7KOW6PU6.js";
15
27
  import {
16
- MetadataEntityService
17
- } from "../../chunk-RFH7N6EP.js";
18
- import {
19
- WithAnalytics
20
- } from "../../chunk-IBGER4YK.js";
28
+ ActivityEntityRepository
29
+ } from "../../chunk-MKWQKKK7.js";
21
30
  import {
22
31
  ActivityEntityService
23
- } from "../../chunk-JYBFPNBJ.js";
32
+ } from "../../chunk-SJGEBMJT.js";
24
33
  import {
25
34
  BaseFindByIdUseCase,
26
35
  BaseListUseCase
27
36
  } from "../../chunk-EXVDJMIY.js";
28
- import {
29
- IntegratedEntityRepository
30
- } from "../../chunk-OTDN3OUQ.js";
31
- import {
32
- IntegratedEntityService
33
- } from "../../chunk-2VHZ7EKC.js";
34
- import {
35
- BaseService
36
- } from "../../chunk-W72PRNJY.js";
37
- import {
38
- buildChangeEvents,
39
- buildLifecycleEvent,
40
- diffSnapshots,
41
- emitSafely,
42
- entitySnapshot
43
- } from "../../chunk-KYR3B3OW.js";
44
- import {
45
- ActivityEntityRepository
46
- } from "../../chunk-MKWQKKK7.js";
47
37
  import {
48
38
  BaseRepository
49
39
  } from "../../chunk-J6KZS54B.js";
@@ -56,6 +46,16 @@ import {
56
46
  withSuperuserScope,
57
47
  withUserScope
58
48
  } from "../../chunk-ZUKFQL6E.js";
49
+ import {
50
+ BaseService
51
+ } from "../../chunk-BPYZCEHS.js";
52
+ import {
53
+ buildChangeEvents,
54
+ buildLifecycleEvent,
55
+ diffSnapshots,
56
+ emitSafely,
57
+ entitySnapshot
58
+ } from "../../chunk-DAHWN63L.js";
59
59
  import "../../chunk-2E224ZSN.js";
60
60
  export {
61
61
  ActivityEntityRepository,
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  IntegratedEntityService
3
- } from "../../chunk-2VHZ7EKC.js";
4
- import "../../chunk-W72PRNJY.js";
5
- import "../../chunk-KYR3B3OW.js";
3
+ } from "../../chunk-5AAA4LTE.js";
4
+ import "../../chunk-BPYZCEHS.js";
5
+ import "../../chunk-DAHWN63L.js";
6
6
  import "../../chunk-2E224ZSN.js";
7
7
  export {
8
8
  IntegratedEntityService
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  KnowledgeEntityService
3
- } from "../../chunk-AS3NAZB6.js";
4
- import "../../chunk-W72PRNJY.js";
5
- import "../../chunk-KYR3B3OW.js";
3
+ } from "../../chunk-B7SC2V45.js";
4
+ import "../../chunk-BPYZCEHS.js";
5
+ import "../../chunk-DAHWN63L.js";
6
6
  import "../../chunk-2E224ZSN.js";
7
7
  export {
8
8
  KnowledgeEntityService
@@ -4,7 +4,7 @@ import {
4
4
  diffSnapshots,
5
5
  emitSafely,
6
6
  entitySnapshot
7
- } from "../../chunk-KYR3B3OW.js";
7
+ } from "../../chunk-DAHWN63L.js";
8
8
  import "../../chunk-2E224ZSN.js";
9
9
  export {
10
10
  buildChangeEvents,
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  MetadataEntityService
3
- } from "../../chunk-RFH7N6EP.js";
4
- import "../../chunk-W72PRNJY.js";
5
- import "../../chunk-KYR3B3OW.js";
3
+ } from "../../chunk-FCPTHS42.js";
4
+ import "../../chunk-BPYZCEHS.js";
5
+ import "../../chunk-DAHWN63L.js";
6
6
  import "../../chunk-2E224ZSN.js";
7
7
  export {
8
8
  MetadataEntityService
@@ -1,4 +1,3 @@
1
- import "../../chunk-W4HOHZVF.js";
2
1
  import "../../chunk-ZUMULSEQ.js";
3
2
  import {
4
3
  StorageModule
@@ -27,6 +26,7 @@ import {
27
26
  OBSERVABILITY_MODULE_OPTIONS
28
27
  } from "../../chunk-Y7RRSEOC.js";
29
28
  import "../../chunk-PLUJEQLU.js";
29
+ import "../../chunk-W4HOHZVF.js";
30
30
  import "../../chunk-SYVZ4MD2.js";
31
31
  import {
32
32
  EventsModule
@@ -7408,7 +7408,7 @@ function resolveJobsScaffoldLocals(input) {
7408
7408
  const { cwd, config, fileExists, readFile } = input;
7409
7409
  const jobsBlock = config?.jobs ?? {};
7410
7410
  const subsystemsRoot = resolveSubsystemsRootFromConfig(cwd, config);
7411
- const workerPath = path16.resolve(cwd, "worker.ts");
7411
+ const workerPath = path16.resolve(cwd, "src", "worker.ts");
7412
7412
  const mainTsPath = path16.resolve(cwd, "src/main.ts");
7413
7413
  const configPath = path16.resolve(cwd, "codegen.config.yaml");
7414
7414
  const schemaPath = path16.resolve(
@@ -7426,10 +7426,37 @@ function resolveJobsScaffoldLocals(input) {
7426
7426
  configPath,
7427
7427
  workerExists: fileExists(workerPath),
7428
7428
  workerPath,
7429
+ jobWorkerModuleImport: resolveJobWorkerModuleImport(config),
7430
+ workerForRootOpts: resolveWorkerForRootOpts(jobsBlock),
7429
7431
  schemaPath,
7430
- mainHookInjected
7432
+ mainHookInjected,
7433
+ // #517 — in package mode the schema ships in the package (consumed via the
7434
+ // schema barrel), so the template is skipped; vendored mode renders it.
7435
+ skipSchema: resolveRuntimeMode(config) === "package"
7431
7436
  };
7432
7437
  }
7438
+ function resolveJobWorkerModuleImport(config) {
7439
+ return runtimeImport(resolveRuntimeMode(config), "subsystems/jobs/index");
7440
+ }
7441
+ function resolveWorkerForRootOpts(jobsBlock) {
7442
+ const backend = jobsBlock.backend ?? "drizzle";
7443
+ const parts = [`mode: 'standalone'`];
7444
+ if (backend === "bullmq") {
7445
+ parts.push(`backend: 'bullmq'`);
7446
+ const bullExt = jobsBlock.extensions?.bullmq;
7447
+ if (bullExt) {
7448
+ parts.push(`domainModuleExtensions: { bullmq: ${jsonToTs(bullExt)} }`);
7449
+ }
7450
+ } else {
7451
+ const workerExtClause = drizzleExtensionsClause(
7452
+ drizzleJobsExtensions(backend, jobsBlock),
7453
+ "domainModuleExtensions"
7454
+ );
7455
+ if (workerExtClause) parts.push(workerExtClause);
7456
+ }
7457
+ parts.push(`allPools: true`);
7458
+ return `{ ${parts.join(", ")} }`;
7459
+ }
7433
7460
  function normaliseWorkerMode(raw) {
7434
7461
  if (raw === "standalone") return "standalone";
7435
7462
  return "embedded";
@@ -7437,6 +7464,9 @@ function normaliseWorkerMode(raw) {
7437
7464
  function normaliseMultiTenant2(raw) {
7438
7465
  return raw === true;
7439
7466
  }
7467
+ function encodeWorkerForRootOpts(opts) {
7468
+ return Buffer.from(opts, "utf-8").toString("base64");
7469
+ }
7440
7470
  function localsToHygenArgs2(locals) {
7441
7471
  return [
7442
7472
  "--appName",
@@ -7453,10 +7483,19 @@ function localsToHygenArgs2(locals) {
7453
7483
  workerSkipValue(locals.workerExists),
7454
7484
  "--workerPath",
7455
7485
  locals.workerPath,
7486
+ "--jobWorkerModuleImport",
7487
+ locals.jobWorkerModuleImport,
7488
+ "--workerForRootOpts",
7489
+ encodeWorkerForRootOpts(locals.workerForRootOpts),
7456
7490
  "--schemaPath",
7457
7491
  locals.schemaPath,
7458
7492
  "--mainHookInjected",
7459
- workerSkipValue(locals.mainHookInjected)
7493
+ workerSkipValue(locals.mainHookInjected),
7494
+ // #517 — boolean-ish for `skip_if` (same '' / 'true' encoding as
7495
+ // workerExists / mainHookInjected). 'true' in package mode → the schema
7496
+ // template is skipped (the package ships the schema).
7497
+ "--skipSchema",
7498
+ workerSkipValue(locals.skipSchema)
7460
7499
  ];
7461
7500
  }
7462
7501
 
@@ -8314,6 +8353,12 @@ var SubsystemInstallCommand = class extends Command3 {
8314
8353
  return 1;
8315
8354
  }
8316
8355
  if (this.dryRun) {
8356
+ const jobsScaffoldDryRun = desc.name === "jobs" ? runJobsScaffold(ctx.cwd, ctx.config, {
8357
+ dryRun: true,
8358
+ json: isJsonMode(),
8359
+ forceConfig: this.forceConfig,
8360
+ skipConfigBlock: true
8361
+ }) : null;
8317
8362
  if (isJsonMode()) {
8318
8363
  printJson({
8319
8364
  command: "subsystem install",
@@ -8321,7 +8366,8 @@ var SubsystemInstallCommand = class extends Command3 {
8321
8366
  runtime: "package",
8322
8367
  dryRun: true,
8323
8368
  installList: already ? installed : [...installed, desc.name],
8324
- configBlockOutcome
8369
+ configBlockOutcome,
8370
+ ...jobsScaffoldDryRun ? { scaffold: jobsScaffoldDryRun } : {}
8325
8371
  });
8326
8372
  } else {
8327
8373
  printInfo(`Dry run \u2014 runtime: package (no files vendored).`);
@@ -8330,6 +8376,14 @@ var SubsystemInstallCommand = class extends Command3 {
8330
8376
  printInfo(` ${desc.name} config block would be ${configBlockOutcome}`);
8331
8377
  }
8332
8378
  printInfo(" would regenerate <generated>/subsystems.ts + subsystems-schema.ts");
8379
+ if (jobsScaffoldDryRun?.planned?.length) {
8380
+ printInfo(
8381
+ ` jobs scaffold \u2014 ${jobsScaffoldDryRun.planned.length} template targets (worker + main.ts hook; schema ships in the package)`
8382
+ );
8383
+ for (const p of jobsScaffoldDryRun.planned) {
8384
+ console.log(` ${theme.muted(icons.arrow)} ${path24.relative(ctx.cwd, p) || p}`);
8385
+ }
8386
+ }
8333
8387
  }
8334
8388
  return 0;
8335
8389
  }
@@ -8374,6 +8428,12 @@ var SubsystemInstallCommand = class extends Command3 {
8374
8428
  const msg = err instanceof Error ? err.message : String(err);
8375
8429
  printWarning(`barrel regeneration failed \u2014 ${msg}`);
8376
8430
  }
8431
+ const jobsScaffold = desc.name === "jobs" ? runJobsScaffold(ctx.cwd, refreshed.config, {
8432
+ dryRun: false,
8433
+ json: isJsonMode(),
8434
+ forceConfig: this.forceConfig,
8435
+ skipConfigBlock: true
8436
+ }) : null;
8377
8437
  if (isJsonMode()) {
8378
8438
  printJson({
8379
8439
  command: "subsystem install",
@@ -8385,7 +8445,8 @@ var SubsystemInstallCommand = class extends Command3 {
8385
8445
  installOutcome: installResult.outcome,
8386
8446
  configBlockOutcome,
8387
8447
  barrelEmitted,
8388
- schemaEmitted
8448
+ schemaEmitted,
8449
+ ...jobsScaffold ? { scaffold: jobsScaffold } : {}
8389
8450
  });
8390
8451
  return 0;
8391
8452
  }
@@ -8393,6 +8454,17 @@ var SubsystemInstallCommand = class extends Command3 {
8393
8454
  if (installResult.outcome === "added") {
8394
8455
  printInfo(`Added '${desc.name}' to subsystems.install.`);
8395
8456
  }
8457
+ if (jobsScaffold) {
8458
+ if (jobsScaffold.ok) {
8459
+ printSuccess(
8460
+ `jobs scaffold applied (emitted src/worker.ts + src/main.ts hook; schema ships in the package).`
8461
+ );
8462
+ } else {
8463
+ printWarning(
8464
+ `jobs scaffold (Hygen) failed \u2014 config + barrels were written; re-run after fixing: ${jobsScaffold.error ?? "unknown error"}`
8465
+ );
8466
+ }
8467
+ }
8396
8468
  printInfo(
8397
8469
  `Regenerated <generated>/subsystems.ts (${barrelEmitted.join(", ") || "none"}) + subsystems-schema.ts (${schemaEmitted.join(", ") || "none"}).`
8398
8470
  );
@@ -8622,14 +8694,10 @@ function runJobsScaffold(cwd, config, opts) {
8622
8694
  const planned = [
8623
8695
  ...!locals.workerExists ? [locals.workerPath] : [],
8624
8696
  locals.mainTsPath,
8625
- locals.configPath,
8626
- locals.schemaPath
8697
+ ...opts.skipConfigBlock ? [] : [locals.configPath],
8698
+ ...locals.skipSchema ? [] : [locals.schemaPath]
8627
8699
  ];
8628
- const configBlockOutcome = planConfigBlockAction(
8629
- locals.configPath,
8630
- "jobs",
8631
- opts.forceConfig
8632
- );
8700
+ const configBlockOutcome = opts.skipConfigBlock ? void 0 : planConfigBlockAction(locals.configPath, "jobs", opts.forceConfig);
8633
8701
  if (configBlockOutcome === "parse-error") {
8634
8702
  return { ok: false, planned, configBlockOutcome };
8635
8703
  }
@@ -8652,21 +8720,23 @@ function runJobsScaffold(cwd, config, opts) {
8652
8720
  configBlockOutcome
8653
8721
  };
8654
8722
  }
8655
- const configResult = runConfigBlockAction({
8656
- cwd,
8657
- actionFolder: "jobs-config",
8658
- configPath: locals.configPath,
8659
- subsystem: "jobs",
8660
- outcome: configBlockOutcome,
8661
- json: opts.json
8662
- });
8663
- if (!configResult.ok) {
8664
- return {
8665
- ok: false,
8666
- planned,
8667
- error: configResult.error,
8668
- configBlockOutcome
8669
- };
8723
+ if (!opts.skipConfigBlock && configBlockOutcome) {
8724
+ const configResult = runConfigBlockAction({
8725
+ cwd,
8726
+ actionFolder: "jobs-config",
8727
+ configPath: locals.configPath,
8728
+ subsystem: "jobs",
8729
+ outcome: configBlockOutcome,
8730
+ json: opts.json
8731
+ });
8732
+ if (!configResult.ok) {
8733
+ return {
8734
+ ok: false,
8735
+ planned,
8736
+ error: configResult.error,
8737
+ configBlockOutcome
8738
+ };
8739
+ }
8670
8740
  }
8671
8741
  return { ok: true, planned, configBlockOutcome };
8672
8742
  }