@classytic/arc 2.11.3 → 2.13.1

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 (185) hide show
  1. package/README.md +27 -18
  2. package/dist/{BaseController-swXruJ2_.mjs → BaseController-DX_T-bDB.mjs} +388 -423
  3. package/dist/EventTransport-CT_52aWU.d.mts +34 -0
  4. package/dist/EventTransport-DLWoUMHy.mjs +103 -0
  5. package/dist/{QueryCache-DOBNHBE0.d.mts → QueryCache-D41bfdBB.d.mts} +1 -1
  6. package/dist/{ResourceRegistry-DkAeAuTX.mjs → ResourceRegistry-CTERg_2x.mjs} +139 -66
  7. package/dist/audit/index.d.mts +2 -2
  8. package/dist/audit/index.mjs +1 -1
  9. package/dist/auth/audit.d.mts +199 -0
  10. package/dist/auth/audit.mjs +288 -0
  11. package/dist/auth/index.d.mts +5 -5
  12. package/dist/auth/index.mjs +117 -191
  13. package/dist/auth/redis-session.d.mts +1 -1
  14. package/dist/{betterAuthOpenApi-DwxtK3uG.mjs → betterAuthOpenApi--M_i87dQ.mjs} +1 -1
  15. package/dist/buildHandler-olo-gt94.mjs +610 -0
  16. package/dist/cache/index.d.mts +3 -3
  17. package/dist/cache/index.mjs +3 -3
  18. package/dist/cli/commands/describe.d.mts +89 -13
  19. package/dist/cli/commands/describe.mjs +56 -2
  20. package/dist/cli/commands/docs.mjs +2 -2
  21. package/dist/cli/commands/generate.mjs +147 -48
  22. package/dist/cli/commands/init.d.mts +13 -0
  23. package/dist/cli/commands/init.mjs +237 -112
  24. package/dist/cli/commands/introspect.mjs +8 -1
  25. package/dist/context/index.mjs +1 -1
  26. package/dist/core/index.d.mts +3 -3
  27. package/dist/core/index.mjs +5 -5
  28. package/dist/core-D72ia0EH.mjs +1399 -0
  29. package/dist/{createActionRouter-u3ql2EDo.mjs → createActionRouter-CEvzKcy8.mjs} +7 -20
  30. package/dist/createAggregationRouter-CyecOxnO.mjs +114 -0
  31. package/dist/{createApp-BFxtdKy6.mjs → createApp-XX2-N0Yd.mjs} +31 -27
  32. package/dist/defineEvent-D5h7EvAx.mjs +188 -0
  33. package/dist/docs/index.d.mts +2 -2
  34. package/dist/docs/index.mjs +2 -2
  35. package/dist/{elevation-DOFoxoDs.mjs → elevation-DgoeTyfX.mjs} +1 -1
  36. package/dist/errorHandler-Bk-AGhkU.mjs +174 -0
  37. package/dist/errorHandler-DFr45ZG4.d.mts +45 -0
  38. package/dist/errors-j4aJm1Wg.mjs +184 -0
  39. package/dist/{eventPlugin-KrFIQ097.mjs → eventPlugin-CaKTYkYM.mjs} +35 -137
  40. package/dist/{eventPlugin-CUNjYYRY.d.mts → eventPlugin-qXpqTebY.d.mts} +57 -7
  41. package/dist/events/index.d.mts +164 -5
  42. package/dist/events/index.mjs +133 -209
  43. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  44. package/dist/events/transports/redis-stream-entry.mjs +204 -31
  45. package/dist/events/transports/redis.d.mts +1 -1
  46. package/dist/factory/index.d.mts +2 -2
  47. package/dist/factory/index.mjs +2 -2
  48. package/dist/{fields-C8Y0XLAu.d.mts → fields-COhcH3fk.d.mts} +23 -2
  49. package/dist/hooks/index.d.mts +1 -1
  50. package/dist/hooks/index.mjs +1 -1
  51. package/dist/idempotency/index.d.mts +3 -3
  52. package/dist/idempotency/index.mjs +1 -20
  53. package/dist/idempotency/redis.d.mts +1 -1
  54. package/dist/idempotency/redis.mjs +1 -1
  55. package/dist/{index-BYCqHCVu.d.mts → index-BTqLEvhu.d.mts} +164 -4
  56. package/dist/{index-6u4_Gg6G.d.mts → index-BtW7qYwa.d.mts} +661 -281
  57. package/dist/{index-BdXnTPRj.d.mts → index-Ds61mrJE.d.mts} +50 -4
  58. package/dist/{index-DdQ3O9Pg.d.mts → index-Dz5IKsrE.d.mts} +360 -219
  59. package/dist/index.d.mts +6 -7
  60. package/dist/index.mjs +9 -10
  61. package/dist/integrations/event-gateway.d.mts +2 -2
  62. package/dist/integrations/event-gateway.mjs +1 -1
  63. package/dist/integrations/index.d.mts +2 -2
  64. package/dist/integrations/mcp/index.d.mts +2 -2
  65. package/dist/integrations/mcp/index.mjs +1 -1
  66. package/dist/integrations/mcp/testing.d.mts +1 -1
  67. package/dist/integrations/mcp/testing.mjs +1 -1
  68. package/dist/integrations/streamline.d.mts +60 -11
  69. package/dist/integrations/streamline.mjs +75 -85
  70. package/dist/integrations/websocket-redis.d.mts +1 -1
  71. package/dist/integrations/websocket.d.mts +1 -1
  72. package/dist/integrations/websocket.mjs +2 -8
  73. package/dist/middleware/index.d.mts +1 -1
  74. package/dist/middleware/index.mjs +2 -2
  75. package/dist/migrations/index.d.mts +23 -3
  76. package/dist/migrations/index.mjs +0 -7
  77. package/dist/{multipartBody-CvTR1Un6.mjs → multipartBody-BOvVSVCD.mjs} +11 -8
  78. package/dist/{openapi-BGUn7Ki1.mjs → openapi-CiOMVW1p.mjs} +143 -13
  79. package/dist/org/index.d.mts +2 -2
  80. package/dist/org/index.mjs +1 -1
  81. package/dist/permissions/index.d.mts +3 -3
  82. package/dist/permissions/index.mjs +3 -3
  83. package/dist/{permissions-gd_aUWrR.mjs → permissions-ohQyv50e.mjs} +404 -176
  84. package/dist/{pipe-DVoIheVC.mjs → pipe-Zr0KXjQe.mjs} +1 -1
  85. package/dist/pipeline/index.d.mts +1 -1
  86. package/dist/pipeline/index.mjs +1 -1
  87. package/dist/plugins/index.d.mts +18 -33
  88. package/dist/plugins/index.mjs +33 -13
  89. package/dist/plugins/response-cache.mjs +1 -1
  90. package/dist/plugins/tracing-entry.d.mts +1 -1
  91. package/dist/plugins/tracing-entry.mjs +1 -1
  92. package/dist/presets/filesUpload.d.mts +5 -5
  93. package/dist/presets/filesUpload.mjs +6 -9
  94. package/dist/presets/index.d.mts +1 -1
  95. package/dist/presets/index.mjs +1 -1
  96. package/dist/presets/multiTenant.d.mts +1 -1
  97. package/dist/presets/multiTenant.mjs +2 -2
  98. package/dist/presets/search.d.mts +2 -2
  99. package/dist/presets/search.mjs +6 -8
  100. package/dist/{presets-Z7P5w4gF.mjs → presets-BbkjdPeH.mjs} +6 -28
  101. package/dist/{queryCachePlugin-BUXBSm4F.d.mts → queryCachePlugin-CqMdLI2-.d.mts} +2 -2
  102. package/dist/{queryCachePlugin-Bq6bO6vc.mjs → queryCachePlugin-m1XsgAIJ.mjs} +3 -3
  103. package/dist/{redis-Cm1gnRDf.d.mts → redis-DiMkdHEl.d.mts} +1 -1
  104. package/dist/redis-stream-D6HzR1Z_.d.mts +232 -0
  105. package/dist/registry/index.d.mts +1 -1
  106. package/dist/registry/index.mjs +2 -2
  107. package/dist/{replyHelpers-ByllIXXV.mjs → replyHelpers-CK-FNO8E.mjs} +3 -21
  108. package/dist/{resourceToTools-ByZpgjeH.mjs → resourceToTools-C5coh64w.mjs} +224 -71
  109. package/dist/{routerShared-BqLRb5l7.mjs → routerShared-D6_fEGHh.mjs} +40 -36
  110. package/dist/{schemaIR-BlG9bY7v.mjs → schemaIR-7Vl611Qs.mjs} +1 -1
  111. package/dist/schemas/index.d.mts +100 -30
  112. package/dist/schemas/index.mjs +86 -29
  113. package/dist/scim/index.d.mts +264 -0
  114. package/dist/scim/index.mjs +963 -0
  115. package/dist/scope/index.d.mts +3 -3
  116. package/dist/scope/index.mjs +4 -4
  117. package/dist/{sse-V7aXc3bW.mjs → sse-Bz-5ZeTt.mjs} +1 -1
  118. package/dist/{store-helpers-BhrzxvyQ.mjs → store-helpers-BkIN9-vu.mjs} +1 -1
  119. package/dist/testing/index.d.mts +2 -8
  120. package/dist/testing/index.mjs +16 -24
  121. package/dist/testing/storageContract.d.mts +1 -1
  122. package/dist/types/index.d.mts +4 -4
  123. package/dist/types/storage.d.mts +1 -1
  124. package/dist/{types-BH7dEGvU.d.mts → types-BvqwCCSx.d.mts} +77 -29
  125. package/dist/{types-tgR4Pt8F.d.mts → types-CTYvcwHe.d.mts} +195 -1
  126. package/dist/{types-AOD8fxIw.mjs → types-C_s5moIu.mjs} +117 -1
  127. package/dist/{types-9beEMe25.d.mts → types-DQHFc8PM.d.mts} +1 -1
  128. package/dist/utils/index.d.mts +2 -2
  129. package/dist/utils/index.mjs +5 -5
  130. package/dist/{utils-CcYTj09l.mjs → utils-_h9B3c57.mjs} +1269 -1334
  131. package/dist/{versioning-M9lNLhO8.d.mts → versioning-DTTvc80y.d.mts} +1 -1
  132. package/package.json +24 -34
  133. package/skills/arc/SKILL.md +521 -785
  134. package/skills/arc/references/agent-auth.md +238 -0
  135. package/skills/arc/references/api-reference.md +187 -0
  136. package/skills/arc/references/auth.md +354 -7
  137. package/skills/arc/references/enterprise-auth.md +94 -0
  138. package/skills/arc/references/events.md +8 -6
  139. package/skills/arc/references/mcp.md +2 -2
  140. package/skills/arc/references/multi-tenancy.md +11 -2
  141. package/skills/arc/references/production.md +10 -9
  142. package/skills/arc/references/scim.md +247 -0
  143. package/skills/arc/references/testing.md +1 -1
  144. package/skills/arc-code-review/SKILL.md +141 -0
  145. package/skills/arc-code-review/references/anti-patterns.md +911 -0
  146. package/skills/arc-code-review/references/arc-cheatsheet.md +380 -0
  147. package/skills/arc-code-review/references/migration-recipes.md +700 -0
  148. package/skills/arc-code-review/references/mongokit-migration.md +386 -0
  149. package/skills/arc-code-review/references/scaffolding.md +230 -0
  150. package/skills/arc-code-review/references/severity.md +127 -0
  151. package/dist/EventTransport-CfVEGaEl.d.mts +0 -293
  152. package/dist/adapters/index.d.mts +0 -3
  153. package/dist/adapters/index.mjs +0 -2
  154. package/dist/adapters-D0tT2Tyo.mjs +0 -949
  155. package/dist/auth/mongoose.d.mts +0 -191
  156. package/dist/auth/mongoose.mjs +0 -73
  157. package/dist/core-DnUsRpuX.mjs +0 -1049
  158. package/dist/errorHandler-BQm8ZxTK.mjs +0 -173
  159. package/dist/errorHandler-Co3lnVmJ.d.mts +0 -114
  160. package/dist/errors-D5c-5BJL.mjs +0 -232
  161. package/dist/index-BbMrcvGp.d.mts +0 -362
  162. package/dist/redis-stream-CM8TXTix.d.mts +0 -110
  163. /package/dist/{HookSystem-CGsMd6oK.mjs → HookSystem-Iiebom92.mjs} +0 -0
  164. /package/dist/{actionPermissions-sUUKDhtP.mjs → actionPermissions-CyUkQu6O.mjs} +0 -0
  165. /package/dist/{caching-CheW3m-S.mjs → caching-SM8gghN6.mjs} +0 -0
  166. /package/dist/{constants-BhY1OHoH.mjs → constants-Cxde4rpC.mjs} +0 -0
  167. /package/dist/{elevation-s5ykdNHr.d.mts → elevation-BXOWoGCF.d.mts} +0 -0
  168. /package/dist/{externalPaths-Bapitwvd.d.mts → externalPaths-BD5nw6St.d.mts} +0 -0
  169. /package/dist/{interface-CkkWm5uR.d.mts → interface-DfLGcus7.d.mts} +0 -0
  170. /package/dist/{interface-Da0r7Lna.d.mts → interface-beEtJyWM.d.mts} +0 -0
  171. /package/dist/{keys-CARyUjiR.mjs → keys-CGcCbNyu.mjs} +0 -0
  172. /package/dist/{loadResources-CPpkyKfM.mjs → loadResources-DBMQg_Aj.mjs} +0 -0
  173. /package/dist/{memory-DikHSvWa.mjs → memory-UBydS5ku.mjs} +0 -0
  174. /package/dist/{metrics-Csh4nsvv.mjs → metrics-Qnvwc-LQ.mjs} +0 -0
  175. /package/dist/{pluralize-BneOJkpi.mjs → pluralize-DQgqgifU.mjs} +0 -0
  176. /package/dist/{registry-D63ee7fl.mjs → registry-I-ogLgL9.mjs} +0 -0
  177. /package/dist/{requestContext-C5XeK3VA.mjs → requestContext-SSaaTgW8.mjs} +0 -0
  178. /package/dist/{schemaConverter-B0oKLuqI.mjs → schemaConverter-De34B1ZG.mjs} +0 -0
  179. /package/dist/{sessionManager-D-oNWHz3.d.mts → sessionManager-C4Le_UB3.d.mts} +0 -0
  180. /package/dist/{storage-BwGQXUpd.d.mts → storage-Dfzt4VTl.d.mts} +0 -0
  181. /package/dist/{tracing-DokiEsuz.d.mts → tracing-QJVprktp.d.mts} +0 -0
  182. /package/dist/{typeGuards-CcFZXgU7.mjs → typeGuards-BzkXkvVv.mjs} +0 -0
  183. /package/dist/{types-DV9WDfeg.mjs → types-D57iXYb8.mjs} +0 -0
  184. /package/dist/{versioning-CGPjkqAg.mjs → versioning-BUrT5aP4.mjs} +0 -0
  185. /package/dist/{websocket-CyJ1VIFI.d.mts → websocket-ChC2rqe1.d.mts} +0 -0
@@ -0,0 +1,127 @@
1
+ # Severity Rubric
2
+
3
+ Score every finding by **blast radius × likelihood of harm × ease of detection in current tests**. Don't grade by code volume — a one-line auth bypass beats 200 lines of duplicated CRUD.
4
+
5
+ Severity legend: 🔴 Critical · 🟠 High · 🟡 Medium · 🟢 Low
6
+
7
+ ---
8
+
9
+ ## 🔴 Critical — fix this release
10
+
11
+ A finding is **critical** if it meets any of:
12
+
13
+ - **Auth/authorization bypass.** `req.user.role` accessed without scope guard on a public route, missing tenant filter, hand-rolled idempotency that double-charges under retry, webhook signature verification on parsed body.
14
+ - **Data leakage.** Manual `toJSON` transform with sensitive fields not declared `hidden`. New sensitive fields (added later) inherit the leak silently.
15
+ - **Drift in security-critical wiring.** Custom controller that doesn't forward `tenantField`, so multi-tenant injection silently fails.
16
+ - **Silent failure modes.** Headers set in `onSend` (intermittent `ERR_HTTP_HEADERS_SENT` under load), `failOpen` events on a path that needs delivery guarantees.
17
+ - **Runtime crashes.** `req.user._id` access on `allowPublic()` routes (crashes only when unauthenticated request hits — usually missed in dev).
18
+
19
+ **Examples (from anti-patterns.md):** §4, §5, §9, §17, §18, §25, §27, §32.
20
+
21
+ **Action:** stop the audit, write a hot-fix recommendation, then continue. These can ship as standalone PRs ahead of the broader migration.
22
+
23
+ ---
24
+
25
+ ## 🟠 High — fix this quarter
26
+
27
+ A finding is **high** if:
28
+
29
+ - **Duplicated arc behavior** that *will* drift. Five `fastify.get/post/patch/delete` calls per resource where one `defineResource` would do — one resource gets a fix the others don't.
30
+ - **Wrong abstraction layer.** Driver imports (`mongoose`, `@prisma/client`, `drizzle-orm`) leaking into `services/`, `hooks/`, `routes/`. Forces every consumer to pull a database driver; complicates testing.
31
+ - **Missing arc capability** that's already a pain point. Manual idempotency, manual rate-limiting, manual event emission inconsistency, hand-rolled audit trail. The team is building tools arc already provides.
32
+ - **Whole-suite refactor.** No mongokit adoption (§28). Each Mongoose model is a 100+ LOC reduction.
33
+
34
+ **Examples:** §3, §7, §10, §19, §20, §22, §28.
35
+
36
+ **Action:** prioritize by occurrence count. A pattern repeated 30 times outranks an isolated high.
37
+
38
+ ---
39
+
40
+ ## 🟡 Medium — fix opportunistically
41
+
42
+ A finding is **medium** if:
43
+
44
+ - **Drift surface, not yet harmful.** Manual query parsing where the fields parsed are well-known and stable; manual cache invalidation where the cache strategy works today but breaks on rollout.
45
+ - **Documentation drift.** Hand-maintained OpenAPI/Swagger that's currently in sync but will inevitably diverge.
46
+ - **Preset adoption gap.** Soft-delete/multi-tenant/bulk wired manually instead of via preset. Code works but doesn't benefit from preset upgrades.
47
+ - **Style of contract.** Custom controller without forwarding hooks (works today, breaks when arc updates).
48
+
49
+ **Examples:** §1, §2, §6, §8, §14, §16, §21, §23, §24, §26.
50
+
51
+ **Action:** bundle into resource-by-resource refactor PRs. Don't open a separate "fix all medium" PR.
52
+
53
+ ---
54
+
55
+ ## 🟢 Low — fix when adjacent
56
+
57
+ A finding is **low** if:
58
+
59
+ - **Code-style only.** `console.log`, `any`, `@ts-ignore`, default exports, tsconfig path aliases breaking auto-discovery.
60
+ - **Cosmetic config.** Missing `displayName` / `module` on `defineResource`, no `arc-cheatsheet` subpath imports, missing `arc docs` script in package.json.
61
+ - **Nicety, not problem.** Manual auth registration instead of `createApp({ auth })` — works fine if app is small.
62
+
63
+ **Examples:** §11, §12, §13, §29, §30, §31.
64
+
65
+ **Action:** fix when touching the file for another reason. Don't write a dedicated PR.
66
+
67
+ ---
68
+
69
+ ## Triage examples
70
+
71
+ ### "Found 47 manual permission checks across 12 resources"
72
+ 🔴 Critical (auth surface) → list each as a separate finding **only if** the check pattern differs. If they're all `if (!req.user.roles.includes('admin')) throw ...`, group as one finding with 47 occurrences.
73
+
74
+ ### "Found `mongoose` imported in 8 service files"
75
+ 🟠 High → architectural. Group by service module, not file, since a service rewrite touches all files in the module together.
76
+
77
+ ### "Found 3 separate `softDelete` reimplementations across resources"
78
+ 🟡 Medium → preset adoption. Bundle with the resource refactor.
79
+
80
+ ### "Found `console.log` in 23 places"
81
+ 🟢 Low → unless any are inside a hot path with sensitive data (then escalate to High for *those* specific calls).
82
+
83
+ ---
84
+
85
+ ## When to escalate severity
86
+
87
+ Escalate one tier higher if:
88
+
89
+ - **The pattern is in a write path.** Any pattern in `POST/PATCH/DELETE` is one tier worse than the same pattern in `GET`.
90
+ - **The pattern is in `auth/`, `webhooks/`, `payments/`, `audit/`, or anything customer-money-touching.** All findings in these paths are at minimum 🟠.
91
+ - **The team has been bitten before.** If `git log` shows a hot-fix commit for a related bug, the underlying pattern is at minimum 🟠.
92
+ - **No tests cover the path.** A medium pattern with no test cover is high — drift will land in prod.
93
+
94
+ Escalate one tier lower if:
95
+
96
+ - **The path is feature-flagged off** in production.
97
+ - **The path is admin-only and there are <5 admins** with manually verified scope.
98
+ - **A migration is already in flight** for this pattern (don't double-count).
99
+
100
+ ---
101
+
102
+ ## Reporting cadence
103
+
104
+ For a single audit:
105
+
106
+ - **Top 3 criticals** in the executive summary.
107
+ - **All highs** in the body.
108
+ - **Mediums grouped by category** (one row each: "12× manual query parsing").
109
+ - **Lows in an appendix** or omitted.
110
+
111
+ Don't dump every finding into one giant table — readers will skip. Give them the headline first.
112
+
113
+ ---
114
+
115
+ ## Score → migration estimate
116
+
117
+ Rough conversion for the executive summary's "estimated effort" line:
118
+
119
+ | Critical findings | Highs | Mediums | Lows | Effort |
120
+ |---|---|---|---|---|
121
+ | 0 | <5 | <10 | any | S (1–3 days, 1 dev) |
122
+ | 0 | 5–15 | 10–30 | any | M (1–2 weeks, 1 dev) |
123
+ | 1–3 | 5–15 | 10–30 | any | M+ (2 weeks, 2 devs — split critical fixes) |
124
+ | any | >15 | >30 | any | L (1 month+, plan in phases) |
125
+ | >3 | any | any | any | Stop the audit, raise critical fixes first, then re-audit |
126
+
127
+ These are heuristics. Adjust for codebase size and test coverage.
@@ -1,293 +0,0 @@
1
- //#region src/events/EventTransport.d.ts
2
- /**
3
- * Event Transport Interface
4
- *
5
- * Defines contract for event delivery backends.
6
- * Implement for durable transports (Redis, RabbitMQ, Kafka, etc.)
7
- *
8
- * @example
9
- * // Redis Pub/Sub implementation
10
- * class RedisEventTransport implements EventTransport {
11
- * async publish(event) {
12
- * await redis.publish(event.type, JSON.stringify(event));
13
- * }
14
- * async subscribe(pattern, handler) {
15
- * redis.psubscribe(pattern);
16
- * redis.on('pmessage', (p, channel, msg) => handler(JSON.parse(msg)));
17
- * }
18
- * }
19
- */
20
- /**
21
- * Event metadata.
22
- *
23
- * Split out as a standalone interface so primitives / downstream packages can
24
- * mirror it without re-declaring the DomainEvent wrapper. See events.ts in
25
- * @classytic/primitives for the sibling shape.
26
- */
27
- interface EventMeta {
28
- /** Unique event ID (UUID v4 recommended) */
29
- id: string;
30
- /** Event timestamp */
31
- timestamp: Date;
32
- /**
33
- * Schema version for this event type. Default: `1`.
34
- *
35
- * Use when the payload shape evolves so handlers can branch on version
36
- * during migration windows (`if (event.meta.schemaVersion === 2) ...`).
37
- * Bump ONLY when the payload contract changes in a breaking way.
38
- */
39
- schemaVersion?: number;
40
- /**
41
- * Correlation ID — stays stable across an entire causal chain so a single
42
- * user action can be traced through every downstream event. Spans service
43
- * boundaries. Generated at the edge (HTTP request, CLI invocation) and
44
- * inherited by every child event.
45
- */
46
- correlationId?: string;
47
- /**
48
- * Causation ID — the `meta.id` of the direct parent event that caused
49
- * this one. Forms a linked-list of cause-and-effect within a correlation.
50
- *
51
- * Distinct from correlationId: correlation groups, causation chains.
52
- * Use {@link createChildEvent} to populate this automatically.
53
- */
54
- causationId?: string;
55
- /**
56
- * Partition key hint for ordered transports (Kafka, Kinesis, Redis Streams
57
- * consumer groups). Events with the same partitionKey are guaranteed to be
58
- * delivered in publish order by transports that honour it.
59
- *
60
- * Defaults to `resourceId` if unset. Transports that don't support ordering
61
- * (in-memory, simple pub/sub) ignore this field.
62
- */
63
- partitionKey?: string;
64
- /** Source resource (e.g. 'order', 'transaction') */
65
- resource?: string;
66
- /** Resource identifier */
67
- resourceId?: string;
68
- /** User who triggered the event */
69
- userId?: string;
70
- /** Organization context */
71
- organizationId?: string;
72
- /**
73
- * Originating service or package (e.g. `'commerce'`, `'billing'`, `'arc-core'`).
74
- *
75
- * In a multi-service deployment, consumers route / log / alert by `source`
76
- * without parsing `type` prefixes. Arc itself never populates this — hosts
77
- * set it once per emitter (`app.events.publish('order.placed', p, { source: 'commerce' })`).
78
- * Inherited by {@link createChildEvent} so downstream events carry the same
79
- * source unless overridden.
80
- */
81
- source?: string;
82
- /**
83
- * Idempotency key — stable hint that this event represents a specific
84
- * operation exactly once. Consumers dedupe with `if (processed.has(meta.idempotencyKey)) return`.
85
- *
86
- * Survives every transport (Memory / Pub-Sub / Streams / Kafka) because it's
87
- * part of the event, not a transport-side option. Distinct from `meta.id`
88
- * (which is fresh per emit — a retry would produce a new id).
89
- *
90
- * Typical sources: HTTP `Idempotency-Key` header, outbox `dedupeKey`, or
91
- * `{aggregate.type}:{aggregate.id}:{action}`. Inherited by child events.
92
- */
93
- idempotencyKey?: string;
94
- /**
95
- * DDD aggregate marker — the aggregate that owns this event's invariant.
96
- *
97
- * Use when routing events by aggregate, doing event-sourcing replay, or
98
- * enforcing consistency boundaries. Distinct from `resource` / `resourceId`
99
- * (HTTP-origin entity) because an event emitted *by* one REST resource can
100
- * *belong to* a different aggregate (e.g. `POST /orders/:id/ship` emits
101
- * `shipment.dispatched` owned by a shipment aggregate).
102
- *
103
- * Downstream packages narrow `aggregate.type` to their own string union via
104
- * interface extension:
105
- *
106
- * ```ts
107
- * type CartAggregateType = 'cart' | 'cart-item';
108
- * interface CartEventMeta extends EventMeta {
109
- * aggregate?: { type: CartAggregateType; id: string };
110
- * }
111
- * ```
112
- *
113
- * Not inherited by {@link createChildEvent} — child events typically belong
114
- * to a different aggregate than their parent.
115
- */
116
- aggregate?: {
117
- type: string;
118
- id: string;
119
- };
120
- }
121
- interface DomainEvent<T = unknown> {
122
- /** Event type (e.g., 'product.created', 'order.shipped') */
123
- type: string;
124
- /** Event payload */
125
- payload: T;
126
- /** Event metadata */
127
- meta: EventMeta;
128
- }
129
- type EventHandler<T = unknown> = (event: DomainEvent<T>) => void | Promise<void>;
130
- /**
131
- * A permanently-failed event routed to a dead-letter sink after retries
132
- * have been exhausted. Mirrors the shape a caller would log, alert on, or
133
- * replay from once the upstream issue is fixed.
134
- */
135
- interface DeadLetteredEvent<T = unknown> {
136
- /** The original event */
137
- event: DomainEvent<T>;
138
- /** Serialised failure reason (message + optional machine code + stack) */
139
- error: {
140
- message: string;
141
- code?: string;
142
- stack?: string;
143
- };
144
- /** How many delivery attempts were made before giving up */
145
- attempts: number;
146
- /** First failure timestamp */
147
- firstFailedAt: Date;
148
- /** Last failure timestamp (immediately before dead-lettering) */
149
- lastFailedAt: Date;
150
- /** Optional handler / subscriber name that last failed (for debug) */
151
- handlerName?: string;
152
- }
153
- /**
154
- * Minimal logger interface for event transports.
155
- * Compatible with `console`, `pino`, `fastify.log`, and any custom logger.
156
- *
157
- * @example
158
- * ```typescript
159
- * // Use Fastify's logger
160
- * new MemoryEventTransport({ logger: fastify.log });
161
- *
162
- * // Use a custom logger
163
- * new MemoryEventTransport({ logger: { warn: myWarn, error: myError } });
164
- *
165
- * // Default: console (no logger option needed)
166
- * new MemoryEventTransport();
167
- * ```
168
- */
169
- interface EventLogger {
170
- warn(message: string, ...args: unknown[]): void;
171
- error(message: string, ...args: unknown[]): void;
172
- }
173
- interface EventTransport {
174
- /** Transport name for logging */
175
- readonly name: string;
176
- /**
177
- * Publish an event to the transport
178
- */
179
- publish(event: DomainEvent): Promise<void>;
180
- /**
181
- * Publish a batch of events to the transport (optional, v2.8.1+).
182
- *
183
- * Transports that can efficiently batch (Kafka producer, Redis pipeline,
184
- * RabbitMQ publisher confirms, SQS send-message-batch) should implement
185
- * this. {@link import('./outbox.js').EventOutbox.relay} auto-detects and
186
- * uses it for much higher throughput than per-event publishing.
187
- *
188
- * **Contract**: the returned `PublishManyResult` must describe the
189
- * per-event outcome so the caller can acknowledge successes and fail the
190
- * rest. Partial success is allowed — the transport reports it per event.
191
- *
192
- * If not implemented, `EventOutbox.relay` falls back to calling
193
- * {@link publish} once per event.
194
- *
195
- * @param events - Events to publish (in order)
196
- * @returns Per-event outcome map keyed by `event.meta.id`
197
- */
198
- publishMany?(events: readonly DomainEvent[]): Promise<PublishManyResult>;
199
- /**
200
- * Subscribe to events matching a pattern
201
- * @param pattern - Event type pattern (e.g., 'product.*', '*')
202
- * @param handler - Handler function
203
- * @returns Unsubscribe function
204
- */
205
- subscribe(pattern: string, handler: EventHandler): Promise<() => void>;
206
- /**
207
- * Route a permanently-failed event to the transport's dead-letter sink
208
- * (Kafka DLQ topic, SQS DLQ, Redis Stream `PEL` timeout handler, etc.).
209
- *
210
- * Called by {@link import('./outbox.js').EventOutbox} after exhausting
211
- * retries. Transports that don't have a native DLQ can omit this —
212
- * callers treat an absent `deadLetter` as "log and drop".
213
- */
214
- deadLetter?(dlq: DeadLetteredEvent): Promise<void>;
215
- /**
216
- * Close transport connections
217
- */
218
- close?(): Promise<void>;
219
- }
220
- /**
221
- * Per-event outcome returned by {@link EventTransport.publishMany}.
222
- *
223
- * The key is `event.meta.id`; the value is `null` for success or an `Error`
224
- * for per-event failure. Transports MUST include an entry for every event
225
- * in the input batch.
226
- */
227
- type PublishManyResult = ReadonlyMap<string, Error | null>;
228
- interface MemoryEventTransportOptions {
229
- /** Logger for error/warning messages (default: console) */
230
- logger?: EventLogger;
231
- }
232
- /**
233
- * In-memory event transport (default)
234
- * Events are delivered synchronously within the process.
235
- * Not suitable for multi-instance deployments.
236
- */
237
- declare class MemoryEventTransport implements EventTransport {
238
- readonly name = "memory";
239
- private handlers;
240
- private logger;
241
- constructor(options?: MemoryEventTransportOptions);
242
- publish(event: DomainEvent): Promise<void>;
243
- /**
244
- * Reference `publishMany` implementation — delegates to `publish()` in order.
245
- *
246
- * Production transports (Kafka, Redis pipeline, SQS batch) should override
247
- * this with a single batched network call. Memory transport has nothing to
248
- * batch, so we just loop — the loop still returns a proper result map so
249
- * `EventOutbox.relay` can exercise the batched code path in tests.
250
- */
251
- publishMany(events: readonly DomainEvent[]): Promise<PublishManyResult>;
252
- subscribe(pattern: string, handler: EventHandler): Promise<() => void>;
253
- close(): Promise<void>;
254
- }
255
- /**
256
- * Create a domain event with auto-generated metadata.
257
- *
258
- * `id` and `timestamp` are filled in; everything else is caller-controlled.
259
- * Set `schemaVersion` explicitly for any event type you plan to evolve.
260
- */
261
- declare function createEvent<T>(type: string, payload: T, meta?: Partial<EventMeta>): DomainEvent<T>;
262
- /**
263
- * Create a child event that chains causation from a parent event.
264
- *
265
- * Rules:
266
- * - `causationId` is set to the parent's `id` (direct cause)
267
- * - `correlationId` is inherited from the parent if set, else falls back
268
- * to the parent's `id` (root correlation)
269
- * - `userId` / `organizationId` are inherited when not overridden so the
270
- * whole chain stays scoped to the originating principal/tenant
271
- *
272
- * Caller-supplied `meta` wins over inherited fields — pass `{ userId: newActor }`
273
- * to override when a subsystem acts on behalf of a different principal.
274
- *
275
- * @example
276
- * ```typescript
277
- * const orderPlaced = createEvent('order.placed', { orderId: 'o1' }, {
278
- * correlationId: req.id, userId: user.id,
279
- * });
280
- * await events.publish(orderPlaced);
281
- *
282
- * // Downstream handler emits a child event:
283
- * const reserved = createChildEvent(orderPlaced, 'inventory.reserved', {
284
- * orderId: 'o1', skus: ['sku-1', 'sku-2'],
285
- * });
286
- * // reserved.meta.causationId === orderPlaced.meta.id
287
- * // reserved.meta.correlationId === orderPlaced.meta.correlationId
288
- * // reserved.meta.userId === user.id (inherited)
289
- * ```
290
- */
291
- declare function createChildEvent<T>(parent: DomainEvent, type: string, payload: T, meta?: Partial<EventMeta>): DomainEvent<T>;
292
- //#endregion
293
- export { EventMeta as a, MemoryEventTransportOptions as c, createEvent as d, EventLogger as i, PublishManyResult as l, DomainEvent as n, EventTransport as o, EventHandler as r, MemoryEventTransport as s, DeadLetteredEvent as t, createChildEvent as u };
@@ -1,3 +0,0 @@
1
- import { An as RelationMetadata, En as AdapterFactory, Mn as SchemaMetadata, Nn as ValidationResult, On as DataAdapter, jn as RepositoryLike, kn as FieldMetadata } from "../index-6u4_Gg6G.mjs";
2
- import { a as PrismaQueryParserOptions, c as MongooseAdapterOptions, d as DrizzleAdapterOptions, f as createDrizzleAdapter, i as PrismaQueryParser, l as createMongooseAdapter, n as PrismaAdapterOptions, o as createPrismaAdapter, r as PrismaQueryOptions, s as MongooseAdapter, t as PrismaAdapter, u as DrizzleAdapter } from "../index-BbMrcvGp.mjs";
3
- export { AdapterFactory, DataAdapter, DrizzleAdapter, DrizzleAdapterOptions, FieldMetadata, MongooseAdapter, MongooseAdapterOptions, PrismaAdapter, PrismaAdapterOptions, PrismaQueryOptions, PrismaQueryParser, PrismaQueryParserOptions, RelationMetadata, RepositoryLike, SchemaMetadata, ValidationResult, createDrizzleAdapter, createMongooseAdapter, createPrismaAdapter };
@@ -1,2 +0,0 @@
1
- import { a as createMongooseAdapter, i as MongooseAdapter, n as PrismaQueryParser, o as DrizzleAdapter, r as createPrismaAdapter, s as createDrizzleAdapter, t as PrismaAdapter } from "../adapters-D0tT2Tyo.mjs";
2
- export { DrizzleAdapter, MongooseAdapter, PrismaAdapter, PrismaQueryParser, createDrizzleAdapter, createMongooseAdapter, createPrismaAdapter };