@classytic/arc 2.41.1 → 2.44.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 (248) hide show
  1. package/dist/{EventTransport-CbUKDzZZ.d.mts → EventTransport-CiicKz2Z.d.mts} +1 -1
  2. package/dist/{EventTransport-DSqD_Xsg.mjs → EventTransport-DZWDsaPa.mjs} +22 -17
  3. package/dist/{HookSystem-CMF94SEA.mjs → HookSystem-yjEgn7Cm.mjs} +2 -2
  4. package/dist/{QueryCache-DFA-QrU9.d.mts → QueryCache--5uAuYPW.d.mts} +7 -3
  5. package/dist/{ResourceRegistry-MGpXoxHZ.mjs → ResourceRegistry-DJxHUpE4.mjs} +44 -13
  6. package/dist/acquire-BozJ-9yt.mjs +35 -0
  7. package/dist/actionPermissions-5N04zBL4.mjs +772 -0
  8. package/dist/audit/index.d.mts +46 -8
  9. package/dist/audit/index.mjs +48 -26
  10. package/dist/auth/audit.d.mts +8 -8
  11. package/dist/auth/audit.mjs +1 -1
  12. package/dist/auth/index.d.mts +46 -16
  13. package/dist/auth/index.mjs +134 -156
  14. package/dist/auth/redis-session.d.mts +4 -5
  15. package/dist/auth/redis-session.mjs +1 -1
  16. package/dist/{authorizationDecision-DawKGoXb.mjs → authorizationDecision-wX3SA9w_.mjs} +7 -102
  17. package/dist/{base-CxrV1LmG.d.mts → base-CZyixEQR.d.mts} +27 -5
  18. package/dist/boundedMap-DWiKW7lP.mjs +57 -0
  19. package/dist/{buildHandler-CvxKOc0m.mjs → buildHandler-Bswu_vNb.mjs} +4 -4
  20. package/dist/cache/index.d.mts +31 -43
  21. package/dist/cache/index.mjs +4 -4
  22. package/dist/{caching-DbCBxlgw.mjs → caching-Drp68DIS.mjs} +3 -3
  23. package/dist/claimed-DYvQoZLv.mjs +8 -0
  24. package/dist/cleanup/index.d.mts +18 -22
  25. package/dist/cleanup/index.mjs +27 -73
  26. package/dist/cli/commands/describe.d.mts +7 -5
  27. package/dist/cli/commands/describe.mjs +7 -4
  28. package/dist/cli/commands/docs.d.mts +2 -3
  29. package/dist/cli/commands/docs.mjs +3 -3
  30. package/dist/cli/commands/doctor.d.mts +2 -3
  31. package/dist/cli/commands/doctor.mjs +1 -1
  32. package/dist/cli/commands/generate.mjs +2 -3
  33. package/dist/cli/commands/init.mjs +2 -3
  34. package/dist/cli/commands/introspect.d.mts +2 -3
  35. package/dist/cli/commands/introspect.mjs +2 -2
  36. package/dist/cli/index.mjs +3 -3
  37. package/dist/{constants-D5Ubn1fe.mjs → constants-B2QHb6u6.mjs} +4 -2
  38. package/dist/context/index.d.mts +11 -14
  39. package/dist/context/index.mjs +18 -38
  40. package/dist/core/index.d.mts +3 -3
  41. package/dist/core/index.mjs +8 -8
  42. package/dist/{core-5lazhva9.mjs → core-COcqo0Cp.mjs} +15 -5
  43. package/dist/{createActionRouter-DNqoaK81.mjs → createActionRouter-zG13rpPJ.mjs} +97 -39
  44. package/dist/{createAggregationRouter-BcbQJf10.mjs → createAggregationRouter-CWRz96Vr.mjs} +11 -8
  45. package/dist/{preloadResources-f3boenVZ.mjs → createApp-BGLYtErt.mjs} +305 -394
  46. package/dist/{createMcpServer-CbDWkZ1T.d.mts → createMcpServer-DSztofa9.d.mts} +1 -1
  47. package/dist/{defineAggregation-D_eJjm5A.mjs → defineAggregation--3xguLkk.mjs} +1 -1
  48. package/dist/{defineResource-DxkMTjRn.mjs → defineResource-gUp9ug66.mjs} +118 -1024
  49. package/dist/discovery/index.d.mts +6 -7
  50. package/dist/discovery/index.mjs +1 -1
  51. package/dist/docs/index.d.mts +11 -5
  52. package/dist/docs/index.mjs +4 -4
  53. package/dist/{elevation-CkvG0LG2.mjs → elevation-BG4gnMsJ.mjs} +41 -12
  54. package/dist/{elevation-BXCfVcNG.d.mts → elevation-BW2J3tNj.d.mts} +1 -2
  55. package/dist/encryption/index.d.mts +5 -5
  56. package/dist/encryption/index.mjs +3 -3
  57. package/dist/{errorHandler-D1GHKGlV.mjs → errorHandler-COHw3N1b.mjs} +26 -5
  58. package/dist/{errors-BH7YU_9O.mjs → errors-CW4anJBy.mjs} +58 -23
  59. package/dist/{errors-BGdVwP25.d.mts → errors-JYc9vwqE.d.mts} +9 -0
  60. package/dist/{eventPlugin-B52abJ8W.d.mts → eventPlugin-BtmA4-3P.d.mts} +65 -9
  61. package/dist/{eventPlugin-zZY-unhr.mjs → eventPlugin-BweHAVws.mjs} +82 -21
  62. package/dist/{subscribe-helpers-DatDkcuG.mjs → eventTypes-N4-omQFR.mjs} +151 -17
  63. package/dist/events/index.d.mts +43 -18
  64. package/dist/events/index.mjs +49 -53
  65. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  66. package/dist/events/transports/redis-stream-entry.mjs +139 -157
  67. package/dist/events/transports/redis.d.mts +5 -6
  68. package/dist/events/transports/redis.mjs +2 -2
  69. package/dist/factory/index.d.mts +42 -27
  70. package/dist/factory/index.mjs +213 -32
  71. package/dist/{fastify-augmentation-Cq2nHVaW.d.mts → fastify-augmentation-DRlCIWE9.d.mts} +11 -25
  72. package/dist/{fields-BHrkoF5y.mjs → fields-A5crhsJb.mjs} +1 -1
  73. package/dist/{fields-I_EeRWND.d.mts → fields-BBSpf8pS.d.mts} +1 -1
  74. package/dist/filter-merge-DGM-GQ1J.mjs +99 -0
  75. package/dist/{generate-BLRf2m3y.mjs → generate-BXKo2Gc8.mjs} +2 -2
  76. package/dist/{headers-BIXWKrzQ.mjs → headers-DKZQKL-Z.mjs} +2 -2
  77. package/dist/health-BYAwA6YS.mjs +22 -0
  78. package/dist/{health-ZRHeDHXH.mjs → health-CrqUp3sz.mjs} +115 -55
  79. package/dist/hooks/index.d.mts +2 -2
  80. package/dist/hooks/index.mjs +2 -3
  81. package/dist/idempotency/index.d.mts +36 -10
  82. package/dist/idempotency/index.mjs +230 -111
  83. package/dist/idempotency/redis.d.mts +1 -1
  84. package/dist/idempotency/redis.mjs +77 -12
  85. package/dist/{index-D4u76eQW.d.mts → index-Beg3aNnK.d.mts} +23 -101
  86. package/dist/{preloadResources-CjS2OfpU.d.mts → index-BkV55WlV.d.mts} +37 -38
  87. package/dist/{index-BHdZD8zK.d.mts → index-Bxriq3so.d.mts} +84 -21
  88. package/dist/index-CUJvoyw3.d.mts +510 -0
  89. package/dist/{index-CbJiYrfv.d.mts → index-Chgz3d0i.d.mts} +1 -1
  90. package/dist/{index-DHbyPo5j.d.mts → index-WH7xgvxS.d.mts} +304 -254
  91. package/dist/index.d.mts +9 -9
  92. package/dist/index.mjs +11 -11
  93. package/dist/{init-CpLkjU18.mjs → init-BPzK5Lnr.mjs} +1 -1
  94. package/dist/integrations/event-gateway.d.mts +11 -7
  95. package/dist/integrations/event-gateway.mjs +4 -4
  96. package/dist/integrations/index.d.mts +3 -3
  97. package/dist/integrations/index.mjs +1 -1
  98. package/dist/integrations/jobs/index.d.mts +1 -1
  99. package/dist/integrations/jobs/index.mjs +18 -5
  100. package/dist/integrations/mcp/index.d.mts +102 -89
  101. package/dist/integrations/mcp/index.mjs +19 -4
  102. package/dist/integrations/mcp/testing.d.mts +8 -9
  103. package/dist/integrations/mcp/testing.mjs +2 -2
  104. package/dist/integrations/streamline.d.mts +85 -144
  105. package/dist/integrations/streamline.mjs +131 -55
  106. package/dist/integrations/webhooks.d.mts +83 -143
  107. package/dist/integrations/webhooks.mjs +36 -80
  108. package/dist/integrations/websocket-pushref-redis.d.mts +5 -6
  109. package/dist/integrations/websocket-pushref-redis.mjs +1 -1
  110. package/dist/integrations/websocket-redis.d.mts +5 -6
  111. package/dist/integrations/websocket-redis.mjs +1 -1
  112. package/dist/integrations/websocket.d.mts +3 -3
  113. package/dist/integrations/websocket.mjs +2 -2
  114. package/dist/{interface-DEWNOMza.d.mts → interface-JJzwH4Ro.d.mts} +34 -2
  115. package/dist/{jsonBody-ELR9lfeU.mjs → jsonBody-YIq-vGLv.mjs} +2 -2
  116. package/dist/{keys-cpZCtcIE.mjs → keys-CpoiZ8hU.mjs} +7 -18
  117. package/dist/{loadResources-BPfWiI5s.mjs → loadResources-6jO52-RR.mjs} +3 -3
  118. package/dist/{loadResourcesFromEntry-ixtfL3J2.mjs → loadResourcesFromEntry-MP8xEppu.mjs} +2 -2
  119. package/dist/logger/index.d.mts +9 -17
  120. package/dist/logger/index.mjs +2 -153
  121. package/dist/logger-D4V1zGLI.mjs +160 -0
  122. package/dist/{mcpPlugin-BX5PujI0.mjs → mcpPlugin-srPc7ItN.mjs} +446 -170
  123. package/dist/{memory-Iotz0cCx.mjs → memory-CTa5pOCW.mjs} +36 -34
  124. package/dist/{metrics-NMsmpRmY.mjs → metrics-DsZrvnpB.mjs} +39 -72
  125. package/dist/middleware/index.d.mts +5 -5
  126. package/dist/middleware/index.mjs +3 -3
  127. package/dist/migrations/index.d.mts +13 -13
  128. package/dist/migrations/index.mjs +2 -2
  129. package/dist/{module-DpLJG2_N.mjs → module--L0iBIZz.mjs} +8 -8
  130. package/dist/mongodb-memory-server-CHhYSq5y.mjs +35539 -0
  131. package/dist/mongoose-CYJCLyi-.mjs +67451 -0
  132. package/dist/multiTenant-CAtYlW6H.d.mts +104 -0
  133. package/dist/{multipartBody-DtRWM6_U.mjs → multipartBody-Cc7eZ9cq.mjs} +46 -7
  134. package/dist/node-D8UZv_8c.mjs +41236 -0
  135. package/dist/{openapi-CmFf3yq_.mjs → openapi-CMegfsm8.mjs} +48 -10
  136. package/dist/outbox-admin/index.d.mts +5 -5
  137. package/dist/outbox-admin/index.mjs +6 -18
  138. package/dist/{outbox-module-D2z5WkDY.mjs → outbox-module-Ryk270jd.mjs} +203 -33
  139. package/dist/{outbox-module-BHdUnuuK.d.mts → outbox-module-gZCHoE4H.d.mts} +79 -6
  140. package/dist/permissions/index.d.mts +5 -4
  141. package/dist/permissions/index.mjs +8 -6
  142. package/dist/{permissions-D8TBH44E.mjs → permissions-C5ijIz5Q.mjs} +149 -33
  143. package/dist/{pipe-FMWNheSO.mjs → pipe-D81zMtWs.mjs} +2 -2
  144. package/dist/pipeline/index.d.mts +7 -7
  145. package/dist/pipeline/index.mjs +2 -2
  146. package/dist/plan-CJGMKoui.mjs +565 -0
  147. package/dist/{BaseController-CYEwjyjN.mjs → plugin-DALd9dcF.mjs} +1269 -346
  148. package/dist/plugins/index.d.mts +17 -14
  149. package/dist/plugins/index.mjs +44 -22
  150. package/dist/plugins/response-cache.d.mts +5 -6
  151. package/dist/plugins/response-cache.mjs +8 -14
  152. package/dist/plugins/tracing-entry.mjs +2 -2
  153. package/dist/{pluralize-CXWZIzTv.mjs → pluralize-COUNYo3d.mjs} +1 -1
  154. package/dist/presets/filesUpload.d.mts +8 -8
  155. package/dist/presets/filesUpload.mjs +5 -5
  156. package/dist/presets/index.d.mts +35 -40
  157. package/dist/presets/index.mjs +4 -4
  158. package/dist/presets/multiTenant.d.mts +2 -107
  159. package/dist/presets/multiTenant.mjs +22 -162
  160. package/dist/presets/search.d.mts +9 -10
  161. package/dist/presets/search.mjs +2 -2
  162. package/dist/{presets-ZJSPgmT2.mjs → presets-CONf2Qem.mjs} +99 -107
  163. package/dist/{projection-BzIgzoKZ.mjs → projection-wFoLqdss.mjs} +2 -2
  164. package/dist/{pushref-registry-Dov9l4qE.d.mts → pushref-registry-UxCkoA4C.d.mts} +1 -1
  165. package/dist/{queryCachePlugin-DZHPOm9p.mjs → queryCachePlugin-BATECpyh.mjs} +12 -14
  166. package/dist/{queryCachePlugin-BzqxconG.d.mts → queryCachePlugin-C2lZjTxk.d.mts} +1 -1
  167. package/dist/{rateLimitKey-BvOvcBDi.mjs → rateLimitKey-DVEZ_UpV.mjs} +1 -1
  168. package/dist/{realtime-8tIQWZz4.mjs → realtime-xyubMKSB.mjs} +25 -21
  169. package/dist/{redis-Bzi1y3F9.d.mts → redis-BDgv9Glw.d.mts} +17 -24
  170. package/dist/redis-stream-BMk-bpQS.d.mts +219 -0
  171. package/dist/redisShapes-CQksY67q.d.mts +55 -0
  172. package/dist/registry/index.d.mts +15 -10
  173. package/dist/registry/index.mjs +4 -4
  174. package/dist/{registry-DNkgGQcK.mjs → registry-Bdzg-hdm.mjs} +13 -10
  175. package/dist/{renewingLease-yF8BdW4b.mjs → renewingLease-BFJxGPuh.mjs} +1 -1
  176. package/dist/{replyHelpers-CNdvMfM4.mjs → replyHelpers-Bnc6lJyy.mjs} +2 -2
  177. package/dist/{requestContext-cDkAUr-P.mjs → requestContext-C10UeFe5.mjs} +1 -1
  178. package/dist/requirement-Bu50QALH.mjs +35 -0
  179. package/dist/requirement-CbiLdQ1n.d.mts +22 -0
  180. package/dist/resourceRateLimit-Wf6d6FL9.d.mts +30 -0
  181. package/dist/resourceRateLimit-urWPJxrt.mjs +180 -0
  182. package/dist/rolldown-runtime-MYrLNGnq.mjs +45 -0
  183. package/dist/routeValidator-DHtpzrzk.mjs +70 -0
  184. package/dist/{runtimeCapabilities-CkhS6jn6.mjs → runtimeCapabilities-DIMKMV2G.mjs} +1 -1
  185. package/dist/{schedules-j6uXXAeJ.mjs → schedules-CKTs5ys8.mjs} +46 -37
  186. package/dist/{schemaConverter-BVA7cFRG.mjs → schemaConverter-BVjkQ5DD.mjs} +2 -2
  187. package/dist/{schemaIR-CTvPDoPB.mjs → schemaIR-BA0Hb21Y.mjs} +2 -2
  188. package/dist/schemas/index.d.mts +20 -10
  189. package/dist/schemas/index.mjs +8 -3
  190. package/dist/scim/index.d.mts +13 -13
  191. package/dist/scim/index.mjs +2 -2
  192. package/dist/scope/index.d.mts +4 -4
  193. package/dist/scope/index.mjs +6 -6
  194. package/dist/{scope-BUi1xV1I.mjs → scope-DINaj7Ax.mjs} +4 -4
  195. package/dist/shutdown-LpLMH8T1.mjs +59 -0
  196. package/dist/{simpleEqualityMatcher-C9bzq2gO.mjs → simpleEqualityMatcher-DbwIM1f1.mjs} +1 -1
  197. package/dist/{sse-BeqVKQKu.mjs → sse-BzJFPX_1.mjs} +11 -15
  198. package/dist/{sseStream-Ppzo-WUH.mjs → sseStream-DQChzGTs.mjs} +2 -2
  199. package/dist/{store-helpers-dW71XVWL.mjs → store-helpers-Coj9RhOZ.mjs} +1 -1
  200. package/dist/{streaming-IcRFjWQU.mjs → streaming-JzB5CAga.mjs} +1 -1
  201. package/dist/subscriberIdentity-DeyppIif.mjs +28 -0
  202. package/dist/tenancy-DxV8OuX2.mjs +43 -0
  203. package/dist/tenantPreparation-CBvvAcAj.mjs +67 -0
  204. package/dist/testing/cleanupStoreContract.d.mts +4 -5
  205. package/dist/testing/cleanupStoreContract.mjs +1 -1
  206. package/dist/testing/index.d.mts +215 -197
  207. package/dist/testing/index.mjs +289 -214
  208. package/dist/testing/outboxStoreContract.d.mts +4 -5
  209. package/dist/testing/outboxStoreContract.mjs +137 -2
  210. package/dist/testing/requiredPorts.d.mts +16 -0
  211. package/dist/testing/requiredPorts.mjs +65 -0
  212. package/dist/testing/storageContract.d.mts +4 -5
  213. package/dist/testing/storageContract.mjs +1 -1
  214. package/dist/timing-CntavTlR.mjs +46 -0
  215. package/dist/{transactionContext-CPbdlnVw.mjs → transactionContext-orvnGu4F.mjs} +1 -1
  216. package/dist/{typeGuards-BLjPgVBm.mjs → typeGuards-kEaP_WmO.mjs} +1 -1
  217. package/dist/types/index.d.mts +4 -4
  218. package/dist/types/index.mjs +1 -1
  219. package/dist/types/storage.mjs +1 -1
  220. package/dist/{types-DfVDvkdP.d.mts → types-BJ-2XqVF.d.mts} +189 -204
  221. package/dist/{types-CWQn9-IC.d.mts → types-D3Ixsh00.d.mts} +22 -9
  222. package/dist/{types-CgenB1gv.mjs → types-fvO6Ovzx.mjs} +4 -4
  223. package/dist/usage/index.d.mts +5 -6
  224. package/dist/usage/index.mjs +5 -5
  225. package/dist/{userHelpers-ChRvkuSZ.mjs → userHelpers-C76zD5pa.mjs} +1 -1
  226. package/dist/utils/index.d.mts +125 -264
  227. package/dist/utils/index.mjs +13 -12
  228. package/dist/{utils-CxcctrAh.mjs → utils-BpkVZ8rB.mjs} +315 -404
  229. package/dist/{validate-DrYWnOzI.mjs → validate-CWp-lsrm.mjs} +6 -14
  230. package/dist/{versioning-D6JIK8Tk.d.mts → versioning-Bsb51gGT.d.mts} +28 -13
  231. package/dist/{versioning-DKkT4hNJ.mjs → versioning-CHhL9P3o.mjs} +4 -4
  232. package/dist/{websocket-BOXVggMf.d.mts → websocket-Cs4awVyD.d.mts} +1 -1
  233. package/dist/{workScope-CxKqoIFn.mjs → workScope-n9a7d_lZ.mjs} +2 -2
  234. package/package.json +57 -59
  235. package/skills/arc/SKILL.md +13 -4
  236. package/skills/arc/references/auth.md +8 -5
  237. package/skills/arc/references/integrations.md +1 -1
  238. package/skills/arc/references/mcp.md +8 -6
  239. package/skills/arc/references/multi-tenancy.md +19 -14
  240. package/skills/arc/references/production.md +27 -10
  241. package/dist/actionPermissions-BoPGQ5-4.mjs +0 -350
  242. package/dist/index-CFfLKMH4.d.mts +0 -290
  243. package/dist/interface-YzIbF7Ii.mjs +0 -17
  244. package/dist/redis-stream-BPKscsTB.d.mts +0 -260
  245. package/dist/registerRoute-Bsnk6NiZ.mjs +0 -364
  246. package/dist/rolldown-runtime-eysyzFAF.mjs +0 -15
  247. package/dist/sync/changelog.d.mts +0 -3
  248. package/dist/sync/changelog.mjs +0 -3
@@ -1,10 +1,10 @@
1
1
 
2
2
  import { i as RequestScope } from "../types-Ddl9OjmE.mjs";
3
- import { l as PermissionCheck, t as AnyRecord } from "../base-CxrV1LmG.mjs";
4
- import { V as ResourceDefinition } from "../index-DHbyPo5j.mjs";
5
- import { n as ArcModuleInput, o as ModuleDisposer, s as ModuleSetupContext } from "../types-DfVDvkdP.mjs";
6
- import "../index-CFfLKMH4.mjs";
7
- import { n as preloadResourcesAsync, r as CreateAppOptions, t as preloadResources } from "../preloadResources-CjS2OfpU.mjs";
3
+ import { l as PermissionCheck, t as AnyRecord } from "../base-CZyixEQR.mjs";
4
+ import { F as ResourceDefinition } from "../index-WH7xgvxS.mjs";
5
+ import { h as ModuleSetupContext, m as ModuleDisposer, o as ArcPorts, p as PortName, r as ArcModuleInput, u as ModuleName } from "../types-BJ-2XqVF.mjs";
6
+ import "../index-CUJvoyw3.mjs";
7
+ import { n as CreateAppOptions } from "../index-BkV55WlV.mjs";
8
8
  import { StorageContractSetup, StorageContractSetupResult, runStorageContract } from "./storageContract.mjs";
9
9
  import { StandardRepo } from "@classytic/repo-core/repository";
10
10
  import { FastifyInstance, FastifyServerOptions } from "fastify";
@@ -72,7 +72,181 @@ interface ArcAssertion {
72
72
  /** Assert a specific key on `body.meta` or flattened top-level (matches sendControllerResponse flattening). */
73
73
  hasMeta(key: string, value?: unknown): ArcAssertion;
74
74
  }
75
- declare function expectArc(response: ArcResponseLike): ArcAssertion;
75
+ export declare function expectArc(response: ArcResponseLike): ArcAssertion;
76
+ //#endregion
77
+ //#region src/testing/testActor.d.ts
78
+ /** The header the testing harness uses to carry a request's actor. */
79
+ export declare const TEST_ACTOR_HEADER = "x-test-actor";
80
+ /**
81
+ * What a test wants to be. An `organizationId` produces a `member` scope (the
82
+ * org-scoped case); without one the actor is `authenticated`.
83
+ */
84
+ interface TestActor {
85
+ /**
86
+ * Defaults to a synthetic id derived from the roles. Pass one explicitly when
87
+ * a test distinguishes two actors — ownership and audit assertions do, and
88
+ * two actors sharing roles would otherwise share an id.
89
+ */
90
+ userId?: string;
91
+ /** Global roles — what `requireRoles` reads. */
92
+ roles?: string[];
93
+ /** Tenant. Present ⇒ a `member` scope. */
94
+ organizationId?: string;
95
+ /** Org-level roles from membership records. Defaults to `roles`. */
96
+ orgRoles?: string[];
97
+ teamId?: string;
98
+ /** App-defined dimensions (branch, project, region) read via `getScopeContext`. */
99
+ context?: Record<string, string>;
100
+ /**
101
+ * Elevated (platform-admin) scope. The value is the `elevatedBy` audit string
102
+ * arc requires — an elevated scope must record who granted it. `true` is
103
+ * shorthand for `'test'`.
104
+ *
105
+ * An elevated scope carries no roles: elevation is a different kind of actor,
106
+ * not a role. A test needing a role gate AND elevation wants `member`.
107
+ */
108
+ elevated?: string | boolean;
109
+ }
110
+ /**
111
+ * Build the headers that make an injected request act as `actor`.
112
+ *
113
+ * A string is shorthand for a single role. `null` means "stay public", so a test
114
+ * can prove an endpoint is reachable anonymously.
115
+ *
116
+ * @example
117
+ * ```ts
118
+ * t.app.inject({ method: 'GET', url: '/pos/shifts/current',
119
+ * headers: testActorHeaders('manager', ORG) });
120
+ * ```
121
+ */
122
+ export declare function testActorHeaders(actor: TestActor | string | null, organizationId?: string): Record<string, string>;
123
+ /**
124
+ * Turn a spec into a `RequestScope`.
125
+ *
126
+ * `orgRoles` defaults to `roles`: a test that says "manager" means it at both
127
+ * levels, and making the caller repeat itself only produces tests that pass a
128
+ * global gate and mysteriously fail an org one.
129
+ */
130
+ export declare function scopeFromTestActor(spec: TestActor): RequestScope;
131
+ /**
132
+ * Build the `auth` option that makes the test actor arc's authenticator.
133
+ *
134
+ * It must be an authenticator, not a hook. Fastify encapsulates plugins and
135
+ * modules register DURING `createApp`, so a hook added to the root instance
136
+ * afterwards never runs for their routes — every request still resolves as
137
+ * public and every role gate still answers 401, which reads exactly like a
138
+ * broken authorization rule in the code under test. Registering as
139
+ * `auth: { type: 'authenticator' }` puts the scope where arc's own auth would,
140
+ * at the phase arc expects, so tenant filtering and permission checks behave
141
+ * identically to production.
142
+ *
143
+ * `defaultActor` applies to requests carrying no header. A malformed header
144
+ * REJECTS rather than falling back to public — a test that meant to be an admin
145
+ * and got quietly demoted is the most expensive way to fail.
146
+ */
147
+ export declare function testActorAuth(defaultActor?: TestActor): {
148
+ type: "authenticator";
149
+ authenticate: (request: unknown) => Promise<void>;
150
+ };
151
+ //#endregion
152
+ //#region src/testing/bootModuleApp.d.ts
153
+ /** Handed to a modules factory — the in-memory DB is live at call time. */
154
+ /**
155
+ * A provisioned test database — what the `database` seam yields. Arc
156
+ * core never names a driver: kits ship factories (`mongoMemoryDatabase`
157
+ * is the built-in default; a sqlitekit/pgkit testkit ships its own) and
158
+ * the connection flows through as an opaque generic.
159
+ */
160
+ interface TestDatabase<TConn = unknown> {
161
+ /** Connection string, when the backend has one (informational). */
162
+ uri: string;
163
+ /** Driver connection handle passed to the modules factory. */
164
+ connection: TConn;
165
+ /** Stop/disconnect everything this factory started. MUST be idempotent-safe to call once. */
166
+ teardown(): Promise<void>;
167
+ }
168
+ /** The DB-provisioning seam — `bootModuleApp({ database })`. */
169
+ type TestDatabaseFactory<TConn = unknown> = (opts: {
170
+ replset?: boolean;
171
+ }) => Promise<TestDatabase<TConn>>;
172
+ interface TestkitContext<TConn = unknown> {
173
+ /** The provisioned database's connection string. */
174
+ uri: string;
175
+ /**
176
+ * Driver connection handle (the default factory yields mongoose's
177
+ * DEFAULT connection). Generic so DB-typed wrappers assert the driver
178
+ * type ONCE: `bootModuleApp<Connection>(...)`. Arc core stays DB-agnostic.
179
+ */
180
+ connection: TConn;
181
+ }
182
+ type BootModulesInput<TConn = unknown> = ArcModuleInput | readonly ArcModuleInput[] | ((ctx: TestkitContext<TConn>) => ArcModuleInput | readonly ArcModuleInput[] | Promise<ArcModuleInput | readonly ArcModuleInput[]>);
183
+ interface BootModuleAppOptions<TConn = unknown> {
184
+ /**
185
+ * DB provisioner. Default: `mongoMemoryDatabase` (in-memory MongoDB —
186
+ * lazy devDep imports, nothing Mongo touches arc's runtime). Kits for
187
+ * other stores inject their own factory here; the rest of the harness
188
+ * (module resolution, app boot, teardown ordering) is DB-agnostic.
189
+ */
190
+ database?: TestDatabaseFactory<TConn>;
191
+ /** Single-node replica set (transactions). Default: standalone. Passed to the database factory. */
192
+ replset?: boolean;
193
+ /**
194
+ * Extra `createApp` options merged over the testing defaults
195
+ * (`preset: 'testing'`, `auth: false`, `sensible: false` — utility
196
+ * plugins stay off so the testkit is dependency-light; re-enable per
197
+ * boot when a module genuinely exercises one).
198
+ */
199
+ app?: Partial<CreateAppOptions>;
200
+ /**
201
+ * Default actor for every injected request that carries no `x-test-actor` header.
202
+ *
203
+ * The harness boots with `auth: false`, so without this every request is
204
+ * `PUBLIC_SCOPE` and role-gated routes answer 401 — correct, but it left tests with
205
+ * no supported way to be somebody. See `testActor.ts` for why the seam lives in the
206
+ * testing entrypoint and can never be reached from production.
207
+ */
208
+ actor?: TestActor;
209
+ /** Host ports for the booted modules — typed and checked exactly as `createApp({ ports })`. */
210
+ ports?: ArcPorts;
211
+ }
212
+ interface ModuleTestApp<TConn = unknown> {
213
+ app: FastifyInstance;
214
+ /** The provisioned database's connection string. */
215
+ uri: string;
216
+ /** The mongoose `Connection` handed to the modules factory. */
217
+ connection: TConn;
218
+ /**
219
+ * Typed module-export accessor — `t.exports<CatalogEngine>('catalog')`
220
+ * instead of reaching through `(t.app as ...).arc.modules.catalog`.
221
+ * Delegates to `getModuleExports` (throws with the registered-module
222
+ * list when the name is unknown — same contract hosts get).
223
+ */
224
+ exports<TExports = unknown>(name: string): TExports;
225
+ /** Close app → disconnect mongoose → stop the in-memory server. Idempotent. */
226
+ close(): Promise<void>;
227
+ }
228
+ /**
229
+ * The built-in DB factory: in-memory MongoDB via lazy devDep imports.
230
+ * Everything Mongo-specific about the harness lives HERE — the harness
231
+ * itself is driver-blind and any kit can replace this via `database`.
232
+ */
233
+ export declare function mongoMemoryDatabase(opts: {
234
+ replset?: boolean;
235
+ }): Promise<TestDatabase<unknown>>;
236
+ export declare function bootModuleApp<TConn = unknown>(modules: BootModulesInput<TConn>, options?: BootModuleAppOptions<TConn>): Promise<ModuleTestApp<TConn>>;
237
+ //#endregion
238
+ //#region src/testing/assertModuleBootsAlone.d.ts
239
+ interface ModuleBootsAloneOptions<TConn = unknown> extends BootModuleAppOptions<TConn> {
240
+ /** Runs against the booted closure before it closes — drive the module's cross-module ports. */
241
+ probe?: (t: ModuleTestApp<TConn>) => void | Promise<void>;
242
+ }
243
+ interface ModuleBootsAloneResult {
244
+ /** The closure's modules (bridges excluded), in input order. */
245
+ readonly closure: readonly string[];
246
+ }
247
+ export declare function assertModuleBootsAlone<TConn = unknown>(modules: BootModulesInput<TConn>,
248
+ /** The module — or several roots booted together, when a deployment rule pairs them. */
249
+ name: ModuleName | readonly ModuleName[], options?: ModuleBootsAloneOptions<TConn>): Promise<ModuleBootsAloneResult>;
76
250
  //#endregion
77
251
  //#region src/testing/authorizationConformance.d.ts
78
252
  /** One surface's observed enforcement: the HTTP status + the filter arc passed the repo. */
@@ -107,7 +281,7 @@ interface AuthorizationConformance {
107
281
  * Boot a one-resource app gated by `permission` on both list + an aggregation,
108
282
  * hit both surfaces anonymously, and report what arc enforced on each.
109
283
  */
110
- declare function runAuthorizationConformance(opts: {
284
+ export declare function runAuthorizationConformance(opts: {
111
285
  /** The permission under test — applied to `list` and the aggregation alike. */
112
286
  permission: PermissionCheck;
113
287
  /** Rows the mock repo returns for list (aggregation returns a count). */
@@ -166,21 +340,21 @@ interface TestAuthProvider {
166
340
  * Accepts both `user` (payload to sign) and `token` (pre-signed) role configs,
167
341
  * so the same provider handles mixed flows in a single test.
168
342
  */
169
- declare function createJwtAuthProvider(app: FastifyInstance, opts?: {
343
+ export declare function createJwtAuthProvider(app: FastifyInstance, opts?: {
170
344
  defaultOrgId?: string;
171
345
  }): TestAuthProvider;
172
346
  /**
173
347
  * Better Auth provider — uses pre-signed tokens (from signUp/signIn flows).
174
348
  * No signing: role configs MUST carry `token`. A `user` alone will throw.
175
349
  */
176
- declare function createBetterAuthProvider(opts?: {
350
+ export declare function createBetterAuthProvider(opts?: {
177
351
  defaultOrgId?: string;
178
352
  }): TestAuthProvider;
179
353
  /**
180
354
  * Custom provider — plug in your own token minting logic. Useful for
181
355
  * mocked external issuers, session-cookie flows, or fixtures that pre-mint.
182
356
  */
183
- declare function createCustomAuthProvider(mintToken: (role: string, config: RoleConfig) => string, opts?: {
357
+ export declare function createCustomAuthProvider(mintToken: (role: string, config: RoleConfig) => string, opts?: {
184
358
  defaultOrgId?: string;
185
359
  }): TestAuthProvider;
186
360
  //#endregion
@@ -313,13 +487,13 @@ interface SetupBetterAuthTestAppResult {
313
487
  * Auth endpoints occasionally emit empty 204 bodies (e.g. set-active) and
314
488
  * tests shouldn't crash on the parse.
315
489
  */
316
- declare function safeParseBody<T = unknown>(body: string | undefined): T | null;
490
+ export declare function safeParseBody<T = unknown>(body: string | undefined): T | null;
317
491
  /**
318
492
  * Stateless Better Auth helpers. Each function takes the app as a positional
319
493
  * argument, so a single helper instance works across multiple test apps in
320
494
  * the same suite.
321
495
  */
322
- declare function createBetterAuthTestHelpers(options?: BetterAuthTestHelpersOptions): BetterAuthTestHelpers;
496
+ export declare function createBetterAuthTestHelpers(options?: BetterAuthTestHelpersOptions): BetterAuthTestHelpers;
323
497
  /**
324
498
  * Composite setup for Better Auth apps. Replaces the pre-v2.11
325
499
  * `setupBetterAuthOrg` with a tighter contract:
@@ -339,183 +513,24 @@ declare function createBetterAuthTestHelpers(options?: BetterAuthTestHelpersOpti
339
513
  * creators are supplied (ambiguous ownership is a boot-time bug, not a
340
514
  * runtime one).
341
515
  */
342
- declare function setupBetterAuthTestApp(input: SetupBetterAuthTestAppInput): Promise<SetupBetterAuthTestAppResult>;
343
- //#endregion
344
- //#region src/testing/testActor.d.ts
345
- /** The header the testing harness uses to carry a request's actor. */
346
- declare const TEST_ACTOR_HEADER = "x-test-actor";
347
- /**
348
- * What a test wants to be. An `organizationId` produces a `member` scope (the
349
- * org-scoped case); without one the actor is `authenticated`.
350
- */
351
- interface TestActor {
352
- /**
353
- * Defaults to a synthetic id derived from the roles. Pass one explicitly when
354
- * a test distinguishes two actors — ownership and audit assertions do, and
355
- * two actors sharing roles would otherwise share an id.
356
- */
357
- userId?: string;
358
- /** Global roles — what `requireRoles` reads. */
359
- roles?: string[];
360
- /** Tenant. Present ⇒ a `member` scope. */
361
- organizationId?: string;
362
- /** Org-level roles from membership records. Defaults to `roles`. */
363
- orgRoles?: string[];
364
- teamId?: string;
365
- /** App-defined dimensions (branch, project, region) read via `getScopeContext`. */
366
- context?: Record<string, string>;
367
- /**
368
- * Elevated (platform-admin) scope. The value is the `elevatedBy` audit string
369
- * arc requires — an elevated scope must record who granted it. `true` is
370
- * shorthand for `'test'`.
371
- *
372
- * An elevated scope carries no roles: elevation is a different kind of actor,
373
- * not a role. A test needing a role gate AND elevation wants `member`.
374
- */
375
- elevated?: string | boolean;
376
- }
377
- /**
378
- * Build the headers that make an injected request act as `actor`.
379
- *
380
- * A string is shorthand for a single role. `null` means "stay public", so a test
381
- * can prove an endpoint is reachable anonymously.
382
- *
383
- * @example
384
- * ```ts
385
- * t.app.inject({ method: 'GET', url: '/pos/shifts/current',
386
- * headers: testActorHeaders('manager', ORG) });
387
- * ```
388
- */
389
- declare function testActorHeaders(actor: TestActor | string | null, organizationId?: string): Record<string, string>;
390
- /**
391
- * Turn a spec into a `RequestScope`.
392
- *
393
- * `orgRoles` defaults to `roles`: a test that says "manager" means it at both
394
- * levels, and making the caller repeat itself only produces tests that pass a
395
- * global gate and mysteriously fail an org one.
396
- */
397
- declare function scopeFromTestActor(spec: TestActor): RequestScope;
398
- /**
399
- * Build the `auth` option that makes the test actor arc's authenticator.
400
- *
401
- * It must be an authenticator, not a hook. Fastify encapsulates plugins and
402
- * modules register DURING `createApp`, so a hook added to the root instance
403
- * afterwards never runs for their routes — every request still resolves as
404
- * public and every role gate still answers 401, which reads exactly like a
405
- * broken authorization rule in the code under test. Registering as
406
- * `auth: { type: 'authenticator' }` puts the scope where arc's own auth would,
407
- * at the phase arc expects, so tenant filtering and permission checks behave
408
- * identically to production.
409
- *
410
- * `defaultActor` applies to requests carrying no header. A malformed header
411
- * REJECTS rather than falling back to public — a test that meant to be an admin
412
- * and got quietly demoted is the most expensive way to fail.
413
- */
414
- declare function testActorAuth(defaultActor?: TestActor): {
415
- type: "authenticator";
416
- authenticate: (request: unknown) => Promise<void>;
417
- };
418
- //#endregion
419
- //#region src/testing/bootModuleApp.d.ts
420
- /** Handed to a modules factory — the in-memory DB is live at call time. */
421
- /**
422
- * A provisioned test database — what the `database` seam yields. Arc
423
- * core never names a driver: kits ship factories (`mongoMemoryDatabase`
424
- * is the built-in default; a sqlitekit/pgkit testkit ships its own) and
425
- * the connection flows through as an opaque generic.
426
- */
427
- interface TestDatabase<TConn = unknown> {
428
- /** Connection string, when the backend has one (informational). */
429
- uri: string;
430
- /** Driver connection handle passed to the modules factory. */
431
- connection: TConn;
432
- /** Stop/disconnect everything this factory started. MUST be idempotent-safe to call once. */
433
- teardown(): Promise<void>;
434
- }
435
- /** The DB-provisioning seam — `bootModuleApp({ database })`. */
436
- type TestDatabaseFactory<TConn = unknown> = (opts: {
437
- replset?: boolean;
438
- }) => Promise<TestDatabase<TConn>>;
439
- interface TestkitContext<TConn = unknown> {
440
- /** The provisioned database's connection string. */
441
- uri: string;
442
- /**
443
- * Driver connection handle (the default factory yields mongoose's
444
- * DEFAULT connection). Generic so DB-typed wrappers assert the driver
445
- * type ONCE: `bootModuleApp<Connection>(...)`. Arc core stays DB-agnostic.
446
- */
447
- connection: TConn;
448
- }
449
- type BootModulesInput<TConn = unknown> = ArcModuleInput | readonly ArcModuleInput[] | ((ctx: TestkitContext<TConn>) => ArcModuleInput | readonly ArcModuleInput[] | Promise<ArcModuleInput | readonly ArcModuleInput[]>);
450
- interface BootModuleAppOptions<TConn = unknown> {
451
- /**
452
- * DB provisioner. Default: `mongoMemoryDatabase` (in-memory MongoDB —
453
- * lazy devDep imports, nothing Mongo touches arc's runtime). Kits for
454
- * other stores inject their own factory here; the rest of the harness
455
- * (module resolution, app boot, teardown ordering) is DB-agnostic.
456
- */
457
- database?: TestDatabaseFactory<TConn>;
458
- /** Single-node replica set (transactions). Default: standalone. Passed to the database factory. */
459
- replset?: boolean;
460
- /**
461
- * Extra `createApp` options merged over the testing defaults
462
- * (`preset: 'testing'`, `auth: false`, `sensible: false` — utility
463
- * plugins stay off so the testkit is dependency-light; re-enable per
464
- * boot when a module genuinely exercises one).
465
- */
466
- app?: Partial<CreateAppOptions>;
467
- /**
468
- * Default actor for every injected request that carries no `x-test-actor` header.
469
- *
470
- * The harness boots with `auth: false`, so without this every request is
471
- * `PUBLIC_SCOPE` and role-gated routes answer 401 — correct, but it left tests with
472
- * no supported way to be somebody. See `testActor.ts` for why the seam lives in the
473
- * testing entrypoint and can never be reached from production.
474
- */
475
- actor?: TestActor;
476
- }
477
- interface ModuleTestApp<TConn = unknown> {
478
- app: FastifyInstance;
479
- /** The provisioned database's connection string. */
480
- uri: string;
481
- /** The mongoose `Connection` handed to the modules factory. */
482
- connection: TConn;
483
- /**
484
- * Typed module-export accessor — `t.exports<CatalogEngine>('catalog')`
485
- * instead of reaching through `(t.app as ...).arc.modules.catalog`.
486
- * Delegates to `getModuleExports` (throws with the registered-module
487
- * list when the name is unknown — same contract hosts get).
488
- */
489
- exports<TExports = unknown>(name: string): TExports;
490
- /** Close app → disconnect mongoose → stop the in-memory server. Idempotent. */
491
- close(): Promise<void>;
492
- }
493
- /**
494
- * The built-in DB factory: in-memory MongoDB via lazy devDep imports.
495
- * Everything Mongo-specific about the harness lives HERE — the harness
496
- * itself is driver-blind and any kit can replace this via `database`.
497
- */
498
- declare function mongoMemoryDatabase(opts: {
499
- replset?: boolean;
500
- }): Promise<TestDatabase<unknown>>;
501
- declare function bootModuleApp<TConn = unknown>(modules: BootModulesInput<TConn>, options?: BootModuleAppOptions<TConn>): Promise<ModuleTestApp<TConn>>;
516
+ export declare function setupBetterAuthTestApp(input: SetupBetterAuthTestAppInput): Promise<SetupBetterAuthTestAppResult>;
502
517
  //#endregion
503
518
  //#region src/testing/fixtures.d.ts
504
- type FixtureFactory<T extends AnyRecord = AnyRecord> = (data: Partial<T>) => Promise<T>;
519
+ type FixtureFactory<T extends object = AnyRecord> = (data: Partial<T>) => Promise<T>;
505
520
  /** Delete hook invoked by `clear()` for records that were created through a factory. */
506
- type FixtureDestroyer<T extends AnyRecord = AnyRecord> = (record: T) => Promise<void>;
507
- interface FixtureRegistration<T extends AnyRecord = AnyRecord> {
521
+ type FixtureDestroyer<T extends object = AnyRecord> = (record: T) => Promise<void>;
522
+ interface FixtureRegistration<T extends object = AnyRecord> {
508
523
  create: FixtureFactory<T>;
509
524
  /** Optional cleanup. Defaults to a no-op; adapters that support deletion should provide one. */
510
525
  destroy?: FixtureDestroyer<T>;
511
526
  }
512
527
  interface TestFixtures {
513
528
  /** Register a named factory. Later calls replace the earlier registration. */
514
- register<T extends AnyRecord = AnyRecord>(name: string, factoryOrRegistration: FixtureFactory<T> | FixtureRegistration<T>): void;
529
+ register<T extends object = AnyRecord>(name: string, factoryOrRegistration: FixtureFactory<T> | FixtureRegistration<T>): void;
515
530
  /** Create one record through the named factory. Tracked for cleanup. */
516
- create<T extends AnyRecord = AnyRecord>(name: string, data?: Partial<T>): Promise<T>;
531
+ create<T extends object = AnyRecord>(name: string, data?: Partial<T>): Promise<T>;
517
532
  /** Create many records with a shared template. Tracked for cleanup. */
518
- createMany<T extends AnyRecord = AnyRecord>(name: string, count: number, template?: Partial<T>): Promise<T[]>;
533
+ createMany<T extends object = AnyRecord>(name: string, count: number, template?: Partial<T>): Promise<T[]>;
519
534
  /**
520
535
  * Run every registered `destroy` hook over the records this instance
521
536
  * created, then forget them. Safe to call multiple times (idempotent).
@@ -524,11 +539,11 @@ interface TestFixtures {
524
539
  */
525
540
  clear(): Promise<void>;
526
541
  /** All records ever created by a given factory name (read-only snapshot). */
527
- all<T extends AnyRecord = AnyRecord>(name: string): readonly T[];
542
+ all<T extends object = AnyRecord>(name: string): readonly T[];
528
543
  /** Registered factory names. */
529
544
  readonly names: readonly string[];
530
545
  }
531
- declare function createTestFixtures(): TestFixtures;
546
+ export declare function createTestFixtures(): TestFixtures;
532
547
  //#endregion
533
548
  //#region src/testing/HttpTestHarness.d.ts
534
549
  interface HttpTestHarnessOptions<T = unknown> {
@@ -548,7 +563,7 @@ interface HttpTestHarnessOptions<T = unknown> {
548
563
  apiPrefix?: string;
549
564
  }
550
565
  type OptionsOrGetter<T> = HttpTestHarnessOptions<T> | (() => HttpTestHarnessOptions<T>);
551
- declare class HttpTestHarness<T = unknown> {
566
+ export declare class HttpTestHarness<T = unknown> {
552
567
  private resource;
553
568
  private optionsOrGetter;
554
569
  private enabledRoutes;
@@ -566,7 +581,7 @@ declare class HttpTestHarness<T = unknown> {
566
581
  * Create an HTTP test harness. `optionsOrGetter` may be a plain object
567
582
  * (for eager app setup) or a getter function (for async `beforeAll` apps).
568
583
  */
569
- declare function createHttpTestHarness<T = unknown>(resource: ResourceDefinition<unknown>, optionsOrGetter: HttpTestHarnessOptions<T> | (() => HttpTestHarnessOptions<T>)): HttpTestHarness<T>;
584
+ export declare function createHttpTestHarness<T = unknown>(resource: ResourceDefinition<unknown>, optionsOrGetter: HttpTestHarnessOptions<T> | (() => HttpTestHarnessOptions<T>)): HttpTestHarness<T>;
570
585
  //#endregion
571
586
  //#region src/testing/mocks.d.ts
572
587
  /**
@@ -591,11 +606,11 @@ interface MockRepository<T> extends StandardRepo<T> {
591
606
  *
592
607
  * await mockRepo.getById('1'); // Returns mocked product
593
608
  */
594
- declare function createMockRepository<T extends AnyRecord = AnyRecord>(overrides?: Partial<MockRepository<T>>): MockRepository<T>;
609
+ export declare function createMockRepository<T extends object = AnyRecord>(overrides?: Partial<MockRepository<T>>): MockRepository<T>;
595
610
  /**
596
611
  * Create a mock user for authentication testing
597
612
  */
598
- declare function createMockUser(overrides?: Partial<AnyRecord>): {
613
+ export declare function createMockUser(overrides?: Partial<AnyRecord>): {
599
614
  _id: string;
600
615
  id: string;
601
616
  email: string;
@@ -605,11 +620,11 @@ declare function createMockUser(overrides?: Partial<AnyRecord>): {
605
620
  /**
606
621
  * Create a mock Fastify request
607
622
  */
608
- declare function createMockRequest(overrides?: Partial<AnyRecord>): unknown;
623
+ export declare function createMockRequest(overrides?: Partial<AnyRecord>): unknown;
609
624
  /**
610
625
  * Create a mock Fastify reply
611
626
  */
612
- declare function createMockReply(): unknown;
627
+ export declare function createMockReply(): unknown;
613
628
  /**
614
629
  * Create a mock controller for testing.
615
630
  *
@@ -625,7 +640,7 @@ declare function createMockReply(): unknown;
625
640
  * arguments) while naming only `vitest`, which arc does declare. Same shape
626
641
  * `MockRepository` above uses.
627
642
  */
628
- declare function createMockController(repository: StandardRepo<AnyRecord>): {
643
+ export declare function createMockController(repository: StandardRepo<AnyRecord>): {
629
644
  repository: StandardRepo<AnyRecord>;
630
645
  list: Mock;
631
646
  get: Mock;
@@ -646,7 +661,7 @@ declare function createMockController(repository: StandardRepo<AnyRecord>): {
646
661
  * const product = productFactory.build();
647
662
  * const products = productFactory.buildMany(10);
648
663
  */
649
- declare function createDataFactory<T extends AnyRecord>(template: Record<keyof T, (index: number) => unknown>): {
664
+ export declare function createDataFactory<T extends AnyRecord>(template: Record<keyof T, (index: number) => unknown>): {
650
665
  build(overrides?: Partial<T>): T;
651
666
  buildMany(count: number, overrides?: Partial<T>): T[];
652
667
  reset(): void;
@@ -656,7 +671,7 @@ declare function createDataFactory<T extends AnyRecord>(template: Record<keyof T
656
671
  *
657
672
  * Useful for testing side effects without full mocking
658
673
  */
659
- declare function createSpy<T extends (...args: unknown[]) => unknown>(_name?: string): Mock<T> & {
674
+ export declare function createSpy<T extends (...args: unknown[]) => unknown>(_name?: string): Mock<T> & {
660
675
  getCalls(): unknown[][];
661
676
  getLastCall(): unknown[];
662
677
  };
@@ -677,7 +692,7 @@ declare function createSpy<T extends (...args: unknown[]) => unknown>(_name?: st
677
692
  * @example
678
693
  * await waitFor(() => runs >= 3, { label: "3 scheduler ticks" });
679
694
  */
680
- declare function waitFor(condition: () => boolean | Promise<boolean>, options?: {
695
+ export declare function waitFor(condition: () => boolean | Promise<boolean>, options?: {
681
696
  timeout?: number;
682
697
  interval?: number;
683
698
  label?: string;
@@ -685,7 +700,7 @@ declare function waitFor(condition: () => boolean | Promise<boolean>, options?:
685
700
  /**
686
701
  * Create a test timer that can be controlled
687
702
  */
688
- declare function createTestTimer(): {
703
+ export declare function createTestTimer(): {
689
704
  now: () => number;
690
705
  advance: (ms: number) => void;
691
706
  set: (timestamp: number) => void;
@@ -695,7 +710,7 @@ declare function createTestTimer(): {
695
710
  //#region src/testing/moduleSetup.d.ts
696
711
  interface TestModuleSetup {
697
712
  /** Pass this as the second argument to `bootstrap` / `plugins` / `afterResources`. */
698
- readonly context: ModuleSetupContext;
713
+ readonly context: ModuleSetupContext<PortName, PortName>;
699
714
  /**
700
715
  * Disposers the module registered, in REGISTRATION order (`dispose()` runs
701
716
  * them backwards). Assert on `.length` to prove a phase registered teardown
@@ -712,7 +727,10 @@ interface TestModuleSetup {
712
727
  */
713
728
  dispose(): Promise<void>;
714
729
  }
715
- declare function createTestModuleSetup(): TestModuleSetup;
730
+ export declare function createTestModuleSetup(options?: {
731
+ /** The `context.ports` the phases see — supply what the module declares. */
732
+ readonly ports?: ArcPorts;
733
+ }): TestModuleSetup;
716
734
  //#endregion
717
735
  //#region src/testing/scopeRoleGate.d.ts
718
736
  /**
@@ -737,7 +755,7 @@ declare function createTestModuleSetup(): TestModuleSetup;
737
755
  * filters by tenant, so a gate that waves a tenant-less request through is how a
738
756
  * green test reads another org's rows.
739
757
  */
740
- declare function scopeRoleGate(...allowed: string[]): PermissionCheck;
758
+ export declare function scopeRoleGate(...allowed: string[]): PermissionCheck;
741
759
  //#endregion
742
760
  //#region src/testing/testApp.d.ts
743
761
  type DbMode = "in-memory" | {
@@ -808,12 +826,12 @@ interface TestAppContext {
808
826
  */
809
827
  close(): Promise<void>;
810
828
  }
811
- declare function createTestApp(options?: CreateTestAppOptions): Promise<TestAppContext>;
829
+ export declare function createTestApp(options?: CreateTestAppOptions): Promise<TestAppContext>;
812
830
  /**
813
831
  * Minimal Fastify instance — no arc plugins, no auth, no db. Use when a test
814
832
  * needs bare Fastify (e.g. plugin unit tests that manually register their
815
833
  * dependencies).
816
834
  */
817
- declare function createMinimalTestApp(options?: FastifyServerOptions): FastifyInstance;
835
+ export declare function createMinimalTestApp(options?: FastifyServerOptions): FastifyInstance;
818
836
  //#endregion
819
- 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 TestModuleSetup, type TestkitContext, bootModuleApp, createBetterAuthProvider, createBetterAuthTestHelpers, createCustomAuthProvider, createDataFactory, createHttpTestHarness, createJwtAuthProvider, createMinimalTestApp, createMockController, createMockReply, createMockRepository, createMockRequest, createMockUser, createSpy, createTestApp, createTestFixtures, createTestModuleSetup, createTestTimer, expectArc, mongoMemoryDatabase, preloadResources, preloadResourcesAsync, runAuthorizationConformance, runStorageContract, safeParseBody, scopeFromTestActor, scopeRoleGate, setupBetterAuthTestApp, testActorAuth, testActorHeaders, waitFor };
837
+ 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, type HttpTestHarnessOptions, type MockRepository, type ModuleBootsAloneOptions, type ModuleBootsAloneResult, type ModuleTestApp, type OrgResponse, type RoleConfig, type SetupBetterAuthTestAppInput, type SetupBetterAuthTestAppResult, type SignInInput, type SignUpInput, type StorageContractSetup, type StorageContractSetupResult, type SurfaceObservation, type TestActor, type TestAppContext, type TestAuthProvider, type TestAuthSession, type TestDatabase, type TestDatabaseFactory, type TestFixtures, type TestModuleSetup, type TestkitContext, runStorageContract };