@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.
- package/CHANGELOG.md +51 -1
- package/consumer-skills/integration/SKILL.md +11 -3
- package/dist/{chunk-XKWOJZZ4.js → chunk-37PILMIT.js} +4 -4
- package/dist/{chunk-2VHZ7EKC.js → chunk-5AAA4LTE.js} +2 -2
- package/dist/{chunk-42763UEE.js → chunk-6M6LZEP6.js} +2 -2
- package/dist/{chunk-AS3NAZB6.js → chunk-B7SC2V45.js} +2 -2
- package/dist/{chunk-W72PRNJY.js → chunk-BPYZCEHS.js} +2 -2
- package/dist/{chunk-FIUC6QB5.js → chunk-CKLM57IE.js} +10 -10
- package/dist/{chunk-KYR3B3OW.js → chunk-DAHWN63L.js} +26 -5
- package/dist/chunk-DAHWN63L.js.map +1 -0
- package/dist/{chunk-SH76CFAY.js → chunk-ENAR3F5S.js} +2 -2
- package/dist/{chunk-RFH7N6EP.js → chunk-FCPTHS42.js} +2 -2
- package/dist/{chunk-FFUDEIFF.js → chunk-HN5HT5WL.js} +2 -2
- package/dist/{chunk-4M66MQYA.js → chunk-K4BQQ2NN.js} +4 -2
- package/dist/chunk-K4BQQ2NN.js.map +1 -0
- package/dist/{chunk-QFUIE37H.js → chunk-KFXXOFDC.js} +4 -4
- package/dist/{chunk-O2A6XHGD.js → chunk-LLDJS7PJ.js} +2 -2
- package/dist/{chunk-JOBQ6RUU.js → chunk-LQZESSM3.js} +28 -1
- package/dist/chunk-LQZESSM3.js.map +1 -0
- package/dist/{chunk-JRQO2IOF.js → chunk-MU54DZCC.js} +27 -1
- package/dist/chunk-MU54DZCC.js.map +1 -0
- package/dist/{chunk-INO47JXD.js → chunk-PBENHIN2.js} +3 -3
- package/dist/{chunk-CLWBNXKF.js → chunk-PLUJEQLU.js} +2 -2
- package/dist/{chunk-S7C6TIIF.js → chunk-S5G3HO7N.js} +3 -1
- package/dist/chunk-S5G3HO7N.js.map +1 -0
- package/dist/{chunk-JYBFPNBJ.js → chunk-SJGEBMJT.js} +2 -2
- package/dist/{chunk-6XP2Q5SS.js → chunk-WZOPWQN2.js} +2 -2
- package/dist/{chunk-TDEHU73T.js → chunk-YIVQ7KLS.js} +46 -5
- package/dist/chunk-YIVQ7KLS.js.map +1 -0
- package/dist/runtime/base-classes/activity-entity-service.js +3 -3
- package/dist/runtime/base-classes/base-service.js +2 -2
- package/dist/runtime/base-classes/index.js +20 -20
- package/dist/runtime/base-classes/integrated-entity-service.js +3 -3
- package/dist/runtime/base-classes/knowledge-entity-service.js +3 -3
- package/dist/runtime/base-classes/lifecycle-events.js +1 -1
- package/dist/runtime/base-classes/metadata-entity-service.js +3 -3
- package/dist/runtime/subsystems/auth/auth.module.js +1 -1
- package/dist/runtime/subsystems/auth/index.js +3 -3
- package/dist/runtime/subsystems/bridge/bridge.module.js +6 -6
- package/dist/runtime/subsystems/bridge/index.js +6 -6
- package/dist/runtime/subsystems/events/events.module.js +4 -4
- package/dist/runtime/subsystems/events/generated/bus.js +3 -3
- package/dist/runtime/subsystems/events/generated/index.d.ts +2 -2
- package/dist/runtime/subsystems/events/generated/index.js +9 -3
- package/dist/runtime/subsystems/events/generated/registry.d.ts +36 -0
- package/dist/runtime/subsystems/events/generated/registry.js +1 -1
- package/dist/runtime/subsystems/events/generated/schemas.d.ts +109 -1
- package/dist/runtime/subsystems/events/generated/schemas.js +7 -1
- package/dist/runtime/subsystems/events/generated/types.d.ts +48 -2
- package/dist/runtime/subsystems/events/index.js +4 -4
- package/dist/runtime/subsystems/index.d.ts +3 -2
- package/dist/runtime/subsystems/index.js +25 -21
- package/dist/runtime/subsystems/integration/execute-integration.use-case.d.ts +11 -1
- package/dist/runtime/subsystems/integration/execute-integration.use-case.js +2 -2
- package/dist/runtime/subsystems/integration/index.d.ts +2 -1
- package/dist/runtime/subsystems/integration/index.js +10 -8
- package/dist/runtime/subsystems/integration/integration-change-emitter.protocol.d.ts +106 -0
- package/dist/runtime/subsystems/integration/integration-change-emitter.protocol.js +1 -0
- package/dist/runtime/subsystems/integration/integration-change-emitter.protocol.js.map +1 -0
- package/dist/runtime/subsystems/integration/integration-cursor-store.drizzle-backend.js +2 -2
- package/dist/runtime/subsystems/integration/integration-run-recorder.drizzle-backend.js +2 -2
- package/dist/runtime/subsystems/integration/integration.module.js +4 -4
- package/dist/runtime/subsystems/integration/integration.tokens.d.ts +11 -1
- package/dist/runtime/subsystems/integration/integration.tokens.js +3 -1
- package/dist/runtime/subsystems/jobs/index.js +11 -11
- package/dist/runtime/subsystems/jobs/job-worker.module.js +5 -5
- package/dist/runtime/subsystems/jobs/jobs-domain.module.js +4 -4
- package/dist/runtime/subsystems/observability/index.js +3 -3
- package/dist/runtime/subsystems/observability/observability.module.js +3 -3
- package/dist/runtime/subsystems/observability/observability.service.js +2 -2
- package/dist/src/cli/index.js +300 -53
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/index.d.ts +13 -0
- package/dist/src/index.js +7 -7
- package/package.json +1 -1
- package/runtime/base-classes/lifecycle-events.ts +39 -6
- package/runtime/subsystems/events/generated/registry.ts +27 -0
- package/runtime/subsystems/events/generated/schemas.ts +26 -0
- package/runtime/subsystems/events/generated/types.ts +52 -0
- package/runtime/subsystems/index.ts +23 -0
- package/runtime/subsystems/integration/execute-integration.use-case.ts +69 -1
- package/runtime/subsystems/integration/index.ts +6 -0
- package/runtime/subsystems/integration/integration-change-emitter.protocol.ts +107 -0
- package/runtime/subsystems/integration/integration.tokens.ts +11 -0
- package/templates/subsystem/jobs/job-orchestration.schema.ejs.t +1 -0
- package/templates/subsystem/jobs/main-hook.ejs.t +1 -1
- package/templates/subsystem/jobs/prompt.js +40 -2
- package/templates/subsystem/jobs/worker.ejs.t +47 -35
- package/dist/chunk-4M66MQYA.js.map +0 -1
- package/dist/chunk-JOBQ6RUU.js.map +0 -1
- package/dist/chunk-JRQO2IOF.js.map +0 -1
- package/dist/chunk-KYR3B3OW.js.map +0 -1
- package/dist/chunk-S7C6TIIF.js.map +0 -1
- package/dist/chunk-TDEHU73T.js.map +0 -1
- /package/dist/{chunk-XKWOJZZ4.js.map → chunk-37PILMIT.js.map} +0 -0
- /package/dist/{chunk-2VHZ7EKC.js.map → chunk-5AAA4LTE.js.map} +0 -0
- /package/dist/{chunk-42763UEE.js.map → chunk-6M6LZEP6.js.map} +0 -0
- /package/dist/{chunk-AS3NAZB6.js.map → chunk-B7SC2V45.js.map} +0 -0
- /package/dist/{chunk-W72PRNJY.js.map → chunk-BPYZCEHS.js.map} +0 -0
- /package/dist/{chunk-FIUC6QB5.js.map → chunk-CKLM57IE.js.map} +0 -0
- /package/dist/{chunk-SH76CFAY.js.map → chunk-ENAR3F5S.js.map} +0 -0
- /package/dist/{chunk-RFH7N6EP.js.map → chunk-FCPTHS42.js.map} +0 -0
- /package/dist/{chunk-FFUDEIFF.js.map → chunk-HN5HT5WL.js.map} +0 -0
- /package/dist/{chunk-QFUIE37H.js.map → chunk-KFXXOFDC.js.map} +0 -0
- /package/dist/{chunk-O2A6XHGD.js.map → chunk-LLDJS7PJ.js.map} +0 -0
- /package/dist/{chunk-INO47JXD.js.map → chunk-PBENHIN2.js.map} +0 -0
- /package/dist/{chunk-CLWBNXKF.js.map → chunk-PLUJEQLU.js.map} +0 -0
- /package/dist/{chunk-JYBFPNBJ.js.map → chunk-SJGEBMJT.js.map} +0 -0
- /package/dist/{chunk-6XP2Q5SS.js.map → chunk-WZOPWQN2.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,57 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
-
## [
|
|
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
|
+
|
|
33
|
+
## [0.24.0] — 2026-06-06
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- **Integration: opt-in post-upsert change-event emission seam.** An entity that
|
|
38
|
+
declares `integration.sink.emit_changes: true` now gets typed per-entity domain
|
|
39
|
+
events published automatically when integration sync upserts/soft-deletes rows.
|
|
40
|
+
Codegen (a) desugars the entity into `<entity>_created` / `<entity>_edited` /
|
|
41
|
+
`<entity>_deleted` events (merged into the generated events registry exactly
|
|
42
|
+
like a hand-authored `events/*.yaml` — TypedEventBus augmentation, the
|
|
43
|
+
`EventTypeName` union, payload schemas), and (b) emits a fully-`@generated`
|
|
44
|
+
`<entity>.change-emitter.ts` that the per-entity assembly module binds to the
|
|
45
|
+
new optional `INTEGRATION_CHANGE_EMITTER` token. `ExecuteIntegrationUseCase`
|
|
46
|
+
injects the emitter `@Optional()` and publishes after every real sink
|
|
47
|
+
write/soft-delete (never on a `noop` diff or a delete that hit no row). Payload:
|
|
48
|
+
`{ entityId, externalId, provider, changedFields?, source: 'integration' }` —
|
|
49
|
+
the `source` provenance marker lets a write-back action detect
|
|
50
|
+
integration-originated changes and break the inbound→writeback loop. The verb
|
|
51
|
+
is `_edited`, NOT `_updated` (swe-brain ADR-0009 B1). Entities that don't opt in
|
|
52
|
+
are byte-for-byte unchanged (the emitter token stays unbound). Generalizes the
|
|
53
|
+
emission swe-brain hand-built in its sinks. See `docs/specs/EMIT-CHANGES-1.md`.
|
|
54
|
+
|
|
55
|
+
## [0.23.0] — 2026-06-06
|
|
6
56
|
|
|
7
57
|
### Fixed
|
|
8
58
|
|
|
@@ -114,9 +114,17 @@ export class AppModule {}
|
|
|
114
114
|
those records. This is the most common "wait, what?" moment; document it in
|
|
115
115
|
your runbooks. Retry semantics are caller-owned.
|
|
116
116
|
|
|
117
|
-
7. **
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
7. **Event emission is an opt-in seam; scheduling/retry/subscription-resolution
|
|
118
|
+
stay consumer concerns.** Declare `integration.sink.emit_changes: true` on an
|
|
119
|
+
entity and codegen generates `<entity>_created` / `<entity>_edited` /
|
|
120
|
+
`<entity>_deleted` typed events plus a `<entity>.change-emitter.ts` the
|
|
121
|
+
assembly binds to `INTEGRATION_CHANGE_EMITTER`; the orchestrator then publishes
|
|
122
|
+
after every real sink write/soft-delete (payload carries
|
|
123
|
+
`source: 'integration'` for loop-breaking). Omit the flag (the default) and the
|
|
124
|
+
orchestrator emits nothing — hand-roll emission in your sink if you need a
|
|
125
|
+
bespoke payload, or override the generated event via a top-level
|
|
126
|
+
`events/<entity>_created.yaml`. Scheduling is still a job/webhook concern;
|
|
127
|
+
retry semantics are still caller-owned. See `docs/specs/EMIT-CHANGES-1.md`.
|
|
120
128
|
|
|
121
129
|
## Do not
|
|
122
130
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BridgeMetricsReporter
|
|
3
3
|
} from "./chunk-AQFQ4BYM.js";
|
|
4
|
-
import {
|
|
5
|
-
ObservabilityService
|
|
6
|
-
} from "./chunk-CLWBNXKF.js";
|
|
7
4
|
import {
|
|
8
5
|
OBSERVABILITY,
|
|
9
6
|
OBSERVABILITY_MODULE_OPTIONS
|
|
10
7
|
} from "./chunk-Y7RRSEOC.js";
|
|
8
|
+
import {
|
|
9
|
+
ObservabilityService
|
|
10
|
+
} from "./chunk-PLUJEQLU.js";
|
|
11
11
|
import {
|
|
12
12
|
__decorateClass
|
|
13
13
|
} from "./chunk-2E224ZSN.js";
|
|
@@ -45,4 +45,4 @@ ObservabilityModule = __decorateClass([
|
|
|
45
45
|
export {
|
|
46
46
|
ObservabilityModule
|
|
47
47
|
};
|
|
48
|
-
//# sourceMappingURL=chunk-
|
|
48
|
+
//# sourceMappingURL=chunk-37PILMIT.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BaseService
|
|
3
|
-
} from "./chunk-
|
|
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-
|
|
37
|
+
//# sourceMappingURL=chunk-5AAA4LTE.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TypedEventBus
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-PBENHIN2.js";
|
|
4
4
|
import {
|
|
5
5
|
EventScheduler,
|
|
6
6
|
scheduledEventsFromRegistry
|
|
@@ -200,4 +200,4 @@ export {
|
|
|
200
200
|
EventSchedulerLifecycle,
|
|
201
201
|
EventsModule
|
|
202
202
|
};
|
|
203
|
-
//# sourceMappingURL=chunk-
|
|
203
|
+
//# sourceMappingURL=chunk-6M6LZEP6.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BaseService
|
|
3
|
-
} from "./chunk-
|
|
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-
|
|
14
|
+
//# sourceMappingURL=chunk-B7SC2V45.js.map
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
diffSnapshots,
|
|
5
5
|
emitSafely,
|
|
6
6
|
entitySnapshot
|
|
7
|
-
} from "./chunk-
|
|
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-
|
|
126
|
+
//# sourceMappingURL=chunk-BPYZCEHS.js.map
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
MemoryJobOrchestrator
|
|
3
|
-
} from "./chunk-VQOAATIG.js";
|
|
4
1
|
import {
|
|
5
2
|
DrizzleJobRunService
|
|
6
3
|
} from "./chunk-3VEVGL74.js";
|
|
@@ -10,12 +7,6 @@ import {
|
|
|
10
7
|
import {
|
|
11
8
|
DrizzleJobStepService
|
|
12
9
|
} from "./chunk-DV4RV2DC.js";
|
|
13
|
-
import {
|
|
14
|
-
MemoryJobStepService
|
|
15
|
-
} from "./chunk-PNZSGAB2.js";
|
|
16
|
-
import {
|
|
17
|
-
MemoryJobStore
|
|
18
|
-
} from "./chunk-SNQ3TOWP.js";
|
|
19
10
|
import {
|
|
20
11
|
BULLMQ_CONNECTION,
|
|
21
12
|
BULLMQ_RESOLVED_CONFIG,
|
|
@@ -24,6 +15,15 @@ import {
|
|
|
24
15
|
import {
|
|
25
16
|
DrizzleJobOrchestrator
|
|
26
17
|
} from "./chunk-E6PLM6QG.js";
|
|
18
|
+
import {
|
|
19
|
+
MemoryJobOrchestrator
|
|
20
|
+
} from "./chunk-VQOAATIG.js";
|
|
21
|
+
import {
|
|
22
|
+
MemoryJobStepService
|
|
23
|
+
} from "./chunk-PNZSGAB2.js";
|
|
24
|
+
import {
|
|
25
|
+
MemoryJobStore
|
|
26
|
+
} from "./chunk-SNQ3TOWP.js";
|
|
27
27
|
import {
|
|
28
28
|
JOBS_LISTEN_NOTIFY,
|
|
29
29
|
JOBS_MULTI_TENANT,
|
|
@@ -114,4 +114,4 @@ JobsDomainModule = __decorateClass([
|
|
|
114
114
|
export {
|
|
115
115
|
JobsDomainModule
|
|
116
116
|
};
|
|
117
|
-
//# sourceMappingURL=chunk-
|
|
117
|
+
//# sourceMappingURL=chunk-CKLM57IE.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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
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":[]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-7B7MMDOJ.js";
|
|
4
4
|
import {
|
|
5
5
|
JobsDomainModule
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-CKLM57IE.js";
|
|
7
7
|
import {
|
|
8
8
|
BULLMQ_CONNECTION,
|
|
9
9
|
BULLMQ_RESOLVED_CONFIG,
|
|
@@ -295,4 +295,4 @@ export {
|
|
|
295
295
|
JobWorkerOrchestrator,
|
|
296
296
|
JobWorkerModule
|
|
297
297
|
};
|
|
298
|
-
//# sourceMappingURL=chunk-
|
|
298
|
+
//# sourceMappingURL=chunk-ENAR3F5S.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BaseService
|
|
3
|
-
} from "./chunk-
|
|
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-
|
|
36
|
+
//# sourceMappingURL=chunk-FCPTHS42.js.map
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "./chunk-SQDOBLBP.js";
|
|
9
9
|
import {
|
|
10
10
|
INTEGRATION_MULTI_TENANT
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-S5G3HO7N.js";
|
|
12
12
|
import {
|
|
13
13
|
assertTenantId
|
|
14
14
|
} from "./chunk-MZ6GV4YF.js";
|
|
@@ -127,4 +127,4 @@ DrizzleIntegrationRunRecorder = __decorateClass([
|
|
|
127
127
|
export {
|
|
128
128
|
DrizzleIntegrationRunRecorder
|
|
129
129
|
};
|
|
130
|
-
//# sourceMappingURL=chunk-
|
|
130
|
+
//# sourceMappingURL=chunk-HN5HT5WL.js.map
|
|
@@ -399,7 +399,9 @@ var ProviderIntegrationSchema = z.object({
|
|
|
399
399
|
var SinkPolicySchema = z.object({
|
|
400
400
|
delete: z.enum(["soft", "tombstone", "noop"]).optional(),
|
|
401
401
|
// NO .default() — see default fence in spec §Goal
|
|
402
|
-
exclude_fields: z.array(z.string()).optional()
|
|
402
|
+
exclude_fields: z.array(z.string()).optional(),
|
|
403
|
+
emit_changes: z.boolean().optional()
|
|
404
|
+
// NO .default() — absent ⇒ no emission
|
|
403
405
|
}).strict();
|
|
404
406
|
var IntegrationConfigSchema = z.object({
|
|
405
407
|
electric: z.boolean().optional().default(false),
|
|
@@ -4347,4 +4349,4 @@ export {
|
|
|
4347
4349
|
analyzeDomain,
|
|
4348
4350
|
validateEntities
|
|
4349
4351
|
};
|
|
4350
|
-
//# sourceMappingURL=chunk-
|
|
4352
|
+
//# sourceMappingURL=chunk-K4BQQ2NN.js.map
|