@classytic/arc 2.28.0 → 2.31.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 (239) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +7 -0
  3. package/TRADEMARK.md +22 -0
  4. package/dist/{BaseController-B65zbz9m.mjs → BaseController-De7GqHck.mjs} +25 -24
  5. package/dist/{EventTransport-QmY7A258.d.mts → EventTransport-2uVV34WU.d.mts} +1 -0
  6. package/dist/EventTransport-9mlTgqzE.mjs +104 -0
  7. package/dist/{HookSystem-C1vB_Gc9.mjs → HookSystem-BcmPyq5I.mjs} +16 -35
  8. package/dist/{QueryCache-DOMT_iq7.d.mts → QueryCache-DFA-QrU9.d.mts} +2 -1
  9. package/dist/{ResourceRegistry-y9Hnypus.mjs → ResourceRegistry-qq0mn2s9.mjs} +3 -2
  10. package/dist/{actionPermissions-CAphcmUG.mjs → actionPermissions-BE5NwaQk.mjs} +1 -0
  11. package/dist/audit/index.d.mts +3 -2
  12. package/dist/audit/index.mjs +3 -2
  13. package/dist/auth/audit.d.mts +1 -0
  14. package/dist/auth/audit.mjs +1 -0
  15. package/dist/auth/index.d.mts +5 -4
  16. package/dist/auth/index.mjs +6 -5
  17. package/dist/auth/redis-session.d.mts +2 -1
  18. package/dist/auth/redis-session.mjs +1 -0
  19. package/dist/authorizationDecision-ChvUQGG1.mjs +266 -0
  20. package/dist/{buildHandler-Dtwd8fdz.mjs → buildHandler-CDrCJzmB.mjs} +34 -7
  21. package/dist/cache/index.d.mts +4 -3
  22. package/dist/cache/index.mjs +4 -3
  23. package/dist/{caching-_NJeDd1_.mjs → caching-BFHA6Scf.mjs} +2 -1
  24. package/dist/cleanup/index.d.mts +4 -3
  25. package/dist/cleanup/index.mjs +9 -13
  26. package/dist/cli/commands/describe.d.mts +2 -1
  27. package/dist/cli/commands/describe.mjs +3 -2
  28. package/dist/cli/commands/docs.d.mts +1 -0
  29. package/dist/cli/commands/docs.mjs +3 -2
  30. package/dist/cli/commands/doctor.d.mts +1 -0
  31. package/dist/cli/commands/doctor.mjs +1 -0
  32. package/dist/cli/commands/generate.d.mts +2 -1
  33. package/dist/cli/commands/generate.mjs +2 -1
  34. package/dist/cli/commands/init.d.mts +2 -1
  35. package/dist/cli/commands/init.mjs +2 -1
  36. package/dist/cli/commands/introspect.d.mts +1 -0
  37. package/dist/cli/commands/introspect.mjs +2 -1
  38. package/dist/cli/index.d.mts +3 -2
  39. package/dist/cli/index.mjs +3 -2
  40. package/dist/{constants-DNre0wRg.mjs → constants-D3Dv4LAV.mjs} +1 -0
  41. package/dist/context/index.d.mts +1 -0
  42. package/dist/context/index.mjs +3 -2
  43. package/dist/core/index.d.mts +3 -2
  44. package/dist/core/index.mjs +7 -5
  45. package/dist/{core-BGa8TXJR.mjs → core-BGpIxINN.mjs} +4 -49
  46. package/dist/{createActionRouter-C-N7z2EL.mjs → createActionRouter-CDXEdasl.mjs} +8 -7
  47. package/dist/{createAggregationRouter-wzwFa_dW.mjs → createAggregationRouter-KrQDzx-k.mjs} +10 -22
  48. package/dist/{createApp-Du5G54TM.mjs → createApp-Df89BEni.mjs} +505 -209
  49. package/dist/defineAggregation-DbPPS8RI.mjs +48 -0
  50. package/dist/{defineResource-2zvVVpxg.mjs → defineResource-Bv6EtN1x.mjs} +90 -72
  51. package/dist/discovery/index.d.mts +1 -0
  52. package/dist/discovery/index.mjs +1 -0
  53. package/dist/docs/index.d.mts +3 -2
  54. package/dist/docs/index.mjs +3 -2
  55. package/dist/{elevation-C9s5hFP_.d.mts → elevation-BXCfVcNG.d.mts} +1 -0
  56. package/dist/{elevation-CIz1GjGm.mjs → elevation-D2l1mh4g.mjs} +4 -3
  57. package/dist/encryption/index.d.mts +2 -1
  58. package/dist/encryption/index.mjs +3 -2
  59. package/dist/{errorHandler-Bq2OeEQL.mjs → errorHandler-C5NeD6bT.mjs} +3 -2
  60. package/dist/{errorHandler-C6yv4ZTW.d.mts → errorHandler-CpYUJmPA.d.mts} +1 -0
  61. package/dist/{errors-DHcHVAgk.d.mts → errors-BGdVwP25.d.mts} +1 -0
  62. package/dist/{errors-DkO8Nk6-.mjs → errors-Cj42AntO.mjs} +1 -0
  63. package/dist/{eventPlugin-DrQ_FesK.mjs → eventPlugin-CkffEihm.mjs} +6 -106
  64. package/dist/{eventPlugin-Bg3cP2_u.d.mts → eventPlugin-GF5nnBIq.d.mts} +2 -1
  65. package/dist/events/index.d.mts +4 -3
  66. package/dist/events/index.mjs +17 -340
  67. package/dist/events/transports/redis-stream-entry.d.mts +2 -1
  68. package/dist/events/transports/redis-stream-entry.mjs +1 -0
  69. package/dist/events/transports/redis.d.mts +2 -1
  70. package/dist/events/transports/redis.mjs +1 -0
  71. package/dist/{externalPaths-BE6wFpYv.d.mts → externalPaths-CmGOxOtD.d.mts} +1 -0
  72. package/dist/factory/index.d.mts +9 -5
  73. package/dist/factory/index.mjs +7 -6
  74. package/dist/{fastify-augmentation-OzYGIiU1.d.mts → fastify-augmentation-zh0_AYHa.d.mts} +13 -4
  75. package/dist/{applyPermissionResult-BnyVE9eD.mjs → fields-CB5Cuzk9.mjs} +2 -107
  76. package/dist/{fields-D3lhgzhD.d.mts → fields-I_EeRWND.d.mts} +1 -0
  77. package/dist/{generate-BnsL9GBm.d.mts → generate-DCGuEbqI.d.mts} +1 -0
  78. package/dist/{generate-D0wZupBg.mjs → generate-EcA6ui4i.mjs} +2 -1
  79. package/dist/{headers-BvlQSDMB.mjs → headers-3zvE0rM3.mjs} +2 -1
  80. package/dist/{health-CB_m4S32.mjs → health-DjZYjM7H.mjs} +1 -0
  81. package/dist/hooks/index.d.mts +2 -1
  82. package/dist/hooks/index.mjs +2 -1
  83. package/dist/idempotency/index.d.mts +3 -2
  84. package/dist/idempotency/index.mjs +5 -4
  85. package/dist/idempotency/redis.d.mts +2 -1
  86. package/dist/idempotency/redis.mjs +1 -0
  87. package/dist/{index-CjVg-Epg.d.mts → index-Bc2ox8_U.d.mts} +6 -5
  88. package/dist/{index-CG4yqMDB.d.mts → index-C-481Zf2.d.mts} +74 -18
  89. package/dist/{index-BMnbzvtO.d.mts → index-CEJNZFtX.d.mts} +242 -24
  90. package/dist/index-CFThn1K9.d.mts +224 -0
  91. package/dist/{index-DPRH0Cme.d.mts → index-CpzxqePp.d.mts} +203 -97
  92. package/dist/index.d.mts +9 -8
  93. package/dist/index.mjs +11 -9
  94. package/dist/{init-tlRSt667.mjs → init-BEiNZBsJ.mjs} +19 -23
  95. package/dist/{init-BPEu8cs-.d.mts → init-Cscs4lab.d.mts} +1 -0
  96. package/dist/integrations/event-gateway.d.mts +3 -2
  97. package/dist/integrations/event-gateway.mjs +2 -1
  98. package/dist/integrations/index.d.mts +4 -3
  99. package/dist/integrations/index.mjs +1 -0
  100. package/dist/integrations/jobs/index.d.mts +2 -1
  101. package/dist/integrations/jobs/index.mjs +108 -32
  102. package/dist/integrations/mcp/index.d.mts +9 -9
  103. package/dist/integrations/mcp/index.mjs +2 -1
  104. package/dist/integrations/mcp/testing.d.mts +3 -2
  105. package/dist/integrations/mcp/testing.mjs +2 -2
  106. package/dist/integrations/streamline.d.mts +1 -0
  107. package/dist/integrations/streamline.mjs +3 -2
  108. package/dist/integrations/webhooks.d.mts +1 -0
  109. package/dist/integrations/webhooks.mjs +1 -0
  110. package/dist/integrations/websocket-pushref-redis.d.mts +2 -1
  111. package/dist/integrations/websocket-pushref-redis.mjs +1 -0
  112. package/dist/integrations/websocket-redis.d.mts +2 -1
  113. package/dist/integrations/websocket-redis.mjs +1 -0
  114. package/dist/integrations/websocket.d.mts +3 -2
  115. package/dist/integrations/websocket.mjs +1 -0
  116. package/dist/{interface-BGZCzOGL.d.mts → interface-BOk3YnTz.d.mts} +1 -0
  117. package/dist/{interface-Uk8ONJv7.d.mts → interface-DEWNOMza.d.mts} +1 -0
  118. package/dist/{interface-n5hpKg1d.mjs → interface-DYzM0q-u.mjs} +1 -0
  119. package/dist/{jsonBody-BlzAoGCe.mjs → jsonBody-BYbLDi5D.mjs} +2 -1
  120. package/dist/{keys-Cd316u_y.mjs → keys-C0_pa1tY.mjs} +1 -0
  121. package/dist/{loadResources-DpU8pfjV.mjs → loadResources-yawi9tAE.mjs} +2 -1
  122. package/dist/{loadResourcesFromEntry-kvGT6EcO.mjs → loadResourcesFromEntry-BAjYZonx.mjs} +2 -1
  123. package/dist/logger/index.d.mts +1 -0
  124. package/dist/logger/index.mjs +1 -0
  125. package/dist/{mcpPlugin-Cs6nRGCt.mjs → mcpPlugin-B_es0hiF.mjs} +52 -60
  126. package/dist/{memory-CmnzXE5Z.mjs → memory-DR6wpa9F.mjs} +2 -1
  127. package/dist/{metrics-fdxI5mn_.mjs → metrics-CUdw_wLB.mjs} +2 -1
  128. package/dist/middleware/index.d.mts +2 -1
  129. package/dist/middleware/index.mjs +3 -2
  130. package/dist/migrations/index.d.mts +1 -3
  131. package/dist/migrations/index.mjs +2 -4
  132. package/dist/module-0pFJA6YW.mjs +78 -0
  133. package/dist/{multipartBody-D0eBvkeq.mjs → multipartBody-wOgj_fnj.mjs} +1 -0
  134. package/dist/{openapi-BLV4OMXb.mjs → openapi-B2L4js1v.mjs} +6 -5
  135. package/dist/permissions/index.d.mts +5 -4
  136. package/dist/permissions/index.mjs +6 -4
  137. package/dist/{permissions-BrtiBKGs.mjs → permissions-L--QDAir.mjs} +518 -316
  138. package/dist/{pipe-BOLmGIxa.mjs → pipe-DRDNsI2T.mjs} +2 -1
  139. package/dist/pipeline/index.d.mts +2 -1
  140. package/dist/pipeline/index.mjs +2 -1
  141. package/dist/{pipeline-BGRnV-To.mjs → pipeline-UPQFatit.mjs} +7 -20
  142. package/dist/plugins/index.d.mts +8 -7
  143. package/dist/plugins/index.mjs +16 -15
  144. package/dist/plugins/response-cache.d.mts +1 -0
  145. package/dist/plugins/response-cache.mjs +2 -1
  146. package/dist/plugins/tracing-entry.d.mts +2 -1
  147. package/dist/plugins/tracing-entry.mjs +2 -1
  148. package/dist/{pluralize-BhrgwZb9.mjs → pluralize-O0FZgESl.mjs} +1 -0
  149. package/dist/{preloadResources-CM4uUaFv.d.mts → preloadResources-CyoJMSiO.d.mts} +117 -12
  150. package/dist/{preloadResources-DSY5HGpS.mjs → preloadResources-Dz6BjzM6.mjs} +1 -0
  151. package/dist/presets/filesUpload.d.mts +6 -5
  152. package/dist/presets/filesUpload.mjs +9 -11
  153. package/dist/presets/index.d.mts +15 -2
  154. package/dist/presets/index.mjs +2 -1
  155. package/dist/presets/multiTenant.d.mts +2 -1
  156. package/dist/presets/multiTenant.mjs +3 -2
  157. package/dist/presets/search.d.mts +3 -2
  158. package/dist/presets/search.mjs +2 -1
  159. package/dist/{presets-DwFDVKP0.mjs → presets-C4-g4_4P.mjs} +27 -10
  160. package/dist/projection-BHw6xlOQ.mjs +18 -0
  161. package/dist/{pushref-registry-BbcnpNTm.d.mts → pushref-registry-Dov9l4qE.d.mts} +1 -0
  162. package/dist/{queryCachePlugin-DSGuSVLW.mjs → queryCachePlugin-BZr8v46E.mjs} +5 -4
  163. package/dist/{queryCachePlugin-br4otiqF.d.mts → queryCachePlugin-BzqxconG.d.mts} +3 -2
  164. package/dist/{rateLimit-DrED-C4v.mjs → rateLimit-CMPY5Qms.mjs} +7 -3
  165. package/dist/{rateLimitKey-BoWRH3e7.mjs → rateLimitKey-Dn5JNmkj.mjs} +1 -0
  166. package/dist/{realtime-DEuDu9io.mjs → realtime-C5NoxWFY.mjs} +20 -8
  167. package/dist/{redis-UDtLaNj6.d.mts → redis-CduhKsJi.d.mts} +2 -1
  168. package/dist/{redis-stream-uIaauNpZ.d.mts → redis-stream-qN6A-RFv.d.mts} +2 -1
  169. package/dist/{registerRoute-DTp18Ah_.mjs → registerRoute-CBN84fc7.mjs} +5 -2
  170. package/dist/registry/index.d.mts +3 -2
  171. package/dist/registry/index.mjs +3 -2
  172. package/dist/{registry-9km_w1aP.mjs → registry-4213U4zb.mjs} +3 -2
  173. package/dist/{renewingLease-3cuQH7h8.mjs → renewingLease-Dll8mGgc.mjs} +1 -0
  174. package/dist/{replyHelpers-67tRawQZ.mjs → replyHelpers-DIiZKGUt.mjs} +2 -1
  175. package/dist/repositoryFilter-f9eAfq_l.mjs +45 -0
  176. package/dist/{requestContext-MrlJwECf.mjs → requestContext-2TxXOJ7T.mjs} +1 -0
  177. package/dist/{rolldown-runtime-8H4AJuhK.mjs → rolldown-runtime-CUsjNX9R.mjs} +1 -0
  178. package/dist/{schedules-CjOd2MG9.mjs → schedules-DdtlICTf.mjs} +3 -2
  179. package/dist/{schemaConverter-DJvodiHj.mjs → schemaConverter-D--wdJM-.mjs} +70 -17
  180. package/dist/{schemaIR-Ca7ySNPx.mjs → schemaIR-Bm2enbnh.mjs} +2 -1
  181. package/dist/schemas/index.d.mts +1 -0
  182. package/dist/schemas/index.mjs +1 -0
  183. package/dist/scim/index.d.mts +1 -0
  184. package/dist/scim/index.mjs +2 -1
  185. package/dist/scope/index.d.mts +3 -2
  186. package/dist/scope/index.mjs +5 -4
  187. package/dist/{scope-DfaPntpo.mjs → scope-DHx5Fous.mjs} +4 -3
  188. package/dist/{sessionManager-BHOM3N_0.d.mts → sessionManager-qimlKV0P.d.mts} +1 -0
  189. package/dist/{simpleEqualityMatcher-Cg05HPsn.mjs → simpleEqualityMatcher-DjQJ7FKA.mjs} +1 -0
  190. package/dist/{sse-BQ1w0dfl.mjs → sse-CUTo9y0X.mjs} +5 -4
  191. package/dist/{sseStream-BQ7Qaynp.mjs → sseStream-B_5XcVVd.mjs} +2 -1
  192. package/dist/{storage-DLUZ04kK.d.mts → storage-Cx9Sz3Ou.d.mts} +1 -0
  193. package/dist/{store-helpers-DY6xq4sM.mjs → store-helpers-D1MP_gRG.mjs} +1 -0
  194. package/dist/{streaming-BQcW6_Kq.mjs → streaming-PSZwi8JV.mjs} +1 -0
  195. package/dist/subscribe-helpers-C0Tb2aUp.mjs +340 -0
  196. package/dist/sync/changelog.d.mts +1 -0
  197. package/dist/sync/changelog.mjs +1 -0
  198. package/dist/testing/cleanupStoreContract.d.mts +2 -1
  199. package/dist/testing/cleanupStoreContract.mjs +1 -0
  200. package/dist/testing/index.d.mts +167 -12
  201. package/dist/testing/index.mjs +522 -205
  202. package/dist/testing/outboxStoreContract.d.mts +1 -0
  203. package/dist/testing/outboxStoreContract.mjs +1 -0
  204. package/dist/testing/storageContract.d.mts +2 -1
  205. package/dist/testing/storageContract.mjs +1 -0
  206. package/dist/{tracing-CsGKQJGg.d.mts → tracing-Dro5eH6j.d.mts} +1 -0
  207. package/dist/{transactionContext-PNdoyLLm.mjs → transactionContext-dAfBVUrk.mjs} +1 -0
  208. package/dist/{typeGuards-C9KXUly6.mjs → typeGuards-B0ryPo3I.mjs} +1 -0
  209. package/dist/types/index.d.mts +6 -5
  210. package/dist/types/index.mjs +1 -0
  211. package/dist/types/storage.d.mts +2 -1
  212. package/dist/types/storage.mjs +1 -0
  213. package/dist/{types-Dmw-6Qeo.d.mts → types-B7XeLEgK.d.mts} +127 -90
  214. package/dist/{types-Cc91nXuA.d.mts → types-ByHn9rEO.d.mts} +1 -0
  215. package/dist/{types-C_ZZRcD6.d.mts → types-C4QE8qnm.d.mts} +1 -0
  216. package/dist/{types-Cu6vVJmh.d.mts → types-CBgvkp8O.d.mts} +82 -12
  217. package/dist/{types-DjC-KUCz.d.mts → types-ChuShpCP.d.mts} +1 -0
  218. package/dist/{types-QFGc3Cjv.d.mts → types-CwcUQ610.d.mts} +2 -6
  219. package/dist/{types-CSyCxl2V.mjs → types-Cys0ko9Z.mjs} +4 -3
  220. package/dist/usage/index.d.mts +3 -2
  221. package/dist/usage/index.mjs +0 -0
  222. package/dist/{userHelpers-Cg_y3fBz.mjs → userHelpers-ChYJ6CdK.mjs} +1 -0
  223. package/dist/utils/index.d.mts +16 -10
  224. package/dist/utils/index.mjs +10 -9
  225. package/dist/{utils-taUVD4p3.mjs → utils-vL8BrDE2.mjs} +3 -2
  226. package/dist/{validate-Bk44F2yT.mjs → validate-_KbifpHF.mjs} +2 -1
  227. package/dist/{versioning-gKWyryT3.mjs → versioning-CHDTor3P.mjs} +3 -2
  228. package/dist/{versioning-DXgY5BUm.d.mts → versioning-D_rhHfZm.d.mts} +5 -2
  229. package/dist/{websocket-_Pd0CgR0.d.mts → websocket-BOXVggMf.d.mts} +2 -1
  230. package/package.json +15 -7
  231. package/skills/arc/SKILL.md +22 -8
  232. package/skills/arc/references/api-reference.md +4 -0
  233. package/skills/arc/references/auth.md +3 -0
  234. package/skills/arc/references/integrations.md +33 -0
  235. package/skills/arc/references/mcp.md +6 -7
  236. package/skills/arc/references/production.md +24 -25
  237. package/skills/arc-code-review/references/anti-patterns.md +3 -3
  238. package/dist/index-CZY4EGga.d.mts +0 -107
  239. package/dist/module-_-M7C5ES.mjs +0 -29
@@ -0,0 +1,340 @@
1
+ /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
+ import { n as createEvent } from "./EventTransport-9mlTgqzE.mjs";
3
+ //#region src/events/defineEvent.ts
4
+ /**
5
+ * defineEvent — Typed Event Definitions with Optional Schema Validation
6
+ *
7
+ * Provides:
8
+ * 1. defineEvent() — declare an event with name, schema, version, description
9
+ * 2. EventRegistry — catalog of all known events + payload validation
10
+ * 3. .create() helper — build DomainEvent with auto-generated metadata
11
+ *
12
+ * The built-in validator checks: object type, required fields, and top-level
13
+ * property types. It does NOT recurse into nested objects, validate arrays,
14
+ * enums, patterns, formats, or $ref. This is intentional — it's a lightweight
15
+ * guard, not a full JSON Schema engine.
16
+ *
17
+ * For full validation, pass a custom `validate` function to `createEventRegistry()`:
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * import Ajv from 'ajv';
22
+ * const ajv = new Ajv();
23
+ *
24
+ * const registry = createEventRegistry({
25
+ * validate: (schema, payload) => {
26
+ * const valid = ajv.validate(schema, payload);
27
+ * return valid
28
+ * ? { valid: true }
29
+ * : { valid: false, errors: ajv.errorsText().split(', ') };
30
+ * },
31
+ * });
32
+ * ```
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * import { defineEvent, createEventRegistry } from '@classytic/arc/events';
37
+ *
38
+ * const OrderCreated = defineEvent({
39
+ * name: 'order.created',
40
+ * version: 1,
41
+ * schema: {
42
+ * type: 'object',
43
+ * properties: {
44
+ * orderId: { type: 'string' },
45
+ * total: { type: 'number' },
46
+ * },
47
+ * required: ['orderId', 'total'],
48
+ * },
49
+ * });
50
+ *
51
+ * // Type-safe event creation
52
+ * const event = OrderCreated.create({ orderId: 'o-1', total: 100 });
53
+ * await fastify.events.publish(event.type, event.payload, event.meta);
54
+ *
55
+ * // Registry for introspection + validation
56
+ * const registry = createEventRegistry();
57
+ * registry.register(OrderCreated);
58
+ * const result = registry.validate('order.created', payload);
59
+ * ```
60
+ */
61
+ /**
62
+ * Define a typed event with optional schema validation.
63
+ *
64
+ * @example
65
+ * const OrderCreated = defineEvent({
66
+ * name: 'order.created',
67
+ * schema: { type: 'object', properties: { orderId: { type: 'string' } }, required: ['orderId'] },
68
+ * });
69
+ *
70
+ * const event = OrderCreated.create({ orderId: '123' });
71
+ */
72
+ function defineEvent(input) {
73
+ const { name, schema, version = 1, description } = input;
74
+ return {
75
+ name,
76
+ schema,
77
+ version,
78
+ description,
79
+ create(payload, meta) {
80
+ return createEvent(name, payload, {
81
+ schemaVersion: version,
82
+ ...meta
83
+ });
84
+ }
85
+ };
86
+ }
87
+ /**
88
+ * Create an event registry for cataloging and validating events.
89
+ *
90
+ * The registry is opt-in — unregistered events pass validation.
91
+ * This allows gradual adoption without breaking existing code.
92
+ *
93
+ * @param options.validate - Custom validator replacing the built-in minimal validator.
94
+ * The built-in validator only checks top-level object structure (type, required, property types).
95
+ * For nested objects, arrays, enums, patterns, or $ref, provide AJV or similar.
96
+ */
97
+ function createEventRegistry(options) {
98
+ const customValidator = options?.validate;
99
+ const definitions = /* @__PURE__ */ new Map();
100
+ function registryKey(name, version) {
101
+ return `${name}:v${version}`;
102
+ }
103
+ return {
104
+ register(definition) {
105
+ const key = registryKey(definition.name, definition.version);
106
+ if (definitions.has(key)) throw new Error(`Event '${definition.name}' v${definition.version} is already registered. Use a different version number for schema evolution.`);
107
+ definitions.set(key, definition);
108
+ },
109
+ get(name, version) {
110
+ if (version !== void 0) return definitions.get(registryKey(name, version));
111
+ let latest;
112
+ let latestVersion = -1;
113
+ for (const def of definitions.values()) if (def.name === name && def.version > latestVersion) {
114
+ latest = def;
115
+ latestVersion = def.version;
116
+ }
117
+ return latest;
118
+ },
119
+ catalog() {
120
+ return Array.from(definitions.values()).map((def) => ({
121
+ name: def.name,
122
+ version: def.version,
123
+ description: def.description,
124
+ schema: def.schema
125
+ }));
126
+ },
127
+ validate(name, payload, version) {
128
+ let target = version !== void 0 ? definitions.get(registryKey(name, version)) : void 0;
129
+ if (!target && version === void 0) {
130
+ let latestVersion = -1;
131
+ for (const candidate of definitions.values()) if (candidate.name === name && candidate.version > latestVersion) {
132
+ target = candidate;
133
+ latestVersion = candidate.version;
134
+ }
135
+ }
136
+ if (!target) return { valid: true };
137
+ if (!target.schema) return { valid: true };
138
+ return customValidator ? customValidator(target.schema, payload) : validatePayload(payload, target.schema);
139
+ }
140
+ };
141
+ }
142
+ /**
143
+ * Built-in minimal validator — lightweight guard, NOT a full JSON Schema engine.
144
+ *
145
+ * Checks:
146
+ * - payload is an object (not null, not array)
147
+ * - required fields are present
148
+ * - top-level property types match (string, number, boolean, array, object)
149
+ *
150
+ * Does NOT check:
151
+ * - nested object properties
152
+ * - array item types
153
+ * - enum, pattern, format, minLength, minimum, $ref
154
+ *
155
+ * For full validation, pass a custom `validate` function to `createEventRegistry()`.
156
+ */
157
+ function validatePayload(payload, schema) {
158
+ const errors = [];
159
+ if (schema.type === "object") {
160
+ if (payload === null || payload === void 0 || typeof payload !== "object" || Array.isArray(payload)) return {
161
+ valid: false,
162
+ errors: ["Payload must be an object"]
163
+ };
164
+ const record = payload;
165
+ if (schema.required) {
166
+ for (const field of schema.required) if (!(field in record) || record[field] === void 0) errors.push(`Missing required field: '${field}'`);
167
+ }
168
+ if (schema.properties) {
169
+ for (const [key, propSchema] of Object.entries(schema.properties)) if (key in record && record[key] !== void 0 && record[key] !== null) {
170
+ const expectedType = propSchema.type;
171
+ if (expectedType) {
172
+ const value = record[key];
173
+ const actualType = Array.isArray(value) ? "array" : typeof value;
174
+ if (expectedType === "integer") {
175
+ if (actualType !== "number" || !Number.isInteger(value)) errors.push(`Field '${key}': expected integer, got ${actualType}`);
176
+ } else if (expectedType !== actualType) errors.push(`Field '${key}': expected ${expectedType}, got ${actualType}`);
177
+ }
178
+ }
179
+ }
180
+ }
181
+ return errors.length === 0 ? { valid: true } : {
182
+ valid: false,
183
+ errors
184
+ };
185
+ }
186
+ //#endregion
187
+ //#region src/events/subscribe-helpers.ts
188
+ /**
189
+ * Subscribe-side helpers — close the symmetry that arc's publish-side
190
+ * already has via [`eventPlugin({ registry, validateMode: 'reject' })`](./eventPlugin.ts).
191
+ *
192
+ * Two wrapper pairs, both transport-agnostic:
193
+ *
194
+ * - `wrapWithSchema` / `subscribeWithSchema` — read the schema from a
195
+ * typed `EventDefinitionOutput<T>` and validate `event.payload` before
196
+ * the handler runs. Single source of truth for event shape: declare
197
+ * once at `defineEvent`, enforced on BOTH sides without parallel Zod
198
+ * schemas in subscriber files.
199
+ *
200
+ * - `wrapWithBoundary` / `subscribeWithBoundary` — catch + log + swallow
201
+ * handler errors, for projection / cache-invalidation / fire-and-forget
202
+ * handlers where retry would just delay the next-event resync. Lighter
203
+ * than `withRetry` (no DLQ, no exponential backoff) and avoids the
204
+ * "single bad event poisons the bus" hazard.
205
+ *
206
+ * Both pairs compose with `withRetry` and with each other:
207
+ *
208
+ * ```ts
209
+ * await subscribeWithSchema(
210
+ * fastify,
211
+ * OrderPaid,
212
+ * withRetry(handler, { maxRetries: 3 }),
213
+ * );
214
+ * ```
215
+ *
216
+ * @see [retry.ts](./retry.ts) for the retry + DLQ wrapper.
217
+ * @see [defineEvent.ts](./defineEvent.ts) for `defineEvent` / `EventDefinitionOutput`.
218
+ */
219
+ /**
220
+ * Pure handler wrapper — returns a new `EventHandler` that validates
221
+ * `event.payload` against the definition's schema before invoking the handler.
222
+ *
223
+ * The returned handler's input is `DomainEvent<unknown>` (since the transport
224
+ * delivers untyped events) but the inner `handler` receives `DomainEvent<T>`.
225
+ * No cast at the call site.
226
+ *
227
+ * @example
228
+ * ```ts
229
+ * await fastify.events.subscribe(
230
+ * OrderPaid.name,
231
+ * wrapWithSchema(OrderPaid, async (event) => {
232
+ * // event.payload is typed via the registered schema — no cast.
233
+ * await postSalesEntry(event.payload.orderId, event.payload.total);
234
+ * }),
235
+ * );
236
+ * ```
237
+ */
238
+ function wrapWithSchema(definition, handler, options = {}) {
239
+ const { validate, registry, onInvalid, logger = console, name } = options;
240
+ const label = name ?? definition.name;
241
+ return async (event) => {
242
+ const eventVersion = typeof event.meta?.schemaVersion === "number" ? event.meta.schemaVersion : definition.version;
243
+ let result;
244
+ if (validate && definition.schema) result = validate(definition.schema, event.payload);
245
+ else if (registry) result = registry.validate(definition.name, event.payload, eventVersion);
246
+ else if (definition.schema) {
247
+ const adhoc = createEventRegistry();
248
+ adhoc.register(definition);
249
+ result = adhoc.validate(definition.name, event.payload);
250
+ } else result = { valid: true };
251
+ if (!result.valid) {
252
+ const errors = result.errors ?? ["payload failed validation"];
253
+ if (onInvalid) try {
254
+ await onInvalid(event, errors);
255
+ } catch (cbErr) {
256
+ logger.error(`[Arc Events] '${label}' onInvalid callback threw:`, cbErr);
257
+ }
258
+ else logger.warn(`[Arc Events] '${label}' skipped event ${event.meta?.id ?? "<no-id>"} — payload failed validation: ${errors.join("; ")}`);
259
+ return;
260
+ }
261
+ await handler(event);
262
+ };
263
+ }
264
+ /**
265
+ * Convenience: validate + subscribe in one call. Equivalent to
266
+ * `fastify.events.subscribe(definition.name, wrapWithSchema(definition, handler, options))`.
267
+ *
268
+ * Returns the unsubscribe function from the underlying transport.
269
+ *
270
+ * @example
271
+ * ```ts
272
+ * await subscribeWithSchema(fastify, OrderPaid, async (event) => {
273
+ * await postSalesEntry(event.payload.orderId, event.payload.total);
274
+ * });
275
+ *
276
+ * // Compose with withRetry — schema validation runs FIRST, then retry on
277
+ * // handler failure. Invalid payloads skip without burning retry attempts.
278
+ * await subscribeWithSchema(
279
+ * fastify,
280
+ * OrderPaid,
281
+ * withRetry(handler, { maxRetries: 3 }),
282
+ * );
283
+ * ```
284
+ */
285
+ async function subscribeWithSchema(fastify, definition, handler, options) {
286
+ return fastify.events.subscribe(definition.name, wrapWithSchema(definition, handler, options));
287
+ }
288
+ /**
289
+ * Pure handler wrapper — returns a new `EventHandler` that catches handler
290
+ * exceptions and routes them to `onError` (or logs and swallows). For
291
+ * projection / cache-invalidation / fire-and-forget handlers where retry
292
+ * would just delay the next-event resync, and where one bad event must NOT
293
+ * stop processing of subsequent events.
294
+ *
295
+ * Lighter than `withRetry`: no exponential backoff, no DLQ. Composes with
296
+ * `withRetry` if you want both ("retry, then log if exhausted, never throw").
297
+ *
298
+ * @example
299
+ * ```ts
300
+ * await fastify.events.subscribe(
301
+ * 'product:variants.changed',
302
+ * wrapWithBoundary(async (event) => {
303
+ * cache.invalidate(event.payload.productId);
304
+ * }),
305
+ * );
306
+ * ```
307
+ */
308
+ function wrapWithBoundary(handler, options = {}) {
309
+ const { onError, logger = console, name } = options;
310
+ const label = name ?? handler.name ?? "anonymous";
311
+ return async (event) => {
312
+ try {
313
+ await handler(event);
314
+ } catch (err) {
315
+ const error = err instanceof Error ? err : new Error(String(err));
316
+ if (onError) try {
317
+ await onError(error, event);
318
+ } catch (cbErr) {
319
+ logger.error(`[Arc Events] '${label}' onError callback threw:`, cbErr);
320
+ }
321
+ else logger.error(`[Arc Events] '${label}' threw on ${event.type} — swallowed (boundary): ${error.message}`, {
322
+ err: error,
323
+ event: event.type,
324
+ eventId: event.meta?.id,
325
+ handler: label
326
+ });
327
+ }
328
+ };
329
+ }
330
+ /**
331
+ * Convenience: subscribe + error-boundary in one call. Equivalent to
332
+ * `fastify.events.subscribe(pattern, wrapWithBoundary(handler, options))`.
333
+ *
334
+ * Returns the unsubscribe function from the underlying transport.
335
+ */
336
+ async function subscribeWithBoundary(fastify, pattern, handler, options) {
337
+ return fastify.events.subscribe(pattern, wrapWithBoundary(handler, options));
338
+ }
339
+ //#endregion
340
+ export { createEventRegistry as a, wrapWithSchema as i, subscribeWithSchema as n, defineEvent as o, wrapWithBoundary as r, subscribeWithBoundary as t };
@@ -1,2 +1,3 @@
1
+
1
2
  import { ChangeEntry, ChangeLogAppendOptions, ChangeLogStore, ChangeOp, ChangesPage, ChangesSinceOptions, CursorExpiredError, MemoryChangeLogStore, PushMutation, PushVerdict, PushVerdictStatus } from "@classytic/repo-core/sync";
2
3
  export { type ChangeEntry, type ChangeLogAppendOptions, type ChangeLogStore, type ChangeOp, type ChangesPage, type ChangesSinceOptions, CursorExpiredError, MemoryChangeLogStore, type PushMutation, type PushVerdict, type PushVerdictStatus };
@@ -1,2 +1,3 @@
1
+ /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
1
2
  import { CursorExpiredError, MemoryChangeLogStore } from "@classytic/repo-core/sync";
2
3
  export { CursorExpiredError, MemoryChangeLogStore };
@@ -1,4 +1,5 @@
1
- import { D as CleanupRunStore } from "../types-C_ZZRcD6.mjs";
1
+
2
+ import { D as CleanupRunStore } from "../types-C4QE8qnm.mjs";
2
3
  //#region src/testing/cleanupStoreContract.d.ts
3
4
  interface CleanupRunStoreContractSetupResult {
4
5
  store: CleanupRunStore;
@@ -1,3 +1,4 @@
1
+ /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
1
2
  import { afterAll, beforeAll, describe, expect, it } from "vitest";
2
3
  //#region src/testing/cleanupStoreContract.ts
3
4
  /**
@@ -1,8 +1,10 @@
1
- import { V as ResourceDefinition } from "../index-DPRH0Cme.mjs";
2
- import { c as AnyRecord } from "../types-Dmw-6Qeo.mjs";
3
- import { n as ArcModuleInput } from "../types-Cu6vVJmh.mjs";
4
- import "../index-CZY4EGga.mjs";
5
- import { n as preloadResourcesAsync, r as CreateAppOptions, t as preloadResources } from "../preloadResources-CM4uUaFv.mjs";
1
+
2
+ import { V as ResourceDefinition } from "../index-CpzxqePp.mjs";
3
+ import { i as RequestScope } from "../types-ChuShpCP.mjs";
4
+ import { l as AnyRecord, r as PermissionCheck } from "../types-B7XeLEgK.mjs";
5
+ import { n as ArcModuleInput } from "../types-CBgvkp8O.mjs";
6
+ import "../index-CFThn1K9.mjs";
7
+ import { n as preloadResourcesAsync, r as CreateAppOptions, t as preloadResources } from "../preloadResources-CyoJMSiO.mjs";
6
8
  import { StorageContractSetup, StorageContractSetupResult, runStorageContract } from "./storageContract.mjs";
7
9
  import { FastifyInstance, FastifyServerOptions } from "fastify";
8
10
  import { Mock } from "vitest";
@@ -72,6 +74,41 @@ interface ArcAssertion {
72
74
  }
73
75
  declare function expectArc(response: ArcResponseLike): ArcAssertion;
74
76
  //#endregion
77
+ //#region src/testing/authorizationConformance.d.ts
78
+ /** One surface's observed enforcement: the HTTP status + the filter arc passed the repo. */
79
+ interface SurfaceObservation {
80
+ /** HTTP status the surface returned (200 = allowed, 401/403 = denied). */
81
+ status: number;
82
+ /** The filter arc handed the repository for this surface (undefined if never reached). */
83
+ filter: AnyRecord | undefined;
84
+ }
85
+ /** Result of {@link runAuthorizationConformance} — one observation per surface. */
86
+ interface AuthorizationConformance {
87
+ /** `GET /confs` — the CRUD list surface. */
88
+ list: SurfaceObservation;
89
+ /**
90
+ * `GET /confs/:id` — the SINGLE-RECORD surface. Its `filter` is the compound
91
+ * `buildIdFilter` output (route id AND policy AND tenant), so a policy that
92
+ * tried to redirect/widen the target would show here — the surface the
93
+ * filter-overwrite class of bug lives on.
94
+ */
95
+ get: SurfaceObservation;
96
+ /** `GET /confs/aggregations/tally` — the aggregation surface. */
97
+ aggregation: SurfaceObservation;
98
+ /** Close the throwaway app. Always call (e.g. in `finally`). */
99
+ close(): Promise<void>;
100
+ }
101
+ /**
102
+ * Boot a one-resource app gated by `permission` on both list + an aggregation,
103
+ * hit both surfaces anonymously, and report what arc enforced on each.
104
+ */
105
+ declare function runAuthorizationConformance(opts: {
106
+ /** The permission under test — applied to `list` and the aggregation alike. */
107
+ permission: PermissionCheck;
108
+ /** Rows the mock repo returns for list (aggregation returns a count). */
109
+ rows?: AnyRecord[];
110
+ }): Promise<AuthorizationConformance>;
111
+ //#endregion
75
112
  //#region src/testing/authSession.d.ts
76
113
  /**
77
114
  * A concrete auth session — headers ready to drop into `app.inject`.
@@ -299,6 +336,81 @@ declare function createBetterAuthTestHelpers(options?: BetterAuthTestHelpersOpti
299
336
  */
300
337
  declare function setupBetterAuthTestApp(input: SetupBetterAuthTestAppInput): Promise<SetupBetterAuthTestAppResult>;
301
338
  //#endregion
339
+ //#region src/testing/testActor.d.ts
340
+ /** The header the testing harness uses to carry a request's actor. */
341
+ declare const TEST_ACTOR_HEADER = "x-test-actor";
342
+ /**
343
+ * What a test wants to be. An `organizationId` produces a `member` scope (the
344
+ * org-scoped case); without one the actor is `authenticated`.
345
+ */
346
+ interface TestActor {
347
+ /**
348
+ * Defaults to a synthetic id derived from the roles. Pass one explicitly when
349
+ * a test distinguishes two actors — ownership and audit assertions do, and
350
+ * two actors sharing roles would otherwise share an id.
351
+ */
352
+ userId?: string;
353
+ /** Global roles — what `requireRoles` reads. */
354
+ roles?: string[];
355
+ /** Tenant. Present ⇒ a `member` scope. */
356
+ organizationId?: string;
357
+ /** Org-level roles from membership records. Defaults to `roles`. */
358
+ orgRoles?: string[];
359
+ teamId?: string;
360
+ /** App-defined dimensions (branch, project, region) read via `getScopeContext`. */
361
+ context?: Record<string, string>;
362
+ /**
363
+ * Elevated (platform-admin) scope. The value is the `elevatedBy` audit string
364
+ * arc requires — an elevated scope must record who granted it. `true` is
365
+ * shorthand for `'test'`.
366
+ *
367
+ * An elevated scope carries no roles: elevation is a different kind of actor,
368
+ * not a role. A test needing a role gate AND elevation wants `member`.
369
+ */
370
+ elevated?: string | boolean;
371
+ }
372
+ /**
373
+ * Build the headers that make an injected request act as `actor`.
374
+ *
375
+ * A string is shorthand for a single role. `null` means "stay public", so a test
376
+ * can prove an endpoint is reachable anonymously.
377
+ *
378
+ * @example
379
+ * ```ts
380
+ * t.app.inject({ method: 'GET', url: '/pos/shifts/current',
381
+ * headers: testActorHeaders('manager', ORG) });
382
+ * ```
383
+ */
384
+ declare function testActorHeaders(actor: TestActor | string | null, organizationId?: string): Record<string, string>;
385
+ /**
386
+ * Turn a spec into a `RequestScope`.
387
+ *
388
+ * `orgRoles` defaults to `roles`: a test that says "manager" means it at both
389
+ * levels, and making the caller repeat itself only produces tests that pass a
390
+ * global gate and mysteriously fail an org one.
391
+ */
392
+ declare function scopeFromTestActor(spec: TestActor): RequestScope;
393
+ /**
394
+ * Build the `auth` option that makes the test actor arc's authenticator.
395
+ *
396
+ * It must be an authenticator, not a hook. Fastify encapsulates plugins and
397
+ * modules register DURING `createApp`, so a hook added to the root instance
398
+ * afterwards never runs for their routes — every request still resolves as
399
+ * public and every role gate still answers 401, which reads exactly like a
400
+ * broken authorization rule in the code under test. Registering as
401
+ * `auth: { type: 'authenticator' }` puts the scope where arc's own auth would,
402
+ * at the phase arc expects, so tenant filtering and permission checks behave
403
+ * identically to production.
404
+ *
405
+ * `defaultActor` applies to requests carrying no header. A malformed header
406
+ * REJECTS rather than falling back to public — a test that meant to be an admin
407
+ * and got quietly demoted is the most expensive way to fail.
408
+ */
409
+ declare function testActorAuth(defaultActor?: TestActor): {
410
+ type: "authenticator";
411
+ authenticate: (request: unknown) => Promise<void>;
412
+ };
413
+ //#endregion
302
414
  //#region src/testing/bootModuleApp.d.ts
303
415
  /** Handed to a modules factory — the in-memory DB is live at call time. */
304
416
  /**
@@ -322,8 +434,6 @@ type TestDatabaseFactory<TConn = unknown> = (opts: {
322
434
  interface TestkitContext<TConn = unknown> {
323
435
  /** The provisioned database's connection string. */
324
436
  uri: string;
325
- /** @deprecated Alias of `uri` from the Mongo-default era — prefer `uri`. */
326
- mongoUri: string;
327
437
  /**
328
438
  * Driver connection handle (the default factory yields mongoose's
329
439
  * DEFAULT connection). Generic so DB-typed wrappers assert the driver
@@ -349,13 +459,20 @@ interface BootModuleAppOptions<TConn = unknown> {
349
459
  * boot when a module genuinely exercises one).
350
460
  */
351
461
  app?: Partial<CreateAppOptions>;
462
+ /**
463
+ * Default actor for every injected request that carries no `x-test-actor` header.
464
+ *
465
+ * The harness boots with `auth: false`, so without this every request is
466
+ * `PUBLIC_SCOPE` and role-gated routes answer 401 — correct, but it left tests with
467
+ * no supported way to be somebody. See `testActor.ts` for why the seam lives in the
468
+ * testing entrypoint and can never be reached from production.
469
+ */
470
+ actor?: TestActor;
352
471
  }
353
472
  interface ModuleTestApp<TConn = unknown> {
354
473
  app: FastifyInstance;
355
474
  /** The provisioned database's connection string. */
356
475
  uri: string;
357
- /** @deprecated Alias of `uri` from the Mongo-default era — prefer `uri`. */
358
- mongoUri: string;
359
476
  /** The mongoose `Connection` handed to the modules factory. */
360
477
  connection: TConn;
361
478
  /**
@@ -527,13 +644,26 @@ declare function createSpy<T extends (...args: unknown[]) => unknown>(_name?: st
527
644
  getLastCall(): unknown[];
528
645
  };
529
646
  /**
530
- * Wait for a condition to be true
647
+ * Wait until `condition` holds — the standard way to assert on asynchronous
648
+ * effects in arc's suites.
649
+ *
650
+ * **Prefer this over `await sleep(n)` + assert.** A fixed delay encodes a guess
651
+ * about scheduling: too short and it flakes the moment the pool is busy, too
652
+ * long and every run pays for the worst case. Polling returns as soon as the
653
+ * effect lands, so the fast path stays fast and a loaded machine simply waits —
654
+ * and the failure mode becomes "this never happened", which is the thing worth
655
+ * asserting.
656
+ *
657
+ * Supply `label`: without it a timeout reports only its own duration, which is
658
+ * the least useful sentence a flaky test can print.
531
659
  *
532
- * Useful for async testing
660
+ * @example
661
+ * await waitFor(() => runs >= 3, { label: "3 scheduler ticks" });
533
662
  */
534
663
  declare function waitFor(condition: () => boolean | Promise<boolean>, options?: {
535
664
  timeout?: number;
536
665
  interval?: number;
666
+ label?: string;
537
667
  }): Promise<void>;
538
668
  /**
539
669
  * Create a test timer that can be controlled
@@ -545,6 +675,31 @@ declare function createTestTimer(): {
545
675
  reset: () => void;
546
676
  };
547
677
  //#endregion
678
+ //#region src/testing/scopeRoleGate.d.ts
679
+ /**
680
+ * Grants iff the caller is an org member holding one of `allowed` as an ORG role.
681
+ *
682
+ * This is `requireOrgRole` under a name package tests reach for — deliberately a
683
+ * delegation, not a reimplementation. It previously read `scope.userRoles` while
684
+ * requiring an organization, so it disagreed with production for any actor whose
685
+ * global and org roles differ: given
686
+ * `{ roles: ["employee"], orgRoles: ["manager"], organizationId: "org-1" }`,
687
+ * `requireOrgRole("manager")` allowed and this denied. The tests never caught it
688
+ * because `scopeFromTestActor` defaults `orgRoles` to `roles`, making the two
689
+ * dimensions identical for the common actor.
690
+ *
691
+ * Delegating also inherits the semantics a hand-rolled gate kept missing:
692
+ * elevated scopes pass, and a service (API-key) identity is refused with a
693
+ * message naming `requireServiceScope` instead of silently failing a role test.
694
+ *
695
+ * **Pair it with an org-bearing actor.** `testActorHeaders('manager', ORG)`
696
+ * yields a `member` scope and passes; `testActorHeaders('manager')` yields an
697
+ * `authenticated` scope with no tenant, which is refused — arc's generated CRUD
698
+ * filters by tenant, so a gate that waves a tenant-less request through is how a
699
+ * green test reads another org's rows.
700
+ */
701
+ declare function scopeRoleGate(...allowed: string[]): PermissionCheck;
702
+ //#endregion
548
703
  //#region src/testing/testApp.d.ts
549
704
  type DbMode = "in-memory" | {
550
705
  uri: string;
@@ -622,4 +777,4 @@ declare function createTestApp(options?: CreateTestAppOptions): Promise<TestAppC
622
777
  */
623
778
  declare function createMinimalTestApp(options?: FastifyServerOptions): FastifyInstance;
624
779
  //#endregion
625
- export { type ArcAssertion, type ArcResponseLike, type AuthMode, type AuthResponse, type BetterAuthTestHelpers, type BetterAuthTestHelpersOptions, type BetterAuthTestUser, type BootModuleAppOptions, type BootModulesInput, type CreateOrgInput, type CreateTestAppOptions, type DbMode, type FixtureDestroyer, type FixtureFactory, type FixtureRegistration, HttpTestHarness, type HttpTestHarnessOptions, type MockRepository, type ModuleTestApp, type OrgResponse, type RoleConfig, type SetupBetterAuthTestAppInput, type SetupBetterAuthTestAppResult, type SignInInput, type SignUpInput, type StorageContractSetup, type StorageContractSetupResult, type TestAppContext, type TestAuthProvider, type TestAuthSession, type TestDatabase, type TestDatabaseFactory, type TestFixtures, type TestkitContext, bootModuleApp, createBetterAuthProvider, createBetterAuthTestHelpers, createCustomAuthProvider, createDataFactory, createHttpTestHarness, createJwtAuthProvider, createMinimalTestApp, createMockController, createMockReply, createMockRepository, createMockRequest, createMockUser, createSpy, createTestApp, createTestFixtures, createTestTimer, expectArc, mongoMemoryDatabase, preloadResources, preloadResourcesAsync, runStorageContract, safeParseBody, setupBetterAuthTestApp, waitFor };
780
+ export { type ArcAssertion, type ArcResponseLike, type AuthMode, type AuthResponse, type AuthorizationConformance, type BetterAuthTestHelpers, type BetterAuthTestHelpersOptions, type BetterAuthTestUser, type BootModuleAppOptions, type BootModulesInput, type CreateOrgInput, type CreateTestAppOptions, type DbMode, type FixtureDestroyer, type FixtureFactory, type FixtureRegistration, HttpTestHarness, type HttpTestHarnessOptions, type MockRepository, type ModuleTestApp, type OrgResponse, type RoleConfig, type SetupBetterAuthTestAppInput, type SetupBetterAuthTestAppResult, type SignInInput, type SignUpInput, type StorageContractSetup, type StorageContractSetupResult, type SurfaceObservation, TEST_ACTOR_HEADER, type TestActor, type TestAppContext, type TestAuthProvider, type TestAuthSession, type TestDatabase, type TestDatabaseFactory, type TestFixtures, type TestkitContext, bootModuleApp, createBetterAuthProvider, createBetterAuthTestHelpers, createCustomAuthProvider, createDataFactory, createHttpTestHarness, createJwtAuthProvider, createMinimalTestApp, createMockController, createMockReply, createMockRepository, createMockRequest, createMockUser, createSpy, createTestApp, createTestFixtures, createTestTimer, expectArc, mongoMemoryDatabase, preloadResources, preloadResourcesAsync, runAuthorizationConformance, runStorageContract, safeParseBody, scopeFromTestActor, scopeRoleGate, setupBetterAuthTestApp, testActorAuth, testActorHeaders, waitFor };