@classytic/arc 2.41.1 → 2.43.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 (230) hide show
  1. package/dist/{EventTransport-CbUKDzZZ.d.mts → EventTransport-CiicKz2Z.d.mts} +1 -1
  2. package/dist/{EventTransport-DSqD_Xsg.mjs → EventTransport-tzA7CAB4.mjs} +22 -17
  3. package/dist/{HookSystem-CMF94SEA.mjs → HookSystem-B6UaKRbF.mjs} +2 -2
  4. package/dist/{QueryCache-DFA-QrU9.d.mts → QueryCache--5uAuYPW.d.mts} +7 -3
  5. package/dist/{ResourceRegistry-MGpXoxHZ.mjs → ResourceRegistry-CuCARu2B.mjs} +44 -13
  6. package/dist/actionPermissions-BotX1YOa.mjs +776 -0
  7. package/dist/audit/index.d.mts +43 -5
  8. package/dist/audit/index.mjs +48 -26
  9. package/dist/auth/audit.mjs +1 -1
  10. package/dist/auth/index.d.mts +43 -13
  11. package/dist/auth/index.mjs +130 -155
  12. package/dist/auth/redis-session.mjs +1 -1
  13. package/dist/{authorizationDecision-DawKGoXb.mjs → authorizationDecision-DQYrkl5f.mjs} +7 -102
  14. package/dist/{base-CxrV1LmG.d.mts → base-CZyixEQR.d.mts} +27 -5
  15. package/dist/boundedMap-BULzfXYU.mjs +57 -0
  16. package/dist/{buildHandler-CvxKOc0m.mjs → buildHandler-CRQ8EcX5.mjs} +4 -4
  17. package/dist/cache/index.d.mts +22 -34
  18. package/dist/cache/index.mjs +4 -4
  19. package/dist/{caching-DbCBxlgw.mjs → caching-Cc2M1DwO.mjs} +3 -3
  20. package/dist/claimed-B10RTfkM.mjs +8 -0
  21. package/dist/cleanup/index.d.mts +6 -10
  22. package/dist/cleanup/index.mjs +27 -73
  23. package/dist/cli/commands/describe.d.mts +4 -2
  24. package/dist/cli/commands/describe.mjs +7 -4
  25. package/dist/cli/commands/docs.mjs +3 -3
  26. package/dist/cli/commands/doctor.mjs +1 -1
  27. package/dist/cli/commands/generate.mjs +2 -2
  28. package/dist/cli/commands/init.mjs +2 -2
  29. package/dist/cli/commands/introspect.mjs +2 -2
  30. package/dist/cli/index.mjs +3 -3
  31. package/dist/{constants-D5Ubn1fe.mjs → constants-Cu7Mx7_U.mjs} +4 -2
  32. package/dist/context/index.d.mts +2 -5
  33. package/dist/context/index.mjs +18 -38
  34. package/dist/core/index.d.mts +3 -3
  35. package/dist/core/index.mjs +8 -8
  36. package/dist/{core-5lazhva9.mjs → core-Cb0LjccA.mjs} +5 -4
  37. package/dist/{createActionRouter-DNqoaK81.mjs → createActionRouter-xjqonMRO.mjs} +87 -39
  38. package/dist/{createAggregationRouter-BcbQJf10.mjs → createAggregationRouter-zRYWw_5D.mjs} +11 -8
  39. package/dist/{preloadResources-f3boenVZ.mjs → createApp-D-953ZAq.mjs} +299 -390
  40. package/dist/{createMcpServer-CbDWkZ1T.d.mts → createMcpServer-C9cxS8zt.d.mts} +1 -1
  41. package/dist/{defineAggregation-D_eJjm5A.mjs → defineAggregation-Bm8RjMbq.mjs} +1 -1
  42. package/dist/{defineResource-DxkMTjRn.mjs → defineResource-DIC7JZGU.mjs} +118 -1024
  43. package/dist/discovery/index.mjs +1 -1
  44. package/dist/docs/index.d.mts +10 -4
  45. package/dist/docs/index.mjs +4 -4
  46. package/dist/{elevation-BXCfVcNG.d.mts → elevation-BW2J3tNj.d.mts} +1 -2
  47. package/dist/{elevation-CkvG0LG2.mjs → elevation-DG8SrLN-.mjs} +41 -12
  48. package/dist/encryption/index.mjs +3 -3
  49. package/dist/{errorHandler-D1GHKGlV.mjs → errorHandler-BnfDviL1.mjs} +26 -5
  50. package/dist/{errors-BH7YU_9O.mjs → errors-CtrywMHP.mjs} +58 -23
  51. package/dist/{errors-BGdVwP25.d.mts → errors-JYc9vwqE.d.mts} +9 -0
  52. package/dist/{eventPlugin-B52abJ8W.d.mts → eventPlugin-BtmA4-3P.d.mts} +65 -9
  53. package/dist/{eventPlugin-zZY-unhr.mjs → eventPlugin-Q6BhzHzs.mjs} +82 -21
  54. package/dist/{subscribe-helpers-DatDkcuG.mjs → eventTypes-Cdhm6ZlV.mjs} +151 -17
  55. package/dist/events/index.d.mts +33 -8
  56. package/dist/events/index.mjs +49 -53
  57. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  58. package/dist/events/transports/redis-stream-entry.mjs +139 -157
  59. package/dist/events/transports/redis.d.mts +1 -1
  60. package/dist/events/transports/redis.mjs +2 -2
  61. package/dist/factory/index.d.mts +32 -17
  62. package/dist/factory/index.mjs +213 -32
  63. package/dist/{fastify-augmentation-Cq2nHVaW.d.mts → fastify-augmentation-DhUJ-mvo.d.mts} +11 -25
  64. package/dist/{fields-I_EeRWND.d.mts → fields-BBSpf8pS.d.mts} +1 -1
  65. package/dist/{fields-BHrkoF5y.mjs → fields-ToPYpMqS.mjs} +1 -1
  66. package/dist/filter-merge-IpGywvym.mjs +99 -0
  67. package/dist/{generate-BLRf2m3y.mjs → generate-DRTkLlIl.mjs} +2 -2
  68. package/dist/{headers-BIXWKrzQ.mjs → headers-BbkIF6vA.mjs} +2 -2
  69. package/dist/health-D-Ft6JM6.mjs +22 -0
  70. package/dist/{health-ZRHeDHXH.mjs → health-DqbsG-_w.mjs} +115 -55
  71. package/dist/hooks/index.d.mts +2 -2
  72. package/dist/hooks/index.mjs +2 -2
  73. package/dist/idempotency/index.d.mts +31 -7
  74. package/dist/idempotency/index.mjs +155 -98
  75. package/dist/idempotency/redis.d.mts +1 -1
  76. package/dist/idempotency/redis.mjs +48 -11
  77. package/dist/{index-BHdZD8zK.d.mts → index-Bxriq3so.d.mts} +84 -21
  78. package/dist/{preloadResources-CjS2OfpU.d.mts → index-C8zVGYsk.d.mts} +37 -38
  79. package/dist/{index-D4u76eQW.d.mts → index-CRoPtISf.d.mts} +23 -73
  80. package/dist/{index-CbJiYrfv.d.mts → index-Chgz3d0i.d.mts} +1 -1
  81. package/dist/index-JdbZAIsm.d.mts +510 -0
  82. package/dist/{index-DHbyPo5j.d.mts → index-mqaqZNpe.d.mts} +253 -254
  83. package/dist/index.d.mts +8 -8
  84. package/dist/index.mjs +11 -11
  85. package/dist/{init-CpLkjU18.mjs → init-B_oUYDXI.mjs} +1 -1
  86. package/dist/integrations/event-gateway.d.mts +8 -3
  87. package/dist/integrations/event-gateway.mjs +4 -4
  88. package/dist/integrations/index.d.mts +3 -3
  89. package/dist/integrations/index.mjs +1 -1
  90. package/dist/integrations/jobs/index.d.mts +1 -1
  91. package/dist/integrations/jobs/index.mjs +18 -5
  92. package/dist/integrations/mcp/index.d.mts +72 -59
  93. package/dist/integrations/mcp/index.mjs +19 -4
  94. package/dist/integrations/mcp/testing.d.mts +2 -2
  95. package/dist/integrations/mcp/testing.mjs +2 -2
  96. package/dist/integrations/streamline.d.mts +78 -136
  97. package/dist/integrations/streamline.mjs +116 -54
  98. package/dist/integrations/webhooks.d.mts +60 -120
  99. package/dist/integrations/webhooks.mjs +36 -80
  100. package/dist/integrations/websocket-pushref-redis.d.mts +1 -1
  101. package/dist/integrations/websocket-pushref-redis.mjs +1 -1
  102. package/dist/integrations/websocket-redis.d.mts +1 -1
  103. package/dist/integrations/websocket-redis.mjs +1 -1
  104. package/dist/integrations/websocket.d.mts +3 -3
  105. package/dist/integrations/websocket.mjs +2 -2
  106. package/dist/{interface-DEWNOMza.d.mts → interface-C0395yUN.d.mts} +13 -1
  107. package/dist/{jsonBody-ELR9lfeU.mjs → jsonBody-B4YVGcql.mjs} +2 -2
  108. package/dist/{keys-cpZCtcIE.mjs → keys-B2KtgMLJ.mjs} +7 -18
  109. package/dist/{loadResources-BPfWiI5s.mjs → loadResources-Dn4lalw2.mjs} +3 -3
  110. package/dist/{loadResourcesFromEntry-ixtfL3J2.mjs → loadResourcesFromEntry-3sLYbuse.mjs} +2 -2
  111. package/dist/logger/index.d.mts +1 -8
  112. package/dist/logger/index.mjs +3 -153
  113. package/dist/logger-DXjfIqjV.mjs +160 -0
  114. package/dist/{mcpPlugin-BX5PujI0.mjs → mcpPlugin-C08HalN5.mjs} +433 -170
  115. package/dist/{memory-Iotz0cCx.mjs → memory-9Cp7611C.mjs} +36 -34
  116. package/dist/{metrics-NMsmpRmY.mjs → metrics-CWI11eRu.mjs} +39 -72
  117. package/dist/middleware/index.d.mts +2 -2
  118. package/dist/middleware/index.mjs +3 -3
  119. package/dist/migrations/index.mjs +2 -2
  120. package/dist/{module-DpLJG2_N.mjs → module-BSvOQC7E.mjs} +8 -8
  121. package/dist/multiTenant-cY0FkDiA.d.mts +104 -0
  122. package/dist/{multipartBody-DtRWM6_U.mjs → multipartBody-CXM2a-Dy.mjs} +46 -7
  123. package/dist/{openapi-CmFf3yq_.mjs → openapi-DT_G4VhY.mjs} +48 -10
  124. package/dist/outbox-admin/index.d.mts +3 -3
  125. package/dist/outbox-admin/index.mjs +6 -18
  126. package/dist/{outbox-module-D2z5WkDY.mjs → outbox-module-Bjgzl6tg.mjs} +203 -33
  127. package/dist/{outbox-module-BHdUnuuK.d.mts → outbox-module-gZCHoE4H.d.mts} +79 -6
  128. package/dist/permissions/index.d.mts +5 -4
  129. package/dist/permissions/index.mjs +8 -6
  130. package/dist/{permissions-D8TBH44E.mjs → permissions-Cm0uYHvd.mjs} +149 -33
  131. package/dist/{pipe-FMWNheSO.mjs → pipe-BqeGT6UO.mjs} +2 -2
  132. package/dist/pipeline/index.d.mts +2 -2
  133. package/dist/pipeline/index.mjs +2 -2
  134. package/dist/plan-FVR6LP59.mjs +565 -0
  135. package/dist/{BaseController-CYEwjyjN.mjs → plugin-BccET1tL.mjs} +1256 -345
  136. package/dist/plugins/index.d.mts +14 -11
  137. package/dist/plugins/index.mjs +44 -22
  138. package/dist/plugins/response-cache.mjs +8 -14
  139. package/dist/plugins/tracing-entry.mjs +2 -2
  140. package/dist/{pluralize-CXWZIzTv.mjs → pluralize-CVIOcgMF.mjs} +1 -1
  141. package/dist/presets/filesUpload.d.mts +2 -2
  142. package/dist/presets/filesUpload.mjs +5 -5
  143. package/dist/presets/index.d.mts +26 -31
  144. package/dist/presets/index.mjs +4 -4
  145. package/dist/presets/multiTenant.d.mts +2 -107
  146. package/dist/presets/multiTenant.mjs +22 -162
  147. package/dist/presets/search.d.mts +2 -2
  148. package/dist/presets/search.mjs +2 -2
  149. package/dist/{presets-ZJSPgmT2.mjs → presets-Cpvj6fGO.mjs} +99 -107
  150. package/dist/{projection-BzIgzoKZ.mjs → projection-Ce4aQhQk.mjs} +2 -2
  151. package/dist/{pushref-registry-Dov9l4qE.d.mts → pushref-registry-UxCkoA4C.d.mts} +1 -1
  152. package/dist/{queryCachePlugin-BzqxconG.d.mts → queryCachePlugin-C2lZjTxk.d.mts} +1 -1
  153. package/dist/{queryCachePlugin-DZHPOm9p.mjs → queryCachePlugin-CFWNH8aT.mjs} +12 -14
  154. package/dist/{rateLimitKey-BvOvcBDi.mjs → rateLimitKey-C4O-kPm0.mjs} +1 -1
  155. package/dist/{realtime-8tIQWZz4.mjs → realtime-DmPE9S54.mjs} +25 -21
  156. package/dist/redis-stream-BMk-bpQS.d.mts +219 -0
  157. package/dist/{redis-Bzi1y3F9.d.mts → redis-vLvtcGy_.d.mts} +13 -24
  158. package/dist/redisShapes-CQksY67q.d.mts +55 -0
  159. package/dist/registry/index.d.mts +9 -4
  160. package/dist/registry/index.mjs +4 -4
  161. package/dist/{registry-DNkgGQcK.mjs → registry-Bcz9G1bh.mjs} +10 -8
  162. package/dist/{renewingLease-yF8BdW4b.mjs → renewingLease-qODa7KJQ.mjs} +1 -1
  163. package/dist/{replyHelpers-CNdvMfM4.mjs → replyHelpers-CG_VtVgS.mjs} +2 -2
  164. package/dist/{requestContext-cDkAUr-P.mjs → requestContext-Dsu9P1bV.mjs} +1 -1
  165. package/dist/requirement-CbiLdQ1n.d.mts +22 -0
  166. package/dist/requirement-KDdoRcOP.mjs +35 -0
  167. package/dist/resourceRateLimit-Wf6d6FL9.d.mts +30 -0
  168. package/dist/resourceRateLimit-dSjVr1pk.mjs +180 -0
  169. package/dist/{rolldown-runtime-eysyzFAF.mjs → rolldown-runtime-D1w9Y1VJ.mjs} +1 -1
  170. package/dist/routeValidator-D36SW8qt.mjs +70 -0
  171. package/dist/{runtimeCapabilities-CkhS6jn6.mjs → runtimeCapabilities-0tccjRlj.mjs} +1 -1
  172. package/dist/{schedules-j6uXXAeJ.mjs → schedules-C-OpmHBq.mjs} +46 -37
  173. package/dist/{schemaConverter-BVA7cFRG.mjs → schemaConverter-BORek3O-.mjs} +2 -2
  174. package/dist/{schemaIR-CTvPDoPB.mjs → schemaIR-C7Vbp71I.mjs} +2 -2
  175. package/dist/schemas/index.d.mts +10 -0
  176. package/dist/schemas/index.mjs +8 -3
  177. package/dist/scim/index.mjs +2 -2
  178. package/dist/scope/index.d.mts +2 -2
  179. package/dist/scope/index.mjs +6 -6
  180. package/dist/{scope-BUi1xV1I.mjs → scope-DQthe88b.mjs} +4 -4
  181. package/dist/shutdown-MqA81z_P.mjs +59 -0
  182. package/dist/{simpleEqualityMatcher-C9bzq2gO.mjs → simpleEqualityMatcher-auW8QjXN.mjs} +1 -1
  183. package/dist/{sse-BeqVKQKu.mjs → sse-CYzQBVFe.mjs} +11 -15
  184. package/dist/{sseStream-Ppzo-WUH.mjs → sseStream-B5_Afiqn.mjs} +2 -2
  185. package/dist/{store-helpers-dW71XVWL.mjs → store-helpers-BOzk-CuX.mjs} +1 -1
  186. package/dist/{streaming-IcRFjWQU.mjs → streaming-DjTQhZrN.mjs} +1 -1
  187. package/dist/subscriberIdentity-CW39uA8G.mjs +28 -0
  188. package/dist/tenancy--ed9eH_z.mjs +43 -0
  189. package/dist/tenantPreparation-BKon6Yox.mjs +67 -0
  190. package/dist/testing/cleanupStoreContract.mjs +1 -1
  191. package/dist/testing/index.d.mts +193 -175
  192. package/dist/testing/index.mjs +286 -212
  193. package/dist/testing/outboxStoreContract.mjs +137 -2
  194. package/dist/testing/requiredPorts.d.mts +17 -0
  195. package/dist/testing/requiredPorts.mjs +65 -0
  196. package/dist/testing/storageContract.mjs +1 -1
  197. package/dist/timing-qczZ0YC-.mjs +46 -0
  198. package/dist/{transactionContext-CPbdlnVw.mjs → transactionContext-DjFkrNG6.mjs} +1 -1
  199. package/dist/{typeGuards-BLjPgVBm.mjs → typeGuards-CySF12G-.mjs} +1 -1
  200. package/dist/types/index.d.mts +4 -4
  201. package/dist/types/index.mjs +1 -1
  202. package/dist/types/storage.mjs +1 -1
  203. package/dist/{types-CWQn9-IC.d.mts → types-B4Aq4Sdj.d.mts} +22 -9
  204. package/dist/{types-DfVDvkdP.d.mts → types-BJ-2XqVF.d.mts} +189 -204
  205. package/dist/{types-CgenB1gv.mjs → types-Bk9NOgOC.mjs} +4 -4
  206. package/dist/usage/index.d.mts +2 -3
  207. package/dist/usage/index.mjs +5 -5
  208. package/dist/{userHelpers-ChRvkuSZ.mjs → userHelpers-aklawRaK.mjs} +1 -1
  209. package/dist/utils/index.d.mts +84 -223
  210. package/dist/utils/index.mjs +13 -12
  211. package/dist/{utils-CxcctrAh.mjs → utils-ec1oTo1n.mjs} +315 -404
  212. package/dist/{validate-DrYWnOzI.mjs → validate-9yzHC1e2.mjs} +6 -14
  213. package/dist/{versioning-D6JIK8Tk.d.mts → versioning-Bsb51gGT.d.mts} +28 -13
  214. package/dist/{versioning-DKkT4hNJ.mjs → versioning-fhhWHV74.mjs} +4 -4
  215. package/dist/{websocket-BOXVggMf.d.mts → websocket-Cs4awVyD.d.mts} +1 -1
  216. package/dist/{workScope-CxKqoIFn.mjs → workScope-zpPyge4t.mjs} +2 -2
  217. package/package.json +16 -12
  218. package/skills/arc/SKILL.md +13 -4
  219. package/skills/arc/references/auth.md +8 -5
  220. package/skills/arc/references/integrations.md +1 -1
  221. package/skills/arc/references/mcp.md +8 -6
  222. package/skills/arc/references/multi-tenancy.md +19 -14
  223. package/skills/arc/references/production.md +27 -10
  224. package/dist/actionPermissions-BoPGQ5-4.mjs +0 -350
  225. package/dist/index-CFfLKMH4.d.mts +0 -290
  226. package/dist/interface-YzIbF7Ii.mjs +0 -17
  227. package/dist/redis-stream-BPKscsTB.d.mts +0 -260
  228. package/dist/registerRoute-Bsnk6NiZ.mjs +0 -364
  229. package/dist/sync/changelog.d.mts +0 -3
  230. package/dist/sync/changelog.mjs +0 -3
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.41.1 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.43.0 | MIT | https://classytic.com */
2
2
  import { readdir } from "node:fs/promises";
3
3
  import { extname, join, resolve } from "node:path";
4
4
  import { pathToFileURL } from "node:url";
@@ -1,5 +1,5 @@
1
1
 
2
- import { p as RegistryEntry } from "../index-DHbyPo5j.mjs";
2
+ import { o as RegistryEntry } from "../index-mqaqZNpe.mjs";
3
3
  import { t as ExternalOpenApiPaths } from "../externalPaths-CmGOxOtD.mjs";
4
4
  import { FastifyPluginAsync } from "fastify";
5
5
  //#region src/docs/openapi/types.d.ts
@@ -86,6 +86,14 @@ interface Operation {
86
86
  type: string;
87
87
  name: string;
88
88
  }>;
89
+ /** Idempotency-key fence: every call (`required`) or the listed actions (`requiredActions`). */
90
+ "x-arc-idempotency"?: {
91
+ required?: true;
92
+ requiredActions?: readonly string[];
93
+ dedup?: "handler";
94
+ owner?: string;
95
+ handlerDedup?: Readonly<Record<string, string>>;
96
+ };
89
97
  }
90
98
  interface Parameter {
91
99
  name: string;
@@ -137,7 +145,6 @@ interface SecurityScheme {
137
145
  }
138
146
  //#endregion
139
147
  //#region src/docs/openapi/index.d.ts
140
- declare const openApiPlugin: FastifyPluginAsync<OpenApiOptions>;
141
148
  /**
142
149
  * Build OpenAPI spec from registry resources.
143
150
  * Shared by HTTP docs endpoint and CLI export command.
@@ -166,7 +173,6 @@ interface ScalarOptions {
166
173
  /** Favicon URL */
167
174
  favicon?: string;
168
175
  }
169
- declare const scalarPlugin: FastifyPluginAsync<ScalarOptions>;
170
176
  declare const _default$1: FastifyPluginAsync<ScalarOptions>;
171
177
  //#endregion
172
- export { type ExternalOpenApiPaths, type OpenApiBuildOptions, type OpenApiOptions, type OpenApiSpec, type ScalarOptions, buildOpenApiSpec, _default as openApiPlugin, openApiPlugin as openApiPluginFn, _default$1 as scalarPlugin, scalarPlugin as scalarPluginFn };
178
+ export { type ExternalOpenApiPaths, type OpenApiBuildOptions, type OpenApiOptions, type OpenApiSpec, type ScalarOptions, buildOpenApiSpec, _default as openApiPlugin, _default$1 as scalarPlugin };
@@ -1,6 +1,6 @@
1
- /*! @classytic/arc v2.41.1 | MIT | https://classytic.com */
2
- import { n as getUserRoles } from "../userHelpers-ChRvkuSZ.mjs";
3
- import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-CmFf3yq_.mjs";
1
+ /*! @classytic/arc v2.43.0 | MIT | https://classytic.com */
2
+ import { n as getUserRoles } from "../userHelpers-aklawRaK.mjs";
3
+ import { n as openapi_default, t as buildOpenApiSpec } from "../openapi-DT_G4VhY.mjs";
4
4
  import fp from "fastify-plugin";
5
5
  //#region src/docs/scalar.ts
6
6
  const scalarPlugin = async (fastify, opts = {}) => {
@@ -54,4 +54,4 @@ var scalar_default = fp(scalarPlugin, {
54
54
  fastify: "5.x"
55
55
  });
56
56
  //#endregion
57
- export { buildOpenApiSpec, openapi_default as openApiPlugin, openApiPlugin as openApiPluginFn, scalar_default as scalarPlugin, scalarPlugin as scalarPluginFn };
57
+ export { buildOpenApiSpec, openapi_default as openApiPlugin, scalar_default as scalarPlugin };
@@ -17,7 +17,6 @@ interface ElevationEvent {
17
17
  request: FastifyRequest;
18
18
  timestamp: Date;
19
19
  }
20
- declare const elevationPlugin: FastifyPluginAsync<ElevationOptions>;
21
20
  declare const _default: FastifyPluginAsync<ElevationOptions>;
22
21
  //#endregion
23
- export { elevationPlugin as i, ElevationOptions as n, _default as r, ElevationEvent as t };
22
+ export { ElevationOptions as n, _default as r, ElevationEvent as t };
@@ -1,10 +1,41 @@
1
- /*! @classytic/arc v2.41.1 | MIT | https://classytic.com */
2
- import { t as __exportAll } from "./rolldown-runtime-eysyzFAF.mjs";
3
- import { arcLog } from "./logger/index.mjs";
4
- import { n as requireSingleHeaderValue } from "./headers-BIXWKrzQ.mjs";
5
- import { n as getUserRoles } from "./userHelpers-ChRvkuSZ.mjs";
1
+ /*! @classytic/arc v2.43.0 | MIT | https://classytic.com */
2
+ import { t as __exportAll } from "./rolldown-runtime-D1w9Y1VJ.mjs";
3
+ import { t as arcLog } from "./logger-DXjfIqjV.mjs";
4
+ import { n as requireSingleHeaderValue } from "./headers-BbkIF6vA.mjs";
5
+ import { n as getUserRoles } from "./userHelpers-aklawRaK.mjs";
6
+ import { ARC_ERROR_CODES } from "@classytic/repo-core/errors";
6
7
  import fp from "fastify-plugin";
7
8
  //#region src/scope/elevation.ts
9
+ /**
10
+ * Elevation Plugin — Explicit Platform Admin Access
11
+ *
12
+ * Opt-in Fastify plugin that allows platform admins to explicitly
13
+ * elevate their scope via the `x-arc-scope: platform` header.
14
+ *
15
+ * Without this header, a superadmin is treated as a normal user.
16
+ * This prevents implicit bypass and enables audit logging.
17
+ *
18
+ * ## Lifecycle
19
+ *
20
+ * Elevation wraps `fastify.authenticate` so it always runs AFTER
21
+ * authentication has set `request.user`. This avoids the `onRequest`
22
+ * timing issue where `request.user` doesn't exist yet.
23
+ *
24
+ * Flow: `authenticate()` → user is set → `elevation check` → scope is set
25
+ *
26
+ * Inspired by Stripe Connect's `Stripe-Account` header.
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * const app = await createApp({
31
+ * auth: { type: 'betterAuth', betterAuth: adapter },
32
+ * elevation: {
33
+ * platformRoles: ['superadmin'],
34
+ * onElevation: (event) => auditLog.write(event),
35
+ * },
36
+ * });
37
+ * ```
38
+ */
8
39
  var elevation_exports = /* @__PURE__ */ __exportAll({
9
40
  default: () => elevation_default,
10
41
  elevationPlugin: () => elevationPlugin
@@ -25,10 +56,9 @@ const elevationPlugin = async (fastify, opts = {}) => {
25
56
  if (!user) {
26
57
  log.debug("Elevation requested but no user after auth");
27
58
  reply.code(401).send({
28
- success: false,
29
- error: "Unauthorized",
59
+ code: ARC_ERROR_CODES.ELEVATION_AUTH_REQUIRED,
30
60
  message: "Authentication required for platform elevation",
31
- code: "ELEVATION_AUTH_REQUIRED"
61
+ status: 401
32
62
  });
33
63
  return;
34
64
  }
@@ -40,10 +70,9 @@ const elevationPlugin = async (fastify, opts = {}) => {
40
70
  required: platformRoles
41
71
  });
42
72
  reply.code(403).send({
43
- success: false,
44
- error: "Forbidden",
73
+ code: ARC_ERROR_CODES.ELEVATION_FORBIDDEN,
45
74
  message: "Insufficient privileges for platform elevation",
46
- code: "ELEVATION_FORBIDDEN"
75
+ status: 403
47
76
  });
48
77
  return;
49
78
  }
@@ -95,4 +124,4 @@ var elevation_default = fp(elevationPlugin, {
95
124
  fastify: "5.x"
96
125
  });
97
126
  //#endregion
98
- export { elevation_default as n, elevation_exports as r, elevationPlugin as t };
127
+ export { elevation_exports as n, elevation_default as t };
@@ -1,6 +1,6 @@
1
- /*! @classytic/arc v2.41.1 | MIT | https://classytic.com */
2
- import { t as ArcError } from "../errors-BH7YU_9O.mjs";
3
- import { t as parseJsonBody } from "../jsonBody-ELR9lfeU.mjs";
1
+ /*! @classytic/arc v2.43.0 | MIT | https://classytic.com */
2
+ import { t as ArcError } from "../errors-CtrywMHP.mjs";
3
+ import { t as parseJsonBody } from "../jsonBody-B4YVGcql.mjs";
4
4
  import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
5
5
  import fp from "fastify-plugin";
6
6
  //#region src/encryption/fieldCipher.ts
@@ -1,8 +1,8 @@
1
- /*! @classytic/arc v2.41.1 | MIT | https://classytic.com */
2
- import { t as __exportAll } from "./rolldown-runtime-eysyzFAF.mjs";
3
- import { m as statusToArcCode, p as isArcError } from "./errors-BH7YU_9O.mjs";
4
- import { isProductionEnv } from "@classytic/primitives/environment";
1
+ /*! @classytic/arc v2.43.0 | MIT | https://classytic.com */
2
+ import { t as __exportAll } from "./rolldown-runtime-D1w9Y1VJ.mjs";
3
+ import { m as statusToArcCode, p as isArcError } from "./errors-CtrywMHP.mjs";
5
4
  import { isHttpError, toErrorContract } from "@classytic/repo-core/errors";
5
+ import { isProductionEnv } from "@classytic/primitives/environment";
6
6
  import fp from "fastify-plugin";
7
7
  //#region src/plugins/errorHandler.ts
8
8
  /**
@@ -154,10 +154,15 @@ async function errorHandlerPluginFn(fastify, options = {}) {
154
154
  };
155
155
  const status = wire.status ?? 500;
156
156
  if (status >= 500 && wire.code === "arc.internal_error" && !exposeInternalMessages) wire.message = "Internal Server Error";
157
- if (status >= 500) request.log.error({
157
+ const deliberateUnavailable = status === 503 && wire.code !== "arc.internal_error";
158
+ if (status >= 500 && !deliberateUnavailable) request.log.error({
158
159
  err: error,
159
160
  status
160
161
  }, "Server error");
162
+ else if (deliberateUnavailable) request.log.warn({
163
+ code: wire.code,
164
+ status
165
+ }, "Service unavailable");
161
166
  else if (status >= 400) request.log.warn({
162
167
  err: error,
163
168
  status
@@ -166,10 +171,26 @@ async function errorHandlerPluginFn(fastify, options = {}) {
166
171
  const causeLevel = status >= 500 ? "error" : "warn";
167
172
  request.log[causeLevel]({ cause: error.cause }, "Error cause chain");
168
173
  }
174
+ if (status === 429 || status === 503) {
175
+ const retryAfter = retryAfterSeconds(error);
176
+ if (retryAfter !== void 0) reply.header("retry-after", String(retryAfter));
177
+ }
169
178
  return reply.status(status).send(wire);
170
179
  });
171
180
  }
172
181
  /**
182
+ * Seconds to put in `Retry-After`, read from the thrown error's own
183
+ * `retryAfter` property (the convention `RateLimitError` set). Whole seconds,
184
+ * never below 1 — `0` would tell every client to retry immediately, which is
185
+ * the stampede the header exists to prevent.
186
+ */
187
+ function retryAfterSeconds(error) {
188
+ if (!error || typeof error !== "object") return void 0;
189
+ const value = error.retryAfter;
190
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return void 0;
191
+ return Math.max(1, Math.ceil(value));
192
+ }
193
+ /**
173
194
  * Is `code` a caller-defined DOMAIN error code that is safe to surface on the
174
195
  * wire, as opposed to a framework/runtime code that must never leak?
175
196
  *
@@ -1,6 +1,26 @@
1
- /*! @classytic/arc v2.41.1 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.43.0 | MIT | https://classytic.com */
2
+ import { ARC_ERROR_CODES } from "@classytic/repo-core/errors";
2
3
  //#region src/utils/errors.ts
3
4
  /**
5
+ * Arc error hierarchy.
6
+ *
7
+ * Throw an `ArcError` (or one of its subclasses) anywhere in a controller
8
+ * or middleware. Arc's global error handler catches it and serializes to
9
+ * the canonical `ErrorContract` wire shape via repo-core's
10
+ * `toErrorContract(err)` — one contract across the org.
11
+ *
12
+ * `ArcError` implements the {@link HttpError} contract from
13
+ * `@classytic/repo-core/errors`, so any host that already speaks that
14
+ * contract (mongokit, sqlitekit, streamline, prismakit) catches and
15
+ * serializes arc errors with the same code path it uses for its own.
16
+ *
17
+ * **Codes are catalogued in `@classytic/repo-core/errors`** (`ARC_ERROR_CODES`,
18
+ * `ARC_REASON_CODES`) so client SDKs read the wire vocabulary without
19
+ * depending on arc. Emit from those constants; `tests/utils/error-code-catalog.test.ts`
20
+ * fails on an uncatalogued `arc.*` literal. Domain packages use their own
21
+ * namespace (`commerce.cart.locked`).
22
+ */
23
+ /**
4
24
  * Base Arc Error. Implements the canonical `HttpError` contract — `status`
5
25
  * mirrors `statusCode` and `meta` mirrors `details`, so consumers reading
6
26
  * either name see the same value without adapter glue.
@@ -13,7 +33,7 @@ var ArcError = class extends Error {
13
33
  cause;
14
34
  constructor(message, options = {}) {
15
35
  super(message, options.cause ? { cause: options.cause } : void 0);
16
- this.code = options.code ?? "arc.error";
36
+ this.code = options.code ?? ARC_ERROR_CODES.ERROR;
17
37
  this.statusCode = options.statusCode ?? 500;
18
38
  this.details = options.details;
19
39
  this.cause = options.cause;
@@ -32,7 +52,7 @@ var NotFoundError = class extends ArcError {
32
52
  constructor(resource, identifier) {
33
53
  const message = identifier ? `${resource} with identifier '${identifier}' not found` : `${resource} not found`;
34
54
  super(message, {
35
- code: "arc.not_found",
55
+ code: ARC_ERROR_CODES.NOT_FOUND,
36
56
  statusCode: 404,
37
57
  details: {
38
58
  resource,
@@ -46,18 +66,29 @@ var ValidationError = class extends ArcError {
46
66
  errors;
47
67
  constructor(message, errors = []) {
48
68
  super(message, {
49
- code: "arc.validation_error",
69
+ code: ARC_ERROR_CODES.VALIDATION_ERROR,
50
70
  statusCode: 400,
51
71
  details: { errors }
52
72
  });
53
73
  this.name = "ValidationError";
54
74
  this.errors = errors;
55
75
  }
76
+ /**
77
+ * `HttpError.validationErrors` — what `toErrorContract` turns into the wire's
78
+ * `details[]`, the one place clients (arc-next `fieldErrors`) read field errors.
79
+ */
80
+ get validationErrors() {
81
+ return this.errors.map((e) => ({
82
+ path: e.field,
83
+ validator: "validation_error",
84
+ error: e.message
85
+ }));
86
+ }
56
87
  };
57
88
  var UnauthorizedError = class extends ArcError {
58
89
  constructor(message = "Authentication required") {
59
90
  super(message, {
60
- code: "arc.unauthorized",
91
+ code: ARC_ERROR_CODES.UNAUTHORIZED,
61
92
  statusCode: 401
62
93
  });
63
94
  this.name = "UnauthorizedError";
@@ -66,7 +97,7 @@ var UnauthorizedError = class extends ArcError {
66
97
  var ForbiddenError = class extends ArcError {
67
98
  constructor(message = "Access denied") {
68
99
  super(message, {
69
- code: "arc.forbidden",
100
+ code: ARC_ERROR_CODES.FORBIDDEN,
70
101
  statusCode: 403
71
102
  });
72
103
  this.name = "ForbiddenError";
@@ -75,7 +106,7 @@ var ForbiddenError = class extends ArcError {
75
106
  var ConflictError = class extends ArcError {
76
107
  constructor(message, field) {
77
108
  super(message, {
78
- code: "arc.conflict",
109
+ code: ARC_ERROR_CODES.CONFLICT,
79
110
  statusCode: 409,
80
111
  ...field ? { details: { field } } : {}
81
112
  });
@@ -86,7 +117,7 @@ var OrgRequiredError = class extends ArcError {
86
117
  organizations;
87
118
  constructor(message, organizations) {
88
119
  super(message, {
89
- code: "arc.org.selection_required",
120
+ code: ARC_ERROR_CODES.ORG_SELECTION_REQUIRED,
90
121
  statusCode: 403,
91
122
  ...organizations ? { details: { organizations } } : {}
92
123
  });
@@ -97,7 +128,7 @@ var OrgRequiredError = class extends ArcError {
97
128
  var OrgAccessDeniedError = class extends ArcError {
98
129
  constructor(orgId) {
99
130
  super("Organization access denied", {
100
- code: "arc.org.access_denied",
131
+ code: ARC_ERROR_CODES.ORG_ACCESS_DENIED,
101
132
  statusCode: 403,
102
133
  ...orgId ? { details: { organizationId: orgId } } : {}
103
134
  });
@@ -108,7 +139,7 @@ var RateLimitError = class extends ArcError {
108
139
  retryAfter;
109
140
  constructor(message = "Too many requests", retryAfter) {
110
141
  super(message, {
111
- code: "arc.rate_limited",
142
+ code: ARC_ERROR_CODES.RATE_LIMITED,
112
143
  statusCode: 429,
113
144
  ...retryAfter ? { details: { retryAfter } } : {}
114
145
  });
@@ -119,7 +150,7 @@ var RateLimitError = class extends ArcError {
119
150
  var ServiceUnavailableError = class extends ArcError {
120
151
  constructor(message = "Service temporarily unavailable") {
121
152
  super(message, {
122
- code: "arc.service_unavailable",
153
+ code: ARC_ERROR_CODES.SERVICE_UNAVAILABLE,
123
154
  statusCode: 503
124
155
  });
125
156
  this.name = "ServiceUnavailableError";
@@ -130,21 +161,25 @@ var ServiceUnavailableError = class extends ArcError {
130
161
  * and the global error handler when no explicit code is supplied.
131
162
  */
132
163
  const STATUS_CODE_MAP = {
133
- 400: "arc.bad_request",
134
- 401: "arc.unauthorized",
135
- 403: "arc.forbidden",
136
- 404: "arc.not_found",
137
- 409: "arc.conflict",
138
- 422: "arc.unprocessable_entity",
139
- 429: "arc.rate_limited",
140
- 500: "arc.internal_error",
141
- 502: "arc.bad_gateway",
142
- 503: "arc.service_unavailable",
143
- 504: "arc.gateway_timeout"
164
+ 400: ARC_ERROR_CODES.BAD_REQUEST,
165
+ 401: ARC_ERROR_CODES.UNAUTHORIZED,
166
+ 403: ARC_ERROR_CODES.FORBIDDEN,
167
+ 404: ARC_ERROR_CODES.NOT_FOUND,
168
+ 409: ARC_ERROR_CODES.CONFLICT,
169
+ 412: ARC_ERROR_CODES.PRECONDITION_FAILED,
170
+ 413: ARC_ERROR_CODES.PAYLOAD_TOO_LARGE,
171
+ 415: ARC_ERROR_CODES.UNSUPPORTED_MEDIA_TYPE,
172
+ 422: ARC_ERROR_CODES.UNPROCESSABLE_ENTITY,
173
+ 429: ARC_ERROR_CODES.RATE_LIMITED,
174
+ 500: ARC_ERROR_CODES.INTERNAL_ERROR,
175
+ 501: ARC_ERROR_CODES.NOT_IMPLEMENTED,
176
+ 502: ARC_ERROR_CODES.BAD_GATEWAY,
177
+ 503: ARC_ERROR_CODES.SERVICE_UNAVAILABLE,
178
+ 504: ARC_ERROR_CODES.GATEWAY_TIMEOUT
144
179
  };
145
180
  /** Status → canonical arc code, falling back to `arc.error`. */
146
181
  function statusToArcCode(status) {
147
- return STATUS_CODE_MAP[status] ?? "arc.error";
182
+ return STATUS_CODE_MAP[status] ?? ARC_ERROR_CODES.ERROR;
148
183
  }
149
184
  /**
150
185
  * Quick `ArcError` constructor when the bundled subclasses don't fit.
@@ -36,6 +36,15 @@ declare class ValidationError extends ArcError {
36
36
  field: string;
37
37
  message: string;
38
38
  }>);
39
+ /**
40
+ * `HttpError.validationErrors` — what `toErrorContract` turns into the wire's
41
+ * `details[]`, the one place clients (arc-next `fieldErrors`) read field errors.
42
+ */
43
+ get validationErrors(): Array<{
44
+ path: string;
45
+ validator: string;
46
+ error: string;
47
+ }>;
39
48
  }
40
49
  declare class UnauthorizedError extends ArcError {
41
50
  constructor(message?: string);
@@ -1,6 +1,7 @@
1
1
 
2
- import { a as EventTransport, i as EventLogger, n as DomainEvent, r as EventHandler, s as MemoryEventTransportOptions } from "./EventTransport-CbUKDzZZ.mjs";
3
- import { FastifyPluginAsync } from "fastify";
2
+ import { a as EventTransport, i as EventLogger, n as DomainEvent, r as EventHandler, s as MemoryEventTransportOptions } from "./EventTransport-CiicKz2Z.mjs";
3
+ import { FastifyInstance, FastifyPluginAsync } from "fastify";
4
+ import { EventDurability, FactExpectation } from "@classytic/primitives/durable-events";
4
5
  //#region src/events/defineEvent.d.ts
5
6
  interface EventSchema {
6
7
  type: "object";
@@ -11,26 +12,68 @@ interface EventSchema {
11
12
  required?: string[];
12
13
  [key: string]: unknown;
13
14
  }
14
- interface EventDefinitionInput {
15
+ /** A zod (v4) schema — the one way to author an event payload. Structural: arc never imports zod for it. */
16
+ interface ZodPayloadSchema {
17
+ readonly _zod: {
18
+ readonly output: unknown;
19
+ };
20
+ safeParse(value: unknown): {
21
+ success: boolean;
22
+ error?: {
23
+ issues: ReadonlyArray<{
24
+ path: ReadonlyArray<PropertyKey>;
25
+ message: string;
26
+ }>;
27
+ };
28
+ };
29
+ }
30
+ /**
31
+ * Whether the event books money or moves stock. `'durable'` needs `occurrence` (aggregate id plus
32
+ * step): `.create()` derives a fixed id from it, and `fastify.events.publish` refuses the type —
33
+ * it is written to the outbox in its unit of work. Undeclared reads as not yet classified.
34
+ */
35
+ type EventDurabilityInput<T> = {
36
+ durability?: "ephemeral";
37
+ occurrence?: never;
38
+ produces?: never;
39
+ } | {
40
+ durability: "durable";
41
+ occurrence(payload: T): string;
42
+ produces?: readonly FactExpectation<T>[];
43
+ };
44
+ interface EventDefinitionBase {
15
45
  /** Event type name (e.g., 'order.created') */
16
46
  name: string;
17
- /** JSON Schema for payload validation */
47
+ /**
48
+ * The payload as a zod schema — preferred. arc derives the JSON Schema (registry, AsyncAPI,
49
+ * contract snapshots) and the payload TYPE from it, and validates with it.
50
+ */
51
+ payload?: ZodPayloadSchema;
52
+ /** Raw JSON Schema, for definitions that do not use zod (kernels with no zod dependency). */
18
53
  schema?: EventSchema;
19
54
  /** Event version for schema evolution (default: 1) */
20
55
  version?: number;
21
56
  /** Human-readable description */
22
57
  description?: string;
23
58
  }
59
+ type EventDefinitionInput<T = unknown> = EventDefinitionBase & EventDurabilityInput<T>;
24
60
  interface EventDefinitionOutput<T = unknown> {
25
61
  /** Event type name */
26
62
  readonly name: string;
27
- /** JSON Schema for payload validation */
63
+ /** JSON Schema for payload validation — generated from `payload` when that was given. */
28
64
  readonly schema?: EventSchema;
65
+ /** The zod schema the payload was declared with, when it was — the registry validates with it. */
66
+ readonly payloadSchema?: ZodPayloadSchema;
29
67
  /** Event version */
30
68
  readonly version: number;
31
69
  /** Human-readable description */
32
70
  readonly description?: string;
33
- /** Create a DomainEvent with this type + auto-generated metadata */
71
+ /** `undefined` = not yet classified. */
72
+ readonly durability?: EventDurability;
73
+ /** Present on a durable definition: the occurrence its fixed id derives from. */
74
+ occurrence?(payload: T): string;
75
+ readonly produces?: readonly FactExpectation<T>[];
76
+ /** Create a DomainEvent with this type + auto-generated metadata (a fixed id when durable) */
34
77
  create(payload: T, meta?: Partial<DomainEvent["meta"]>): DomainEvent<T>;
35
78
  }
36
79
  interface ValidationResult {
@@ -72,6 +115,7 @@ interface EventRegistry {
72
115
  version: number;
73
116
  description?: string;
74
117
  schema?: EventSchema;
118
+ durability?: EventDurability;
75
119
  }>;
76
120
  /**
77
121
  * Validate a payload against a registered event's schema.
@@ -94,7 +138,11 @@ interface EventRegistry {
94
138
  *
95
139
  * const event = OrderCreated.create({ orderId: '123' });
96
140
  */
97
- declare function defineEvent<T = unknown>(input: EventDefinitionInput): EventDefinitionOutput<T>;
141
+ declare function defineEvent<S extends ZodPayloadSchema>(input: EventDefinitionInput<S["_zod"]["output"]> & {
142
+ payload: S;
143
+ schema?: never;
144
+ }): EventDefinitionOutput<S["_zod"]["output"]>;
145
+ declare function defineEvent<T = unknown>(input: EventDefinitionInput<T>): EventDefinitionOutput<T>;
98
146
  /**
99
147
  * Create an event registry for cataloging and validating events.
100
148
  *
@@ -161,8 +209,8 @@ interface RetryOptions {
161
209
  */
162
210
  onDead?: (event: DomainEvent, errors: Error[]) => void | Promise<void>;
163
211
  /**
164
- * What to do when `transport.deadLetter()` ITSELF fails after retries are
165
- * exhausted.
212
+ * What to do when retries are exhausted and no durable sink took the event —
213
+ * `transport.deadLetter()` / `deadLetter` failed, or neither is wired.
166
214
  *
167
215
  * - `'rethrow'` (default) — the wrapper throws, so the transport treats
168
216
  * the handler as failed: an at-least-once transport (Redis Streams,
@@ -278,6 +326,9 @@ interface EventPluginOptions {
278
326
  * silently drop events while requests continue succeeding. Pair with the
279
327
  * `onPublishError` callback to monitor failures, or use `wal` for
280
328
  * at-least-once delivery guarantees.
329
+ *
330
+ * Never applies to a type the `registry` declares `durability: 'durable'`: the facade
331
+ * refuses it with `NonDurablePublishError` (it belongs in the outbox).
281
332
  */
282
333
  failOpen?: boolean;
283
334
  /**
@@ -383,6 +434,11 @@ declare module "fastify" {
383
434
  transportName: string;
384
435
  /** Event registry for introspection (undefined when no registry configured) */
385
436
  registry?: EventRegistry;
437
+ /**
438
+ * Watch every event that reaches the transport — a live publish or an outbox relay.
439
+ * Read-only: a listener cannot change or stop delivery, and one that throws is ignored.
440
+ */
441
+ observe: (listener: (event: DomainEvent) => void) => () => void;
386
442
  };
387
443
  }
388
444
  }