@classytic/arc 2.32.0 → 2.34.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 (193) hide show
  1. package/README.md +1 -1
  2. package/bin/arc.js +58 -17
  3. package/dist/{BaseController-Dk34dxhI.mjs → BaseController-CbkuhNI2.mjs} +329 -35
  4. package/dist/{EventTransport-2uVV34WU.d.mts → EventTransport-BEVP50ka.d.mts} +16 -0
  5. package/dist/{EventTransport-BV10D0oG.mjs → EventTransport-tq4CEB-q.mjs} +39 -2
  6. package/dist/{HookSystem-vimw5D7Z.mjs → HookSystem-DqXkMXkB.mjs} +2 -2
  7. package/dist/{ResourceRegistry-BVr7PgA0.mjs → ResourceRegistry-DoALUlOO.mjs} +3 -2
  8. package/dist/{actionPermissions-Dti7ebyv.mjs → actionPermissions-CUeCmpUd.mjs} +1 -1
  9. package/dist/audit/index.d.mts +2 -2
  10. package/dist/audit/index.mjs +2 -2
  11. package/dist/auth/audit.mjs +1 -1
  12. package/dist/auth/index.d.mts +2 -2
  13. package/dist/auth/index.mjs +39 -7
  14. package/dist/auth/redis-session.mjs +1 -1
  15. package/dist/{authorizationDecision-__T3EJDA.mjs → authorizationDecision-CMMLWmuZ.mjs} +6 -2
  16. package/dist/{types-B7XeLEgK.d.mts → base-Csjc2oF-.d.mts} +74 -74
  17. package/dist/{buildHandler-Dn7rzUJo.mjs → buildHandler-BrdYrG_1.mjs} +4 -4
  18. package/dist/cache/index.mjs +4 -4
  19. package/dist/{caching-DFJqHyFs.mjs → caching-BcGmvnHh.mjs} +2 -2
  20. package/dist/cleanup/index.d.mts +17 -5
  21. package/dist/cleanup/index.mjs +240 -7
  22. package/dist/cli/commands/describe.d.mts +1 -1
  23. package/dist/cli/commands/describe.mjs +3 -3
  24. package/dist/cli/commands/docs.mjs +3 -3
  25. package/dist/cli/commands/doctor.mjs +1 -1
  26. package/dist/cli/commands/generate.mjs +2 -2
  27. package/dist/cli/commands/init.mjs +2 -2
  28. package/dist/cli/commands/introspect.mjs +2 -2
  29. package/dist/cli/index.mjs +3 -3
  30. package/dist/{constants-J99LGTJI.mjs → constants-BxCoxmiN.mjs} +1 -1
  31. package/dist/context/index.mjs +3 -3
  32. package/dist/core/index.d.mts +3 -3
  33. package/dist/core/index.mjs +9 -8
  34. package/dist/{core-BwwmNSp7.mjs → core-BYKa8wHu.mjs} +3 -3
  35. package/dist/{createActionRouter-DkJZWo0m.mjs → createActionRouter-D6T0jWhS.mjs} +8 -8
  36. package/dist/{createAggregationRouter-B1exOVD8.mjs → createAggregationRouter-QLV2PrWP.mjs} +7 -7
  37. package/dist/{createApp-Bv0m-Q6_.mjs → createApp-zR-DEesr.mjs} +128 -24
  38. package/dist/{defineAggregation-gX4No1gt.mjs → defineAggregation-Nv-DwfOf.mjs} +1 -1
  39. package/dist/{defineResource-XFPPUu2c.mjs → defineResource-ZhuLonLm.mjs} +297 -23
  40. package/dist/discovery/index.mjs +1 -1
  41. package/dist/docs/index.d.mts +1 -1
  42. package/dist/docs/index.mjs +3 -3
  43. package/dist/{elevation-DNXXxgjl.mjs → elevation-B0tlY8y1.mjs} +4 -4
  44. package/dist/encryption/index.mjs +3 -3
  45. package/dist/{errorHandler-B2AZUJUj.mjs → errorHandler-C7xBqHsI.mjs} +42 -5
  46. package/dist/{errorHandler-CpYUJmPA.d.mts → errorHandler-DI5AN2b5.d.mts} +14 -3
  47. package/dist/{errors-Bh1KK5ps.mjs → errors-Cd_yy7aW.mjs} +1 -1
  48. package/dist/{eventPlugin-GF5nnBIq.d.mts → eventPlugin-DSNEZWfV.d.mts} +29 -1
  49. package/dist/{eventPlugin-Dk_TyXeE.mjs → eventPlugin-Dar8qRaj.mjs} +65 -9
  50. package/dist/events/index.d.mts +5 -351
  51. package/dist/events/index.mjs +5 -780
  52. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  53. package/dist/events/transports/redis-stream-entry.mjs +1 -1
  54. package/dist/events/transports/redis.d.mts +1 -1
  55. package/dist/events/transports/redis.mjs +1 -1
  56. package/dist/factory/index.d.mts +20 -5
  57. package/dist/factory/index.mjs +7 -7
  58. package/dist/{fastify-augmentation-BppG5bMT.d.mts → fastify-augmentation-DVsTAy6X.d.mts} +3 -3
  59. package/dist/{fields-DEi65pGj.mjs → fields-CojeUkS4.mjs} +1 -1
  60. package/dist/{generate-CRSG0jTv.mjs → generate-DiB0nHPR.mjs} +2 -2
  61. package/dist/{headers-BXjQYbeC.mjs → headers-CveNO9gR.mjs} +2 -2
  62. package/dist/{health-5XnTa2uo.mjs → health-CasG2A28.mjs} +1 -1
  63. package/dist/hooks/index.d.mts +1 -1
  64. package/dist/hooks/index.mjs +2 -2
  65. package/dist/idempotency/index.d.mts +45 -1
  66. package/dist/idempotency/index.mjs +90 -9
  67. package/dist/idempotency/redis.mjs +1 -1
  68. package/dist/{index-zq6VrjaB.d.mts → index-B-DvUzsr.d.mts} +12 -2
  69. package/dist/{index-CpzxqePp.d.mts → index-BcR2bFZQ.d.mts} +707 -373
  70. package/dist/{index-ZWhLTp_s.d.mts → index-C5NnMEKF.d.mts} +1 -1
  71. package/dist/{index-DXlHwvuE.d.mts → index-CFAJEWCX.d.mts} +18 -5
  72. package/dist/{index-C-481Zf2.d.mts → index-ugr1tQlW.d.mts} +17 -1
  73. package/dist/index.d.mts +6 -6
  74. package/dist/index.mjs +13 -12
  75. package/dist/{init-BbfP8aky.mjs → init-mdJ-v4Xp.mjs} +18 -12
  76. package/dist/integrations/event-gateway.d.mts +1 -1
  77. package/dist/integrations/event-gateway.mjs +2 -2
  78. package/dist/integrations/index.d.mts +2 -2
  79. package/dist/integrations/index.mjs +1 -1
  80. package/dist/integrations/jobs/index.d.mts +1 -1
  81. package/dist/integrations/jobs/index.mjs +99 -97
  82. package/dist/integrations/mcp/index.d.mts +12 -3
  83. package/dist/integrations/mcp/index.mjs +2 -2
  84. package/dist/integrations/mcp/testing.d.mts +1 -1
  85. package/dist/integrations/mcp/testing.mjs +2 -2
  86. package/dist/integrations/streamline.mjs +3 -3
  87. package/dist/integrations/webhooks.d.mts +124 -1
  88. package/dist/integrations/webhooks.mjs +180 -2
  89. package/dist/integrations/websocket-pushref-redis.mjs +1 -1
  90. package/dist/integrations/websocket-redis.mjs +1 -1
  91. package/dist/integrations/websocket.mjs +1 -1
  92. package/dist/{interface-BP4IJCBO.mjs → interface-DznJrm9R.mjs} +1 -1
  93. package/dist/{jsonBody-DDSR2HFl.mjs → jsonBody-CfGH-GxO.mjs} +2 -2
  94. package/dist/{keys-B-HBTGXl.mjs → keys-WeKvY1dE.mjs} +1 -1
  95. package/dist/{loadResources-DisEAmkm.mjs → loadResources-Bj-aSsXi.mjs} +2 -2
  96. package/dist/{loadResourcesFromEntry-D1MJp13f.mjs → loadResourcesFromEntry-DwaxNcE2.mjs} +2 -2
  97. package/dist/logger/index.mjs +1 -1
  98. package/dist/{mcpPlugin-CpfVpKHE.mjs → mcpPlugin-DX3PHD7K.mjs} +60 -21
  99. package/dist/{memory-DsuWnj4T.mjs → memory-qYSB7rMQ.mjs} +2 -2
  100. package/dist/{metrics-DdQL8syd.mjs → metrics-D7uchLjN.mjs} +2 -2
  101. package/dist/middleware/index.d.mts +1 -1
  102. package/dist/middleware/index.mjs +3 -3
  103. package/dist/migrations/index.mjs +2 -2
  104. package/dist/{module-Br81am6m.mjs → module-CwKsgZXp.mjs} +1 -1
  105. package/dist/{multipartBody-BnkBLN7v.mjs → multipartBody-4w-S3-PU.mjs} +1 -1
  106. package/dist/{openapi-DIRzvxC0.mjs → openapi-CkV5mQ53.mjs} +6 -6
  107. package/dist/outbox-admin/index.d.mts +2 -2
  108. package/dist/outbox-admin/index.mjs +4 -4
  109. package/dist/outbox-module-C1Bs_FXF.d.mts +382 -0
  110. package/dist/outbox-module-D1QfHqO4.mjs +846 -0
  111. package/dist/permissions/index.d.mts +2 -2
  112. package/dist/permissions/index.mjs +5 -5
  113. package/dist/{permissions-Dl_m0NCe.mjs → permissions-CP47jdi7.mjs} +25 -6
  114. package/dist/{pipe-ELHCP3zj.mjs → pipe-BzzoEhHj.mjs} +2 -2
  115. package/dist/pipeline/index.d.mts +1 -1
  116. package/dist/pipeline/index.mjs +2 -2
  117. package/dist/{pipeline-CPA-jx0M.mjs → pipeline-q69DZzgG.mjs} +6 -6
  118. package/dist/plugins/index.d.mts +6 -6
  119. package/dist/plugins/index.mjs +16 -16
  120. package/dist/plugins/response-cache.mjs +2 -2
  121. package/dist/plugins/tracing-entry.mjs +2 -2
  122. package/dist/{pluralize-C2ZkKbsn.mjs → pluralize-B7xf8qZF.mjs} +1 -1
  123. package/dist/{preloadResources-CDs87fTw.mjs → preloadResources-BkyqeTDz.mjs} +1 -1
  124. package/dist/{preloadResources-T1hmlTEZ.d.mts → preloadResources-g07ldtzh.d.mts} +30 -7
  125. package/dist/presets/filesUpload.d.mts +2 -2
  126. package/dist/presets/filesUpload.mjs +5 -5
  127. package/dist/presets/index.d.mts +2 -2
  128. package/dist/presets/index.mjs +2 -2
  129. package/dist/presets/multiTenant.d.mts +1 -1
  130. package/dist/presets/multiTenant.mjs +3 -3
  131. package/dist/presets/search.d.mts +2 -2
  132. package/dist/presets/search.mjs +2 -2
  133. package/dist/{presets-Dntd_pUO.mjs → presets-BAPijK_A.mjs} +4 -4
  134. package/dist/projection-BKM0Ui-s.mjs +42 -0
  135. package/dist/{queryCachePlugin-Dhps-Ldt.mjs → queryCachePlugin-DhsZ0ZIc.mjs} +49 -7
  136. package/dist/{rateLimit-C7mmAGs3.mjs → rateLimit-D4-ASwsI.mjs} +2 -2
  137. package/dist/{rateLimitKey-CccEFBfk.mjs → rateLimitKey-XngqVNEV.mjs} +1 -1
  138. package/dist/{realtime-DVvVZZFz.mjs → realtime-G1TC6Yzc.mjs} +9 -9
  139. package/dist/{redis-stream-qN6A-RFv.d.mts → redis-stream-mwLWlfHG.d.mts} +1 -1
  140. package/dist/{registerRoute-B_QrjYZS.mjs → registerRoute-Ba8v0PCa.mjs} +4 -4
  141. package/dist/registry/index.d.mts +3 -3
  142. package/dist/registry/index.mjs +3 -3
  143. package/dist/{registry-DqUmzA9W.mjs → registry-CLxCR5LF.mjs} +2 -2
  144. package/dist/{renewingLease-BpP9wwj7.mjs → renewingLease-BnWtbA2U.mjs} +1 -1
  145. package/dist/{replyHelpers-DS-P0b32.mjs → replyHelpers-BSBVCwL3.mjs} +2 -2
  146. package/dist/repositoryFilter-BANpz6BX.mjs +78 -0
  147. package/dist/{requestContext-B6vQF-sy.mjs → requestContext-uYE35JxI.mjs} +1 -1
  148. package/dist/{rolldown-runtime-BhflRrBs.mjs → rolldown-runtime-DNg-KNCk.mjs} +1 -1
  149. package/dist/runtimeCapabilities-Dm88DaTW.mjs +49 -0
  150. package/dist/{schedules-C2Q3uv2d.mjs → schedules-CAcZgia0.mjs} +3 -3
  151. package/dist/{schemaConverter-Crjvczi_.mjs → schemaConverter-XH1RZRyu.mjs} +1 -1
  152. package/dist/{schemaIR-CnyKK_1j.mjs → schemaIR-CDvclAew.mjs} +2 -2
  153. package/dist/schemas/index.mjs +1 -1
  154. package/dist/scim/index.mjs +2 -2
  155. package/dist/scope/index.mjs +5 -5
  156. package/dist/{scope-afz_Ieek.mjs → scope-BaWcqBvr.mjs} +4 -4
  157. package/dist/{simpleEqualityMatcher-C4KiMWUa.mjs → simpleEqualityMatcher-Se8VrsaP.mjs} +1 -1
  158. package/dist/{sse-B9P4Y-UI.mjs → sse-Cf0jUHsh.mjs} +5 -5
  159. package/dist/{sseStream-B3zb_d1h.mjs → sseStream-Bvpi-UXQ.mjs} +2 -2
  160. package/dist/{store-helpers-DmEMHlPQ.mjs → store-helpers-B88p99Z2.mjs} +1 -1
  161. package/dist/{streaming-DPZdQmDz.mjs → streaming-DsT1B5zJ.mjs} +1 -1
  162. package/dist/{subscribe-helpers-sp5xTDVA.mjs → subscribe-helpers-CLIOHsOK.mjs} +2 -2
  163. package/dist/sync/changelog.mjs +1 -1
  164. package/dist/testing/cleanupStoreContract.d.mts +1 -1
  165. package/dist/testing/cleanupStoreContract.mjs +3 -1
  166. package/dist/testing/index.d.mts +24 -12
  167. package/dist/testing/index.mjs +24 -12
  168. package/dist/testing/outboxStoreContract.mjs +1 -1
  169. package/dist/testing/storageContract.mjs +1 -1
  170. package/dist/{transactionContext-BvLKvOIL.mjs → transactionContext-BYtWnwAS.mjs} +1 -1
  171. package/dist/{typeGuards-B_5-hKjJ.mjs → typeGuards-jjKJDN13.mjs} +1 -1
  172. package/dist/types/index.d.mts +3 -3
  173. package/dist/types/index.mjs +1 -1
  174. package/dist/types/storage.mjs +1 -1
  175. package/dist/{types-CT5vu6M0.d.mts → types-BcTumAz_.d.mts} +41 -7
  176. package/dist/{types-CwcUQ610.d.mts → types-BfC83KsP.d.mts} +15 -1
  177. package/dist/{types-DXYX7dIR.mjs → types-CoqIRrkY.mjs} +4 -4
  178. package/dist/{types-C4QE8qnm.d.mts → types-DVLddu2q.d.mts} +144 -1
  179. package/dist/usage/index.d.mts +1 -1
  180. package/dist/usage/index.mjs +0 -0
  181. package/dist/{userHelpers-BNsOXzOd.mjs → userHelpers-CWF5pbZD.mjs} +1 -1
  182. package/dist/utils/index.d.mts +57 -5
  183. package/dist/utils/index.mjs +12 -11
  184. package/dist/{utils-BtOha_Sp.mjs → utils-h1V_sT-t.mjs} +38 -7
  185. package/dist/{validate-PMCPR9El.mjs → validate-CdQlz52F.mjs} +2 -2
  186. package/dist/{versioning-D_rhHfZm.d.mts → versioning-DEs-_hFi.d.mts} +1 -1
  187. package/dist/{versioning-CKv2jz_U.mjs → versioning-rZbyLVD-.mjs} +3 -3
  188. package/package.json +17 -16
  189. package/skills/arc/SKILL.md +96 -4
  190. package/skills/arc/references/api-reference.md +19 -0
  191. package/skills/arc/references/production.md +2 -2
  192. package/dist/projection-CjHhM5W1.mjs +0 -18
  193. package/dist/repositoryFilter-DotlxG3L.mjs +0 -45
@@ -1,3 +1,3 @@
1
1
 
2
- import { n as RedisStreamTransport, r as RedisStreamTransportOptions, t as RedisStreamLike } from "../../redis-stream-qN6A-RFv.mjs";
2
+ import { n as RedisStreamTransport, r as RedisStreamTransportOptions, t as RedisStreamLike } from "../../redis-stream-mwLWlfHG.mjs";
3
3
  export { type RedisStreamLike, RedisStreamTransport, type RedisStreamTransportOptions };
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
2
  import sjson from "secure-json-parse";
3
3
  //#region src/events/transports/redis-stream.ts
4
4
  /**
@@ -1,5 +1,5 @@
1
1
 
2
- import { a as EventTransport, i as EventLogger, n as DomainEvent, r as EventHandler } from "../../EventTransport-2uVV34WU.mjs";
2
+ import { a as EventTransport, i as EventLogger, n as DomainEvent, r as EventHandler } from "../../EventTransport-BEVP50ka.mjs";
3
3
  //#region src/events/transports/redis.d.ts
4
4
  interface RedisLike {
5
5
  publish(channel: string, message: string): Promise<number>;
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
2
  import sjson from "secure-json-parse";
3
3
  //#region src/events/transports/redis.ts
4
4
  /**
@@ -1,10 +1,25 @@
1
1
 
2
- import { _ as HealthCheck, a as ModuleContribution, c as LoadResourcesOptions, d as loadResources, i as EventHandlerDefinition, l as ResourceLike, n as ArcModuleInput, o as ModuleDisposer, r as ArcModuleRegistry, s as ModuleSetupContext, t as ArcModule, u as ResourceModule } from "../types-CT5vu6M0.mjs";
3
- import { _ as collectModuleScheduledJobs, a as lazyModuleExports, c as getModuleState, d as resolveModule, f as orderModules, g as collectModuleHealthChecks, h as extendModule, i as hasModuleExports, l as hasModule, m as ModuleExtension, n as getModuleExports, o as lazyRequiredModuleExports, p as subscribeModuleEventHandlers, r as getOptionalModuleExports, s as ModuleState, t as defineModule, u as resolveContribution, v as collectModuleWorkflows } from "../index-ZWhLTp_s.mjs";
4
- import { c as ResolvedResourceDescriptor, l as describeResolvedModule, o as ResolvedModuleDescriptor, s as ResolvedModuleLifecycle } from "../fastify-augmentation-BppG5bMT.mjs";
5
- import { a as RawBodyOptions, c as BetterAuthOption, d as JwtAuthOption, i as MultipartOptions, l as CustomAuthenticatorOption, n as preloadResourcesAsync, o as UnderPressureOptions, r as CreateAppOptions, s as AuthOption, t as preloadResources, u as CustomPluginAuthOption } from "../preloadResources-T1hmlTEZ.mjs";
2
+ import { _ as HealthCheck, a as ModuleContribution, c as LoadResourcesOptions, d as loadResources, i as EventHandlerDefinition, l as ResourceLike, n as ArcModuleInput, o as ModuleDisposer, r as ArcModuleRegistry, s as ModuleSetupContext, t as ArcModule, u as ResourceModule } from "../types-BcTumAz_.mjs";
3
+ import { _ as collectModuleScheduledJobs, a as lazyModuleExports, c as getModuleState, d as resolveModule, f as orderModules, g as collectModuleHealthChecks, h as extendModule, i as hasModuleExports, l as hasModule, m as ModuleExtension, n as getModuleExports, o as lazyRequiredModuleExports, p as subscribeModuleEventHandlers, r as getOptionalModuleExports, s as ModuleState, t as defineModule, u as resolveContribution, v as collectModuleWorkflows } from "../index-C5NnMEKF.mjs";
4
+ import { c as ResolvedResourceDescriptor, l as describeResolvedModule, o as ResolvedModuleDescriptor, s as ResolvedModuleLifecycle } from "../fastify-augmentation-DVsTAy6X.mjs";
5
+ import { a as RawBodyOptions, c as BetterAuthOption, d as JwtAuthOption, i as MultipartOptions, l as CustomAuthenticatorOption, n as preloadResourcesAsync, o as UnderPressureOptions, r as CreateAppOptions, s as AuthOption, t as preloadResources, u as CustomPluginAuthOption } from "../preloadResources-g07ldtzh.mjs";
6
6
  import { FastifyInstance, FastifyServerOptions } from "fastify";
7
7
  //#region src/factory/createApp.d.ts
8
+ /**
9
+ * Default redact paths layered into Fastify's pino logger when the host
10
+ * doesn't supply a `logger.redact` of their own. Covers the common token /
11
+ * cookie / password leak surfaces — `Authorization` and `Cookie` headers
12
+ * (and their case-variants because Node lower-cases incoming headers but
13
+ * outgoing logs may carry either), API-key headers, and any nested
14
+ * `password` / `token` / `secret` / `apiKey` fields anywhere in the log
15
+ * tree.
16
+ *
17
+ * Hosts that need NO redaction (test fixtures, security audits) opt out
18
+ * with `logger: { redact: [] }`. Hosts that need MORE redaction supply
19
+ * their own `redact` and arc steps aside — this default never overrides
20
+ * an explicit setting. (2.15.1)
21
+ */
22
+ declare const DEFAULT_LOGGER_REDACT_PATHS: readonly ["req.headers.authorization", 'req.headers["x-api-key"]', 'req.headers["x-internal-api-key"]', "req.headers.cookie", 'req.headers["set-cookie"]', 'res.headers["set-cookie"]', "*.password", "*.passwordHash", "*.token", "*.accessToken", "*.refreshToken", "*.secret", "*.apiKey"];
8
23
  /**
9
24
  * Create a production-ready Fastify application with Arc framework.
10
25
  *
@@ -137,4 +152,4 @@ declare const testingPreset: Partial<CreateAppOptions>;
137
152
  declare const edgePreset: Partial<CreateAppOptions>;
138
153
  declare function getPreset(name: "production" | "development" | "testing" | "edge" | "worker"): Partial<CreateAppOptions>;
139
154
  //#endregion
140
- export { ArcFactory, type ArcModule, type ArcModuleInput, type ArcModuleRegistry, type ArcWorker, type AuthOption, type BetterAuthOption, type CreateAppOptions, type CreateWorkerOptions, type CustomAuthenticatorOption, type CustomPluginAuthOption, type EventHandlerDefinition, type FetchHandlerOptions, type JwtAuthOption, type LoadResourcesOptions, type ModuleContribution, type ModuleDisposer, type ModuleExtension, type ModuleSetupContext, type ModuleState, type MultipartOptions, type RawBodyOptions, type ResolvedModuleDescriptor, type ResolvedModuleLifecycle, type ResolvedResourceDescriptor, type ResourceLike, type ResourceModule, type UnderPressureOptions, type WorkerHealthOptions, collectModuleHealthChecks, collectModuleScheduledJobs, collectModuleWorkflows, createApp, createWorker, defineModule, describeResolvedModule, developmentPreset, edgePreset, extendModule, getModuleExports, getModuleState, getOptionalModuleExports, getPreset, hasModule, hasModuleExports, lazyModuleExports, lazyRequiredModuleExports, loadResources, orderModules, preloadResources, preloadResourcesAsync, productionPreset, resolveContribution, resolveModule, subscribeModuleEventHandlers, testingPreset, toFetchHandler };
155
+ export { ArcFactory, type ArcModule, type ArcModuleInput, type ArcModuleRegistry, type ArcWorker, type AuthOption, type BetterAuthOption, type CreateAppOptions, type CreateWorkerOptions, type CustomAuthenticatorOption, type CustomPluginAuthOption, DEFAULT_LOGGER_REDACT_PATHS, type EventHandlerDefinition, type FetchHandlerOptions, type JwtAuthOption, type LoadResourcesOptions, type ModuleContribution, type ModuleDisposer, type ModuleExtension, type ModuleSetupContext, type ModuleState, type MultipartOptions, type RawBodyOptions, type ResolvedModuleDescriptor, type ResolvedModuleLifecycle, type ResolvedResourceDescriptor, type ResourceLike, type ResourceModule, type UnderPressureOptions, type WorkerHealthOptions, collectModuleHealthChecks, collectModuleScheduledJobs, collectModuleWorkflows, createApp, createWorker, defineModule, describeResolvedModule, developmentPreset, edgePreset, extendModule, getModuleExports, getModuleState, getOptionalModuleExports, getPreset, hasModule, hasModuleExports, lazyModuleExports, lazyRequiredModuleExports, loadResources, orderModules, preloadResources, preloadResourcesAsync, productionPreset, resolveContribution, resolveModule, subscribeModuleEventHandlers, testingPreset, toFetchHandler };
@@ -1,9 +1,9 @@
1
- /*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
2
- import { r as mergeHealthChecks, t as healthPlugin } from "../health-5XnTa2uo.mjs";
3
- import { _ as collectModuleWorkflows, a as edgePreset, c as testingPreset, d as hasModule, f as orderModules, g as collectModuleScheduledJobs, h as collectModuleHealthChecks, i as developmentPreset, l as workerPreset, m as describeResolvedModule, n as createApp, o as getPreset, p as subscribeModuleEventHandlers, s as productionPreset, t as ArcFactory, u as getModuleState, v as resolveContribution, y as resolveModule } from "../createApp-Bv0m-Q6_.mjs";
4
- import { a as lazyModuleExports, i as hasModuleExports, n as getModuleExports, o as lazyRequiredModuleExports, r as getOptionalModuleExports, t as defineModule } from "../module-Br81am6m.mjs";
5
- import { t as loadResources } from "../loadResources-DisEAmkm.mjs";
6
- import { n as preloadResourcesAsync, t as preloadResources } from "../preloadResources-CDs87fTw.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { r as mergeHealthChecks, t as healthPlugin } from "../health-CasG2A28.mjs";
3
+ import { _ as collectModuleScheduledJobs, a as developmentPreset, b as resolveModule, c as productionPreset, d as getModuleState, f as hasModule, g as collectModuleHealthChecks, h as describeResolvedModule, l as testingPreset, m as subscribeModuleEventHandlers, n as DEFAULT_LOGGER_REDACT_PATHS, o as edgePreset, p as orderModules, r as createApp, s as getPreset, t as ArcFactory, u as workerPreset, v as collectModuleWorkflows, y as resolveContribution } from "../createApp-zR-DEesr.mjs";
4
+ import { a as lazyModuleExports, i as hasModuleExports, n as getModuleExports, o as lazyRequiredModuleExports, r as getOptionalModuleExports, t as defineModule } from "../module-CwKsgZXp.mjs";
5
+ import { t as loadResources } from "../loadResources-Bj-aSsXi.mjs";
6
+ import { n as preloadResourcesAsync, t as preloadResources } from "../preloadResources-BkyqeTDz.mjs";
7
7
  //#region src/factory/module/extend.ts
8
8
  /** Concatenate two contributions, resolving factories only when arc asks. */
9
9
  function mergeContribution(own, extra) {
@@ -244,4 +244,4 @@ function payloadTooLarge(limit) {
244
244
  });
245
245
  }
246
246
  //#endregion
247
- export { ArcFactory, collectModuleHealthChecks, collectModuleScheduledJobs, collectModuleWorkflows, createApp, createWorker, defineModule, describeResolvedModule, developmentPreset, edgePreset, extendModule, getModuleExports, getModuleState, getOptionalModuleExports, getPreset, hasModule, hasModuleExports, lazyModuleExports, lazyRequiredModuleExports, loadResources, orderModules, preloadResources, preloadResourcesAsync, productionPreset, resolveContribution, resolveModule, subscribeModuleEventHandlers, testingPreset, toFetchHandler };
247
+ export { ArcFactory, DEFAULT_LOGGER_REDACT_PATHS, collectModuleHealthChecks, collectModuleScheduledJobs, collectModuleWorkflows, createApp, createWorker, defineModule, describeResolvedModule, developmentPreset, edgePreset, extendModule, getModuleExports, getModuleState, getOptionalModuleExports, getPreset, hasModule, hasModuleExports, lazyModuleExports, lazyRequiredModuleExports, loadResources, orderModules, preloadResources, preloadResourcesAsync, productionPreset, resolveContribution, resolveModule, subscribeModuleEventHandlers, testingPreset, toFetchHandler };
@@ -1,8 +1,8 @@
1
1
 
2
- import { hn as HookSystem, z as ResourceRegistry } from "./index-CpzxqePp.mjs";
2
+ import { on as HookSystem, z as ResourceRegistry } from "./index-BcR2bFZQ.mjs";
3
3
  import { t as ExternalOpenApiPaths } from "./externalPaths-CmGOxOtD.mjs";
4
- import { _ as HealthCheck, f as ScheduleDefinition, r as ArcModuleRegistry, t as ArcModule } from "./types-CT5vu6M0.mjs";
5
- import { s as ModuleState } from "./index-ZWhLTp_s.mjs";
4
+ import { _ as HealthCheck, f as ScheduleDefinition, r as ArcModuleRegistry, t as ArcModule } from "./types-BcTumAz_.mjs";
5
+ import { s as ModuleState } from "./index-C5NnMEKF.mjs";
6
6
  import { FastifyPluginAsync } from "fastify";
7
7
  //#region src/factory/module/descriptor.d.ts
8
8
  /**
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
2
  //#region src/permissions/fields.ts
3
3
  /**
4
4
  * Field-Level Permissions
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
2
- import { t as pluralize } from "./pluralize-C2ZkKbsn.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { t as pluralize } from "./pluralize-B7xf8qZF.mjs";
3
3
  import { join } from "node:path";
4
4
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
5
5
  //#region src/cli/commands/generate/name-helpers.ts
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
2
- import { u as ValidationError } from "./errors-Bh1KK5ps.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { u as ValidationError } from "./errors-Cd_yy7aW.mjs";
3
3
  //#region src/utils/headers.ts
4
4
  /**
5
5
  * Canonical header typing + accessor.
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
2
  import { randomUUID } from "node:crypto";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/plugins/requestId.ts
@@ -1,3 +1,3 @@
1
1
 
2
- import { Cn as createHookSystem, Sn as beforeUpdate, _n as afterCreate, bn as beforeCreate, dn as HookHandler, fn as HookOperation, gn as HookSystemOptions, hn as HookSystem, ln as DefineHookOptions, mn as HookRegistration, pn as HookPhase, un as HookContext, vn as afterDelete, wn as defineHook, xn as beforeDelete, yn as afterUpdate } from "../index-CpzxqePp.mjs";
2
+ import { an as HookRegistration, cn as afterCreate, dn as beforeCreate, en as DefineHookOptions, fn as beforeDelete, hn as defineHook, in as HookPhase, ln as afterDelete, mn as createHookSystem, nn as HookHandler, on as HookSystem, pn as beforeUpdate, rn as HookOperation, sn as HookSystemOptions, tn as HookContext, un as afterUpdate } from "../index-BcR2bFZQ.mjs";
3
3
  export { type DefineHookOptions, type HookContext, type HookHandler, type HookOperation, type HookPhase, type HookRegistration, HookSystem, type HookSystemOptions, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
@@ -1,3 +1,3 @@
1
- /*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
2
- import { a as beforeCreate, c as createHookSystem, i as afterUpdate, l as defineHook, n as afterCreate, o as beforeDelete, r as afterDelete, s as beforeUpdate, t as HookSystem } from "../HookSystem-vimw5D7Z.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { a as beforeCreate, c as createHookSystem, i as afterUpdate, l as defineHook, n as afterCreate, o as beforeDelete, r as afterDelete, s as beforeUpdate, t as HookSystem } from "../HookSystem-DqXkMXkB.mjs";
3
3
  export { HookSystem, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
@@ -47,6 +47,22 @@ interface IdempotencyPluginOptions {
47
47
  * Omit for the common case where the store is per-deployment.
48
48
  */
49
49
  namespace?: string;
50
+ /**
51
+ * Boot-time store self-check (default: true). Writes one probe entry,
52
+ * verifies it reads back under ITS OWN key and NOT under a different key,
53
+ * then deletes it. Registration THROWS if the store fails — because the
54
+ * failure mode this catches is silent and catastrophic: a repository
55
+ * whose schema strips the key filter (observed live: a pathless Mongoose
56
+ * schema under `strictQuery: true`) collapses every idempotency key onto
57
+ * one shared row, and every request then replays the most recent cached
58
+ * response across keys AND across users. A store that cannot round-trip
59
+ * a key must never be allowed to serve traffic.
60
+ *
61
+ * Disable only for a store that genuinely cannot accept a probe write at
62
+ * boot — and if you disable it, the adapter's per-read identity checks
63
+ * remain as the runtime backstop.
64
+ */
65
+ selfCheck?: boolean;
50
66
  }
51
67
  declare module "fastify" {
52
68
  interface FastifyRequest {
@@ -92,6 +108,34 @@ declare const idempotencyPlugin: FastifyPluginAsync<IdempotencyPluginOptions>;
92
108
  declare const _default: FastifyPluginAsync<IdempotencyPluginOptions>;
93
109
  //#endregion
94
110
  //#region src/idempotency/repository-idempotency-adapter.d.ts
111
+ /**
112
+ * The backing repository returned a document whose key does not match the
113
+ * key that was asked for — which means the repository is NOT applying the
114
+ * key filter. Concretely observed (2026-08-14, be-prod): a Mongoose schema
115
+ * with no declared paths (`new Schema({}, { _id: false })`) under a global
116
+ * `mongoose.set('strictQuery', true)` strips EVERY filter key as an
117
+ * "unknown path", so `getOne({ _id: key })` becomes `getOne({})` — one
118
+ * shared document then absorbs every idempotency key, and every request
119
+ * replays the most recent cached response ACROSS KEYS AND ACROSS USERS
120
+ * (a cancel response for order A was served as "success" for order B,
121
+ * which was never actually canceled).
122
+ *
123
+ * That failure mode is silent by construction — every read "succeeds" with
124
+ * a plausible document — so the adapter verifies the identity of every
125
+ * document it gets back and THROWS this instead of trusting it. Returning
126
+ * `undefined` (treat as miss) would be worse, not safer: the very next
127
+ * `tryLock`/`set` on the same broken repository would corrupt the shared
128
+ * document again.
129
+ *
130
+ * Fix on the host side: declare the key path on the schema (e.g.
131
+ * `_id: String`) and/or set `strictQuery: false` in the SCHEMA options so
132
+ * filters on it are never stripped — see `idempotencyPlugin`'s
133
+ * `repository` option docs.
134
+ */
135
+ declare class IdempotencyStoreMisconfiguredError extends Error {
136
+ readonly code = "IDEMPOTENCY_STORE_MISCONFIGURED";
137
+ constructor(operation: string, expectedKey: string, actualKey: unknown);
138
+ }
95
139
  declare function repositoryAsIdempotencyStore(repository: RepositoryLike, defaultTtlMs: number): IdempotencyStore;
96
140
  //#endregion
97
141
  //#region src/idempotency/stores/memory.d.ts
@@ -129,4 +173,4 @@ declare class MemoryIdempotencyStore implements IdempotencyStore {
129
173
  private evictOldest;
130
174
  }
131
175
  //#endregion
132
- export { type IdempotencyLock, type IdempotencyPluginOptions, type IdempotencyResult, type IdempotencyStore, MemoryIdempotencyStore, type MemoryIdempotencyStoreOptions, type RedisClient, type RedisIdempotencyStoreOptions, createIdempotencyResult, _default as idempotencyPlugin, idempotencyPlugin as idempotencyPluginFn, repositoryAsIdempotencyStore };
176
+ export { type IdempotencyLock, type IdempotencyPluginOptions, type IdempotencyResult, type IdempotencyStore, IdempotencyStoreMisconfiguredError, MemoryIdempotencyStore, type MemoryIdempotencyStoreOptions, type RedisClient, type RedisIdempotencyStoreOptions, createIdempotencyResult, _default as idempotencyPlugin, idempotencyPlugin as idempotencyPluginFn, repositoryAsIdempotencyStore };
@@ -1,12 +1,43 @@
1
- /*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
2
- import { n as requireSingleHeaderValue } from "../headers-BXjQYbeC.mjs";
3
- import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-DmEMHlPQ.mjs";
4
- import { t as createIdempotencyResult } from "../interface-BP4IJCBO.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { n as requireSingleHeaderValue } from "../headers-CveNO9gR.mjs";
3
+ import { n as createSafeGetOne, t as createIsDuplicateKeyError } from "../store-helpers-B88p99Z2.mjs";
4
+ import { t as createIdempotencyResult } from "../interface-DznJrm9R.mjs";
5
5
  import { and, eq, exists, gt, lt, or, startsWith } from "@classytic/repo-core/filter";
6
6
  import { createHash } from "node:crypto";
7
7
  import fp from "fastify-plugin";
8
8
  import { update } from "@classytic/repo-core/update";
9
9
  //#region src/idempotency/repository-idempotency-adapter.ts
10
+ /**
11
+ * The backing repository returned a document whose key does not match the
12
+ * key that was asked for — which means the repository is NOT applying the
13
+ * key filter. Concretely observed (2026-08-14, be-prod): a Mongoose schema
14
+ * with no declared paths (`new Schema({}, { _id: false })`) under a global
15
+ * `mongoose.set('strictQuery', true)` strips EVERY filter key as an
16
+ * "unknown path", so `getOne({ _id: key })` becomes `getOne({})` — one
17
+ * shared document then absorbs every idempotency key, and every request
18
+ * replays the most recent cached response ACROSS KEYS AND ACROSS USERS
19
+ * (a cancel response for order A was served as "success" for order B,
20
+ * which was never actually canceled).
21
+ *
22
+ * That failure mode is silent by construction — every read "succeeds" with
23
+ * a plausible document — so the adapter verifies the identity of every
24
+ * document it gets back and THROWS this instead of trusting it. Returning
25
+ * `undefined` (treat as miss) would be worse, not safer: the very next
26
+ * `tryLock`/`set` on the same broken repository would corrupt the shared
27
+ * document again.
28
+ *
29
+ * Fix on the host side: declare the key path on the schema (e.g.
30
+ * `_id: String`) and/or set `strictQuery: false` in the SCHEMA options so
31
+ * filters on it are never stripped — see `idempotencyPlugin`'s
32
+ * `repository` option docs.
33
+ */
34
+ var IdempotencyStoreMisconfiguredError = class extends Error {
35
+ code = "IDEMPOTENCY_STORE_MISCONFIGURED";
36
+ constructor(operation, expectedKey, actualKey) {
37
+ super(`idempotency repository store: ${operation} for key '${expectedKey}' returned a document keyed '${String(actualKey)}' — the repository is not applying the key filter (commonly: a pathless Mongoose schema under strictQuery:true strips the filter to {}). Declare the key path on the schema (e.g. _id: String) and set strictQuery: false in the schema options. Refusing to serve cross-key results.`);
38
+ this.name = "IdempotencyStoreMisconfiguredError";
39
+ }
40
+ };
10
41
  function repositoryAsIdempotencyStore(repository, defaultTtlMs) {
11
42
  const missing = [];
12
43
  if (typeof repository.getOne !== "function") missing.push("getOne");
@@ -17,11 +48,23 @@ function repositoryAsIdempotencyStore(repository, defaultTtlMs) {
17
48
  const idField = repository.idField ?? "_id";
18
49
  const isDuplicateKeyError = createIsDuplicateKeyError(repository);
19
50
  const safeGetOne = createSafeGetOne(repository);
51
+ /**
52
+ * Every document read back MUST carry the key it was fetched by. A
53
+ * mismatch means the repository dropped the filter (see
54
+ * {@link IdempotencyStoreMisconfiguredError}) — fail loud, never serve
55
+ * or mutate a cross-key document.
56
+ */
57
+ function assertKeyIdentity(operation, doc, expectedKey) {
58
+ const actual = doc[idField];
59
+ if (String(actual) !== expectedKey) throw new IdempotencyStoreMisconfiguredError(operation, expectedKey, actual);
60
+ }
20
61
  return {
21
62
  name: "repository",
22
63
  async get(key) {
23
64
  const doc = await safeGetOne(eq(idField, key));
24
- if (!doc?.result) return void 0;
65
+ if (!doc) return void 0;
66
+ assertKeyIdentity("get", doc, key);
67
+ if (!doc.result) return void 0;
25
68
  if (new Date(doc.expiresAt) < /* @__PURE__ */ new Date()) return void 0;
26
69
  return {
27
70
  key,
@@ -33,7 +76,7 @@ function repositoryAsIdempotencyStore(repository, defaultTtlMs) {
33
76
  };
34
77
  },
35
78
  async set(key, result) {
36
- await r.findOneAndUpdate(eq(idField, key), update({
79
+ const doc = await r.findOneAndUpdate(eq(idField, key), update({
37
80
  set: {
38
81
  result: {
39
82
  statusCode: result.statusCode,
@@ -43,11 +86,13 @@ function repositoryAsIdempotencyStore(repository, defaultTtlMs) {
43
86
  createdAt: result.createdAt,
44
87
  expiresAt: result.expiresAt
45
88
  },
89
+ setOnInsert: { [idField]: key },
46
90
  unset: ["lock"]
47
91
  }), {
48
92
  upsert: true,
49
93
  returnDocument: "after"
50
94
  });
95
+ if (doc) assertKeyIdentity("set", doc, key);
51
96
  },
52
97
  async tryLock(key, requestId, ttlMs) {
53
98
  const now = /* @__PURE__ */ new Date();
@@ -60,6 +105,7 @@ function repositoryAsIdempotencyStore(repository, defaultTtlMs) {
60
105
  expiresAt: lockExpiresAt
61
106
  } },
62
107
  setOnInsert: {
108
+ [idField]: key,
63
109
  createdAt: now,
64
110
  expiresAt: docExpiresAt
65
111
  }
@@ -67,6 +113,7 @@ function repositoryAsIdempotencyStore(repository, defaultTtlMs) {
67
113
  upsert: true,
68
114
  returnDocument: "after"
69
115
  });
116
+ if (doc) assertKeyIdentity("tryLock", doc, key);
70
117
  return doc !== null && doc !== void 0;
71
118
  } catch (err) {
72
119
  if (isDuplicateKeyError(err)) return false;
@@ -90,6 +137,7 @@ function repositoryAsIdempotencyStore(repository, defaultTtlMs) {
90
137
  async findByPrefix(prefix) {
91
138
  const doc = await safeGetOne(and(startsWith(idField, prefix, "sensitive"), exists("result", true), gt("expiresAt", /* @__PURE__ */ new Date())));
92
139
  if (!doc?.result) return void 0;
140
+ if (!String(doc[idField] ?? "").startsWith(prefix)) throw new IdempotencyStoreMisconfiguredError("findByPrefix", prefix, doc[idField]);
93
141
  return {
94
142
  key: String(doc[idField] ?? prefix),
95
143
  statusCode: doc.result.statusCode,
@@ -287,8 +335,41 @@ const idempotencyPlugin = async (fastify, opts = {}) => {
287
335
  "POST",
288
336
  "PUT",
289
337
  "PATCH"
290
- ], include, exclude, repository, store: explicitStore, retryAfterSeconds = 1, namespace } = opts;
338
+ ], include, exclude, repository, store: explicitStore, retryAfterSeconds = 1, namespace, selfCheck = true } = opts;
291
339
  const store = repository ? repositoryAsIdempotencyStore(repository, ttlMs) : explicitStore ?? new MemoryIdempotencyStore({ ttlMs });
340
+ /**
341
+ * Who owns the store's lifecycle — arc closes ONLY what arc built.
342
+ *
343
+ * A host-supplied `store` may outlive this app: two arc apps in one process
344
+ * (a documented topology) can share one, and `MemoryIdempotencyStore.close()`
345
+ * CLEARS its maps. Closing on the first app's shutdown therefore wiped the
346
+ * second app's live idempotency records — replayable requests silently
347
+ * became re-executable. A store handed in from outside is the host's to
348
+ * close. The same rule now applies to the events transport and the
349
+ * query-cache store, which had the identical defect.
350
+ *
351
+ * The `repository` path builds its own adapter here, so arc owns that
352
+ * wrapper — but the adapter has no `close`, and the underlying repository
353
+ * (host-owned) is never touched.
354
+ */
355
+ const ownsStore = !explicitStore;
356
+ if (enabled && selfCheck) {
357
+ const probeSuffix = createHash("sha256").update(`${process.pid}:${Date.now()}:${Math.random()}`).digest("hex").slice(0, 12);
358
+ const probeKeyA = `__arc_idempotency_selfcheck__:${probeSuffix}:a`;
359
+ const probeKeyB = `__arc_idempotency_selfcheck__:${probeSuffix}:b`;
360
+ /** Correctness verdicts rethrow; everything else degrades to a warning. */
361
+ class SelfCheckViolation extends Error {}
362
+ try {
363
+ await store.set(probeKeyA, createIdempotencyResult(299, { probe: true }, {}, 6e4));
364
+ if ((await store.get(probeKeyA))?.statusCode !== 299) fastify.log?.warn?.({ probe: "own-key" }, "idempotencyPlugin self-check: probe entry did not read back under its own key. This is usually the store being unreachable at boot (connection not ready), not a misconfiguration — continuing, with the adapter's per-read key-identity checks as the runtime backstop. If keyed requests later fail with IDEMPOTENCY_STORE_MISCONFIGURED, the store's key filter is being stripped (see IdempotencyStoreMisconfiguredError).");
365
+ else if (await store.get(probeKeyB)) throw new SelfCheckViolation("idempotencyPlugin self-check: a probe read under key B returned key A's entry — the store is ignoring the key filter, which in production replays cached responses across keys and users (observed cause: a pathless Mongoose schema under strictQuery:true strips every filter to {}). Declare the key path on the schema (e.g. _id: String) and set strictQuery: false in the schema options.");
366
+ } catch (err) {
367
+ if (err instanceof SelfCheckViolation || err?.code === "IDEMPOTENCY_STORE_MISCONFIGURED") throw err;
368
+ fastify.log?.warn?.({ err }, "idempotencyPlugin self-check could not complete (store unreachable at boot?) — continuing. The adapter's per-read key-identity checks remain the runtime backstop.");
369
+ } finally {
370
+ await store.deleteByPrefix(`__arc_idempotency_selfcheck__:${probeSuffix}:`).catch(() => {});
371
+ }
372
+ }
292
373
  if (!enabled) {
293
374
  fastify.decorate("idempotency", {
294
375
  invalidate: async () => {},
@@ -431,7 +512,7 @@ const idempotencyPlugin = async (fastify, opts = {}) => {
431
512
  await store.unlock(fullKey, request.id);
432
513
  });
433
514
  fastify.addHook("onClose", async () => {
434
- await store.close?.();
515
+ if (ownsStore) await store.close?.();
435
516
  });
436
517
  fastify.log?.debug?.({
437
518
  headerName,
@@ -444,4 +525,4 @@ var idempotencyPlugin_default = fp(idempotencyPlugin, {
444
525
  fastify: "5.x"
445
526
  });
446
527
  //#endregion
447
- export { MemoryIdempotencyStore, createIdempotencyResult, idempotencyPlugin_default as idempotencyPlugin, idempotencyPlugin as idempotencyPluginFn, repositoryAsIdempotencyStore };
528
+ export { IdempotencyStoreMisconfiguredError, MemoryIdempotencyStore, createIdempotencyResult, idempotencyPlugin_default as idempotencyPlugin, idempotencyPlugin as idempotencyPluginFn, repositoryAsIdempotencyStore };
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
2
  //#region src/idempotency/stores/redis.ts
3
3
  var RedisIdempotencyStore = class {
4
4
  name = "redis";
@@ -1,7 +1,7 @@
1
1
 
2
- import { r as CacheStore, t as CacheLogger } from "./interface-BOk3YnTz.mjs";
3
2
  import { i as RequestScope, n as Mandate } from "./types-ChuShpCP.mjs";
4
- import { i as PermissionContext, r as PermissionCheck, t as AuthorizationDecision } from "./types-B7XeLEgK.mjs";
3
+ import { l as PermissionCheck, s as AuthorizationDecision, u as PermissionContext } from "./base-Csjc2oF-.mjs";
4
+ import { r as CacheStore, t as CacheLogger } from "./interface-BOk3YnTz.mjs";
5
5
  import { FastifyReply, FastifyRequest } from "fastify";
6
6
  //#region src/permissions/agent.d.ts
7
7
  /**
@@ -1021,6 +1021,16 @@ interface PermissionMatrixRegistry {
1021
1021
  name: string;
1022
1022
  permissions?: unknown;
1023
1023
  }>;
1024
+ /**
1025
+ * Custom routes. Only those declaring `capability` are published — see the
1026
+ * loop in `introspectRegistry` for why a route needs an explicit name.
1027
+ */
1028
+ customRoutes?: ReadonlyArray<{
1029
+ method: string;
1030
+ path: string;
1031
+ capability?: string;
1032
+ permissions?: unknown;
1033
+ }>;
1024
1034
  }>;
1025
1035
  }
1026
1036
  interface PermissionMatrixOptions {