@pattern-stack/codegen 0.27.3 → 0.28.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 (49) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/{chunk-YQA5PMOD.js → chunk-3GMQKHJD.js} +2 -2
  3. package/dist/{chunk-5TK7MEN4.js → chunk-CPUSJPAP.js} +1 -1
  4. package/dist/{chunk-5TK7MEN4.js.map → chunk-CPUSJPAP.js.map} +1 -1
  5. package/dist/{chunk-PBENHIN2.js → chunk-IB733A6R.js} +2 -2
  6. package/dist/{chunk-YHVZAL6U.js → chunk-K6LH4PXZ.js} +2 -2
  7. package/dist/{chunk-XW4XKN3F.js → chunk-KS4BZHIA.js} +7 -7
  8. package/dist/{chunk-BK5ICA2F.js → chunk-RUSUZZAF.js} +4 -4
  9. package/dist/{chunk-7LKAMLV4.js → chunk-T6SCOJF4.js} +4 -4
  10. package/dist/{chunk-LQZESSM3.js → chunk-WE6DIDMM.js} +1 -1
  11. package/dist/chunk-WE6DIDMM.js.map +1 -0
  12. package/dist/{chunk-K4BQQ2NN.js → chunk-YUVEJNRE.js} +133 -10
  13. package/dist/chunk-YUVEJNRE.js.map +1 -0
  14. package/dist/{chunk-EGXFEZ2N.js → chunk-Z7YFYK6H.js} +4 -4
  15. package/dist/runtime/subsystems/auth/auth.module.js +2 -2
  16. package/dist/runtime/subsystems/auth/index.js +11 -11
  17. package/dist/runtime/subsystems/bridge/bridge.module.js +6 -6
  18. package/dist/runtime/subsystems/bridge/index.js +6 -6
  19. package/dist/runtime/subsystems/events/events.module.js +3 -3
  20. package/dist/runtime/subsystems/events/generated/bus.js +2 -2
  21. package/dist/runtime/subsystems/events/generated/index.js +2 -2
  22. package/dist/runtime/subsystems/events/generated/registry.d.ts +6 -0
  23. package/dist/runtime/subsystems/events/generated/registry.js +1 -1
  24. package/dist/runtime/subsystems/events/index.js +3 -3
  25. package/dist/runtime/subsystems/index.js +34 -34
  26. package/dist/runtime/subsystems/integration/detection-config.schema.d.ts +6 -4
  27. package/dist/runtime/subsystems/integration/detection-config.schema.js +1 -1
  28. package/dist/runtime/subsystems/integration/index.js +1 -1
  29. package/dist/runtime/subsystems/jobs/index.js +13 -13
  30. package/dist/runtime/subsystems/jobs/job-worker.module.js +5 -5
  31. package/dist/runtime/subsystems/jobs/jobs-domain.module.js +3 -3
  32. package/dist/runtime/subsystems/observability/index.js +3 -3
  33. package/dist/runtime/subsystems/storage/index.js +4 -4
  34. package/dist/runtime/subsystems/storage/storage.module.js +2 -2
  35. package/dist/src/cli/index.js +18 -6
  36. package/dist/src/cli/index.js.map +1 -1
  37. package/dist/src/index.js +2 -2
  38. package/package.json +1 -1
  39. package/runtime/subsystems/events/generated/registry.ts +1 -0
  40. package/runtime/subsystems/integration/detection-config.schema.ts +7 -5
  41. package/dist/chunk-K4BQQ2NN.js.map +0 -1
  42. package/dist/chunk-LQZESSM3.js.map +0 -1
  43. /package/dist/{chunk-YQA5PMOD.js.map → chunk-3GMQKHJD.js.map} +0 -0
  44. /package/dist/{chunk-PBENHIN2.js.map → chunk-IB733A6R.js.map} +0 -0
  45. /package/dist/{chunk-YHVZAL6U.js.map → chunk-K6LH4PXZ.js.map} +0 -0
  46. /package/dist/{chunk-XW4XKN3F.js.map → chunk-KS4BZHIA.js.map} +0 -0
  47. /package/dist/{chunk-BK5ICA2F.js.map → chunk-RUSUZZAF.js.map} +0 -0
  48. /package/dist/{chunk-7LKAMLV4.js.map → chunk-T6SCOJF4.js.map} +0 -0
  49. /package/dist/{chunk-EGXFEZ2N.js.map → chunk-Z7YFYK6H.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,26 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.28.0] — 2026-06-14
6
+
7
+ ### Added
8
+
9
+ - **`trigger:` block on event definitions — a projectable workflow-trigger
10
+ catalog.** Event YAMLs may now declare an optional, strict
11
+ `trigger: { surface, label?, description?, fields[] }` block. Its presence
12
+ marks the event as a *selectable workflow trigger* — a domain change-fact an
13
+ automation can fire on — as opposed to inbound transport events whose only job
14
+ is to sync state. Selectability is an explicit opt-in, deliberately decoupled
15
+ from `direction`: a `direction: change` event can still be a non-trigger (e.g.
16
+ metadata-churn edits like read/label flips), so the block is simply omitted
17
+ there. The parsed `trigger` is emitted verbatim into
18
+ `eventRegistry[type].trigger` (and the `EventMetadata` interface), so consumers
19
+ **project** their authoring trigger catalog from the event registry instead of
20
+ hand-maintaining a parallel list that drifts from the event definitions.
21
+ Backward-compatible — events without a `trigger:` block emit no `trigger` key,
22
+ so existing generated registries are unchanged. Dogfood-driven from swe-brain's
23
+ directive authoring surface.
24
+
5
25
  ## [0.27.3] — 2026-06-13
6
26
 
7
27
  ### Fixed
@@ -24,7 +24,7 @@ import {
24
24
  } from "./chunk-NXXDZ6ZF.js";
25
25
  import {
26
26
  JOB_WORKER_MODULE_OPTIONS
27
- } from "./chunk-EGXFEZ2N.js";
27
+ } from "./chunk-Z7YFYK6H.js";
28
28
  import {
29
29
  BRIDGE_DELIVERY_REPO,
30
30
  BRIDGE_MODULE_OPTIONS,
@@ -119,4 +119,4 @@ BridgeModule = __decorateClass([
119
119
  export {
120
120
  BridgeModule
121
121
  };
122
- //# sourceMappingURL=chunk-YQA5PMOD.js.map
122
+ //# sourceMappingURL=chunk-3GMQKHJD.js.map
@@ -87,4 +87,4 @@ export {
87
87
  WebhookDetectionSchema,
88
88
  DetectionConfigSchema
89
89
  };
90
- //# sourceMappingURL=chunk-5TK7MEN4.js.map
90
+ //# sourceMappingURL=chunk-CPUSJPAP.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../runtime/subsystems/integration/detection-config.schema.ts"],"sourcesContent":["/**\n * Integration subsystem — DetectionConfig schema (#226-1)\n *\n * Canonical Zod schema for per-entity integration detection config. The schema is\n * the single source of truth for filter/mapping shape and is consumed by:\n *\n * 1. Runtime primitives — `PollChangeSource<T>`, `WebhookChangeSource<T>`\n * (#226-3, #226-4) accept a parsed `DetectionConfig` at construction.\n * 2. Codegen — `src/schema/entity-definition.schema.ts` (#226-6) imports\n * this schema so per-entity YAML `detection:` blocks validate against\n * the same shape the runtime enforces.\n *\n * Locked decisions (see ADR-033 + decision memo Q1–Q6):\n * - Filter vocabulary is flat AND of `{ field, op, value }` triples; richer\n * boolean expressions (OR / NOT / nested) are deferred per epic open Q3.\n * - Cursor strategy is a tagged union over the four shapes the three modes\n * need (`systemModstamp`, `replayId`, `timestamp`, `eventId`). Each\n * strategy types its cursor internally; the orchestrator persists what\n * the iterator last yielded (integration skill rule 2).\n * - `mode: 'poll'` may opt into `provenance: 'cdc'` so Stripe-style event\n * endpoints (mechanically a poll, semantically CDC) reuse the poll\n * primitive while emitting `Change<T>.source = 'cdc'`. Long-lived\n * streaming CDC (SFDC Pub-Sub, Debezium) is a separate primitive\n * deferred to #226-8.\n * - `webhook` mode's `eventIdField` is optional: `WebhookChangeSource<T>`\n * prefers an `eventId` yielded by the queue iterator and falls back to the\n * `eventIdField` record extraction (precedence: yielded eventId >\n * eventIdField extraction > undefined dedupKey).\n */\nimport { z } from \"zod\";\n\n// ============================================================================\n// Field mapping — provider field → canonical target\n// ============================================================================\n\n/**\n * Maps a single provider field onto the canonical record. `transform` is an\n * opt-in tag the adapter callback may inspect (`date-iso`, `decimal-string`,\n * etc.); the schema does not enumerate transforms — adapters interpret them.\n */\nexport const FieldMappingSchema = z.object({\n\tsource: z.string().min(1),\n\ttarget: z.string().min(1),\n\ttransform: z.string().min(1).optional(),\n});\n\nexport type FieldMapping = z.infer<typeof FieldMappingSchema>;\n\n// ============================================================================\n// Resolved filter — flat-AND triple\n// ============================================================================\n\n/**\n * A single resolved filter clause applied at fetch time. `value` is `unknown`\n * to admit primitives, arrays (for `in` / `nin`), and dates as ISO strings —\n * adapters interpret per provider.\n */\nexport const ResolvedFilterSchema = z.object({\n\tfield: z.string().min(1),\n\top: z.enum([\"eq\", \"neq\", \"in\", \"nin\", \"gt\", \"gte\", \"lt\", \"lte\"]),\n\tvalue: z.unknown(),\n});\n\nexport type ResolvedFilter = z.infer<typeof ResolvedFilterSchema>;\n\n// ============================================================================\n// Cursor strategy — tagged union over the four shapes the modes need\n// ============================================================================\n\nconst SystemModstampCursorSchema = z.object({\n\tkind: z.literal(\"systemModstamp\"),\n\tfield: z.string().min(1),\n});\n\nconst ReplayIdCursorSchema = z.object({\n\tkind: z.literal(\"replayId\"),\n\tfield: z.string().min(1),\n});\n\nconst TimestampCursorSchema = z.object({\n\tkind: z.literal(\"timestamp\"),\n\tfield: z.string().min(1),\n});\n\nconst EventIdCursorSchema = z.object({\n\tkind: z.literal(\"eventId\"),\n\tfield: z.string().min(1),\n});\n\n/**\n * Gmail `historyId` (RFC-0003 §3) — an opaque, atomic vendor token. The next\n * watermark only exists at end-of-walk; there is no resumable mid-walk value.\n * `field` is metadata for codegen/adapters (the response key the token lives on).\n */\nconst HistoryIdCursorSchema = z.object({\n\tkind: z.literal(\"historyId\"),\n\tfield: z.string().min(1),\n});\n\n/**\n * Google Calendar `syncToken` (RFC-0003 §3) — an opaque, atomic sync token,\n * same divisibility profile as `historyId`.\n */\nconst SyncTokenCursorSchema = z.object({\n\tkind: z.literal(\"syncToken\"),\n\tfield: z.string().min(1),\n});\n\nexport const CursorStrategySchema = z.discriminatedUnion(\"kind\", [\n\tSystemModstampCursorSchema,\n\tReplayIdCursorSchema,\n\tTimestampCursorSchema,\n\tEventIdCursorSchema,\n\tHistoryIdCursorSchema,\n\tSyncTokenCursorSchema,\n]);\n\nexport type CursorStrategy = z.infer<typeof CursorStrategySchema>;\n\n// ============================================================================\n// Cursor divisibility (RFC-0003 §3)\n// ============================================================================\n\n/**\n * Whether a cursor strategy is *divisible* — a property of the strategy, not\n * the read primitive. Divisible cursors are sortable/monotonic watermarks whose\n * value is meaningful AS OF any single record (HubSpot `systemModstamp`, a\n * `timestamp` field, a Salesforce CDC `replayId`); the read primitive may\n * checkpoint per-ref mid-walk, so a crash resumes from the last delivered ref.\n *\n * Atomic cursors are opaque vendor tokens (Gmail `historyId`, Calendar\n * `syncToken`, a generic `eventId`) whose next value only exists at end-of-walk.\n * The primitive must withhold per-ref cursors and emit the token only at a safe\n * boundary, so an interrupted run never persists an unresumable mid-walk token\n * (it resumes all-or-nothing from the prior token — see `IncrementalReadBase`).\n *\n * `eventId` is classified atomic conservatively: a generic opaque id is treated\n * all-or-nothing unless a concrete strategy proves it monotonically resumable.\n */\nexport const CURSOR_DIVISIBILITY: Readonly<\n\tRecord<CursorStrategy[\"kind\"], boolean>\n> = {\n\tsystemModstamp: true,\n\ttimestamp: true,\n\treplayId: true,\n\teventId: false,\n\thistoryId: false,\n\tsyncToken: false,\n};\n\n/** Predicate form of {@link CURSOR_DIVISIBILITY}. */\nexport function isDivisibleCursor(kind: CursorStrategy[\"kind\"]): boolean {\n\treturn CURSOR_DIVISIBILITY[kind];\n}\n\n// ============================================================================\n// Mode-specific blocks\n// ============================================================================\n\n/**\n * Poll-mode block. `provenance: 'cdc'` opts the poll primitive into stamping\n * `Change<T>.source = 'cdc'` and populating `dedupKey` from the cursor's\n * `field` — used for Stripe-style event endpoints. Defaults to `'poll'`.\n */\nexport const PollDetectionSchema = z.object({\n\tcursor: CursorStrategySchema,\n\tprovenance: z.enum([\"poll\", \"cdc\"]).optional(),\n});\n\nexport type PollDetection = z.infer<typeof PollDetectionSchema>;\n\n/**\n * Webhook-mode block. `eventIdField`, when present, names the field on the\n * emitted canonical record that `WebhookChangeSource<T>` reads to set\n * `Change<T>.dedupKey` — used only as the fallback when the queue iterator\n * does NOT yield an `eventId` alongside the record.\n *\n * `eventIdField` is **optional**: a queue iterator that always yields an\n * `eventId` (vendor delivery metadata, the preferred channel) need not declare\n * a record field for it. dedupKey precedence is: yielded `eventId` >\n * `eventIdField` record extraction > undefined.\n */\nexport const WebhookDetectionSchema = z.object({\n\teventIdField: z.string().min(1).optional(),\n});\n\nexport type WebhookDetection = z.infer<typeof WebhookDetectionSchema>;\n\n// ============================================================================\n// DetectionConfig — top-level discriminated union over `mode`\n// ============================================================================\n\nconst PollModeSchema = z.object({\n\tmode: z.literal(\"poll\"),\n\tpoll: PollDetectionSchema,\n\tmapping: z.array(FieldMappingSchema).min(1),\n\tfilters: z.array(ResolvedFilterSchema).default([]),\n});\n\nconst WebhookModeSchema = z.object({\n\tmode: z.literal(\"webhook\"),\n\twebhook: WebhookDetectionSchema,\n\tmapping: z.array(FieldMappingSchema).min(1),\n\tfilters: z.array(ResolvedFilterSchema).default([]),\n});\n\n/**\n * Top-level detection config. Discriminated on `mode` so the relevant\n * mode-block (poll/webhook) is structurally required for that mode. CDC as a\n * long-lived streaming primitive is deferred (#226-8); CDC-as-provenance\n * (Stripe-style event endpoints) is expressed via `mode: 'poll'` with\n * `poll.provenance: 'cdc'`.\n */\nexport const DetectionConfigSchema = z.discriminatedUnion(\"mode\", [\n\tPollModeSchema,\n\tWebhookModeSchema,\n]);\n\nexport type DetectionConfig = z.infer<typeof DetectionConfigSchema>;\n"],"mappings":";AA6BA,SAAS,SAAS;AAWX,IAAM,qBAAqB,EAAE,OAAO;AAAA,EAC1C,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACxB,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACxB,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AACvC,CAAC;AAaM,IAAM,uBAAuB,EAAE,OAAO;AAAA,EAC5C,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,IAAI,EAAE,KAAK,CAAC,MAAM,OAAO,MAAM,OAAO,MAAM,OAAO,MAAM,KAAK,CAAC;AAAA,EAC/D,OAAO,EAAE,QAAQ;AAClB,CAAC;AAQD,IAAM,6BAA6B,EAAE,OAAO;AAAA,EAC3C,MAAM,EAAE,QAAQ,gBAAgB;AAAA,EAChC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AACxB,CAAC;AAED,IAAM,uBAAuB,EAAE,OAAO;AAAA,EACrC,MAAM,EAAE,QAAQ,UAAU;AAAA,EAC1B,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AACxB,CAAC;AAED,IAAM,wBAAwB,EAAE,OAAO;AAAA,EACtC,MAAM,EAAE,QAAQ,WAAW;AAAA,EAC3B,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AACxB,CAAC;AAED,IAAM,sBAAsB,EAAE,OAAO;AAAA,EACpC,MAAM,EAAE,QAAQ,SAAS;AAAA,EACzB,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AACxB,CAAC;AAOD,IAAM,wBAAwB,EAAE,OAAO;AAAA,EACtC,MAAM,EAAE,QAAQ,WAAW;AAAA,EAC3B,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AACxB,CAAC;AAMD,IAAM,wBAAwB,EAAE,OAAO;AAAA,EACtC,MAAM,EAAE,QAAQ,WAAW;AAAA,EAC3B,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AACxB,CAAC;AAEM,IAAM,uBAAuB,EAAE,mBAAmB,QAAQ;AAAA,EAChE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAC;AAwBM,IAAM,sBAET;AAAA,EACH,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX,UAAU;AAAA,EACV,SAAS;AAAA,EACT,WAAW;AAAA,EACX,WAAW;AACZ;AAGO,SAAS,kBAAkB,MAAuC;AACxE,SAAO,oBAAoB,IAAI;AAChC;AAWO,IAAM,sBAAsB,EAAE,OAAO;AAAA,EAC3C,QAAQ;AAAA,EACR,YAAY,EAAE,KAAK,CAAC,QAAQ,KAAK,CAAC,EAAE,SAAS;AAC9C,CAAC;AAeM,IAAM,yBAAyB,EAAE,OAAO;AAAA,EAC9C,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAC1C,CAAC;AAQD,IAAM,iBAAiB,EAAE,OAAO;AAAA,EAC/B,MAAM,EAAE,QAAQ,MAAM;AAAA,EACtB,MAAM;AAAA,EACN,SAAS,EAAE,MAAM,kBAAkB,EAAE,IAAI,CAAC;AAAA,EAC1C,SAAS,EAAE,MAAM,oBAAoB,EAAE,QAAQ,CAAC,CAAC;AAClD,CAAC;AAED,IAAM,oBAAoB,EAAE,OAAO;AAAA,EAClC,MAAM,EAAE,QAAQ,SAAS;AAAA,EACzB,SAAS;AAAA,EACT,SAAS,EAAE,MAAM,kBAAkB,EAAE,IAAI,CAAC;AAAA,EAC1C,SAAS,EAAE,MAAM,oBAAoB,EAAE,QAAQ,CAAC,CAAC;AAClD,CAAC;AASM,IAAM,wBAAwB,EAAE,mBAAmB,QAAQ;AAAA,EACjE;AAAA,EACA;AACD,CAAC;","names":[]}
1
+ {"version":3,"sources":["../runtime/subsystems/integration/detection-config.schema.ts"],"sourcesContent":["/**\n * Integration subsystem — DetectionConfig schema (#226-1)\n *\n * Canonical Zod schema for per-entity integration detection config. The schema is\n * the single source of truth for filter/mapping shape and is consumed by:\n *\n * 1. Runtime primitives — `PollChangeSource<T>`, `WebhookChangeSource<T>`\n * (#226-3, #226-4) accept a parsed `DetectionConfig` at construction.\n * 2. Codegen — `src/schema/entity-definition.schema.ts` (#226-6) imports\n * this schema so per-entity YAML `detection:` blocks validate against\n * the same shape the runtime enforces.\n *\n * Locked decisions (see ADR-033 + decision memo Q1–Q6):\n * - Filter vocabulary is flat AND of `{ field, op, value }` triples; richer\n * boolean expressions (OR / NOT / nested) are deferred per epic open Q3.\n * - Cursor strategy is a tagged union over the six shapes the modes need\n * (`systemModstamp`, `replayId`, `timestamp`, `eventId`, plus `historyId`\n * and `syncToken` added in RFC-0003). Each strategy types its cursor\n * internally; the orchestrator persists what the iterator last yielded\n * (integration skill rule 2). Divisibility per strategy is tabled in\n * `CURSOR_DIVISIBILITY` below.\n * - `mode: 'poll'` may opt into `provenance: 'cdc'` so Stripe-style event\n * endpoints (mechanically a poll, semantically CDC) reuse the poll\n * primitive while emitting `Change<T>.source = 'cdc'`. Long-lived\n * streaming CDC (SFDC Pub-Sub, Debezium) is a separate primitive\n * deferred to #226-8.\n * - `webhook` mode's `eventIdField` is optional: `WebhookChangeSource<T>`\n * prefers an `eventId` yielded by the queue iterator and falls back to the\n * `eventIdField` record extraction (precedence: yielded eventId >\n * eventIdField extraction > undefined dedupKey).\n */\nimport { z } from \"zod\";\n\n// ============================================================================\n// Field mapping — provider field → canonical target\n// ============================================================================\n\n/**\n * Maps a single provider field onto the canonical record. `transform` is an\n * opt-in tag the adapter callback may inspect (`date-iso`, `decimal-string`,\n * etc.); the schema does not enumerate transforms — adapters interpret them.\n */\nexport const FieldMappingSchema = z.object({\n\tsource: z.string().min(1),\n\ttarget: z.string().min(1),\n\ttransform: z.string().min(1).optional(),\n});\n\nexport type FieldMapping = z.infer<typeof FieldMappingSchema>;\n\n// ============================================================================\n// Resolved filter — flat-AND triple\n// ============================================================================\n\n/**\n * A single resolved filter clause applied at fetch time. `value` is `unknown`\n * to admit primitives, arrays (for `in` / `nin`), and dates as ISO strings —\n * adapters interpret per provider.\n */\nexport const ResolvedFilterSchema = z.object({\n\tfield: z.string().min(1),\n\top: z.enum([\"eq\", \"neq\", \"in\", \"nin\", \"gt\", \"gte\", \"lt\", \"lte\"]),\n\tvalue: z.unknown(),\n});\n\nexport type ResolvedFilter = z.infer<typeof ResolvedFilterSchema>;\n\n// ============================================================================\n// Cursor strategy — tagged union over the six shapes the modes need\n// ============================================================================\n\nconst SystemModstampCursorSchema = z.object({\n\tkind: z.literal(\"systemModstamp\"),\n\tfield: z.string().min(1),\n});\n\nconst ReplayIdCursorSchema = z.object({\n\tkind: z.literal(\"replayId\"),\n\tfield: z.string().min(1),\n});\n\nconst TimestampCursorSchema = z.object({\n\tkind: z.literal(\"timestamp\"),\n\tfield: z.string().min(1),\n});\n\nconst EventIdCursorSchema = z.object({\n\tkind: z.literal(\"eventId\"),\n\tfield: z.string().min(1),\n});\n\n/**\n * Gmail `historyId` (RFC-0003 §3) — an opaque, atomic vendor token. The next\n * watermark only exists at end-of-walk; there is no resumable mid-walk value.\n * `field` is metadata for codegen/adapters (the response key the token lives on).\n */\nconst HistoryIdCursorSchema = z.object({\n\tkind: z.literal(\"historyId\"),\n\tfield: z.string().min(1),\n});\n\n/**\n * Google Calendar `syncToken` (RFC-0003 §3) — an opaque, atomic sync token,\n * same divisibility profile as `historyId`.\n */\nconst SyncTokenCursorSchema = z.object({\n\tkind: z.literal(\"syncToken\"),\n\tfield: z.string().min(1),\n});\n\nexport const CursorStrategySchema = z.discriminatedUnion(\"kind\", [\n\tSystemModstampCursorSchema,\n\tReplayIdCursorSchema,\n\tTimestampCursorSchema,\n\tEventIdCursorSchema,\n\tHistoryIdCursorSchema,\n\tSyncTokenCursorSchema,\n]);\n\nexport type CursorStrategy = z.infer<typeof CursorStrategySchema>;\n\n// ============================================================================\n// Cursor divisibility (RFC-0003 §3)\n// ============================================================================\n\n/**\n * Whether a cursor strategy is *divisible* — a property of the strategy, not\n * the read primitive. Divisible cursors are sortable/monotonic watermarks whose\n * value is meaningful AS OF any single record (HubSpot `systemModstamp`, a\n * `timestamp` field, a Salesforce CDC `replayId`); the read primitive may\n * checkpoint per-ref mid-walk, so a crash resumes from the last delivered ref.\n *\n * Atomic cursors are opaque vendor tokens (Gmail `historyId`, Calendar\n * `syncToken`, a generic `eventId`) whose next value only exists at end-of-walk.\n * The primitive must withhold per-ref cursors and emit the token only at a safe\n * boundary, so an interrupted run never persists an unresumable mid-walk token\n * (it resumes all-or-nothing from the prior token — see `IncrementalReadBase`).\n *\n * `eventId` is classified atomic conservatively: a generic opaque id is treated\n * all-or-nothing unless a concrete strategy proves it monotonically resumable.\n */\nexport const CURSOR_DIVISIBILITY: Readonly<\n\tRecord<CursorStrategy[\"kind\"], boolean>\n> = {\n\tsystemModstamp: true,\n\ttimestamp: true,\n\treplayId: true,\n\teventId: false,\n\thistoryId: false,\n\tsyncToken: false,\n};\n\n/** Predicate form of {@link CURSOR_DIVISIBILITY}. */\nexport function isDivisibleCursor(kind: CursorStrategy[\"kind\"]): boolean {\n\treturn CURSOR_DIVISIBILITY[kind];\n}\n\n// ============================================================================\n// Mode-specific blocks\n// ============================================================================\n\n/**\n * Poll-mode block. `provenance: 'cdc'` opts the poll primitive into stamping\n * `Change<T>.source = 'cdc'` and populating `dedupKey` from the cursor's\n * `field` — used for Stripe-style event endpoints. Defaults to `'poll'`.\n */\nexport const PollDetectionSchema = z.object({\n\tcursor: CursorStrategySchema,\n\tprovenance: z.enum([\"poll\", \"cdc\"]).optional(),\n});\n\nexport type PollDetection = z.infer<typeof PollDetectionSchema>;\n\n/**\n * Webhook-mode block. `eventIdField`, when present, names the field on the\n * emitted canonical record that `WebhookChangeSource<T>` reads to set\n * `Change<T>.dedupKey` — used only as the fallback when the queue iterator\n * does NOT yield an `eventId` alongside the record.\n *\n * `eventIdField` is **optional**: a queue iterator that always yields an\n * `eventId` (vendor delivery metadata, the preferred channel) need not declare\n * a record field for it. dedupKey precedence is: yielded `eventId` >\n * `eventIdField` record extraction > undefined.\n */\nexport const WebhookDetectionSchema = z.object({\n\teventIdField: z.string().min(1).optional(),\n});\n\nexport type WebhookDetection = z.infer<typeof WebhookDetectionSchema>;\n\n// ============================================================================\n// DetectionConfig — top-level discriminated union over `mode`\n// ============================================================================\n\nconst PollModeSchema = z.object({\n\tmode: z.literal(\"poll\"),\n\tpoll: PollDetectionSchema,\n\tmapping: z.array(FieldMappingSchema).min(1),\n\tfilters: z.array(ResolvedFilterSchema).default([]),\n});\n\nconst WebhookModeSchema = z.object({\n\tmode: z.literal(\"webhook\"),\n\twebhook: WebhookDetectionSchema,\n\tmapping: z.array(FieldMappingSchema).min(1),\n\tfilters: z.array(ResolvedFilterSchema).default([]),\n});\n\n/**\n * Top-level detection config. Discriminated on `mode` so the relevant\n * mode-block (poll/webhook) is structurally required for that mode. CDC as a\n * long-lived streaming primitive is deferred (#226-8); CDC-as-provenance\n * (Stripe-style event endpoints) is expressed via `mode: 'poll'` with\n * `poll.provenance: 'cdc'`.\n */\nexport const DetectionConfigSchema = z.discriminatedUnion(\"mode\", [\n\tPollModeSchema,\n\tWebhookModeSchema,\n]);\n\nexport type DetectionConfig = z.infer<typeof DetectionConfigSchema>;\n"],"mappings":";AA+BA,SAAS,SAAS;AAWX,IAAM,qBAAqB,EAAE,OAAO;AAAA,EAC1C,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACxB,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACxB,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AACvC,CAAC;AAaM,IAAM,uBAAuB,EAAE,OAAO;AAAA,EAC5C,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,IAAI,EAAE,KAAK,CAAC,MAAM,OAAO,MAAM,OAAO,MAAM,OAAO,MAAM,KAAK,CAAC;AAAA,EAC/D,OAAO,EAAE,QAAQ;AAClB,CAAC;AAQD,IAAM,6BAA6B,EAAE,OAAO;AAAA,EAC3C,MAAM,EAAE,QAAQ,gBAAgB;AAAA,EAChC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AACxB,CAAC;AAED,IAAM,uBAAuB,EAAE,OAAO;AAAA,EACrC,MAAM,EAAE,QAAQ,UAAU;AAAA,EAC1B,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AACxB,CAAC;AAED,IAAM,wBAAwB,EAAE,OAAO;AAAA,EACtC,MAAM,EAAE,QAAQ,WAAW;AAAA,EAC3B,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AACxB,CAAC;AAED,IAAM,sBAAsB,EAAE,OAAO;AAAA,EACpC,MAAM,EAAE,QAAQ,SAAS;AAAA,EACzB,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AACxB,CAAC;AAOD,IAAM,wBAAwB,EAAE,OAAO;AAAA,EACtC,MAAM,EAAE,QAAQ,WAAW;AAAA,EAC3B,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AACxB,CAAC;AAMD,IAAM,wBAAwB,EAAE,OAAO;AAAA,EACtC,MAAM,EAAE,QAAQ,WAAW;AAAA,EAC3B,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AACxB,CAAC;AAEM,IAAM,uBAAuB,EAAE,mBAAmB,QAAQ;AAAA,EAChE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAC;AAwBM,IAAM,sBAET;AAAA,EACH,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX,UAAU;AAAA,EACV,SAAS;AAAA,EACT,WAAW;AAAA,EACX,WAAW;AACZ;AAGO,SAAS,kBAAkB,MAAuC;AACxE,SAAO,oBAAoB,IAAI;AAChC;AAWO,IAAM,sBAAsB,EAAE,OAAO;AAAA,EAC3C,QAAQ;AAAA,EACR,YAAY,EAAE,KAAK,CAAC,QAAQ,KAAK,CAAC,EAAE,SAAS;AAC9C,CAAC;AAeM,IAAM,yBAAyB,EAAE,OAAO;AAAA,EAC9C,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAC1C,CAAC;AAQD,IAAM,iBAAiB,EAAE,OAAO;AAAA,EAC/B,MAAM,EAAE,QAAQ,MAAM;AAAA,EACtB,MAAM;AAAA,EACN,SAAS,EAAE,MAAM,kBAAkB,EAAE,IAAI,CAAC;AAAA,EAC1C,SAAS,EAAE,MAAM,oBAAoB,EAAE,QAAQ,CAAC,CAAC;AAClD,CAAC;AAED,IAAM,oBAAoB,EAAE,OAAO;AAAA,EAClC,MAAM,EAAE,QAAQ,SAAS;AAAA,EACzB,SAAS;AAAA,EACT,SAAS,EAAE,MAAM,kBAAkB,EAAE,IAAI,CAAC;AAAA,EAC1C,SAAS,EAAE,MAAM,oBAAoB,EAAE,QAAQ,CAAC,CAAC;AAClD,CAAC;AASM,IAAM,wBAAwB,EAAE,mBAAmB,QAAQ;AAAA,EACjE;AAAA,EACA;AACD,CAAC;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getEventMetadata
3
- } from "./chunk-LQZESSM3.js";
3
+ } from "./chunk-WE6DIDMM.js";
4
4
  import {
5
5
  eventPayloadSchemas
6
6
  } from "./chunk-MU54DZCC.js";
@@ -89,4 +89,4 @@ TypedEventBus = __decorateClass([
89
89
  export {
90
90
  TypedEventBus
91
91
  };
92
- //# sourceMappingURL=chunk-PBENHIN2.js.map
92
+ //# sourceMappingURL=chunk-IB733A6R.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TypedEventBus
3
- } from "./chunk-PBENHIN2.js";
3
+ } from "./chunk-IB733A6R.js";
4
4
  import {
5
5
  MemoryEventBus
6
6
  } from "./chunk-GOO5ZMYO.js";
@@ -200,4 +200,4 @@ export {
200
200
  EventSchedulerLifecycle,
201
201
  EventsModule
202
202
  };
203
- //# sourceMappingURL=chunk-YHVZAL6U.js.map
203
+ //# sourceMappingURL=chunk-K6LH4PXZ.js.map
@@ -1,3 +1,6 @@
1
+ import {
2
+ MemoryJobRunService
3
+ } from "./chunk-BHZP6LOV.js";
1
4
  import {
2
5
  DrizzleJobStepService
3
6
  } from "./chunk-DV4RV2DC.js";
@@ -10,15 +13,12 @@ import {
10
13
  import {
11
14
  MemoryJobStepService
12
15
  } from "./chunk-PNZSGAB2.js";
13
- import {
14
- DrizzleJobRunService
15
- } from "./chunk-VNBC3VXM.js";
16
- import {
17
- MemoryJobRunService
18
- } from "./chunk-BHZP6LOV.js";
19
16
  import {
20
17
  MemoryJobStore
21
18
  } from "./chunk-SNQ3TOWP.js";
19
+ import {
20
+ DrizzleJobRunService
21
+ } from "./chunk-VNBC3VXM.js";
22
22
  import {
23
23
  BULLMQ_CONNECTION,
24
24
  BULLMQ_RESOLVED_CONFIG,
@@ -114,4 +114,4 @@ JobsDomainModule = __decorateClass([
114
114
  export {
115
115
  JobsDomainModule
116
116
  };
117
- //# sourceMappingURL=chunk-XW4XKN3F.js.map
117
+ //# sourceMappingURL=chunk-KS4BZHIA.js.map
@@ -1,12 +1,12 @@
1
+ import {
2
+ MemoryStorageBackend
3
+ } from "./chunk-3SZFUTXE.js";
1
4
  import {
2
5
  STORAGE
3
6
  } from "./chunk-NYBCQZC7.js";
4
7
  import {
5
8
  LocalStorageBackend
6
9
  } from "./chunk-JWNHNUYL.js";
7
- import {
8
- MemoryStorageBackend
9
- } from "./chunk-3SZFUTXE.js";
10
10
  import {
11
11
  __decorateClass
12
12
  } from "./chunk-2E224ZSN.js";
@@ -37,4 +37,4 @@ StorageModule = __decorateClass([
37
37
  export {
38
38
  StorageModule
39
39
  };
40
- //# sourceMappingURL=chunk-BK5ICA2F.js.map
40
+ //# sourceMappingURL=chunk-RUSUZZAF.js.map
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  EnvEncryptionKey
3
3
  } from "./chunk-IP4OO26U.js";
4
+ import {
5
+ AuthController
6
+ } from "./chunk-SZVPIHWE.js";
4
7
  import {
5
8
  DrizzleOAuthStateStore
6
9
  } from "./chunk-N5OTOWTP.js";
7
10
  import {
8
11
  MemoryOAuthStateStore
9
12
  } from "./chunk-QLTJSCE6.js";
10
- import {
11
- AuthController
12
- } from "./chunk-SZVPIHWE.js";
13
13
  import {
14
14
  AUTH_OPTIONS,
15
15
  ENCRYPTION_KEY,
@@ -89,4 +89,4 @@ AuthModule = __decorateClass([
89
89
  export {
90
90
  AuthModule
91
91
  };
92
- //# sourceMappingURL=chunk-7LKAMLV4.js.map
92
+ //# sourceMappingURL=chunk-T6SCOJF4.js.map
@@ -112,4 +112,4 @@ export {
112
112
  eventRegistry,
113
113
  getEventMetadata
114
114
  };
115
- //# sourceMappingURL=chunk-LQZESSM3.js.map
115
+ //# sourceMappingURL=chunk-WE6DIDMM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../runtime/subsystems/events/generated/registry.ts"],"sourcesContent":["// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.\n// Run `codegen entity new --all` to refresh.\n\n\nimport type { EventTypeName } from './types';\n\nexport interface EventMetadata {\n\ttype: EventTypeName;\n\ttier: 'domain' | 'audit';\n\tdirection: 'inbound' | 'change' | 'outbound' | null;\n\tpool: 'events_inbound' | 'events_change' | 'events_outbound' | null;\n\taggregate?: string;\n\tsource?: string;\n\tdestination?: string;\n\tversion: number;\n\tretry: { attempts: number; backoff: 'linear' | 'exponential' };\n\tschedule?: { every: string | number; align: boolean; catchUp: boolean; maxCatchUpSlots: number };\n\ttrigger?: { surface: string; label?: string; description?: string; fields: string[] };\n}\n\nexport const eventRegistry = {\n\t'contact_created': {\n\t\ttype: 'contact_created',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'contact',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'contact_marked_champion': {\n\t\ttype: 'contact_marked_champion',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'contact',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'contact_merged': {\n\t\ttype: 'contact_merged',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'contact',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'crm_sync_started': {\n\t\ttype: 'crm_sync_started',\n\t\ttier: 'audit',\n\t\tdirection: null,\n\t\tpool: null,\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'deal_created': {\n\t\ttype: 'deal_created',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'deal',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'deal_stage_changed': {\n\t\ttype: 'deal_stage_changed',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'deal',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'message_created': {\n\t\ttype: 'message_created',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'message',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'message_deleted': {\n\t\ttype: 'message_deleted',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'message',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'message_edited': {\n\t\ttype: 'message_edited',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'message',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'stripe_payment_received': {\n\t\ttype: 'stripe_payment_received',\n\t\ttier: 'domain',\n\t\tdirection: 'inbound',\n\t\tpool: 'events_inbound',\n\t\tsource: 'stripe',\n\t\tversion: 1,\n\t\tretry: { attempts: 5, backoff: 'exponential' },\n\t},\n\t'webhook_outbound_contact_sync': {\n\t\ttype: 'webhook_outbound_contact_sync',\n\t\ttier: 'domain',\n\t\tdirection: 'outbound',\n\t\tpool: 'events_outbound',\n\t\taggregate: 'contact',\n\t\tdestination: 'crm',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n} as const satisfies Record<EventTypeName, EventMetadata>;\n\nexport function getEventMetadata<T extends EventTypeName>(type: T): EventMetadata {\n\tconst meta = eventRegistry[type];\n\tif (!meta) {\n\t\tthrow new Error(`No registry entry for event type '${String(type)}' — declare events under events/*.yaml and re-run \\`codegen entity new --all\\`.`);\n\t}\n\treturn meta;\n}\n"],"mappings":";AAoBO,IAAM,gBAAgB;AAAA,EAC5B,mBAAmB;AAAA,IAClB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AAAA,EACA,2BAA2B;AAAA,IAC1B,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AAAA,EACA,kBAAkB;AAAA,IACjB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AAAA,EACA,oBAAoB;AAAA,IACnB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AAAA,EACA,gBAAgB;AAAA,IACf,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AAAA,EACA,sBAAsB;AAAA,IACrB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AAAA,EACA,mBAAmB;AAAA,IAClB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AAAA,EACA,mBAAmB;AAAA,IAClB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AAAA,EACA,kBAAkB;AAAA,IACjB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AAAA,EACA,2BAA2B;AAAA,IAC1B,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AAAA,EACA,iCAAiC;AAAA,IAChC,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AACD;AAEO,SAAS,iBAA0C,MAAwB;AACjF,QAAM,OAAO,cAAc,IAAI;AAC/B,MAAI,CAAC,MAAM;AACV,UAAM,IAAI,MAAM,qCAAqC,OAAO,IAAI,CAAC,sFAAiF;AAAA,EACnJ;AACA,SAAO;AACR;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  DetectionConfigSchema
3
- } from "./chunk-5TK7MEN4.js";
3
+ } from "./chunk-CPUSJPAP.js";
4
4
 
5
5
  // src/parser/load-entities.ts
6
6
  import { resolve as resolve2 } from "path";
@@ -691,6 +691,17 @@ var ScheduleSchema = z2.object({
691
691
  maxCatchUpSlots: z2.number().int().positive().optional().default(1e3)
692
692
  }).strict();
693
693
  var SNAKE_CASE_RE = /^[a-z][a-z0-9_]*$/;
694
+ var EventTriggerSchema = z2.object({
695
+ surface: z2.string().min(1),
696
+ label: z2.string().optional(),
697
+ description: z2.string().optional(),
698
+ fields: z2.array(
699
+ z2.string().regex(
700
+ SNAKE_CASE_RE,
701
+ "trigger.fields entries must be snake_case payload paths"
702
+ )
703
+ ).default([])
704
+ }).strict();
694
705
  var EventDefinitionSchemaCore = z2.object({
695
706
  type: z2.string().regex(
696
707
  SNAKE_CASE_RE,
@@ -714,7 +725,13 @@ var EventDefinitionSchemaCore = z2.object({
714
725
  // platform emits this event on the given cadence (see ScheduleSchema).
715
726
  schedule: ScheduleSchema.optional(),
716
727
  version: z2.number().int().min(1).optional().default(1),
717
- description: z2.string().optional()
728
+ description: z2.string().optional(),
729
+ // Trigger-catalog projection (workflow authoring). Present ⇒ this event is
730
+ // a selectable workflow trigger; consumers build the catalog from it. No
731
+ // refinement ties it to `direction` — selectability is an explicit opt-in,
732
+ // deliberately decoupled from transport (a change-fact may still be a
733
+ // non-trigger; an inbound event could opt in if a consumer hydrates it).
734
+ trigger: EventTriggerSchema.optional()
718
735
  }).strict();
719
736
  var EventDefinitionSchemaRefined = EventDefinitionSchemaCore.superRefine(
720
737
  (data, ctx) => {
@@ -1145,6 +1162,109 @@ function isActiveProvider(def) {
1145
1162
  return def.status !== "planned";
1146
1163
  }
1147
1164
 
1165
+ // src/schema/job-definition.schema.ts
1166
+ import { z as z6 } from "zod";
1167
+ var JOB_BACKOFF_STRATEGIES = ["fixed", "exponential"];
1168
+ var COLLISION_MODES = ["queue", "reject", "replace"];
1169
+ var REPLAY_FROM = ["scratch", "last_step", "last_checkpoint"];
1170
+ var SNAKE_CASE_RE2 = /^[a-z][a-z0-9_]*$/;
1171
+ var RetryPolicySchema = z6.object({
1172
+ attempts: z6.number().int().min(0).max(20),
1173
+ backoff: z6.enum(JOB_BACKOFF_STRATEGIES),
1174
+ baseMs: z6.number().int().positive(),
1175
+ nonRetryableErrors: z6.array(z6.string().min(1)).optional()
1176
+ }).strict();
1177
+ var ConcurrencyPolicySchema = z6.object({
1178
+ key: z6.string().min(1),
1179
+ collisionMode: z6.enum(COLLISION_MODES)
1180
+ }).strict();
1181
+ var DedupePolicySchema = z6.object({
1182
+ key: z6.string().min(1),
1183
+ windowMs: z6.number().int().positive()
1184
+ }).strict();
1185
+ var ScopeRefSchema = z6.object({
1186
+ entity: z6.string().regex(SNAKE_CASE_RE2, "scope.entity must be snake_case"),
1187
+ from: z6.string().min(1)
1188
+ }).strict();
1189
+ var DifferOverrideSchema = z6.object({
1190
+ // Deliberately `.min(1)`: the runtime `DeepEqualDifferOptions.unignore` accepts
1191
+ // `[]` (a harmless no-op), but an empty `differ` block in YAML is meaningless
1192
+ // and almost certainly an authoring mistake — reject it rather than silently
1193
+ // accept a pointless block. (Schema is intentionally stricter than the runtime.)
1194
+ unignore: z6.array(z6.string().min(1)).min(1)
1195
+ }).strict();
1196
+ var ScheduleTriggerSchema = z6.object({
1197
+ schedule: ScheduleSchema
1198
+ }).strict();
1199
+ var EventTriggerSchema2 = z6.object({
1200
+ event: z6.string().regex(SNAKE_CASE_RE2, "trigger.event must be a snake_case event type")
1201
+ }).strict();
1202
+ var TriggerSchema = z6.union([ScheduleTriggerSchema, EventTriggerSchema2]);
1203
+ var PollArmSchema = z6.object({
1204
+ kind: z6.literal("poll"),
1205
+ domain: z6.string().regex(SNAKE_CASE_RE2, "arm.domain must be snake_case"),
1206
+ read: DetectionConfigSchema
1207
+ }).strict();
1208
+ var ReconcileArmSchema = z6.object({
1209
+ kind: z6.literal("reconcile"),
1210
+ domain: z6.string().regex(SNAKE_CASE_RE2, "arm.domain must be snake_case"),
1211
+ window: z6.object({ hours: z6.number().positive().finite() }).strict(),
1212
+ cursorWithheld: z6.literal(true).optional().default(true),
1213
+ read: DetectionConfigSchema
1214
+ }).strict();
1215
+ var RealtimeArmSchema = z6.object({
1216
+ kind: z6.literal("realtime"),
1217
+ domain: z6.string().regex(SNAKE_CASE_RE2, "arm.domain must be snake_case"),
1218
+ staging: z6.object({
1219
+ table: z6.string().min(1),
1220
+ pushAccelerate: z6.boolean().optional()
1221
+ }).strict(),
1222
+ read: DetectionConfigSchema
1223
+ }).strict();
1224
+ var ArmSchema = z6.discriminatedUnion("kind", [
1225
+ PollArmSchema,
1226
+ ReconcileArmSchema,
1227
+ RealtimeArmSchema
1228
+ ]);
1229
+ var JobDefinitionSchemaCore = z6.object({
1230
+ type: z6.string().regex(SNAKE_CASE_RE2, "Job type must be snake_case starting with a letter"),
1231
+ // ── JobHandlerMeta surface (8 fields) ──────────────────────────────────
1232
+ pool: z6.string().min(1).optional(),
1233
+ scope: ScopeRefSchema.optional(),
1234
+ retry: RetryPolicySchema.optional(),
1235
+ concurrency: ConcurrencyPolicySchema.optional(),
1236
+ dedupe: DedupePolicySchema.optional(),
1237
+ timeoutMs: z6.number().int().positive().optional(),
1238
+ replayFrom: z6.enum(REPLAY_FROM).optional(),
1239
+ // `triggers` is the 8th meta field, reshaped to the declarative surface.
1240
+ triggers: z6.array(TriggerSchema).default([]),
1241
+ // ── job-definition additions ───────────────────────────────────────────
1242
+ differ: DifferOverrideSchema.optional(),
1243
+ arms: z6.array(ArmSchema).min(1, "a job must declare at least one arm"),
1244
+ description: z6.string().optional()
1245
+ }).strict();
1246
+ var JobDefinitionSchema = JobDefinitionSchemaCore.superRefine(
1247
+ (data, ctx) => {
1248
+ data.arms.forEach((arm, i) => {
1249
+ const mode = arm.read.mode;
1250
+ if (arm.kind === "realtime" && mode !== "webhook") {
1251
+ ctx.addIssue({
1252
+ code: z6.ZodIssueCode.custom,
1253
+ message: `realtime arm '${arm.domain}' requires read.mode 'webhook' (got '${mode}'). Realtime is a webhook-drain shape (ADR-0018 D1).`,
1254
+ path: ["arms", i, "read", "mode"]
1255
+ });
1256
+ }
1257
+ if ((arm.kind === "poll" || arm.kind === "reconcile") && mode !== "poll") {
1258
+ ctx.addIssue({
1259
+ code: z6.ZodIssueCode.custom,
1260
+ message: `${arm.kind} arm '${arm.domain}' requires read.mode 'poll' (got '${mode}').`,
1261
+ path: ["arms", i, "read", "mode"]
1262
+ });
1263
+ }
1264
+ });
1265
+ }
1266
+ );
1267
+
1148
1268
  // src/utils/yaml-loader.ts
1149
1269
  function loadEntityFromYaml(filePath) {
1150
1270
  if (!existsSync(filePath)) {
@@ -2005,6 +2125,9 @@ function validateProviders(providers, opts) {
2005
2125
  return issues;
2006
2126
  }
2007
2127
 
2128
+ // src/parser/load-jobs.ts
2129
+ import { basename, resolve as resolve5 } from "path";
2130
+
2008
2131
  // src/analyzer/graph-builder.ts
2009
2132
  function inferCardinality(type) {
2010
2133
  switch (type) {
@@ -3994,14 +4117,14 @@ function formatMermaidGraph(result) {
3994
4117
  }
3995
4118
 
3996
4119
  // src/patterns/library/activity.pattern.ts
3997
- import { z as z6 } from "zod";
3998
- var ActivityPatternConfigSchema = z6.object({
4120
+ import { z as z7 } from "zod";
4121
+ var ActivityPatternConfigSchema = z7.object({
3999
4122
  /** Subject entity name → derives the FK column `<subject>_id`. */
4000
- subject: z6.string().optional(),
4123
+ subject: z7.string().optional(),
4001
4124
  /** Explicit snake_case FK column, when it does not follow `<subject>_id`. */
4002
- subjectColumn: z6.string().optional(),
4125
+ subjectColumn: z7.string().optional(),
4003
4126
  /** snake_case recency-ordering column; defaults to `occurred_at`. */
4004
- occurredAt: z6.string().optional()
4127
+ occurredAt: z7.string().optional()
4005
4128
  }).strict();
4006
4129
  var ActivityPattern = definePattern({
4007
4130
  name: "Activity",
@@ -4039,8 +4162,8 @@ var BasePattern = definePattern({
4039
4162
  });
4040
4163
 
4041
4164
  // src/patterns/library/junction.pattern.ts
4042
- import { z as z7 } from "zod";
4043
- var JunctionPatternConfigSchema = z7.object({}).strict();
4165
+ import { z as z8 } from "zod";
4166
+ var JunctionPatternConfigSchema = z8.object({}).strict();
4044
4167
  var JunctionPattern = definePattern({
4045
4168
  name: "Junction",
4046
4169
  description: "Explicit many-to-many junction with role + temporal + sourcing metadata",
@@ -4349,4 +4472,4 @@ export {
4349
4472
  analyzeDomain,
4350
4473
  validateEntities
4351
4474
  };
4352
- //# sourceMappingURL=chunk-K4BQQ2NN.js.map
4475
+ //# sourceMappingURL=chunk-YUVEJNRE.js.map