@classytic/arc 2.41.1 → 2.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. package/dist/{EventTransport-CbUKDzZZ.d.mts → EventTransport-CiicKz2Z.d.mts} +1 -1
  2. package/dist/{EventTransport-DSqD_Xsg.mjs → EventTransport-tzA7CAB4.mjs} +22 -17
  3. package/dist/{HookSystem-CMF94SEA.mjs → HookSystem-B6UaKRbF.mjs} +2 -2
  4. package/dist/{QueryCache-DFA-QrU9.d.mts → QueryCache--5uAuYPW.d.mts} +7 -3
  5. package/dist/{ResourceRegistry-MGpXoxHZ.mjs → ResourceRegistry-CuCARu2B.mjs} +44 -13
  6. package/dist/actionPermissions-BotX1YOa.mjs +776 -0
  7. package/dist/audit/index.d.mts +43 -5
  8. package/dist/audit/index.mjs +48 -26
  9. package/dist/auth/audit.mjs +1 -1
  10. package/dist/auth/index.d.mts +43 -13
  11. package/dist/auth/index.mjs +130 -155
  12. package/dist/auth/redis-session.mjs +1 -1
  13. package/dist/{authorizationDecision-DawKGoXb.mjs → authorizationDecision-DQYrkl5f.mjs} +7 -102
  14. package/dist/{base-CxrV1LmG.d.mts → base-CZyixEQR.d.mts} +27 -5
  15. package/dist/boundedMap-BULzfXYU.mjs +57 -0
  16. package/dist/{buildHandler-CvxKOc0m.mjs → buildHandler-CRQ8EcX5.mjs} +4 -4
  17. package/dist/cache/index.d.mts +22 -34
  18. package/dist/cache/index.mjs +4 -4
  19. package/dist/{caching-DbCBxlgw.mjs → caching-Cc2M1DwO.mjs} +3 -3
  20. package/dist/claimed-B10RTfkM.mjs +8 -0
  21. package/dist/cleanup/index.d.mts +6 -10
  22. package/dist/cleanup/index.mjs +27 -73
  23. package/dist/cli/commands/describe.d.mts +4 -2
  24. package/dist/cli/commands/describe.mjs +7 -4
  25. package/dist/cli/commands/docs.mjs +3 -3
  26. package/dist/cli/commands/doctor.mjs +1 -1
  27. package/dist/cli/commands/generate.mjs +2 -2
  28. package/dist/cli/commands/init.mjs +2 -2
  29. package/dist/cli/commands/introspect.mjs +2 -2
  30. package/dist/cli/index.mjs +3 -3
  31. package/dist/{constants-D5Ubn1fe.mjs → constants-Cu7Mx7_U.mjs} +4 -2
  32. package/dist/context/index.d.mts +2 -5
  33. package/dist/context/index.mjs +18 -38
  34. package/dist/core/index.d.mts +3 -3
  35. package/dist/core/index.mjs +8 -8
  36. package/dist/{core-5lazhva9.mjs → core-Cb0LjccA.mjs} +5 -4
  37. package/dist/{createActionRouter-DNqoaK81.mjs → createActionRouter-xjqonMRO.mjs} +87 -39
  38. package/dist/{createAggregationRouter-BcbQJf10.mjs → createAggregationRouter-zRYWw_5D.mjs} +11 -8
  39. package/dist/{preloadResources-f3boenVZ.mjs → createApp-D-953ZAq.mjs} +299 -390
  40. package/dist/{createMcpServer-CbDWkZ1T.d.mts → createMcpServer-C9cxS8zt.d.mts} +1 -1
  41. package/dist/{defineAggregation-D_eJjm5A.mjs → defineAggregation-Bm8RjMbq.mjs} +1 -1
  42. package/dist/{defineResource-DxkMTjRn.mjs → defineResource-DIC7JZGU.mjs} +118 -1024
  43. package/dist/discovery/index.mjs +1 -1
  44. package/dist/docs/index.d.mts +10 -4
  45. package/dist/docs/index.mjs +4 -4
  46. package/dist/{elevation-BXCfVcNG.d.mts → elevation-BW2J3tNj.d.mts} +1 -2
  47. package/dist/{elevation-CkvG0LG2.mjs → elevation-DG8SrLN-.mjs} +41 -12
  48. package/dist/encryption/index.mjs +3 -3
  49. package/dist/{errorHandler-D1GHKGlV.mjs → errorHandler-BnfDviL1.mjs} +26 -5
  50. package/dist/{errors-BH7YU_9O.mjs → errors-CtrywMHP.mjs} +58 -23
  51. package/dist/{errors-BGdVwP25.d.mts → errors-JYc9vwqE.d.mts} +9 -0
  52. package/dist/{eventPlugin-B52abJ8W.d.mts → eventPlugin-BtmA4-3P.d.mts} +65 -9
  53. package/dist/{eventPlugin-zZY-unhr.mjs → eventPlugin-Q6BhzHzs.mjs} +82 -21
  54. package/dist/{subscribe-helpers-DatDkcuG.mjs → eventTypes-Cdhm6ZlV.mjs} +151 -17
  55. package/dist/events/index.d.mts +33 -8
  56. package/dist/events/index.mjs +49 -53
  57. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  58. package/dist/events/transports/redis-stream-entry.mjs +139 -157
  59. package/dist/events/transports/redis.d.mts +1 -1
  60. package/dist/events/transports/redis.mjs +2 -2
  61. package/dist/factory/index.d.mts +32 -17
  62. package/dist/factory/index.mjs +213 -32
  63. package/dist/{fastify-augmentation-Cq2nHVaW.d.mts → fastify-augmentation-DhUJ-mvo.d.mts} +11 -25
  64. package/dist/{fields-I_EeRWND.d.mts → fields-BBSpf8pS.d.mts} +1 -1
  65. package/dist/{fields-BHrkoF5y.mjs → fields-ToPYpMqS.mjs} +1 -1
  66. package/dist/filter-merge-IpGywvym.mjs +99 -0
  67. package/dist/{generate-BLRf2m3y.mjs → generate-DRTkLlIl.mjs} +2 -2
  68. package/dist/{headers-BIXWKrzQ.mjs → headers-BbkIF6vA.mjs} +2 -2
  69. package/dist/health-D-Ft6JM6.mjs +22 -0
  70. package/dist/{health-ZRHeDHXH.mjs → health-DqbsG-_w.mjs} +115 -55
  71. package/dist/hooks/index.d.mts +2 -2
  72. package/dist/hooks/index.mjs +2 -2
  73. package/dist/idempotency/index.d.mts +31 -7
  74. package/dist/idempotency/index.mjs +155 -98
  75. package/dist/idempotency/redis.d.mts +1 -1
  76. package/dist/idempotency/redis.mjs +48 -11
  77. package/dist/{index-BHdZD8zK.d.mts → index-Bxriq3so.d.mts} +84 -21
  78. package/dist/{preloadResources-CjS2OfpU.d.mts → index-C8zVGYsk.d.mts} +37 -38
  79. package/dist/{index-D4u76eQW.d.mts → index-CRoPtISf.d.mts} +23 -73
  80. package/dist/{index-CbJiYrfv.d.mts → index-Chgz3d0i.d.mts} +1 -1
  81. package/dist/index-JdbZAIsm.d.mts +510 -0
  82. package/dist/{index-DHbyPo5j.d.mts → index-mqaqZNpe.d.mts} +253 -254
  83. package/dist/index.d.mts +8 -8
  84. package/dist/index.mjs +11 -11
  85. package/dist/{init-CpLkjU18.mjs → init-B_oUYDXI.mjs} +1 -1
  86. package/dist/integrations/event-gateway.d.mts +8 -3
  87. package/dist/integrations/event-gateway.mjs +4 -4
  88. package/dist/integrations/index.d.mts +3 -3
  89. package/dist/integrations/index.mjs +1 -1
  90. package/dist/integrations/jobs/index.d.mts +1 -1
  91. package/dist/integrations/jobs/index.mjs +18 -5
  92. package/dist/integrations/mcp/index.d.mts +72 -59
  93. package/dist/integrations/mcp/index.mjs +19 -4
  94. package/dist/integrations/mcp/testing.d.mts +2 -2
  95. package/dist/integrations/mcp/testing.mjs +2 -2
  96. package/dist/integrations/streamline.d.mts +78 -136
  97. package/dist/integrations/streamline.mjs +116 -54
  98. package/dist/integrations/webhooks.d.mts +60 -120
  99. package/dist/integrations/webhooks.mjs +36 -80
  100. package/dist/integrations/websocket-pushref-redis.d.mts +1 -1
  101. package/dist/integrations/websocket-pushref-redis.mjs +1 -1
  102. package/dist/integrations/websocket-redis.d.mts +1 -1
  103. package/dist/integrations/websocket-redis.mjs +1 -1
  104. package/dist/integrations/websocket.d.mts +3 -3
  105. package/dist/integrations/websocket.mjs +2 -2
  106. package/dist/{interface-DEWNOMza.d.mts → interface-C0395yUN.d.mts} +13 -1
  107. package/dist/{jsonBody-ELR9lfeU.mjs → jsonBody-B4YVGcql.mjs} +2 -2
  108. package/dist/{keys-cpZCtcIE.mjs → keys-B2KtgMLJ.mjs} +7 -18
  109. package/dist/{loadResources-BPfWiI5s.mjs → loadResources-Dn4lalw2.mjs} +3 -3
  110. package/dist/{loadResourcesFromEntry-ixtfL3J2.mjs → loadResourcesFromEntry-3sLYbuse.mjs} +2 -2
  111. package/dist/logger/index.d.mts +1 -8
  112. package/dist/logger/index.mjs +3 -153
  113. package/dist/logger-DXjfIqjV.mjs +160 -0
  114. package/dist/{mcpPlugin-BX5PujI0.mjs → mcpPlugin-C08HalN5.mjs} +433 -170
  115. package/dist/{memory-Iotz0cCx.mjs → memory-9Cp7611C.mjs} +36 -34
  116. package/dist/{metrics-NMsmpRmY.mjs → metrics-CWI11eRu.mjs} +39 -72
  117. package/dist/middleware/index.d.mts +2 -2
  118. package/dist/middleware/index.mjs +3 -3
  119. package/dist/migrations/index.mjs +2 -2
  120. package/dist/{module-DpLJG2_N.mjs → module-BSvOQC7E.mjs} +8 -8
  121. package/dist/multiTenant-cY0FkDiA.d.mts +104 -0
  122. package/dist/{multipartBody-DtRWM6_U.mjs → multipartBody-CXM2a-Dy.mjs} +46 -7
  123. package/dist/{openapi-CmFf3yq_.mjs → openapi-DT_G4VhY.mjs} +48 -10
  124. package/dist/outbox-admin/index.d.mts +3 -3
  125. package/dist/outbox-admin/index.mjs +6 -18
  126. package/dist/{outbox-module-D2z5WkDY.mjs → outbox-module-Bjgzl6tg.mjs} +203 -33
  127. package/dist/{outbox-module-BHdUnuuK.d.mts → outbox-module-gZCHoE4H.d.mts} +79 -6
  128. package/dist/permissions/index.d.mts +5 -4
  129. package/dist/permissions/index.mjs +8 -6
  130. package/dist/{permissions-D8TBH44E.mjs → permissions-Cm0uYHvd.mjs} +149 -33
  131. package/dist/{pipe-FMWNheSO.mjs → pipe-BqeGT6UO.mjs} +2 -2
  132. package/dist/pipeline/index.d.mts +2 -2
  133. package/dist/pipeline/index.mjs +2 -2
  134. package/dist/plan-FVR6LP59.mjs +565 -0
  135. package/dist/{BaseController-CYEwjyjN.mjs → plugin-BccET1tL.mjs} +1256 -345
  136. package/dist/plugins/index.d.mts +14 -11
  137. package/dist/plugins/index.mjs +44 -22
  138. package/dist/plugins/response-cache.mjs +8 -14
  139. package/dist/plugins/tracing-entry.mjs +2 -2
  140. package/dist/{pluralize-CXWZIzTv.mjs → pluralize-CVIOcgMF.mjs} +1 -1
  141. package/dist/presets/filesUpload.d.mts +2 -2
  142. package/dist/presets/filesUpload.mjs +5 -5
  143. package/dist/presets/index.d.mts +26 -31
  144. package/dist/presets/index.mjs +4 -4
  145. package/dist/presets/multiTenant.d.mts +2 -107
  146. package/dist/presets/multiTenant.mjs +22 -162
  147. package/dist/presets/search.d.mts +2 -2
  148. package/dist/presets/search.mjs +2 -2
  149. package/dist/{presets-ZJSPgmT2.mjs → presets-Cpvj6fGO.mjs} +99 -107
  150. package/dist/{projection-BzIgzoKZ.mjs → projection-Ce4aQhQk.mjs} +2 -2
  151. package/dist/{pushref-registry-Dov9l4qE.d.mts → pushref-registry-UxCkoA4C.d.mts} +1 -1
  152. package/dist/{queryCachePlugin-BzqxconG.d.mts → queryCachePlugin-C2lZjTxk.d.mts} +1 -1
  153. package/dist/{queryCachePlugin-DZHPOm9p.mjs → queryCachePlugin-CFWNH8aT.mjs} +12 -14
  154. package/dist/{rateLimitKey-BvOvcBDi.mjs → rateLimitKey-C4O-kPm0.mjs} +1 -1
  155. package/dist/{realtime-8tIQWZz4.mjs → realtime-DmPE9S54.mjs} +25 -21
  156. package/dist/redis-stream-BMk-bpQS.d.mts +219 -0
  157. package/dist/{redis-Bzi1y3F9.d.mts → redis-vLvtcGy_.d.mts} +13 -24
  158. package/dist/redisShapes-CQksY67q.d.mts +55 -0
  159. package/dist/registry/index.d.mts +9 -4
  160. package/dist/registry/index.mjs +4 -4
  161. package/dist/{registry-DNkgGQcK.mjs → registry-Bcz9G1bh.mjs} +10 -8
  162. package/dist/{renewingLease-yF8BdW4b.mjs → renewingLease-qODa7KJQ.mjs} +1 -1
  163. package/dist/{replyHelpers-CNdvMfM4.mjs → replyHelpers-CG_VtVgS.mjs} +2 -2
  164. package/dist/{requestContext-cDkAUr-P.mjs → requestContext-Dsu9P1bV.mjs} +1 -1
  165. package/dist/requirement-CbiLdQ1n.d.mts +22 -0
  166. package/dist/requirement-KDdoRcOP.mjs +35 -0
  167. package/dist/resourceRateLimit-Wf6d6FL9.d.mts +30 -0
  168. package/dist/resourceRateLimit-dSjVr1pk.mjs +180 -0
  169. package/dist/{rolldown-runtime-eysyzFAF.mjs → rolldown-runtime-D1w9Y1VJ.mjs} +1 -1
  170. package/dist/routeValidator-D36SW8qt.mjs +70 -0
  171. package/dist/{runtimeCapabilities-CkhS6jn6.mjs → runtimeCapabilities-0tccjRlj.mjs} +1 -1
  172. package/dist/{schedules-j6uXXAeJ.mjs → schedules-C-OpmHBq.mjs} +46 -37
  173. package/dist/{schemaConverter-BVA7cFRG.mjs → schemaConverter-BORek3O-.mjs} +2 -2
  174. package/dist/{schemaIR-CTvPDoPB.mjs → schemaIR-C7Vbp71I.mjs} +2 -2
  175. package/dist/schemas/index.d.mts +10 -0
  176. package/dist/schemas/index.mjs +8 -3
  177. package/dist/scim/index.mjs +2 -2
  178. package/dist/scope/index.d.mts +2 -2
  179. package/dist/scope/index.mjs +6 -6
  180. package/dist/{scope-BUi1xV1I.mjs → scope-DQthe88b.mjs} +4 -4
  181. package/dist/shutdown-MqA81z_P.mjs +59 -0
  182. package/dist/{simpleEqualityMatcher-C9bzq2gO.mjs → simpleEqualityMatcher-auW8QjXN.mjs} +1 -1
  183. package/dist/{sse-BeqVKQKu.mjs → sse-CYzQBVFe.mjs} +11 -15
  184. package/dist/{sseStream-Ppzo-WUH.mjs → sseStream-B5_Afiqn.mjs} +2 -2
  185. package/dist/{store-helpers-dW71XVWL.mjs → store-helpers-BOzk-CuX.mjs} +1 -1
  186. package/dist/{streaming-IcRFjWQU.mjs → streaming-DjTQhZrN.mjs} +1 -1
  187. package/dist/subscriberIdentity-CW39uA8G.mjs +28 -0
  188. package/dist/tenancy--ed9eH_z.mjs +43 -0
  189. package/dist/tenantPreparation-BKon6Yox.mjs +67 -0
  190. package/dist/testing/cleanupStoreContract.mjs +1 -1
  191. package/dist/testing/index.d.mts +193 -175
  192. package/dist/testing/index.mjs +286 -212
  193. package/dist/testing/outboxStoreContract.mjs +137 -2
  194. package/dist/testing/requiredPorts.d.mts +17 -0
  195. package/dist/testing/requiredPorts.mjs +65 -0
  196. package/dist/testing/storageContract.mjs +1 -1
  197. package/dist/timing-qczZ0YC-.mjs +46 -0
  198. package/dist/{transactionContext-CPbdlnVw.mjs → transactionContext-DjFkrNG6.mjs} +1 -1
  199. package/dist/{typeGuards-BLjPgVBm.mjs → typeGuards-CySF12G-.mjs} +1 -1
  200. package/dist/types/index.d.mts +4 -4
  201. package/dist/types/index.mjs +1 -1
  202. package/dist/types/storage.mjs +1 -1
  203. package/dist/{types-CWQn9-IC.d.mts → types-B4Aq4Sdj.d.mts} +22 -9
  204. package/dist/{types-DfVDvkdP.d.mts → types-BJ-2XqVF.d.mts} +189 -204
  205. package/dist/{types-CgenB1gv.mjs → types-Bk9NOgOC.mjs} +4 -4
  206. package/dist/usage/index.d.mts +2 -3
  207. package/dist/usage/index.mjs +5 -5
  208. package/dist/{userHelpers-ChRvkuSZ.mjs → userHelpers-aklawRaK.mjs} +1 -1
  209. package/dist/utils/index.d.mts +84 -223
  210. package/dist/utils/index.mjs +13 -12
  211. package/dist/{utils-CxcctrAh.mjs → utils-ec1oTo1n.mjs} +315 -404
  212. package/dist/{validate-DrYWnOzI.mjs → validate-9yzHC1e2.mjs} +6 -14
  213. package/dist/{versioning-D6JIK8Tk.d.mts → versioning-Bsb51gGT.d.mts} +28 -13
  214. package/dist/{versioning-DKkT4hNJ.mjs → versioning-fhhWHV74.mjs} +4 -4
  215. package/dist/{websocket-BOXVggMf.d.mts → websocket-Cs4awVyD.d.mts} +1 -1
  216. package/dist/{workScope-CxKqoIFn.mjs → workScope-zpPyge4t.mjs} +2 -2
  217. package/package.json +16 -12
  218. package/skills/arc/SKILL.md +13 -4
  219. package/skills/arc/references/auth.md +8 -5
  220. package/skills/arc/references/integrations.md +1 -1
  221. package/skills/arc/references/mcp.md +8 -6
  222. package/skills/arc/references/multi-tenancy.md +19 -14
  223. package/skills/arc/references/production.md +27 -10
  224. package/dist/actionPermissions-BoPGQ5-4.mjs +0 -350
  225. package/dist/index-CFfLKMH4.d.mts +0 -290
  226. package/dist/interface-YzIbF7Ii.mjs +0 -17
  227. package/dist/redis-stream-BPKscsTB.d.mts +0 -260
  228. package/dist/registerRoute-Bsnk6NiZ.mjs +0 -364
  229. package/dist/sync/changelog.d.mts +0 -3
  230. package/dist/sync/changelog.mjs +0 -3
@@ -1,350 +0,0 @@
1
- /*! @classytic/arc v2.41.1 | MIT | https://classytic.com */
2
- import { n as getUserRoles } from "./userHelpers-ChRvkuSZ.mjs";
3
- import { b as isElevated, n as PUBLIC_SCOPE, x as isMember } from "./types-CgenB1gv.mjs";
4
- import { a as resolveEffectiveRoles, t as applyFieldReadPermissions } from "./fields-BHrkoF5y.mjs";
5
- import { t as buildRequestScopeProjection } from "./projection-BzIgzoKZ.mjs";
6
- import { t as executePipeline } from "./pipe-FMWNheSO.mjs";
7
- import { isPaginatedResult, toCanonicalList } from "@classytic/repo-core/pagination";
8
- //#region src/core/fastifyAdapter.ts
9
- /** Type guard for Mongoose-like documents with toObject() */
10
- function isMongooseDoc(obj) {
11
- return !!obj && typeof obj === "object" && "toObject" in obj && typeof obj.toObject === "function";
12
- }
13
- /**
14
- * Apply field mask to a single object
15
- * Filters fields based on include/exclude rules
16
- */
17
- function applyFieldMaskToObject(obj, fieldMask) {
18
- if (!obj || typeof obj !== "object") return obj;
19
- const plain = isMongooseDoc(obj) ? obj.toObject() : obj;
20
- const { include, exclude } = fieldMask;
21
- if (include && include.length > 0) {
22
- const filtered = {};
23
- for (const field of include) if (field in plain) filtered[field] = plain[field];
24
- return filtered;
25
- }
26
- if (exclude && exclude.length > 0) {
27
- const filtered = { ...plain };
28
- for (const field of exclude) delete filtered[field];
29
- return filtered;
30
- }
31
- return plain;
32
- }
33
- /**
34
- * Apply field mask to response data (handles both objects and arrays)
35
- */
36
- function applyFieldMask(data, fieldMask) {
37
- if (!fieldMask) return data;
38
- if (Array.isArray(data)) return data.map((item) => applyFieldMaskToObject(item, fieldMask));
39
- if (data && typeof data === "object") return applyFieldMaskToObject(data, fieldMask);
40
- return data;
41
- }
42
- /**
43
- * Project `FastifyRequest` into the curated `IRequestContext` shape that
44
- * arc's controllers receive. This is a developer-facing facade, not a
45
- * portability boundary — arc is Fastify-only. The projection lifts the
46
- * fields tenant-scoped controllers reach for (`organizationId`,
47
- * `teamId`, `scope`, `context`, server accessor) onto a flat, typed
48
- * surface so handler code doesn't have to dig through Fastify's
49
- * decorator surface or `req.metadata._scope` internals.
50
- */
51
- function createRequestContext(req) {
52
- const reqWithExtras = req;
53
- const requestContext = reqWithExtras.context ?? {};
54
- const srv = req.server;
55
- const serverAccessor = {
56
- events: srv && "events" in srv ? srv.events : void 0,
57
- audit: srv && "audit" in srv ? srv.audit : void 0,
58
- queryCache: srv && "queryCache" in srv ? srv.queryCache : void 0,
59
- log: req.log
60
- };
61
- const rawScope = reqWithExtras.scope;
62
- const scopeProjection = buildRequestScopeProjection(rawScope);
63
- return {
64
- query: reqWithExtras.query ?? {},
65
- body: reqWithExtras.body ?? {},
66
- params: reqWithExtras.params ?? {},
67
- headers: reqWithExtras.headers,
68
- user: reqWithExtras.user ? (() => {
69
- const user = reqWithExtras.user;
70
- const rawId = user._id ?? user.id;
71
- const normalizedId = rawId ? String(rawId) : void 0;
72
- return {
73
- ...user,
74
- id: normalizedId,
75
- _id: normalizedId
76
- };
77
- })() : null,
78
- context: requestContext,
79
- scope: scopeProjection,
80
- metadata: {
81
- ...reqWithExtras.context,
82
- arc: reqWithExtras.arc,
83
- _scope: rawScope,
84
- _ownershipCheck: reqWithExtras._ownershipCheck,
85
- _crossTenantRead: reqWithExtras._crossTenantRead,
86
- _policyFilters: reqWithExtras._policyFilters ?? {},
87
- log: reqWithExtras.log
88
- },
89
- server: serverAccessor
90
- };
91
- }
92
- /**
93
- * Get typed auth context from an IRequestContext.
94
- * Use this in controller overrides to access request context.
95
- *
96
- * For org scope, use `getControllerScope(req)` instead.
97
- */
98
- function getControllerContext(req) {
99
- return req.context ?? req.metadata ?? {};
100
- }
101
- /**
102
- * Get request scope from an IRequestContext.
103
- * Returns the RequestScope set by auth adapters.
104
- */
105
- function getControllerScope(req) {
106
- return req.metadata?._scope ?? PUBLIC_SCOPE;
107
- }
108
- /**
109
- * Compute per-field capability metadata for the current user.
110
- * Only includes fields that have restrictions — unrestricted fields
111
- * are omitted (frontend defaults to { readable: true, writable: true }).
112
- */
113
- function computeFieldCapabilities(fieldPerms, effectiveRoles) {
114
- const caps = {};
115
- for (const [field, perm] of Object.entries(fieldPerms)) {
116
- let readable = true;
117
- let writable = true;
118
- switch (perm._type) {
119
- case "hidden":
120
- readable = false;
121
- writable = false;
122
- break;
123
- case "visibleTo":
124
- readable = perm.roles?.some((r) => effectiveRoles.includes(r)) ?? false;
125
- break;
126
- case "writableBy": writable = perm.roles?.some((r) => effectiveRoles.includes(r)) ?? false;
127
- }
128
- caps[field] = {
129
- readable,
130
- writable
131
- };
132
- }
133
- return caps;
134
- }
135
- /**
136
- * Send a controller's `IControllerResponse` through Fastify's reply.
137
- *
138
- * The `IControllerResponse<T>` envelope is arc's internal pipeline
139
- * contract — it's how custom `status`, `meta`, `headers`, and field
140
- * permissions thread from a handler through interceptors to the wire
141
- * without each step having to touch `reply` directly. Not a portability
142
- * abstraction (arc is Fastify-only); a pipeline-internal one.
143
- *
144
- * **Auto-envelope of bare returns.** Custom route handlers are
145
- * expected to return the envelope shape so this function can apply
146
- * field permissions, attach `fieldCaps`, and flatten paginated lists.
147
- * A handler that returns raw `T` (array, plain object, primitive) used
148
- * to silently produce a broken response — `response.data` was
149
- * `undefined`, the body sent was `undefined`, and any declared
150
- * `fields:` permission map was bypassed (the leak shape mentora
151
- * flagged). 2.17 detects bare returns and wraps them into
152
- * `{ data: response, status: 200 }` before the field-permission
153
- * pipeline runs, so `fields:` applies to ALL custom routes whether the
154
- * handler envelopes its return value or not. The envelope shape is
155
- * still the canonical contract — auto-wrapping is a safety net, not
156
- * an invitation to drop the envelope.
157
- */
158
- function sendControllerResponse(reply, response, request) {
159
- if (response === null || typeof response !== "object" || !Object.hasOwn(response, "data")) response = {
160
- data: response,
161
- status: 200
162
- };
163
- const reqWithExtras = request;
164
- const fieldMaskConfig = reqWithExtras?.fieldMask;
165
- const arcMeta = reqWithExtras?.arc;
166
- const scope = reqWithExtras?.scope ?? PUBLIC_SCOPE;
167
- const fieldPerms = isElevated(scope) ? void 0 : arcMeta?.fields;
168
- const effectiveRoles = fieldPerms ? resolveEffectiveRoles(getUserRoles(reqWithExtras?.user), isMember(scope) ? scope.orgRoles : []) : [];
169
- const fieldCaps = fieldPerms ? computeFieldCapabilities(fieldPerms, effectiveRoles) : void 0;
170
- const hasFieldRestrictions = !!(fieldMaskConfig || fieldPerms);
171
- /** Apply both field mask and field-level permissions to a data item */
172
- const applyPermissions = (data) => {
173
- let result = fieldMaskConfig ? applyFieldMask(data, fieldMaskConfig) : data;
174
- if (fieldPerms && result && typeof result === "object") {
175
- if (Array.isArray(result)) result = result.map((item) => applyFieldReadPermissions(item, fieldPerms, effectiveRoles));
176
- else result = applyFieldReadPermissions(result, fieldPerms, effectiveRoles);
177
- }
178
- return result;
179
- };
180
- if (response.headers) for (const [key, value] of Object.entries(response.headers)) reply.header(key, value);
181
- if (response.data && typeof response.data === "object" && Array.isArray(response.data.data)) {
182
- const payload = response.data;
183
- const filteredRows = hasFieldRestrictions ? applyPermissions(payload.data) : payload.data;
184
- let canonical;
185
- if (isPaginatedResult(payload)) canonical = toCanonicalList({
186
- ...payload,
187
- data: filteredRows
188
- });
189
- else if (typeof payload.page === "number" && typeof payload.limit === "number" && typeof payload.total === "number") canonical = toCanonicalList({
190
- method: "offset",
191
- data: filteredRows,
192
- page: payload.page,
193
- limit: payload.limit,
194
- total: payload.total,
195
- pages: payload.pages ?? Math.ceil(payload.total / Math.max(1, payload.limit)),
196
- hasNext: payload.hasNext ?? false,
197
- hasPrev: payload.hasPrev ?? false
198
- });
199
- else canonical = toCanonicalList(filteredRows);
200
- reply.code(response.status ?? 200).send({
201
- ...canonical,
202
- ...response.meta ?? {},
203
- ...fieldCaps ? { fieldPermissions: fieldCaps } : {}
204
- });
205
- return;
206
- }
207
- const rawData = hasFieldRestrictions ? applyPermissions(response.data) : response.data;
208
- const filteredData = rawData !== null && typeof rawData === "object" && typeof rawData.toJSON === "function" ? rawData.toJSON() : rawData;
209
- const status = response.status ?? 200;
210
- if (filteredData !== null && typeof filteredData === "object" && !Array.isArray(filteredData) && (response.meta || fieldCaps)) {
211
- reply.code(status).send({
212
- ...filteredData,
213
- ...response.meta ?? {},
214
- ...fieldCaps ? { fieldPermissions: fieldCaps } : {}
215
- });
216
- return;
217
- }
218
- reply.code(status).send(filteredData);
219
- }
220
- /**
221
- * Bridge an `IController` method (`(ctx: IRequestContext) => Promise<IControllerResponse<T>>`)
222
- * into a Fastify route handler. Translates between arc's curated request
223
- * context surface and Fastify's request/reply, and routes the envelope
224
- * through `sendControllerResponse` so the pipeline applies field
225
- * permissions, status, and meta uniformly. Internal plumbing, not a
226
- * portability layer — arc is Fastify-only.
227
- *
228
- * @example
229
- * ```typescript
230
- * const controller = new BaseController(repository);
231
- * const listHandler = createFastifyHandler(controller.list.bind(controller));
232
- * fastify.get('/products', listHandler);
233
- * ```
234
- */
235
- function createFastifyHandler(controllerMethod) {
236
- return async (req, reply) => {
237
- sendControllerResponse(reply, await controllerMethod(createRequestContext(req)), req);
238
- return reply;
239
- };
240
- }
241
- /**
242
- * Create Fastify adapters for all CRUD methods of an IController
243
- *
244
- * Returns Fastify-compatible handlers for each CRUD operation
245
- *
246
- * @example
247
- * ```typescript
248
- * const controller = new BaseController(repository);
249
- * const handlers = createCrudHandlers(controller);
250
- *
251
- * fastify.get('/', handlers.list);
252
- * fastify.get('/:id', handlers.get);
253
- * fastify.post('/', handlers.create);
254
- * fastify.patch('/:id', handlers.update);
255
- * fastify.delete('/:id', handlers.delete);
256
- * ```
257
- */
258
- function createCrudHandlers(controller) {
259
- return {
260
- list: createFastifyHandler(controller.list.bind(controller)),
261
- get: createFastifyHandler(controller.get.bind(controller)),
262
- create: createFastifyHandler(controller.create.bind(controller)),
263
- update: createFastifyHandler(controller.update.bind(controller)),
264
- delete: createFastifyHandler(controller.delete.bind(controller))
265
- };
266
- }
267
- //#endregion
268
- //#region src/core/middlewares/pipeline.ts
269
- /**
270
- * Resolve pipeline steps for a specific operation.
271
- * Flat-array config applies to every op; map config applies per-op.
272
- */
273
- function resolvePipelineSteps(pipeline, operation) {
274
- if (!pipeline) return [];
275
- if (Array.isArray(pipeline)) return pipeline;
276
- return pipeline[operation] ?? [];
277
- }
278
- /**
279
- * Wrap a controller method (one that takes `IRequestContext` and returns
280
- * `IControllerResponse<T>`) with pipeline execution. Used by CRUD ops and
281
- * string-handler custom routes.
282
- */
283
- function buildPipelineHandler(controllerMethod, steps, operation, resourceName) {
284
- return async (req, reply) => {
285
- const pipeCtx = {
286
- ...createRequestContext(req),
287
- resource: resourceName,
288
- operation
289
- };
290
- sendControllerResponse(reply, await executePipeline(steps, pipeCtx, (ctx) => controllerMethod(ctx), operation), req);
291
- };
292
- }
293
- /**
294
- * Wrap an action handler (one that takes `(id, data, req)` and returns a raw
295
- * result) with pipeline execution. Returns a function that produces a full
296
- * `IControllerResponse<unknown>` — the action router feeds this directly into
297
- * `sendControllerResponse`, so field masking, custom status codes, `meta`,
298
- * `details`, and structured error codes from pipeline interceptors flow
299
- * through to the client unchanged.
300
- *
301
- * CRUD and actions now share the same parity invariant: a pipeline that
302
- * returns `{ success: false, status: 422, error, details, meta }` reaches the
303
- * client with all four fields intact. Previously the action path stringified
304
- * failures into a generic `Error` and dropped everything except `statusCode`.
305
- *
306
- * Handler throws still bubble out — the caller's try/catch handles `onError`
307
- * shaping and the generic `ACTION_FAILED` fallback.
308
- */
309
- function buildActionPipelineHandler(handler, steps, operation, resourceName) {
310
- if (steps.length === 0) return async (id, data, req) => ({
311
- status: 200,
312
- data: await handler(id, data, req)
313
- });
314
- return async (id, data, req) => {
315
- const pipeCtx = {
316
- ...createRequestContext(req),
317
- resource: resourceName,
318
- operation
319
- };
320
- return executePipeline(steps, pipeCtx, async (_ctx) => ({
321
- status: 200,
322
- data: await handler(id, data, req)
323
- }), operation);
324
- };
325
- }
326
- //#endregion
327
- //#region src/core/actionPermissions.ts
328
- /**
329
- * Return the effective `PermissionCheck` for a single action, or `undefined`
330
- * when the resource declares no gate at any level.
331
- *
332
- * Callers decide what "no gate" means:
333
- * - HTTP: boot-time throw in `normalizeActionsToRouterConfig`.
334
- * - MCP: tool-generation throw in `resourceToTools` (mirrors HTTP — the
335
- * two surfaces fail closed identically so MCP can't expose an
336
- * unauthenticated mutating tool when the HTTP plugin lifecycle hasn't
337
- * run).
338
- * - OpenAPI: docs advertise the endpoint as unauthenticated.
339
- */
340
- function resolveActionPermission(input) {
341
- const { action, resourcePermissions, resourceActionPermissions, globalAuth } = input;
342
- const explicit = typeof action !== "function" && action.permissions ? action.permissions : void 0;
343
- if (explicit) return explicit;
344
- if (resourceActionPermissions) return resourceActionPermissions;
345
- if (globalAuth) return globalAuth;
346
- const updateFallback = resourcePermissions?.update;
347
- if (updateFallback) return updateFallback;
348
- }
349
- //#endregion
350
- export { createCrudHandlers as a, getControllerContext as c, resolvePipelineSteps as i, getControllerScope as l, buildActionPipelineHandler as n, createFastifyHandler as o, buildPipelineHandler as r, createRequestContext as s, resolveActionPermission as t, sendControllerResponse as u };
@@ -1,290 +0,0 @@
1
-
2
- import { _ as HealthCheck, a as ModuleContribution, f as ScheduleDefinition, n as ArcModuleInput, r as ArcModuleRegistry, s as ModuleSetupContext, t as ArcModule } from "./types-DfVDvkdP.mjs";
3
- import { FastifyInstance } from "fastify";
4
- //#region src/factory/module/contributions.d.ts
5
- /**
6
- * Collect every module's `healthChecks` in the caller's order. Fails at boot
7
- * on a duplicate check `name` across modules, naming BOTH owning modules.
8
- * The host's app-level checks are appended AFTER this (modules-first,
9
- * host-last) by the caller.
10
- */
11
- declare function collectModuleHealthChecks(modules: readonly ArcModule[]): HealthCheck[];
12
- /**
13
- * Collect every module's `workflows`. Resolves factory contributions (so a
14
- * factory can close over a container the caller has already decorated on
15
- * `fastify`) and flattens to a single opaque array. Arc core deliberately
16
- * does NOT validate or interpret the values — the streamline integration
17
- * owns name/shape checks and registration. Called by the integration at init
18
- * time, not by arc's boot pipeline (workflows depend on the integration's
19
- * container).
20
- */
21
- declare function collectModuleWorkflows(fastify: FastifyInstance, modules: readonly ArcModule[]): Promise<unknown[]>;
22
- /**
23
- * Collect every module's `scheduledJobs`. Resolves factory contributions
24
- * (after bootstraps) and fails at boot on a duplicate job `name` across
25
- * modules. The caller passes the returned definitions to the canonical
26
- * schedules plugin; factories must therefore be resolved only once.
27
- */
28
- declare function collectModuleScheduledJobs(fastify: FastifyInstance, modules: readonly ArcModule[],
29
- /**
30
- * Optional sink for per-module counts, filled as each arm resolves.
31
- *
32
- * Exists so `arc.moduleDescriptors` can report real numbers without
33
- * resolving the factories a SECOND time — a contribution factory closes over
34
- * booted engines and may register or allocate, so running it twice is not a
35
- * free read. One resolution feeds both activation and introspection.
36
- */
37
- countsByModule?: Map<string, number>): Promise<ScheduleDefinition[]>;
38
- //#endregion
39
- //#region src/factory/module/extend.d.ts
40
- /**
41
- * What a caller may add. Every mergeable arm of `ArcModule`, plus `bootstrap`
42
- * in wrapper form only.
43
- *
44
- * `name` is absent on purpose: renaming a module mid-composition breaks the
45
- * `dependsOn` graph and the registry key its consumers read, and it is the one
46
- * "extension" that is never additive.
47
- */
48
- interface ModuleExtension<TExports = unknown> {
49
- dependsOn?: readonly string[];
50
- owns?: readonly string[] | "provided";
51
- resources?: ArcModule<TExports>["resources"];
52
- eventHandlers?: ArcModule<TExports>["eventHandlers"];
53
- scheduledJobs?: ArcModule<TExports>["scheduledJobs"];
54
- workflows?: ArcModule<TExports>["workflows"];
55
- healthChecks?: ArcModule<TExports>["healthChecks"];
56
- errorMappers?: ArcModule<TExports>["errorMappers"];
57
- plugins?: ArcModule<TExports>["plugins"];
58
- afterResources?: ArcModule<TExports>["afterResources"];
59
- onClose?: ArcModule<TExports>["onClose"];
60
- /**
61
- * WRAP the module's bootstrap — it is never replaced.
62
- *
63
- * Bootstrap returns the module's exports, so two of them cannot be
64
- * concatenated: one value has to win, and a host silently winning is the gym
65
- * failure (`{ ...mod, bootstrap }` overwrote the factory's own, so the engine
66
- * the module published was never created). The wrapper form makes the
67
- * relationship explicit — call `inner` and decorate its result, or
68
- * deliberately do not.
69
- *
70
- * `inner` is `undefined` when the module has no bootstrap of its own.
71
- */
72
- bootstrap?: (inner: ((f: FastifyInstance, c: ModuleSetupContext) => TExports | Promise<TExports>) | undefined) => (f: FastifyInstance, c: ModuleSetupContext) => TExports | Promise<TExports>;
73
- }
74
- /**
75
- * Merge a host's additions onto a module. Nothing the module declared is lost.
76
- *
77
- * ```ts
78
- * return extendModule(createOrderModule({ … }), {
79
- * eventHandlers: () => hostHandlers(), // appended after the module's
80
- * dependsOn: ["outbox"], // unioned
81
- * bootstrap: (inner) => async (f, c) => { // wraps, never replaces
82
- * const exports = await inner?.(f, c);
83
- * return decorate(exports);
84
- * },
85
- * });
86
- * ```
87
- */
88
- declare function extendModule<TExports = unknown>(mod: ArcModule<TExports>, extension: ModuleExtension<TExports>): ArcModule<TExports>;
89
- //#endregion
90
- //#region src/factory/module/lifecycle.d.ts
91
- /**
92
- * Subscribe every module's `eventHandlers` in dependency order (pass the
93
- * `orderModules`-sorted list). Returns the ordered list of unsubscribe
94
- * functions so the caller can tear them down at shutdown BEFORE module
95
- * `onClose` (while module deps are still alive). Fails at boot on:
96
- * - a duplicate NAMED handler across modules (attributing both owners);
97
- * - a module declaring handlers while the event subsystem is unavailable.
98
- * Resolves factory contributions (after bootstraps) so a handler can close over
99
- * booted engines rather than a global getter.
100
- */
101
- declare function subscribeModuleEventHandlers(fastify: FastifyInstance, modules: readonly ArcModule[],
102
- /**
103
- * Optional sink for per-module handler counts, filled as each arm resolves.
104
- * Lets `arc.moduleDescriptors` report real numbers without resolving the
105
- * factories a SECOND time — see the note on `collectModuleScheduledJobs`.
106
- */
107
- countsByModule?: Map<string, number>): Promise<Array<() => void | Promise<void>>>;
108
- //#endregion
109
- //#region src/factory/module/order.d.ts
110
- /**
111
- * Order modules for composition by their `dependsOn` edges — a STABLE
112
- * topological sort. Called once at the start of the bootstrap phase; every
113
- * subsequent phase (bootstrap, resources, afterResources, and reverse-order
114
- * onClose) iterates the returned list, so a module's declared dependencies are
115
- * always composed before it.
116
- *
117
- * "Stable" = modules with no edge between them keep their original list order,
118
- * so declaring `dependsOn` on one module never silently reorders an unrelated
119
- * one. Backward compatible: a `modules` array with NO `dependsOn` anywhere is
120
- * returned unchanged.
121
- *
122
- * Fail-fast — throws (never reorders past a broken contract) on:
123
- * - duplicate module names (the name is the graph key)
124
- * - a `dependsOn` name not present in the composed set
125
- * - a self-reference (`dependsOn` includes the module's own name)
126
- * - a dependency cycle (reports the concrete `a → b → … → a` path)
127
- */
128
- declare function orderModules(modules: readonly ArcModule[]): ArcModule[];
129
- //#endregion
130
- //#region src/factory/module/resolve.d.ts
131
- /**
132
- * Resolve any module-input form to a concrete `ArcModule`. A thunk is invoked
133
- * (this is where a dynamic `import()` fires); a promise (or plain module) is
134
- * awaited. Called once per module at the start of the bootstrap phase.
135
- */
136
- declare function resolveModule(input: ArcModuleInput): Promise<ArcModule>;
137
- /** Resolve a `ModuleContribution` to a concrete array (array passthrough or factory call). */
138
- declare function resolveContribution<T>(contribution: ModuleContribution<T> | undefined, fastify: FastifyInstance): Promise<readonly T[]>;
139
- //#endregion
140
- //#region src/factory/module/state.d.ts
141
- type ModuleState = "resolved" | "bootstrapping" | "ready" | "closing" | "closed" | "failed";
142
- /**
143
- * Is `name` in the composed module graph? TRUE for resource-only modules and
144
- * modules that exported nothing — the question `hasModuleExports()` cannot
145
- * answer. FALSE before registerResources runs (no graph yet) and for
146
- * uncomposed names.
147
- */
148
- declare function hasModule(fastify: FastifyInstance, name: string): boolean;
149
- /**
150
- * The module's current lifecycle state, or `undefined` when the module is not
151
- * composed (or no graph has been composed on this instance). See the state
152
- * machine in the file header.
153
- */
154
- declare function getModuleState(fastify: FastifyInstance, name: string): ModuleState | undefined;
155
- //#endregion
156
- //#region src/factory/module/index.d.ts
157
- /**
158
- * Identity helper for authoring a typed module — mirrors `defineResource`.
159
- * Gives inference + a single obvious construction site; does no work.
160
- *
161
- * `TExports` is inferred from the `bootstrap` return value, so a module
162
- * author gets a typed public export for free:
163
- *
164
- * ```ts
165
- * export const accountingModule = (deps: Deps) =>
166
- * defineModule({
167
- * name: "accounting",
168
- * bootstrap: async () => createAccountingEngine(deps), // TExports inferred
169
- * });
170
- * ```
171
- */
172
- declare function defineModule<TExports = unknown>(module: ArcModule<TExports>): ArcModule<TExports>;
173
- /**
174
- * Typed accessor for a module's public export (its `bootstrap` return value),
175
- * recorded at `fastify.arc.modules[name]`.
176
- *
177
- * Throwing, in line with the fail-fast contract (and `requireOrgId`-style
178
- * accessors): a missing entry means the module either isn't composed, is
179
- * composed AFTER the caller (list order = init order), or returned nothing —
180
- * all wiring bugs that must surface at boot, not as `undefined` downstream.
181
- *
182
- * The type parameter is an assertion, not a proof. Two ways to type it:
183
- * - augment `ArcModuleRegistry` once — then the name alone infers the type:
184
- * `getModuleExports(f, "accounting")` → `AccountingEngine`.
185
- * - or pass it inline: `getModuleExports<AccountingEngine>(f, "accounting")`.
186
- *
187
- * Siblings, for the two shapes this one is wrong for:
188
- * - `getOptionalModuleExports` — the module is genuinely OPTIONAL.
189
- * - `lazyModuleExports` / `lazyRequiredModuleExports` — the read happens at
190
- * composition time, where boot order decides the answer.
191
- */
192
- declare function getModuleExports<K extends keyof ArcModuleRegistry>(fastify: FastifyInstance, name: K): ArcModuleRegistry[K];
193
- declare function getModuleExports<TExports = unknown>(fastify: FastifyInstance, name: string): TExports;
194
- /**
195
- * Non-throwing sibling of `getModuleExports`: `undefined` when the module is
196
- * not composed (or has not bootstrapped yet).
197
- *
198
- * Exists because OPTIONAL sibling modules are a first-class composition shape —
199
- * a deployment that turns `inventory` off still sells services, so its POS
200
- * module must ask "is inventory here?" rather than fail-fast. Hosts were
201
- * spelling that question as
202
- *
203
- * ```ts
204
- * (fastify as { arc?: { modules?: Record<string, unknown> } })
205
- * .arc?.modules?.inventory;
206
- * ```
207
- *
208
- * — a double cast that (a) defeats `ArcModuleRegistry` inference, (b) silently
209
- * survives a typo in the module name, and (c) is impossible to grep for. Use
210
- * `getModuleExports` when the dependency is REQUIRED (boot must fail), this
211
- * when it is genuinely optional.
212
- *
213
- * Prefer `lazyModuleExports` whenever the read happens at COMPOSITION time —
214
- * see its doc for why a value read once can latch `undefined` forever.
215
- */
216
- declare function getOptionalModuleExports<K extends keyof ArcModuleRegistry>(fastify: FastifyInstance, name: K): ArcModuleRegistry[K] | undefined;
217
- declare function getOptionalModuleExports<TExports = unknown>(fastify: FastifyInstance, name: string): TExports | undefined;
218
- /**
219
- * Is a module's public export recorded yet? The predicate form of
220
- * `getOptionalModuleExports`, for readiness gates (`ready: () => ...`) that
221
- * should not have to reason about falsy-but-present exports.
222
- */
223
- declare function hasModuleExports(fastify: FastifyInstance, name: string): boolean;
224
- /**
225
- * A DEFERRED reader of a sibling module's export: returns a getter that reads
226
- * the registry at CALL time, not now.
227
- *
228
- * ── Why this exists (the bug it removes) ─────────────────────────────────────
229
- *
230
- * Module composition runs bootstraps in dependency/list order, but a lot of
231
- * wiring is *registered* earlier than it *runs*: an `eventHandlers` factory, a
232
- * bridge accessor handed to another module, a hook added during bootstrap and
233
- * fired per request. Such a factory can execute BEFORE the sibling it needs has
234
- * bootstrapped — so a sibling engine captured into a local at that moment is
235
- * `undefined`, and stays `undefined` for the life of the process even though the
236
- * sibling came up milliseconds later.
237
- *
238
- * That failure is SILENT by construction: the consumer sees a null bridge and
239
- * treats it as "this deployment has no inventory / no revenue engine", which is
240
- * a legitimate configuration. Real cost in this codebase: orders were created
241
- * and never payment-confirmed (no entitlement, no card, no door) and nothing
242
- * errored anywhere.
243
- *
244
- * The getter therefore:
245
- * - re-reads while the module is ABSENT, so boot order cannot matter;
246
- * - memoizes the FIRST resolved value, so the steady-state read is a closure
247
- * variable rather than a registry lookup per request;
248
- * - never memoizes absence — that is precisely the latch this replaces.
249
- *
250
- * ```ts
251
- * const inventory = lazyModuleExports<FlowEngine>(fastify, "inventory");
252
- * return {
253
- * flowBridge: () => (inventory() ? createFlowEngineBridge({ getFlowEngine: () => inventory()! }) : null),
254
- * ready: () => inventory() !== undefined,
255
- * };
256
- * ```
257
- */
258
- declare function lazyModuleExports<K extends keyof ArcModuleRegistry>(fastify: FastifyInstance, name: K): () => ArcModuleRegistry[K] | undefined;
259
- declare function lazyModuleExports<TExports = unknown>(fastify: FastifyInstance, name: string): () => TExports | undefined;
260
- /**
261
- * Required counterpart of `lazyModuleExports`: defers the read, then throws
262
- * `getModuleExports`' error if the module is still absent at first use.
263
- *
264
- * The pair matters because "required" and "readable now" are different
265
- * questions. A hook registered at bootstrap that needs the `order` engine at
266
- * REQUEST time is a hard dependency, but reading it eagerly turns a correct
267
- * composition into a boot crash purely because of list order. Deferring keeps
268
- * the fail-fast guarantee and moves it to the first moment the answer is
269
- * actually needed.
270
- *
271
- * Deferred does NOT mean unvalidated: a lazily-required module is still a
272
- * HARD dependency, so PRESENCE is checked eagerly. When the composed module
273
- * graph is known (any `createApp`/`registerResources` boot — the normal
274
- * case), a name that is not in the graph throws HERE, at composition time,
275
- * instead of surviving startup and failing on the first request or event.
276
- * Only the EXPORT read (does bootstrap's return value exist yet?) is
277
- * deferred to first call.
278
- *
279
- * Convention for hard sibling access: also declare the target in the
280
- * consumer's `dependsOn`. That orders composition (the sibling's bootstrap
281
- * runs first), while this accessor merely defers the read — the two are
282
- * complementary, not alternatives:
283
- * - hard dependency, read during bootstrap → `dependsOn` + `getModuleExports`
284
- * - hard dependency, read at request/event time → `dependsOn` + this
285
- * - optional integration → `lazyModuleExports` (no `dependsOn` needed)
286
- */
287
- declare function lazyRequiredModuleExports<K extends keyof ArcModuleRegistry>(fastify: FastifyInstance, name: K): () => ArcModuleRegistry[K];
288
- declare function lazyRequiredModuleExports<TExports = unknown>(fastify: FastifyInstance, name: string): () => TExports;
289
- //#endregion
290
- export { collectModuleScheduledJobs as _, lazyModuleExports as a, getModuleState as c, resolveModule as d, orderModules as f, collectModuleHealthChecks as g, extendModule as h, hasModuleExports as i, hasModule as l, ModuleExtension as m, getModuleExports as n, lazyRequiredModuleExports as o, subscribeModuleEventHandlers as p, getOptionalModuleExports as r, ModuleState as s, defineModule as t, resolveContribution as u, collectModuleWorkflows as v };
@@ -1,17 +0,0 @@
1
- /*! @classytic/arc v2.41.1 | MIT | https://classytic.com */
2
- //#region src/idempotency/stores/interface.ts
3
- /**
4
- * Helper to create a result object
5
- */
6
- function createIdempotencyResult(statusCode, body, headers, ttlMs) {
7
- const now = /* @__PURE__ */ new Date();
8
- return {
9
- statusCode,
10
- headers,
11
- body,
12
- createdAt: now,
13
- expiresAt: new Date(now.getTime() + ttlMs)
14
- };
15
- }
16
- //#endregion
17
- export { createIdempotencyResult as t };