@classytic/arc 2.40.0 → 2.41.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 (187) hide show
  1. package/dist/{BaseController-BqJtbiUA.mjs → BaseController-DYJRZ0EJ.mjs} +18 -12
  2. package/dist/{EventTransport-BPOQsEer.d.mts → EventTransport-CbUKDzZZ.d.mts} +25 -0
  3. package/dist/{EventTransport-BUkTwY_x.mjs → EventTransport-n7qO5Cz3.mjs} +11 -2
  4. package/dist/{HookSystem-96nzZLmk.mjs → HookSystem-CxvZBo77.mjs} +2 -2
  5. package/dist/{ResourceRegistry-B9WnuG2Q.mjs → ResourceRegistry-Cu7uTJp9.mjs} +2 -2
  6. package/dist/{actionPermissions-4OGbe3Hf.mjs → actionPermissions-DPwPWPOV.mjs} +7 -6
  7. package/dist/audit/index.d.mts +2 -2
  8. package/dist/audit/index.mjs +10 -3
  9. package/dist/auth/audit.mjs +1 -1
  10. package/dist/auth/index.d.mts +2 -2
  11. package/dist/auth/index.mjs +12 -6
  12. package/dist/auth/redis-session.mjs +1 -1
  13. package/dist/{authorizationDecision-D_LFvMlm.mjs → authorizationDecision-2YY_Kaj1.mjs} +2 -2
  14. package/dist/{base-C-NL2fTi.d.mts → base-CxrV1LmG.d.mts} +10 -0
  15. package/dist/{buildHandler-BG_CHXqQ.mjs → buildHandler-CUhjGHGZ.mjs} +4 -4
  16. package/dist/cache/index.d.mts +4 -2
  17. package/dist/cache/index.mjs +4 -4
  18. package/dist/{caching-Bqcn3Brl.mjs → caching-DsWDjIxx.mjs} +2 -2
  19. package/dist/cleanup/index.d.mts +2 -2
  20. package/dist/cleanup/index.mjs +4 -4
  21. package/dist/cli/commands/describe.d.mts +1 -1
  22. package/dist/cli/commands/describe.mjs +3 -3
  23. package/dist/cli/commands/docs.mjs +3 -3
  24. package/dist/cli/commands/doctor.mjs +1 -1
  25. package/dist/cli/commands/generate.mjs +2 -2
  26. package/dist/cli/commands/init.mjs +2 -2
  27. package/dist/cli/commands/introspect.mjs +2 -2
  28. package/dist/cli/index.mjs +3 -3
  29. package/dist/{constants-BQ2FbhPB.mjs → constants-BxLgNFF7.mjs} +1 -1
  30. package/dist/context/index.mjs +36 -11
  31. package/dist/core/index.d.mts +2 -2
  32. package/dist/core/index.mjs +7 -7
  33. package/dist/{core-CsZR037F.mjs → core-iNGqYerO.mjs} +3 -3
  34. package/dist/{createActionRouter-BR93gCKg.mjs → createActionRouter-BBlbPs3k.mjs} +7 -7
  35. package/dist/{createAggregationRouter-CF40Aw95.mjs → createAggregationRouter-Dv5SuK2x.mjs} +7 -7
  36. package/dist/{createMcpServer-BVTs2S5G.d.mts → createMcpServer-CbDWkZ1T.d.mts} +1 -1
  37. package/dist/{defineAggregation-BDA2Tw7v.mjs → defineAggregation-UyeurGkp.mjs} +1 -1
  38. package/dist/{defineResource-DaIySrQr.mjs → defineResource-DzGT-2LP.mjs} +18 -18
  39. package/dist/discovery/index.mjs +1 -1
  40. package/dist/docs/index.d.mts +1 -1
  41. package/dist/docs/index.mjs +3 -3
  42. package/dist/{elevation-CZy6n50b.mjs → elevation-BF-vhGxY.mjs} +4 -4
  43. package/dist/encryption/index.mjs +3 -3
  44. package/dist/{errorHandler-By9keRvX.mjs → errorHandler-CIMkCOWm.mjs} +3 -3
  45. package/dist/{errors-BHD3L8of.mjs → errors-C_YhELhe.mjs} +1 -1
  46. package/dist/{eventPlugin-DfHaKEWQ.d.mts → eventPlugin-B52abJ8W.d.mts} +1 -1
  47. package/dist/{eventPlugin-DB26V7uX.mjs → eventPlugin-CmXaPWLv.mjs} +5 -5
  48. package/dist/events/index.d.mts +4 -4
  49. package/dist/events/index.mjs +5 -5
  50. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  51. package/dist/events/transports/redis-stream-entry.mjs +15 -6
  52. package/dist/events/transports/redis.d.mts +1 -1
  53. package/dist/events/transports/redis.mjs +2 -2
  54. package/dist/factory/index.d.mts +5 -5
  55. package/dist/factory/index.mjs +5 -5
  56. package/dist/{fastify-augmentation-HncZMmze.d.mts → fastify-augmentation-Cq2nHVaW.d.mts} +3 -3
  57. package/dist/{fields-fA-Dkou5.mjs → fields-BTyPLHK0.mjs} +1 -1
  58. package/dist/{generate-BSSdtiOy.mjs → generate-D_YmiCNf.mjs} +2 -2
  59. package/dist/{headers-BFEEshDS.mjs → headers-CNECDE6q.mjs} +2 -2
  60. package/dist/{health-BlGHjkqZ.mjs → health-CxQzbJmr.mjs} +10 -2
  61. package/dist/hooks/index.d.mts +1 -1
  62. package/dist/hooks/index.mjs +2 -2
  63. package/dist/idempotency/index.d.mts +1 -1
  64. package/dist/idempotency/index.mjs +4 -4
  65. package/dist/idempotency/redis.d.mts +1 -1
  66. package/dist/idempotency/redis.mjs +1 -1
  67. package/dist/{index-BtYoMip1.d.mts → index-BHdZD8zK.d.mts} +10 -2
  68. package/dist/{index-DbMglURO.d.mts → index-CFfLKMH4.d.mts} +1 -1
  69. package/dist/{index-eyg5WEcy.d.mts → index-CbJiYrfv.d.mts} +1 -1
  70. package/dist/{index-SCsOJxWB.d.mts → index-D4u76eQW.d.mts} +3 -3
  71. package/dist/{index-D3sIPcD4.d.mts → index-DHbyPo5j.d.mts} +6 -2
  72. package/dist/index.d.mts +5 -5
  73. package/dist/index.mjs +11 -11
  74. package/dist/{init-pl88PHzb.mjs → init-Y2MlSN9n.mjs} +1 -1
  75. package/dist/integrations/event-gateway.d.mts +1 -1
  76. package/dist/integrations/event-gateway.mjs +2 -2
  77. package/dist/integrations/index.d.mts +2 -2
  78. package/dist/integrations/index.mjs +1 -1
  79. package/dist/integrations/jobs/index.d.mts +1 -1
  80. package/dist/integrations/jobs/index.mjs +2 -2
  81. package/dist/integrations/mcp/index.d.mts +4 -4
  82. package/dist/integrations/mcp/index.mjs +2 -2
  83. package/dist/integrations/mcp/testing.d.mts +2 -2
  84. package/dist/integrations/mcp/testing.mjs +2 -2
  85. package/dist/integrations/streamline.mjs +3 -3
  86. package/dist/integrations/webhooks.d.mts +2 -2
  87. package/dist/integrations/webhooks.mjs +3 -3
  88. package/dist/integrations/websocket-pushref-redis.d.mts +1 -1
  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 +12 -1
  92. package/dist/{interface-DjtFnZxH.mjs → interface-BIpgzbZl.mjs} +1 -1
  93. package/dist/{jsonBody-Dx6jH_Nb.mjs → jsonBody-Cq9KYl2Z.mjs} +2 -2
  94. package/dist/{keys-Ds3ekBiu.mjs → keys-Cmv4cBRa.mjs} +1 -1
  95. package/dist/{loadResources-E5UFlRrT.mjs → loadResources-CblF7xt2.mjs} +2 -2
  96. package/dist/{loadResourcesFromEntry-C2jrJbWG.mjs → loadResourcesFromEntry-99fIMC3p.mjs} +2 -2
  97. package/dist/logger/index.mjs +1 -1
  98. package/dist/{mcpPlugin-D-3OLxNz.mjs → mcpPlugin-xF3Gw-HW.mjs} +15 -15
  99. package/dist/{memory-CNvjxzB2.mjs → memory-CpDZ9NPw.mjs} +2 -2
  100. package/dist/{metrics-P37sNV5H.mjs → metrics-BaKnq8ag.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-CNcwCKUJ.mjs → module-BkQEesNQ.mjs} +1 -1
  105. package/dist/{multipartBody-Bl_gU3Wg.mjs → multipartBody-C92aJ8am.mjs} +1 -1
  106. package/dist/{openapi-BYrL8zvY.mjs → openapi-C3LFRzPq.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-CzsKRBvO.d.mts → outbox-module-BHdUnuuK.d.mts} +6 -2
  110. package/dist/{outbox-module-6DMC_WNu.mjs → outbox-module-dsCyLxXH.mjs} +9 -6
  111. package/dist/permissions/index.d.mts +2 -2
  112. package/dist/permissions/index.mjs +5 -5
  113. package/dist/{permissions-C0GpDsB_.mjs → permissions-DiHXy8Ck.mjs} +12 -6
  114. package/dist/{pipe-4_XamfxI.mjs → pipe-CBVmUJ-j.mjs} +2 -2
  115. package/dist/pipeline/index.d.mts +1 -1
  116. package/dist/pipeline/index.mjs +2 -2
  117. package/dist/plugins/index.d.mts +6 -36
  118. package/dist/plugins/index.mjs +33 -22
  119. package/dist/plugins/response-cache.mjs +9 -2
  120. package/dist/plugins/tracing-entry.mjs +2 -2
  121. package/dist/{pluralize-BaQ62hOW.mjs → pluralize-2_U6QZQg.mjs} +1 -1
  122. package/dist/{preloadResources-BAx5s9EF.mjs → preloadResources-Bbp4QJ8V.mjs} +33 -26
  123. package/dist/{preloadResources-DVgPCNcD.d.mts → preloadResources-CjS2OfpU.d.mts} +13 -8
  124. package/dist/presets/filesUpload.d.mts +2 -2
  125. package/dist/presets/filesUpload.mjs +5 -5
  126. package/dist/presets/index.d.mts +2 -2
  127. package/dist/presets/index.mjs +2 -2
  128. package/dist/presets/multiTenant.d.mts +38 -1
  129. package/dist/presets/multiTenant.mjs +24 -6
  130. package/dist/presets/search.d.mts +2 -2
  131. package/dist/presets/search.mjs +2 -2
  132. package/dist/{presets-CAaqVVcW.mjs → presets-BdlugYTc.mjs} +4 -4
  133. package/dist/{projection-qbCOEvsh.mjs → projection-Uvgp-EEj.mjs} +2 -2
  134. package/dist/{queryCachePlugin-2Pp9w-8D.mjs → queryCachePlugin-B5F09bYr.mjs} +11 -5
  135. package/dist/{rateLimitKey-umrS6-vu.mjs → rateLimitKey-CK-EU2L8.mjs} +1 -1
  136. package/dist/{realtime-zzoNLDtj.mjs → realtime-FnnD0n3Z.mjs} +9 -9
  137. package/dist/{redis-CduhKsJi.d.mts → redis-Bzi1y3F9.d.mts} +10 -2
  138. package/dist/{redis-stream-DSsPyYzd.d.mts → redis-stream-BPKscsTB.d.mts} +6 -6
  139. package/dist/{registerRoute-_6zHiz0x.mjs → registerRoute-DRsSHPSM.mjs} +6 -6
  140. package/dist/registry/index.d.mts +2 -2
  141. package/dist/registry/index.mjs +3 -3
  142. package/dist/{registry-CEpoRpLP.mjs → registry-D3y8VEJ1.mjs} +2 -2
  143. package/dist/{renewingLease-B5Grm0pI.mjs → renewingLease-B3VYh5aU.mjs} +1 -1
  144. package/dist/{replyHelpers-9h-a592u.mjs → replyHelpers-DPHsdw-5.mjs} +2 -2
  145. package/dist/{requestContext-D4PuGhEw.mjs → requestContext-cSVKnYPk.mjs} +1 -1
  146. package/dist/{rolldown-runtime-DzE6ikSH.mjs → rolldown-runtime-DjDuyglE.mjs} +1 -1
  147. package/dist/{runtimeCapabilities-Bo7rSKjm.mjs → runtimeCapabilities-DSA_dH1_.mjs} +31 -5
  148. package/dist/{schedules-Dm21pqHU.mjs → schedules-BktJb3Y3.mjs} +4 -4
  149. package/dist/{schemaConverter-DENbixyA.mjs → schemaConverter-BLCSmNbr.mjs} +1 -1
  150. package/dist/{schemaIR-C2qUNzC6.mjs → schemaIR-K16Bb5BX.mjs} +2 -2
  151. package/dist/schemas/index.mjs +1 -1
  152. package/dist/scim/index.mjs +2 -2
  153. package/dist/scope/index.mjs +5 -5
  154. package/dist/{scope-CdYxQVxt.mjs → scope-jSxuBTFM.mjs} +4 -4
  155. package/dist/{simpleEqualityMatcher-Cldubvul.mjs → simpleEqualityMatcher-BiOnyflP.mjs} +1 -1
  156. package/dist/{sse-DbyXoQun.mjs → sse-CH7Slxc1.mjs} +5 -5
  157. package/dist/{sseStream-BfZtL5-m.mjs → sseStream-CN-Lh1Tu.mjs} +2 -2
  158. package/dist/{store-helpers-BfyOd5i6.mjs → store-helpers-9DX9-1j_.mjs} +1 -1
  159. package/dist/{streaming-CFwCzEvU.mjs → streaming-dvppnxsr.mjs} +1 -1
  160. package/dist/{subscribe-helpers-KgVEcn8L.mjs → subscribe-helpers-AVYPgqTl.mjs} +2 -2
  161. package/dist/sync/changelog.mjs +1 -1
  162. package/dist/testing/cleanupStoreContract.mjs +1 -1
  163. package/dist/testing/index.d.mts +5 -5
  164. package/dist/testing/index.mjs +10 -10
  165. package/dist/testing/outboxStoreContract.mjs +1 -1
  166. package/dist/testing/storageContract.mjs +1 -1
  167. package/dist/{transactionContext-46KyUADP.mjs → transactionContext-DCWMI6hV.mjs} +1 -1
  168. package/dist/{typeGuards-t_CVgRXN.mjs → typeGuards-D7tHFdH6.mjs} +1 -1
  169. package/dist/types/index.d.mts +2 -2
  170. package/dist/types/index.mjs +1 -1
  171. package/dist/types/storage.mjs +1 -1
  172. package/dist/{types-CNQyOrLk.mjs → types-CDy3-zw1.mjs} +4 -4
  173. package/dist/{types-9rvxn5Ym.d.mts → types-CWQn9-IC.d.mts} +1 -1
  174. package/dist/{types-BVlowlm7.d.mts → types-DfVDvkdP.d.mts} +19 -1
  175. package/dist/usage/index.d.mts +58 -2
  176. package/dist/usage/index.mjs +55 -4
  177. package/dist/{userHelpers-DLueLQdQ.mjs → userHelpers-DDMOZ_Pm.mjs} +1 -1
  178. package/dist/utils/index.d.mts +107 -5
  179. package/dist/utils/index.mjs +12 -12
  180. package/dist/{utils-CUFBrhq-.mjs → utils-B-zj_b__.mjs} +50 -9
  181. package/dist/{validate-DV3hRbsz.mjs → validate-R0G_JrnK.mjs} +2 -2
  182. package/dist/{versioning-P3V6ATyC.d.mts → versioning-D6JIK8Tk.d.mts} +58 -2
  183. package/dist/{versioning-BXwmj5SD.mjs → versioning-DuVWcu-F.mjs} +3 -3
  184. package/dist/{workScope-CoGpuzDX.mjs → workScope-BhsWde4k.mjs} +3 -4
  185. package/package.json +574 -574
  186. package/skills/arc/SKILL.md +8 -4
  187. package/skills/arc/references/production.md +94 -9
@@ -1,15 +1,15 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import { h as SYSTEM_FIELDS, o as DEFAULT_TENANT_FIELD } from "./constants-BQ2FbhPB.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import { h as SYSTEM_FIELDS, o as DEFAULT_TENANT_FIELD } from "./constants-BxLgNFF7.mjs";
3
3
  import { arcLog } from "./logger/index.mjs";
4
- import { a as conjoinPolicyFilters } from "./authorizationDecision-D_LFvMlm.mjs";
5
- import { d as createDomainError, f as createError, i as NotFoundError, p as isArcError, r as ForbiddenError, u as ValidationError } from "./errors-BHD3L8of.mjs";
6
- import { n as getUserRoles, t as getUserId } from "./userHelpers-DLueLQdQ.mjs";
7
- import { b as isElevated, c as getOrgId, n as PUBLIC_SCOPE, x as isMember } from "./types-CNQyOrLk.mjs";
8
- import { t as simpleEqualityMatcher } from "./simpleEqualityMatcher-Cldubvul.mjs";
9
- import { t as buildQueryKey } from "./keys-Ds3ekBiu.mjs";
10
- import { t as transactionContext } from "./transactionContext-46KyUADP.mjs";
11
- import { A as scheduleBackground, E as ArcQueryParser } from "./utils-CUFBrhq-.mjs";
12
- import { a as resolveEffectiveRoles, n as applyFieldWritePermissions } from "./fields-fA-Dkou5.mjs";
4
+ import { a as conjoinPolicyFilters } from "./authorizationDecision-2YY_Kaj1.mjs";
5
+ import { d as createDomainError, f as createError, i as NotFoundError, p as isArcError, r as ForbiddenError, u as ValidationError } from "./errors-C_YhELhe.mjs";
6
+ import { n as getUserRoles, t as getUserId } from "./userHelpers-DDMOZ_Pm.mjs";
7
+ import { b as isElevated, c as getOrgId, n as PUBLIC_SCOPE, x as isMember } from "./types-CDy3-zw1.mjs";
8
+ import { t as simpleEqualityMatcher } from "./simpleEqualityMatcher-BiOnyflP.mjs";
9
+ import { t as buildQueryKey } from "./keys-Cmv4cBRa.mjs";
10
+ import { t as transactionContext } from "./transactionContext-DCWMI6hV.mjs";
11
+ import { D as ArcQueryParser, j as scheduleBackground } from "./utils-B-zj_b__.mjs";
12
+ import { a as resolveEffectiveRoles, n as applyFieldWritePermissions } from "./fields-BTyPLHK0.mjs";
13
13
  import { policyRecordToFilter } from "@classytic/repo-core/filter";
14
14
  import { retryingTransaction } from "@classytic/repo-core/repository";
15
15
  import { isProductionEnv } from "@classytic/primitives/environment";
@@ -179,6 +179,7 @@ var AccessControl = class {
179
179
  */
180
180
  checkOrgScope(item, arcContext) {
181
181
  if (!this.tenantField) return true;
182
+ if (arcContext?._crossTenantRead === true) return true;
182
183
  const scope = arcContext?._scope;
183
184
  const orgId = scope ? getOrgId(scope) : void 0;
184
185
  if (!item || !orgId) return true;
@@ -423,6 +424,11 @@ function buildTenantRepoOptions(req, tenantField, arcContext) {
423
424
  if (cached) return cached;
424
425
  const out = {};
425
426
  const scope = arcContext?._scope;
427
+ if (arcContext?._crossTenantRead === true) {
428
+ out.bypassTenant = true;
429
+ req._tenantRepoOptions = out;
430
+ return out;
431
+ }
426
432
  if (tenantField) {
427
433
  const orgId = scope ? getOrgId(scope) : void 0;
428
434
  if (orgId) out[tenantField] = orgId;
@@ -948,7 +954,7 @@ var QueryResolver = class {
948
954
  let filters = conjoinPolicyFilters(parsed.filters, policyFilters);
949
955
  const scope = arcContext?._scope;
950
956
  const orgId = scope ? getOrgId(scope) : void 0;
951
- if (this.tenantField && orgId && !policyFilters?.[this.tenantField]) filters = conjoinPolicyFilters(filters, { [this.tenantField]: orgId });
957
+ if (this.tenantField && orgId && !arcContext?._crossTenantRead && !policyFilters?.[this.tenantField]) filters = conjoinPolicyFilters(filters, { [this.tenantField]: orgId });
952
958
  const portableFilters = toRepositoryFilter(filters);
953
959
  return {
954
960
  page,
@@ -42,6 +42,30 @@ interface MemoryEventTransportOptions {
42
42
  * QUEUE, not of the work.
43
43
  */
44
44
  handlerDispatch?: "sequential" | "parallel";
45
+ /**
46
+ * Called when a published event matched ZERO subscribers.
47
+ *
48
+ * Silence is the default because a fire-and-forget bus legitimately carries
49
+ * events nobody wants. It stops being legitimate the moment an OUTBOX is
50
+ * wired: the relay acknowledges a row it delivered to nobody, so the numbers
51
+ * report success and the instruction the event carried was never carried
52
+ * out. A host that expects its events to be consumed passes this and finds
53
+ * out.
54
+ *
55
+ * Runs inside the publish's work scope, after handler resolution and before
56
+ * the (empty) dispatch. It must not throw — a reporter that fails must not
57
+ * decide whether an event was published.
58
+ *
59
+ * MEMORY TRANSPORT ONLY, and deliberately so — this is not an oversight to be
60
+ * fixed by adding it to the Redis transports. In-process, "no handler
61
+ * matched" IS "nobody consumed it": this process is the whole bus. On a
62
+ * broker, no LOCAL handler matched says nothing about consumption — another
63
+ * replica, another consumer group, or a consumer not yet started may own the
64
+ * event, and firing there would report a healthy fan-out as a fault every
65
+ * time work is routed away from this node. The broker's own pending/lag
66
+ * metrics answer that question; this one cannot.
67
+ */
68
+ onUnroutedEvent?: (event: DomainEvent) => void;
45
69
  /**
46
70
  * Cap on handlers running at once under `'parallel'`. Default: unlimited.
47
71
  *
@@ -69,6 +93,7 @@ declare class MemoryEventTransport implements EventTransport {
69
93
  private onHandlerError;
70
94
  private handlerDispatch;
71
95
  private handlerConcurrency;
96
+ private onUnroutedEvent;
72
97
  constructor(options?: MemoryEventTransportOptions);
73
98
  /**
74
99
  * One work scope per publish, around the WHOLE handler set — so every
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import { r as workSeedFromEvent, t as runWorkScope } from "./workScope-CoGpuzDX.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import { r as workSeedFromEvent, t as runWorkScope } from "./workScope-BhsWde4k.mjs";
3
3
  import { createEvent, matchEventPattern } from "@classytic/primitives/events";
4
4
  //#region src/events/EventTransport.ts
5
5
  /**
@@ -82,10 +82,12 @@ var MemoryEventTransport = class {
82
82
  onHandlerError;
83
83
  handlerDispatch;
84
84
  handlerConcurrency;
85
+ onUnroutedEvent;
85
86
  constructor(options) {
86
87
  this.logger = options?.logger ?? console;
87
88
  this.onHandlerError = options?.onHandlerError ?? "log";
88
89
  this.handlerDispatch = options?.handlerDispatch ?? "sequential";
90
+ this.onUnroutedEvent = options?.onUnroutedEvent;
89
91
  const cap = options?.handlerConcurrency;
90
92
  if (cap !== void 0 && (!Number.isInteger(cap) || cap < 1)) throw new TypeError(`MemoryEventTransport: handlerConcurrency must be a positive integer, received ${String(cap)}`);
91
93
  this.handlerConcurrency = cap ?? Number.POSITIVE_INFINITY;
@@ -103,6 +105,13 @@ var MemoryEventTransport = class {
103
105
  async dispatch(event) {
104
106
  const allHandlers = /* @__PURE__ */ new Set();
105
107
  for (const [pattern, handlers] of this.handlers) if (matchEventPattern(pattern, event.type)) for (const h of handlers) allHandlers.add(h);
108
+ if (allHandlers.size === 0 && this.onUnroutedEvent) try {
109
+ this.onUnroutedEvent(event);
110
+ } catch (err) {
111
+ try {
112
+ this.logger.error(`[EventTransport] onUnroutedEvent threw for ${event.type}:`, err);
113
+ } catch {}
114
+ }
106
115
  const failures = [];
107
116
  const run = async (handler) => {
108
117
  try {
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import { t as buildRequestScopeProjection } from "./projection-qbCOEvsh.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import { t as buildRequestScopeProjection } from "./projection-Uvgp-EEj.mjs";
3
3
  //#region src/hooks/HookSystem.ts
4
4
  /**
5
5
  * Hook System
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import "./constants-BQ2FbhPB.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import "./constants-BxLgNFF7.mjs";
3
3
  //#region src/registry/ResourceRegistry.ts
4
4
  /**
5
5
  * Resource Registry
@@ -1,9 +1,9 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import { n as getUserRoles } from "./userHelpers-DLueLQdQ.mjs";
3
- import { b as isElevated, n as PUBLIC_SCOPE, x as isMember } from "./types-CNQyOrLk.mjs";
4
- import { a as resolveEffectiveRoles, t as applyFieldReadPermissions } from "./fields-fA-Dkou5.mjs";
5
- import { t as buildRequestScopeProjection } from "./projection-qbCOEvsh.mjs";
6
- import { t as executePipeline } from "./pipe-4_XamfxI.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import { n as getUserRoles } from "./userHelpers-DDMOZ_Pm.mjs";
3
+ import { b as isElevated, n as PUBLIC_SCOPE, x as isMember } from "./types-CDy3-zw1.mjs";
4
+ import { a as resolveEffectiveRoles, t as applyFieldReadPermissions } from "./fields-BTyPLHK0.mjs";
5
+ import { t as buildRequestScopeProjection } from "./projection-Uvgp-EEj.mjs";
6
+ import { t as executePipeline } from "./pipe-CBVmUJ-j.mjs";
7
7
  import { isPaginatedResult, toCanonicalList } from "@classytic/repo-core/pagination";
8
8
  //#region src/core/fastifyAdapter.ts
9
9
  /** Type guard for Mongoose-like documents with toObject() */
@@ -82,6 +82,7 @@ function createRequestContext(req) {
82
82
  arc: reqWithExtras.arc,
83
83
  _scope: rawScope,
84
84
  _ownershipCheck: reqWithExtras._ownershipCheck,
85
+ _crossTenantRead: reqWithExtras._crossTenantRead,
85
86
  _policyFilters: reqWithExtras._policyFilters ?? {},
86
87
  log: reqWithExtras.log
87
88
  },
@@ -1,6 +1,6 @@
1
1
 
2
- import { d as UserBase } from "../base-C-NL2fTi.mjs";
3
- import "../index-D3sIPcD4.mjs";
2
+ import { d as UserBase } from "../base-CxrV1LmG.mjs";
3
+ import "../index-DHbyPo5j.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
@@ -1,5 +1,6 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import { t as transactionContext } from "../transactionContext-46KyUADP.mjs";
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";
3
4
  import { and, anyOf, eq, gte, lt, lte } from "@classytic/repo-core/filter";
4
5
  import fp from "fastify-plugin";
5
6
  //#region src/audit/repository-audit-adapter.ts
@@ -187,7 +188,13 @@ const auditPlugin = async (fastify, opts = {}) => {
187
188
  const stores = [];
188
189
  if (repository) stores.push(repositoryAsAuditStore(repository, { sessionProvider: sessionProvider === false ? void 0 : sessionProvider }));
189
190
  stores.push(...customStores);
190
- if (stores.length === 0) stores.push(new MemoryAuditStore());
191
+ const memoryFallback = stores.length === 0;
192
+ if (memoryFallback) stores.push(new MemoryAuditStore());
193
+ declareRuntimeCapability(fastify, {
194
+ subsystem: "audit.store",
195
+ durability: memoryFallback ? "memory" : "shared",
196
+ detail: "default MemoryAuditStore: the trail is replica-local and lost on restart"
197
+ });
191
198
  async function logToStores(entry) {
192
199
  await Promise.all(stores.map((store) => store.log(entry)));
193
200
  }
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.41.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,6 @@
1
1
 
2
- import { l as PermissionCheck } from "../base-C-NL2fTi.mjs";
3
- import { Ft as AuthPluginOptions, Pt as AuthHelpers } from "../index-D3sIPcD4.mjs";
2
+ import { l as PermissionCheck } from "../base-CxrV1LmG.mjs";
3
+ import { Ft as AuthPluginOptions, Pt as AuthHelpers } from "../index-DHbyPo5j.mjs";
4
4
  import { t as ExternalOpenApiPaths } from "../externalPaths-CmGOxOtD.mjs";
5
5
  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
6
  import { FastifyPluginAsync, FastifyReply as FastifyReply$1, FastifyRequest } from "fastify";
@@ -1,9 +1,10 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import { d as createDomainError, l as UnauthorizedError, p as isArcError, t as ArcError } from "../errors-BHD3L8of.mjs";
3
- import { n as requireSingleHeaderValue } from "../headers-BFEEshDS.mjs";
4
- import { n as getUserRoles, r as normalizeRoles } from "../userHelpers-DLueLQdQ.mjs";
5
- import { o as toJsonSchema } from "../schemaConverter-DENbixyA.mjs";
6
- import { E as requireOrgRole, T as requireOrgMembership, k as requireTeamMembership } from "../permissions-C0GpDsB_.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import { d as createDomainError, l as UnauthorizedError, p as isArcError, t as ArcError } from "../errors-C_YhELhe.mjs";
3
+ import { n as requireSingleHeaderValue } from "../headers-CNECDE6q.mjs";
4
+ import { n as getUserRoles, r as normalizeRoles } from "../userHelpers-DDMOZ_Pm.mjs";
5
+ import { o as toJsonSchema } from "../schemaConverter-BLCSmNbr.mjs";
6
+ import { n as declareRuntimeCapability } from "../runtimeCapabilities-DSA_dH1_.mjs";
7
+ import { E as requireOrgRole, T as requireOrgMembership, k as requireTeamMembership } from "../permissions-DiHXy8Ck.mjs";
7
8
  import { isProductionEnv } from "@classytic/primitives/environment";
8
9
  import { createHmac, randomUUID, timingSafeEqual } from "node:crypto";
9
10
  import fp from "fastify-plugin";
@@ -1298,6 +1299,11 @@ function createSessionManager(options) {
1298
1299
  }
1299
1300
  };
1300
1301
  const sessionPlugin = async (fastify) => {
1302
+ declareRuntimeCapability(fastify, {
1303
+ subsystem: "auth.sessions",
1304
+ durability: store instanceof MemorySessionStore ? "memory" : "shared",
1305
+ detail: "MemorySessionStore: sessions exist on the replica that created them"
1306
+ });
1301
1307
  const authenticate = async (request, reply) => {
1302
1308
  const cookieHeader = request.headers.cookie;
1303
1309
  const signedValue = parseCookies(typeof cookieHeader === "string" ? cookieHeader : void 0).get(cookieName);
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
2
  import sjson from "secure-json-parse";
3
3
  //#region src/auth/redis-session.ts
4
4
  /**
@@ -1,6 +1,6 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
2
  import { arcLog } from "./logger/index.mjs";
3
- import { t as ArcError } from "./errors-BHD3L8of.mjs";
3
+ import { t as ArcError } from "./errors-C_YhELhe.mjs";
4
4
  //#region src/permissions/filter-merge.ts
5
5
  /**
6
6
  * Policy-filter composition — logical AND, never last-writer-wins.
@@ -294,6 +294,16 @@ declare module "fastify" {
294
294
  document?: unknown;
295
295
  /** Ownership check context (field name + user field) */
296
296
  _ownershipCheck?: Record<string, unknown>;
297
+ /**
298
+ * This read is deliberately NOT scoped to a tenant — a marketplace listing.
299
+ *
300
+ * Set by `multiTenantPreset({ crossTenant: [...] })`. Tenancy is applied in four separate
301
+ * places for a read (the preset middleware, `QueryResolver`, `buildTenantRepoOptions` and the
302
+ * post-fetch `checkOrgScope`), each deriving the org from the scope on its own, so a decision
303
+ * made in one of them is silently re-made by the other three. This flag is how that decision
304
+ * travels. Never set from user input.
305
+ */
306
+ _crossTenantRead?: boolean;
297
307
  }
298
308
  }
299
309
  type AnyRecord = Record<string, unknown>;
@@ -1,7 +1,7 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import { a as conjoinPolicyFilters } from "./authorizationDecision-D_LFvMlm.mjs";
3
- import { g as toRepositoryFilter } from "./BaseController-BqJtbiUA.mjs";
4
- import { i as compileAggRequest, t as adapterSupportsAggregate } from "./validate-DV3hRbsz.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import { a as conjoinPolicyFilters } from "./authorizationDecision-2YY_Kaj1.mjs";
3
+ import { g as toRepositoryFilter } from "./BaseController-DYJRZ0EJ.mjs";
4
+ import { i as compileAggRequest, t as adapterSupportsAggregate } from "./validate-R0G_JrnK.mjs";
5
5
  //#region src/core/aggregation/buildHandler.ts
6
6
  /**
7
7
  * Framework-agnostic aggregation execution. Runs safety guards,
@@ -180,13 +180,15 @@ declare class RedisCacheStore<TValue = unknown> implements CacheStore<TValue> {
180
180
  }
181
181
  /**
182
182
  * Minimal ioredis shape we depend on. We don't import ioredis itself so the
183
- * cache subpath stays peer-dep-free.
183
+ * cache subpath stays peer-dep-free. The `scan` tail is `unknown[]` so a real
184
+ * ioredis `Redis` (overloads with literal tokens + optional callback) is
185
+ * assignable — see the same note on the idempotency `IoredisLike`.
184
186
  */
185
187
  interface IoredisLike {
186
188
  get(key: string): Promise<string | null>;
187
189
  set(...args: unknown[]): Promise<string | null>;
188
190
  del(...keys: string[]): Promise<number>;
189
- scan(cursor: string | number, ...args: (string | number)[]): Promise<[string, string[]]>;
191
+ scan(cursor: string | number, ...args: unknown[]): Promise<[string, string[]]>;
190
192
  pipeline?(): {
191
193
  del(key: string): unknown;
192
194
  exec(): Promise<unknown>;
@@ -1,7 +1,7 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import { i as versionKey, n as hashParams, r as tagVersionKey, t as buildQueryKey } from "../keys-Ds3ekBiu.mjs";
3
- import { t as MemoryCacheStore } from "../memory-CNvjxzB2.mjs";
4
- import { r as QueryCache, t as queryCachePlugin } from "../queryCachePlugin-2Pp9w-8D.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import { i as versionKey, n as hashParams, r as tagVersionKey, t as buildQueryKey } from "../keys-Cmv4cBRa.mjs";
3
+ import { t as MemoryCacheStore } from "../memory-CpDZ9NPw.mjs";
4
+ import { r as QueryCache, t as queryCachePlugin } from "../queryCachePlugin-B5F09bYr.mjs";
5
5
  //#region src/cache/redis.ts
6
6
  /**
7
7
  * Redis-backed cache store.
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import { t as __exportAll } from "./rolldown-runtime-DzE6ikSH.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import { t as __exportAll } from "./rolldown-runtime-DjDuyglE.mjs";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/plugins/caching.ts
5
5
  var caching_exports = /* @__PURE__ */ __exportAll({
@@ -1,7 +1,7 @@
1
1
 
2
- import { L as RequestWithExtras } from "../index-D3sIPcD4.mjs";
2
+ import { L as RequestWithExtras } from "../index-DHbyPo5j.mjs";
3
3
  import { A as CleanupStepResult, B as VerificationResult, C as CleanupResult, D as CleanupRunStore, E as CleanupRunStatus, F as PurgeEvidence, I as PurgeResourceResult, L as PurgeStrategyKind, M as CleanupWriteFence, N as DEFAULT_CLEANUP_LIMITS, O as CleanupRunTransitionPatch, P as PurgeActor, R as PurgeVerificationSummary, S as CleanupRecipe, T as CleanupRunCreateResult, _ as CleanupPermissions, a as CleanupEvidenceStore, b as CleanupPlanItem, c as CleanupInput, d as CleanupLease, f as CleanupLimits, g as CleanupPermissionCheck, h as CleanupOutcomeStatus, i as CleanupContext, j as CleanupStepRunStatus, k as CleanupStepProgress, l as CleanupJob, m as CleanupManifest, n as CLEANUP_TERMINAL_STATUSES, o as CleanupExecutionContext, p as CleanupLogger, r as CleanupCancelRequest, s as CleanupFinalizationPayload, t as Availability, u as CleanupJobQueue, v as CleanupPlan, w as CleanupRun, x as CleanupProgressSummary, y as CleanupPlanDraft, z as VerificationCheck } from "../types-DVLddu2q.mjs";
4
- import { t as ArcModule } from "../types-BVlowlm7.mjs";
4
+ import { t as ArcModule } from "../types-DfVDvkdP.mjs";
5
5
  import { PurgeStrategyKind as PurgeStrategyKind$1 } from "@classytic/primitives/retention";
6
6
  import { canonicalJson } from "@classytic/primitives/canonical";
7
7
  import { CleanupStep } from "@classytic/repo-core/cleanup";
@@ -1,7 +1,7 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import { g as getUserId } from "../types-CNQyOrLk.mjs";
3
- import { t as defineResource } from "../defineResource-DaIySrQr.mjs";
4
- import { t as defineModule } from "../module-CNcwCKUJ.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import { g as getUserId } from "../types-CDy3-zw1.mjs";
3
+ import { t as defineResource } from "../defineResource-DzGT-2LP.mjs";
4
+ import { t as defineModule } from "../module-BkQEesNQ.mjs";
5
5
  import { createPurgeEvidence } from "@classytic/primitives/retention";
6
6
  import { canonicalJson, sha256Hex } from "@classytic/primitives/canonical";
7
7
  //#region src/cleanup/errors.ts
@@ -1,5 +1,5 @@
1
1
 
2
- import { Nt as RateLimitConfig, V as ResourceDefinition, et as RouteSchemaOptions } from "../../index-D3sIPcD4.mjs";
2
+ import { Nt as RateLimitConfig, V as ResourceDefinition, et as RouteSchemaOptions } from "../../index-DHbyPo5j.mjs";
3
3
  //#region src/cli/commands/describe.d.ts
4
4
  interface DescribedResource {
5
5
  name: string;
@@ -1,6 +1,6 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import { t as CRUD_OPERATIONS } from "../../constants-BQ2FbhPB.mjs";
3
- import { n as stringifyMeasureMap } from "../../ResourceRegistry-B9WnuG2Q.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import { t as CRUD_OPERATIONS } from "../../constants-BxLgNFF7.mjs";
3
+ import { n as stringifyMeasureMap } from "../../ResourceRegistry-Cu7uTJp9.mjs";
4
4
  import { resolve } from "node:path";
5
5
  import { pathToFileURL } from "node:url";
6
6
  //#region src/cli/commands/describe.ts
@@ -1,6 +1,6 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import { t as buildOpenApiSpec } from "../../openapi-BYrL8zvY.mjs";
3
- import { t as loadResourcesFromEntry } from "../../loadResourcesFromEntry-C2jrJbWG.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import { t as buildOpenApiSpec } from "../../openapi-C3LFRzPq.mjs";
3
+ import { t as loadResourcesFromEntry } from "../../loadResourcesFromEntry-99fIMC3p.mjs";
4
4
  import { dirname, resolve } from "node:path";
5
5
  import { mkdirSync, writeFileSync } from "node:fs";
6
6
  //#region src/cli/commands/docs.ts
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
2
  import { dirname, join, parse, resolve } from "node:path";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  //#region src/cli/commands/doctor.ts
@@ -1,3 +1,3 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import { t as generate } from "../../generate-BSSdtiOy.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import { t as generate } from "../../generate-D_YmiCNf.mjs";
3
3
  export { generate };
@@ -1,3 +1,3 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import { t as init } from "../../init-pl88PHzb.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import { t as init } from "../../init-Y2MlSN9n.mjs";
3
3
  export { init };
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import { t as loadResourcesFromEntry } from "../../loadResourcesFromEntry-C2jrJbWG.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import { t as loadResourcesFromEntry } from "../../loadResourcesFromEntry-99fIMC3p.mjs";
3
3
  //#region src/cli/commands/introspect.ts
4
4
  function describePermission(value) {
5
5
  if (!value) return "none";
@@ -1,8 +1,8 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
2
  import { describe } from "./commands/describe.mjs";
3
3
  import { exportDocs } from "./commands/docs.mjs";
4
4
  import { doctor } from "./commands/doctor.mjs";
5
- import { t as generate } from "../generate-BSSdtiOy.mjs";
6
- import { t as init } from "../init-pl88PHzb.mjs";
5
+ import { t as generate } from "../generate-D_YmiCNf.mjs";
6
+ import { t as init } from "../init-Y2MlSN9n.mjs";
7
7
  import { introspect } from "./commands/introspect.mjs";
8
8
  export { describe, doctor, exportDocs, generate, init, introspect };
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
2
  //#region src/constants.ts
3
3
  /**
4
4
  * Arc Framework Constants — Single Source of Truth
@@ -1,27 +1,52 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import { t as transactionContext } from "../transactionContext-46KyUADP.mjs";
3
- import { n as requestContext, t as getTraceHeaders } from "../requestContext-D4PuGhEw.mjs";
4
- import { n as scopedValue, r as workSeedFromEvent, t as runWorkScope } from "../workScope-CoGpuzDX.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import { t as transactionContext } from "../transactionContext-DCWMI6hV.mjs";
3
+ import { n as requestContext, t as getTraceHeaders } from "../requestContext-cSVKnYPk.mjs";
4
+ import { n as scopedValue, r as workSeedFromEvent, t as runWorkScope } from "../workScope-BhsWde4k.mjs";
5
5
  //#region src/context/requestScopedCache.ts
6
6
  /** The memo slot the per-scope store hangs off. */
7
7
  const SLOT = Symbol.for("arc.requestScopedCache");
8
8
  /**
9
- * A `Map`-backed `CacheAdapter` with NO eviction and NO TTL — both deliberate.
9
+ * Entry cap for one scope's cache. A request touching this many distinct keys
10
+ * is already pathological; a JOB RUN reaching it is ordinary, and that is the
11
+ * case this exists for (see the eviction note below).
12
+ */
13
+ const MAX_ENTRIES = 1e4;
14
+ /**
15
+ * A `Map`-backed `CacheAdapter` with NO TTL and LRU eviction above
16
+ * {@link MAX_ENTRIES}.
17
+ *
18
+ * TTL is accepted and ignored because repo-core stamps freshness INTO the
19
+ * envelope and re-checks on read — honouring it here too would put two clocks
20
+ * on one question.
10
21
  *
11
- * The store is unreachable once the request's async context ends, so it is
12
- * garbage in milliseconds and bounded by what one request touches; an LRU
13
- * would guard a lifetime that cannot occur. TTL is accepted and ignored
14
- * because repo-core stamps freshness INTO the envelope and re-checks on read —
15
- * honouring it here too would put two clocks on one question.
22
+ * Eviction is newer than the rest of this file and the reason is worth
23
+ * keeping. Unbounded was correct while a scope meant an HTTP REQUEST: the
24
+ * store is unreachable once that async context ends, so it was garbage in
25
+ * milliseconds and bounded by what one request touched, and an LRU would have
26
+ * guarded a lifetime that could not occur. 2.40 extended scopes to job runs
27
+ * and event dispatches — and `schedulesPlugin` wraps the WHOLE handler in one
28
+ * scope, so a nightly job sweeping a million rows holds a single cache for the
29
+ * duration. That is now a lifetime that occurs, and the old premise no longer
30
+ * holds. Evicting is always safe here: this is a cache, so the worst a miss
31
+ * costs is the re-read it was avoiding.
16
32
  */
17
33
  function createRequestCacheAdapter() {
18
34
  const map = /* @__PURE__ */ new Map();
19
35
  return {
20
36
  async get(key) {
21
- return map.get(key);
37
+ if (!map.has(key)) return void 0;
38
+ const value = map.get(key);
39
+ map.delete(key);
40
+ map.set(key, value);
41
+ return value;
22
42
  },
23
43
  async set(key, value, _ttlSeconds) {
44
+ map.delete(key);
24
45
  map.set(key, value);
46
+ if (map.size > MAX_ENTRIES) {
47
+ const oldest = map.keys().next();
48
+ if (!oldest.done) map.delete(oldest.value);
49
+ }
25
50
  },
26
51
  async delete(key) {
27
52
  map.delete(key);
@@ -1,4 +1,4 @@
1
1
 
2
- import { $t as AccessControlConfig, B as defineResource, Bt as BaseController, Cn as ControllerConstructionOptions, En as BodySanitizerConfig, Gt as SlugExt, Ht as SoftDeleteMixin, Jt as BulkMixin, Kt as SlugMixin, Qt as AccessControl, Sn as ControllerConfigurableOptions, Tn as BodySanitizer, Ut as TreeExt, V as ResourceDefinition, Vt as SoftDeleteExt, Wt as TreeMixin, Xt as QueryResolver, Yt as BaseCrudController, Zt as QueryResolverConfig, ct as AggMeasureShorthand, dt as AggregationDateRangeRequirement, ft as AggregationIndexHint, gt as AggregationsMap, ht as AggregationRateLimit, lt as AggregationCacheConfig, mt as AggregationMaterializedResult, pt as AggregationMaterializedContext, qt as BulkExt, st as AggMeasureInput, ut as AggregationConfig, wn as ListResult, xn as BaseControllerOptions } from "../index-D3sIPcD4.mjs";
3
- import { A as CRUD_OPERATIONS, B as HookOperation, C as SeamedResourceConfig, D as createCrudRouter, E as defineAction, F as DEFAULT_SORT, G as MUTATION_OPERATIONS, H as MAX_FILTER_DEPTH, I as DEFAULT_TENANT_FIELD, J as SYSTEM_FIELDS, K as MutationOperation, L as DEFAULT_UPDATE_METHOD, M as DEFAULT_ID_FIELD, N as DEFAULT_LIMIT, O as createPermissionMiddleware, P as DEFAULT_MAX_LIMIT, R as HOOK_OPERATIONS, S as ResourceSeams, T as DefineActionConfig, U as MAX_REGEX_LENGTH, V as HookPhase, W as MAX_SEARCH_LENGTH, _ as getEntityId, a as formatValidationErrors, b as defineResourceVariants, c as nativePolicyFilter, d as createCrudHandlers, f as createFastifyHandler, g as sendControllerResponse, h as getControllerScope, i as assertValidConfig, j as CrudOperation, k as defineAggregation, l as collectReadBlockedFields, m as getControllerContext, n as ValidateOptions, o as validateResourceConfig, p as createRequestContext, q as RESERVED_QUERY_PARAMS, r as ValidationResult, s as NativePolicyFilter, t as ConfigError, u as isFieldReadable, v as getEntityIdField, w as mergeResourceConfig, x as AdapterLike, y as getEntityQuery, z as HOOK_PHASES } from "../index-SCsOJxWB.mjs";
2
+ import { $t as AccessControlConfig, B as defineResource, Bt as BaseController, Cn as ControllerConstructionOptions, En as BodySanitizerConfig, Gt as SlugExt, Ht as SoftDeleteMixin, Jt as BulkMixin, Kt as SlugMixin, Qt as AccessControl, Sn as ControllerConfigurableOptions, Tn as BodySanitizer, Ut as TreeExt, V as ResourceDefinition, Vt as SoftDeleteExt, Wt as TreeMixin, Xt as QueryResolver, Yt as BaseCrudController, Zt as QueryResolverConfig, ct as AggMeasureShorthand, dt as AggregationDateRangeRequirement, ft as AggregationIndexHint, gt as AggregationsMap, ht as AggregationRateLimit, lt as AggregationCacheConfig, mt as AggregationMaterializedResult, pt as AggregationMaterializedContext, qt as BulkExt, st as AggMeasureInput, ut as AggregationConfig, wn as ListResult, xn as BaseControllerOptions } from "../index-DHbyPo5j.mjs";
3
+ import { A as CRUD_OPERATIONS, B as HookOperation, C as SeamedResourceConfig, D as createCrudRouter, E as defineAction, F as DEFAULT_SORT, G as MUTATION_OPERATIONS, H as MAX_FILTER_DEPTH, I as DEFAULT_TENANT_FIELD, J as SYSTEM_FIELDS, K as MutationOperation, L as DEFAULT_UPDATE_METHOD, M as DEFAULT_ID_FIELD, N as DEFAULT_LIMIT, O as createPermissionMiddleware, P as DEFAULT_MAX_LIMIT, R as HOOK_OPERATIONS, S as ResourceSeams, T as DefineActionConfig, U as MAX_REGEX_LENGTH, V as HookPhase, W as MAX_SEARCH_LENGTH, _ as getEntityId, a as formatValidationErrors, b as defineResourceVariants, c as nativePolicyFilter, d as createCrudHandlers, f as createFastifyHandler, g as sendControllerResponse, h as getControllerScope, i as assertValidConfig, j as CrudOperation, k as defineAggregation, l as collectReadBlockedFields, m as getControllerContext, n as ValidateOptions, o as validateResourceConfig, p as createRequestContext, q as RESERVED_QUERY_PARAMS, r as ValidationResult, s as NativePolicyFilter, t as ConfigError, u as isFieldReadable, v as getEntityIdField, w as mergeResourceConfig, x as AdapterLike, y as getEntityQuery, z as HOOK_PHASES } from "../index-D4u76eQW.mjs";
4
4
  export { AccessControl, type AccessControlConfig, type AdapterLike, type AggMeasureInput, type AggMeasureShorthand, type AggregationCacheConfig, type AggregationConfig, type AggregationDateRangeRequirement, type AggregationIndexHint, type AggregationMaterializedContext, type AggregationMaterializedResult, type AggregationRateLimit, type AggregationsMap, BaseController, type BaseControllerOptions, BaseCrudController, BodySanitizer, type BodySanitizerConfig, type BulkExt, BulkMixin, CRUD_OPERATIONS, type ConfigError, type ControllerConfigurableOptions, type ControllerConstructionOptions, CrudOperation, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, type DefineActionConfig, HOOK_OPERATIONS, HOOK_PHASES, HookOperation, HookPhase, type ListResult, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MutationOperation, type NativePolicyFilter, QueryResolver, type QueryResolverConfig, RESERVED_QUERY_PARAMS, ResourceDefinition, type ResourceSeams, SYSTEM_FIELDS, type SeamedResourceConfig, type SlugExt, SlugMixin, type SoftDeleteExt, SoftDeleteMixin, type TreeExt, TreeMixin, type ValidateOptions, type ValidationResult, assertValidConfig, collectReadBlockedFields, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineAction, defineAggregation, defineResource, defineResourceVariants, formatValidationErrors, getControllerContext, getControllerScope, getEntityId, getEntityIdField, getEntityQuery, isFieldReadable, mergeResourceConfig, nativePolicyFilter, sendControllerResponse, validateResourceConfig };
@@ -1,8 +1,8 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import { a as DEFAULT_SORT, c as HOOK_OPERATIONS, d as MAX_REGEX_LENGTH, f as MAX_SEARCH_LENGTH, h as SYSTEM_FIELDS, i as DEFAULT_MAX_LIMIT, l as HOOK_PHASES, m as RESERVED_QUERY_PARAMS, n as DEFAULT_ID_FIELD, o as DEFAULT_TENANT_FIELD, p as MUTATION_OPERATIONS, r as DEFAULT_LIMIT, s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS, u as MAX_FILTER_DEPTH } from "../constants-BQ2FbhPB.mjs";
3
- import { a as BulkMixin, c as collectReadBlockedFields, f as BodySanitizer, h as nativePolicyFilter, i as SlugMixin, l as isFieldReadable, m as AccessControl, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, s as QueryResolver, t as BaseController } from "../BaseController-BqJtbiUA.mjs";
4
- import { t as defineAggregation } from "../defineAggregation-BDA2Tw7v.mjs";
5
- import { a as createCrudHandlers, c as getControllerContext, l as getControllerScope, o as createFastifyHandler, s as createRequestContext, u as sendControllerResponse } from "../actionPermissions-4OGbe3Hf.mjs";
6
- import { a as ResourceDefinition, i as validateResourceConfig, n as assertValidConfig, o as createCrudRouter, r as formatValidationErrors, s as createPermissionMiddleware, t as defineResource } from "../defineResource-DaIySrQr.mjs";
7
- import { a as mergeResourceConfig, i as defineResourceVariants, n as getEntityIdField, o as defineAction, r as getEntityQuery, t as getEntityId } from "../core-CsZR037F.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import { a as DEFAULT_SORT, c as HOOK_OPERATIONS, d as MAX_REGEX_LENGTH, f as MAX_SEARCH_LENGTH, h as SYSTEM_FIELDS, i as DEFAULT_MAX_LIMIT, l as HOOK_PHASES, m as RESERVED_QUERY_PARAMS, n as DEFAULT_ID_FIELD, o as DEFAULT_TENANT_FIELD, p as MUTATION_OPERATIONS, r as DEFAULT_LIMIT, s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS, u as MAX_FILTER_DEPTH } from "../constants-BxLgNFF7.mjs";
3
+ import { a as BulkMixin, c as collectReadBlockedFields, f as BodySanitizer, h as nativePolicyFilter, i as SlugMixin, l as isFieldReadable, m as AccessControl, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, s as QueryResolver, t as BaseController } from "../BaseController-DYJRZ0EJ.mjs";
4
+ import { t as defineAggregation } from "../defineAggregation-UyeurGkp.mjs";
5
+ import { a as createCrudHandlers, c as getControllerContext, l as getControllerScope, o as createFastifyHandler, s as createRequestContext, u as sendControllerResponse } from "../actionPermissions-DPwPWPOV.mjs";
6
+ import { a as ResourceDefinition, i as validateResourceConfig, n as assertValidConfig, o as createCrudRouter, r as formatValidationErrors, s as createPermissionMiddleware, t as defineResource } from "../defineResource-DzGT-2LP.mjs";
7
+ import { a as mergeResourceConfig, i as defineResourceVariants, n as getEntityIdField, o as defineAction, r as getEntityQuery, t as getEntityId } from "../core-iNGqYerO.mjs";
8
8
  export { AccessControl, BaseController, BaseCrudController, BodySanitizer, BulkMixin, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, QueryResolver, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, SlugMixin, SoftDeleteMixin, TreeMixin, assertValidConfig, collectReadBlockedFields, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineAction, defineAggregation, defineResource, defineResourceVariants, formatValidationErrors, getControllerContext, getControllerScope, getEntityId, getEntityIdField, getEntityQuery, isFieldReadable, mergeResourceConfig, nativePolicyFilter, sendControllerResponse, validateResourceConfig };
@@ -1,6 +1,6 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import "./constants-BQ2FbhPB.mjs";
3
- import { t as defineResource } from "./defineResource-DaIySrQr.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import "./constants-BxLgNFF7.mjs";
3
+ import { t as defineResource } from "./defineResource-DzGT-2LP.mjs";
4
4
  //#region src/core/defineAction.ts
5
5
  /**
6
6
  * Build an `ActionDefinition` with a typed handler. The literal schema
@@ -1,10 +1,10 @@
1
- /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
- import { t as __exportAll } from "./rolldown-runtime-DzE6ikSH.mjs";
3
- import "./constants-BQ2FbhPB.mjs";
4
- import { f as createError } from "./errors-BHD3L8of.mjs";
5
- import { i as resolvePipelineSteps, n as buildActionPipelineHandler, u as sendControllerResponse } from "./actionPermissions-4OGbe3Hf.mjs";
6
- import { a as selectPluginMw, c as buildRouteHooks, f as buildAuthMiddlewareForPermissions, i as resolveRouterPluginMw, n as buildRateLimitConfig, o as buildActionPermissionMw, p as buildArcDecorator, r as buildRouteConfig, t as tryRegisterRoute, u as routeHookOptions } from "./registerRoute-_6zHiz0x.mjs";
7
- import { n as schemaIRToJsonSchemaBranch, t as normalizeSchemaIR } from "./schemaIR-C2qUNzC6.mjs";
1
+ /*! @classytic/arc v2.41.0 | MIT | https://classytic.com */
2
+ import { t as __exportAll } from "./rolldown-runtime-DjDuyglE.mjs";
3
+ import "./constants-BxLgNFF7.mjs";
4
+ import { f as createError } from "./errors-C_YhELhe.mjs";
5
+ import { i as resolvePipelineSteps, n as buildActionPipelineHandler, u as sendControllerResponse } from "./actionPermissions-DPwPWPOV.mjs";
6
+ import { a as selectPluginMw, c as buildRouteHooks, f as buildAuthMiddlewareForPermissions, i as resolveRouterPluginMw, n as buildRateLimitConfig, o as buildActionPermissionMw, p as buildArcDecorator, r as buildRouteConfig, t as tryRegisterRoute, u as routeHookOptions } from "./registerRoute-DRsSHPSM.mjs";
7
+ import { n as schemaIRToJsonSchemaBranch, t as normalizeSchemaIR } from "./schemaIR-K16Bb5BX.mjs";
8
8
  //#region src/core/createActionRouter.ts
9
9
  var createActionRouter_exports = /* @__PURE__ */ __exportAll({
10
10
  buildActionBodySchema: () => buildActionBodySchema,