@classytic/arc 2.41.0 → 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-n7qO5Cz3.mjs → EventTransport-tzA7CAB4.mjs} +22 -17
  3. package/dist/{HookSystem-CxvZBo77.mjs → HookSystem-B6UaKRbF.mjs} +2 -2
  4. package/dist/{QueryCache-DFA-QrU9.d.mts → QueryCache--5uAuYPW.d.mts} +7 -3
  5. package/dist/{ResourceRegistry-Cu7uTJp9.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-2YY_Kaj1.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-CUhjGHGZ.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-DsWDjIxx.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-BxLgNFF7.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-iNGqYerO.mjs → core-Cb0LjccA.mjs} +5 -4
  37. package/dist/{createActionRouter-BBlbPs3k.mjs → createActionRouter-xjqonMRO.mjs} +87 -39
  38. package/dist/{createAggregationRouter-Dv5SuK2x.mjs → createAggregationRouter-zRYWw_5D.mjs} +11 -8
  39. package/dist/{preloadResources-Bbp4QJ8V.mjs → createApp-D-953ZAq.mjs} +299 -390
  40. package/dist/{createMcpServer-CbDWkZ1T.d.mts → createMcpServer-C9cxS8zt.d.mts} +1 -1
  41. package/dist/{defineAggregation-UyeurGkp.mjs → defineAggregation-Bm8RjMbq.mjs} +1 -1
  42. package/dist/{defineResource-DzGT-2LP.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-BF-vhGxY.mjs → elevation-DG8SrLN-.mjs} +41 -12
  48. package/dist/encryption/index.mjs +3 -3
  49. package/dist/{errorHandler-CIMkCOWm.mjs → errorHandler-BnfDviL1.mjs} +26 -5
  50. package/dist/{errors-C_YhELhe.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-CmXaPWLv.mjs → eventPlugin-Q6BhzHzs.mjs} +82 -21
  54. package/dist/{subscribe-helpers-AVYPgqTl.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-BTyPLHK0.mjs → fields-ToPYpMqS.mjs} +1 -1
  66. package/dist/filter-merge-IpGywvym.mjs +99 -0
  67. package/dist/{generate-D_YmiCNf.mjs → generate-DRTkLlIl.mjs} +2 -2
  68. package/dist/{headers-CNECDE6q.mjs → headers-BbkIF6vA.mjs} +2 -2
  69. package/dist/health-D-Ft6JM6.mjs +22 -0
  70. package/dist/{health-CxQzbJmr.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-Y2MlSN9n.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-Cq9KYl2Z.mjs → jsonBody-B4YVGcql.mjs} +2 -2
  108. package/dist/{keys-Cmv4cBRa.mjs → keys-B2KtgMLJ.mjs} +7 -18
  109. package/dist/{loadResources-CblF7xt2.mjs → loadResources-Dn4lalw2.mjs} +3 -3
  110. package/dist/{loadResourcesFromEntry-99fIMC3p.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-xF3Gw-HW.mjs → mcpPlugin-C08HalN5.mjs} +433 -170
  115. package/dist/{memory-CpDZ9NPw.mjs → memory-9Cp7611C.mjs} +36 -34
  116. package/dist/{metrics-BaKnq8ag.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-BkQEesNQ.mjs → module-BSvOQC7E.mjs} +8 -8
  121. package/dist/multiTenant-cY0FkDiA.d.mts +104 -0
  122. package/dist/{multipartBody-C92aJ8am.mjs → multipartBody-CXM2a-Dy.mjs} +46 -7
  123. package/dist/{openapi-C3LFRzPq.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-dsCyLxXH.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-DiHXy8Ck.mjs → permissions-Cm0uYHvd.mjs} +149 -33
  131. package/dist/{pipe-CBVmUJ-j.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-DYJRZ0EJ.mjs → plugin-BccET1tL.mjs} +1256 -344
  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-2_U6QZQg.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-BdlugYTc.mjs → presets-Cpvj6fGO.mjs} +99 -107
  150. package/dist/{projection-Uvgp-EEj.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-B5F09bYr.mjs → queryCachePlugin-CFWNH8aT.mjs} +12 -14
  154. package/dist/{rateLimitKey-CK-EU2L8.mjs → rateLimitKey-C4O-kPm0.mjs} +1 -1
  155. package/dist/{realtime-FnnD0n3Z.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-D3y8VEJ1.mjs → registry-Bcz9G1bh.mjs} +10 -8
  162. package/dist/{renewingLease-B3VYh5aU.mjs → renewingLease-qODa7KJQ.mjs} +1 -1
  163. package/dist/{replyHelpers-DPHsdw-5.mjs → replyHelpers-CG_VtVgS.mjs} +2 -2
  164. package/dist/{requestContext-cSVKnYPk.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-DjDuyglE.mjs → rolldown-runtime-D1w9Y1VJ.mjs} +1 -1
  170. package/dist/routeValidator-D36SW8qt.mjs +70 -0
  171. package/dist/{runtimeCapabilities-DSA_dH1_.mjs → runtimeCapabilities-0tccjRlj.mjs} +1 -1
  172. package/dist/{schedules-BktJb3Y3.mjs → schedules-C-OpmHBq.mjs} +46 -37
  173. package/dist/{schemaConverter-BLCSmNbr.mjs → schemaConverter-BORek3O-.mjs} +2 -2
  174. package/dist/{schemaIR-K16Bb5BX.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-jSxuBTFM.mjs → scope-DQthe88b.mjs} +4 -4
  181. package/dist/shutdown-MqA81z_P.mjs +59 -0
  182. package/dist/{simpleEqualityMatcher-BiOnyflP.mjs → simpleEqualityMatcher-auW8QjXN.mjs} +1 -1
  183. package/dist/{sse-CH7Slxc1.mjs → sse-CYzQBVFe.mjs} +11 -15
  184. package/dist/{sseStream-CN-Lh1Tu.mjs → sseStream-B5_Afiqn.mjs} +2 -2
  185. package/dist/{store-helpers-9DX9-1j_.mjs → store-helpers-BOzk-CuX.mjs} +1 -1
  186. package/dist/{streaming-dvppnxsr.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-DCWMI6hV.mjs → transactionContext-DjFkrNG6.mjs} +1 -1
  199. package/dist/{typeGuards-D7tHFdH6.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-CDy3-zw1.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-DDMOZ_Pm.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-B-zj_b__.mjs → utils-ec1oTo1n.mjs} +315 -404
  212. package/dist/{validate-R0G_JrnK.mjs → validate-9yzHC1e2.mjs} +6 -14
  213. package/dist/{versioning-D6JIK8Tk.d.mts → versioning-Bsb51gGT.d.mts} +28 -13
  214. package/dist/{versioning-DuVWcu-F.mjs → versioning-fhhWHV74.mjs} +4 -4
  215. package/dist/{websocket-BOXVggMf.d.mts → websocket-Cs4awVyD.d.mts} +1 -1
  216. package/dist/{workScope-BhsWde4k.mjs → workScope-zpPyge4t.mjs} +2 -2
  217. package/package.json +578 -574
  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-DPwPWPOV.mjs +0 -350
  225. package/dist/index-CFfLKMH4.d.mts +0 -290
  226. package/dist/interface-BIpgzbZl.mjs +0 -17
  227. package/dist/redis-stream-BPKscsTB.d.mts +0 -260
  228. package/dist/registerRoute-DRsSHPSM.mjs +0 -364
  229. package/dist/sync/changelog.d.mts +0 -3
  230. package/dist/sync/changelog.mjs +0 -3
@@ -1,6 +1,6 @@
1
1
 
2
- import { d as UserBase } from "../base-CxrV1LmG.mjs";
3
- import "../index-DHbyPo5j.mjs";
2
+ import { d as UserBase } from "../base-CZyixEQR.mjs";
3
+ import "../index-mqaqZNpe.mjs";
4
4
  import { FastifyPluginAsync } from "fastify";
5
5
  import { RepositoryLike } from "@classytic/repo-core/adapter";
6
6
  //#region src/audit/stores/interface.d.ts
@@ -37,6 +37,8 @@ interface AuditEntry {
37
37
  }
38
38
  interface AuditContext {
39
39
  user?: UserBase;
40
+ /** The actor from the request's VALIDATED scope (user or service client). Wins over `user`. */
41
+ actorId?: string;
40
42
  organizationId?: string;
41
43
  requestId?: string;
42
44
  ipAddress?: string;
@@ -191,8 +193,13 @@ declare module "fastify" {
191
193
  audit: AuditLogger;
192
194
  }
193
195
  interface FastifyRequest {
194
- /** Audit context for current request */
196
+ /**
197
+ * Audit context for the current request. The actor and organization are read from
198
+ * the VALIDATED scope when this is read — never captured before auth ran.
199
+ */
195
200
  auditContext?: AuditContext;
201
+ /** Extra fields a handler attaches to the audit row arc writes for this request. */
202
+ auditMetadata?: Record<string, unknown>;
196
203
  }
197
204
  }
198
205
  interface AuditLogger {
@@ -206,6 +213,11 @@ interface AuditLogger {
206
213
  restore: (resource: string, documentId: string, data: Record<string, unknown>, context?: AuditContext) => Promise<void>;
207
214
  /** Log a custom action */
208
215
  custom: (resource: string, documentId: string, action: string, data?: Record<string, unknown>, context?: AuditContext) => Promise<void>;
216
+ /**
217
+ * A logger bound to one request: every entry's actor and organization come from that
218
+ * request's validated scope, so a caller can neither forget nor forge them.
219
+ */
220
+ forRequest: (request: AuditRequestLike) => RequestAuditLogger;
209
221
  /** Query audit logs (if stores support it) */
210
222
  query: (options: AuditQueryOptions) => Promise<AuditEntry[]>;
211
223
  /**
@@ -215,7 +227,33 @@ interface AuditLogger {
215
227
  */
216
228
  purge: (cutoff: Date) => Promise<number>;
217
229
  }
218
- declare const auditPlugin: FastifyPluginAsync<AuditPluginOptions>;
230
+ /** {@link AuditLogger} writes with the context bound to one request. */
231
+ interface RequestAuditLogger {
232
+ create: (resource: string, documentId: string, data: Record<string, unknown>) => Promise<void>;
233
+ update: (resource: string, documentId: string, before: Record<string, unknown>, after: Record<string, unknown>) => Promise<void>;
234
+ delete: (resource: string, documentId: string, data: Record<string, unknown>) => Promise<void>;
235
+ restore: (resource: string, documentId: string, data: Record<string, unknown>) => Promise<void>;
236
+ custom: (resource: string, documentId: string, action: string, data?: Record<string, unknown>) => Promise<void>;
237
+ }
238
+ /** What {@link auditContextOf} reads — a FastifyRequest, or arc's `IRequestContext`. */
239
+ interface AuditRequestLike {
240
+ readonly scope?: unknown;
241
+ readonly user?: unknown;
242
+ readonly id?: string;
243
+ readonly ip?: string;
244
+ readonly headers?: Record<string, unknown>;
245
+ readonly method?: string;
246
+ readonly url?: string;
247
+ readonly routeOptions?: {
248
+ readonly url?: string;
249
+ };
250
+ readonly metadata?: unknown;
251
+ }
252
+ /**
253
+ * The audit context of a request, from its VALIDATED scope: the actor is the scope's user
254
+ * (or service client) and the organization is the scope's active organization.
255
+ */
256
+ declare function auditContextOf(request: AuditRequestLike): AuditContext;
219
257
  declare const _default: FastifyPluginAsync<AuditPluginOptions>;
220
258
  //#endregion
221
259
  //#region src/audit/repository-audit-adapter.d.ts
@@ -259,4 +297,4 @@ declare class MemoryAuditStore implements AuditStore {
259
297
  clear(): void;
260
298
  }
261
299
  //#endregion
262
- export { type AuditAction, type AuditContext, type AuditEntry, type AuditLogger, type AuditPluginOptions, type AuditQueryOptions, type AuditStore, type AuditStoreOptions, MemoryAuditStore, type MemoryAuditStoreOptions, _default as auditPlugin, auditPlugin as auditPluginFn, createAuditEntry, repositoryAsAuditStore };
300
+ export { type AuditAction, type AuditContext, type AuditEntry, type AuditLogger, type AuditPluginOptions, type AuditQueryOptions, type AuditRequestLike, type AuditStore, type AuditStoreOptions, MemoryAuditStore, type MemoryAuditStoreOptions, type RepositoryAuditStoreOptions, type RequestAuditLogger, auditContextOf, _default as auditPlugin, createAuditEntry, repositoryAsAuditStore };
@@ -1,6 +1,7 @@
1
- /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
- import { t as transactionContext } from "../transactionContext-DCWMI6hV.mjs";
3
- import { n as declareRuntimeCapability } from "../runtimeCapabilities-DSA_dH1_.mjs";
1
+ /*! @classytic/arc v2.43.0 | MIT | https://classytic.com */
2
+ import { g as getUserId, i as getClientId } from "../types-Bk9NOgOC.mjs";
3
+ import { t as transactionContext } from "../transactionContext-DjFkrNG6.mjs";
4
+ import { n as declareRuntimeCapability } from "../runtimeCapabilities-0tccjRlj.mjs";
4
5
  import { and, anyOf, eq, gte, lt, lte } from "@classytic/repo-core/filter";
5
6
  import fp from "fastify-plugin";
6
7
  //#region src/audit/repository-audit-adapter.ts
@@ -86,7 +87,7 @@ function createAuditEntry(resource, documentId, action, context, data) {
86
87
  resource,
87
88
  documentId,
88
89
  action,
89
- userId: extractUserId(context.user),
90
+ userId: context.actorId ?? extractUserId(context.user),
90
91
  organizationId: context.organizationId,
91
92
  before: data?.before,
92
93
  after: data?.after,
@@ -182,6 +183,7 @@ const auditPlugin = async (fastify, opts = {}) => {
182
183
  if (!enabled) {
183
184
  fastify.decorate("audit", createNoopLogger());
184
185
  fastify.decorateRequest("auditContext", void 0);
186
+ fastify.decorateRequest("auditMetadata", void 0);
185
187
  fastify.log?.debug?.("Audit plugin disabled");
186
188
  return;
187
189
  }
@@ -220,6 +222,16 @@ const auditPlugin = async (fastify, opts = {}) => {
220
222
  ...data
221
223
  } }));
222
224
  },
225
+ forRequest(request) {
226
+ const ctx = () => auditContextOf(request);
227
+ return {
228
+ create: (resource, documentId, data) => audit.create(resource, documentId, data, ctx()),
229
+ update: (resource, documentId, before, after) => audit.update(resource, documentId, before, after, ctx()),
230
+ delete: (resource, documentId, data) => audit.delete(resource, documentId, data, ctx()),
231
+ restore: (resource, documentId, data) => audit.restore(resource, documentId, data, ctx()),
232
+ custom: (resource, documentId, action, data) => audit.custom(resource, documentId, action, data, ctx())
233
+ };
234
+ },
223
235
  async query(options) {
224
236
  for (const store of stores) if (store.query) return store.query(options);
225
237
  return [];
@@ -231,27 +243,10 @@ const auditPlugin = async (fastify, opts = {}) => {
231
243
  }
232
244
  };
233
245
  fastify.decorate("audit", audit);
234
- fastify.decorateRequest("auditContext", void 0);
235
- fastify.addHook("onRequest", async (request) => {
236
- const user = request.user;
237
- request.context;
238
- const scope = request.scope;
239
- request.auditContext = {
240
- user,
241
- organizationId: scope?.kind === "member" ? scope.organizationId : scope?.kind === "elevated" ? scope.organizationId : void 0,
242
- requestId: request.id,
243
- ipAddress: request.ip,
244
- userAgent: request.headers["user-agent"],
245
- endpoint: void 0,
246
- duration: void 0
247
- };
248
- });
249
- fastify.addHook("onResponse", async (request, reply) => {
250
- if (request.auditContext) {
251
- request.auditContext.endpoint = `${request.method} ${request.routeOptions?.url ?? request.url}`;
252
- request.auditContext.duration = Math.round(reply.elapsedTime);
253
- }
254
- });
246
+ fastify.decorateRequest("auditContext", { getter() {
247
+ return auditContextOf(this);
248
+ } });
249
+ fastify.decorateRequest("auditMetadata", void 0);
255
250
  const retention = opts.retention;
256
251
  let retentionTimer = null;
257
252
  if (retention) {
@@ -307,8 +302,10 @@ const auditPlugin = async (fastify, opts = {}) => {
307
302
  } else if (excludeResources.has(ctx.resource)) return;
308
303
  const docId = autoAuditExtractId(ctx.result);
309
304
  const scope = ctx.context?._scope;
305
+ const scopedActor = scope ? getUserId(scope) ?? getClientId(scope) : void 0;
310
306
  const auditCtx = {
311
307
  user: ctx.user,
308
+ ...scopedActor ? { actorId: String(scopedActor) } : {},
312
309
  organizationId: scope ? autoAuditGetOrgId(scope) : void 0
313
310
  };
314
311
  try {
@@ -331,6 +328,24 @@ const auditPlugin = async (fastify, opts = {}) => {
331
328
  }
332
329
  fastify.log?.debug?.({ stores: stores.map((s) => s.name) }, "Audit plugin enabled");
333
330
  };
331
+ /**
332
+ * The audit context of a request, from its VALIDATED scope: the actor is the scope's user
333
+ * (or service client) and the organization is the scope's active organization.
334
+ */
335
+ function auditContextOf(request) {
336
+ const scope = request.metadata?._scope ?? request.scope;
337
+ const actorId = scope ? getUserId(scope) ?? getClientId(scope) : void 0;
338
+ const userAgent = request.headers?.["user-agent"];
339
+ return {
340
+ user: request.user,
341
+ ...actorId ? { actorId: String(actorId) } : {},
342
+ organizationId: scope ? autoAuditGetOrgId(scope) : void 0,
343
+ requestId: request.id,
344
+ ipAddress: request.ip,
345
+ userAgent: typeof userAgent === "string" ? userAgent : void 0,
346
+ endpoint: request.method && request.routeOptions?.url ? `${request.method} ${request.routeOptions.url}` : void 0
347
+ };
348
+ }
334
349
  /** Extract document ID from a result */
335
350
  function autoAuditExtractId(doc) {
336
351
  if (!doc || typeof doc !== "object") return "";
@@ -361,6 +376,13 @@ function createNoopLogger() {
361
376
  delete: noop,
362
377
  restore: noop,
363
378
  custom: noop,
379
+ forRequest: () => ({
380
+ create: noop,
381
+ update: noop,
382
+ delete: noop,
383
+ restore: noop,
384
+ custom: noop
385
+ }),
364
386
  query: async () => [],
365
387
  purge: async () => 0,
366
388
  _noop: true
@@ -372,4 +394,4 @@ var auditPlugin_default = fp(auditPlugin, {
372
394
  dependencies: ["arc-core"]
373
395
  });
374
396
  //#endregion
375
- export { MemoryAuditStore, auditPlugin_default as auditPlugin, auditPlugin as auditPluginFn, createAuditEntry, repositoryAsAuditStore };
397
+ export { MemoryAuditStore, auditContextOf, auditPlugin_default as auditPlugin, createAuditEntry, repositoryAsAuditStore };
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.43.0 | MIT | https://classytic.com */
2
2
  //#region src/auth/audit.ts
3
3
  function compileGlobs(patterns) {
4
4
  if (patterns.length === 0) return () => false;
@@ -1,6 +1,7 @@
1
1
 
2
- import { l as PermissionCheck } from "../base-CxrV1LmG.mjs";
3
- import { Ft as AuthPluginOptions, Pt as AuthHelpers } from "../index-DHbyPo5j.mjs";
2
+ import { i as RequestScope } from "../types-Ddl9OjmE.mjs";
3
+ import { l as PermissionCheck } from "../base-CZyixEQR.mjs";
4
+ import { At as AuthHelpers, jt as AuthPluginOptions } from "../index-mqaqZNpe.mjs";
4
5
  import { t as ExternalOpenApiPaths } from "../externalPaths-CmGOxOtD.mjs";
5
6
  import { a as SessionManagerOptions, c as createSessionManager, i as SessionData, n as MemorySessionStoreOptions, o as SessionManagerResult, r as SessionCookieOptions, s as SessionStore, t as MemorySessionStore } from "../sessionManager-qimlKV0P.mjs";
6
7
  import { FastifyPluginAsync, FastifyReply as FastifyReply$1, FastifyRequest } from "fastify";
@@ -17,7 +18,6 @@ declare module "fastify" {
17
18
  auth: AuthHelpers;
18
19
  }
19
20
  }
20
- declare const authPlugin: FastifyPluginAsync<AuthPluginOptions>;
21
21
  declare const _default: FastifyPluginAsync<AuthPluginOptions>;
22
22
  //#endregion
23
23
  //#region src/auth/betterAuth.d.ts
@@ -50,6 +50,30 @@ interface BetterAuthAdapterOptions {
50
50
  * @default false
51
51
  */
52
52
  orgContext?: boolean;
53
+ /**
54
+ * Effective roles in the active organization — the seam for an organization HIERARCHY (roles held
55
+ * at a parent, e.g. a head office, apply in its child organizations). Called with the caller's own
56
+ * membership roles there (`null` when not a member); returns the roles the request carries, or
57
+ * `null` to leave it non-member. Requires `orgContext`.
58
+ */
59
+ resolveOrgRoles?: (input: {
60
+ userId: string;
61
+ organizationId: string;
62
+ memberRoles: readonly string[] | null;
63
+ }) => readonly string[] | null | Promise<readonly string[] | null>;
64
+ /**
65
+ * Where the caller's own membership roles come from. Default `'better-auth'`: arc asks Better
66
+ * Auth (`getActiveMember`, then `getActiveMemberRole`) and passes the answer to `resolveOrgRoles`
67
+ * as `memberRoles`.
68
+ *
69
+ * `'resolver'`: `resolveOrgRoles` reads membership itself, so arc skips Better Auth's lookup — one
70
+ * fewer membership read per authenticated request — and calls it with `memberRoles: null`. Choose
71
+ * it ONLY for a resolver that never reads `memberRoles`; one that extends them would lose them.
72
+ * Requires `resolveOrgRoles`.
73
+ *
74
+ * @default 'better-auth'
75
+ */
76
+ memberLookup?: "better-auth" | "resolver";
53
77
  /**
54
78
  * OpenAPI documentation for auth endpoints.
55
79
  * - `true` (default): auto-extract from auth.api if available
@@ -86,16 +110,20 @@ interface BetterAuthAdapterOptions {
86
110
  */
87
111
  exposeAuthErrors?: boolean;
88
112
  /**
89
- * Per-route rate limit for the Better Auth catch-all (`/api/auth/*`),
90
- * applied via `@fastify/rate-limit`'s route config (requires the
91
- * limiter to be registered, which createApp does by default).
113
+ * Credentials other than a session, by `Authorization` scheme (RFC 7235) — a paired device, an
114
+ * API key. A request presenting a registered scheme is authenticated by its verifier ONLY: the
115
+ * scope it returns (usually `{ kind: 'service', … }`) is installed; `null` is a 401. Gate such
116
+ * routes with `requireServiceScope(...)`. `Bearer` is the session's and cannot be registered.
92
117
  *
93
- * Credential endpoints deserve a tighter bucket than the global limit
94
- * (brute-force / credential-stuffing surface), BUT the same catch-all
95
- * also serves Better Auth's chatty `get-session` heartbeat — so arc
96
- * ships NO default here; a forced strict limit (the classic "5/min on
97
- * /login") would 429 every SPA that polls sessions. Pick a ceiling that
98
- * covers your session-poll cadence, or key the bucket smarter:
118
+ * @example
119
+ * credentials: { Device: (value) => verifyDevice(value) } // Authorization: Device <sn>:<token>
120
+ */
121
+ credentials?: Readonly<Record<string, CredentialVerifier>>;
122
+ /**
123
+ * Per-route `@fastify/rate-limit` config for the auth catch-all. No default:
124
+ * the same route serves the chatty `get-session` heartbeat, so a strict
125
+ * login-style limit would 429 every SPA that polls sessions. Pick a ceiling
126
+ * above your poll cadence, or exempt the heartbeat:
99
127
  *
100
128
  * @example
101
129
  * ```ts
@@ -173,6 +201,8 @@ declare module "fastify" {
173
201
  * fastify.get('/me', { preHandler: [authenticate] }, handler);
174
202
  * ```
175
203
  */
204
+ /** Verifies one credential scheme's value; the scope to install, or `null` when it is not valid. */
205
+ type CredentialVerifier = (credentials: string, request: FastifyRequest) => Promise<RequestScope | null>;
176
206
  declare function createBetterAuthAdapter(options: BetterAuthAdapterOptions): BetterAuthAdapterResult;
177
207
  //#endregion
178
208
  //#region src/auth/betterAuthOpenApi.d.ts
@@ -290,4 +320,4 @@ interface MirrorTrustedOriginsOptions {
290
320
  */
291
321
  declare function mirrorTrustedOriginsFromCors(options: MirrorTrustedOriginsOptions): string[];
292
322
  //#endregion
293
- export { type AuthPluginOptions, type BetterAuthAdapterOptions, type BetterAuthAdapterResult, type BetterAuthHandler, type BetterAuthOpenApiOptions, type CorsOriginsConfig, MemorySessionStore, type MemorySessionStoreOptions, type MirrorTrustedOriginsOptions, type SessionCookieOptions, type SessionData, type SessionManagerOptions, type SessionManagerResult, type SessionStore, _default as authPlugin, authPlugin as authPluginFn, createBetterAuthAdapter, createSessionManager, extractBetterAuthOpenApi, mirrorTrustedOriginsFromCors };
323
+ export { type AuthPluginOptions, type BetterAuthAdapterOptions, type BetterAuthAdapterResult, type BetterAuthHandler, type BetterAuthOpenApiOptions, type CorsOriginsConfig, type CredentialVerifier, MemorySessionStore, type MemorySessionStoreOptions, type MirrorTrustedOriginsOptions, type SessionCookieOptions, type SessionData, type SessionManagerOptions, type SessionManagerResult, type SessionStore, _default as authPlugin, createBetterAuthAdapter, createSessionManager, extractBetterAuthOpenApi, mirrorTrustedOriginsFromCors };