@classytic/arc 2.37.1 → 2.40.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 (183) hide show
  1. package/dist/{BaseController-Chkf0Aiw.mjs → BaseController-BqJtbiUA.mjs} +107 -23
  2. package/dist/{EventTransport-BEVP50ka.d.mts → EventTransport-BPOQsEer.d.mts} +45 -0
  3. package/dist/{EventTransport-CFdtK25P.mjs → EventTransport-BUkTwY_x.mjs} +51 -8
  4. package/dist/{HookSystem-Csy31WS-.mjs → HookSystem-96nzZLmk.mjs} +2 -2
  5. package/dist/{ResourceRegistry-OQA13slI.mjs → ResourceRegistry-B9WnuG2Q.mjs} +2 -2
  6. package/dist/{actionPermissions-DGGqqSIV.mjs → actionPermissions-4OGbe3Hf.mjs} +6 -6
  7. package/dist/audit/index.d.mts +1 -1
  8. package/dist/audit/index.mjs +2 -2
  9. package/dist/auth/audit.mjs +1 -1
  10. package/dist/auth/index.d.mts +1 -1
  11. package/dist/auth/index.mjs +6 -6
  12. package/dist/auth/redis-session.mjs +1 -1
  13. package/dist/{authorizationDecision-BzZi2bsf.mjs → authorizationDecision-D_LFvMlm.mjs} +2 -2
  14. package/dist/{buildHandler-CIz0NsGS.mjs → buildHandler-BG_CHXqQ.mjs} +4 -4
  15. package/dist/cache/index.mjs +4 -4
  16. package/dist/{caching-DldVgnC9.mjs → caching-Bqcn3Brl.mjs} +2 -2
  17. package/dist/cleanup/index.d.mts +2 -2
  18. package/dist/cleanup/index.mjs +21 -5
  19. package/dist/cli/commands/describe.d.mts +1 -1
  20. package/dist/cli/commands/describe.mjs +3 -3
  21. package/dist/cli/commands/docs.mjs +3 -3
  22. package/dist/cli/commands/doctor.mjs +1 -1
  23. package/dist/cli/commands/generate.mjs +2 -2
  24. package/dist/cli/commands/init.mjs +2 -2
  25. package/dist/cli/commands/introspect.mjs +2 -2
  26. package/dist/cli/index.mjs +3 -3
  27. package/dist/{constants-DDKf25s4.mjs → constants-BQ2FbhPB.mjs} +1 -1
  28. package/dist/context/index.d.mts +34 -6
  29. package/dist/context/index.mjs +12 -19
  30. package/dist/core/index.d.mts +2 -2
  31. package/dist/core/index.mjs +7 -7
  32. package/dist/{core-uHQonaHf.mjs → core-CsZR037F.mjs} +3 -3
  33. package/dist/{createActionRouter-C22Xn11N.mjs → createActionRouter-BR93gCKg.mjs} +7 -7
  34. package/dist/{createAggregationRouter-DgyksLHH.mjs → createAggregationRouter-CF40Aw95.mjs} +7 -7
  35. package/dist/createMcpServer-BVTs2S5G.d.mts +48 -0
  36. package/dist/{defineAggregation-B1m-45Fe.mjs → defineAggregation-BDA2Tw7v.mjs} +1 -1
  37. package/dist/{defineResource-DS3Uj2-8.mjs → defineResource-DaIySrQr.mjs} +20 -22
  38. package/dist/discovery/index.mjs +1 -1
  39. package/dist/docs/index.d.mts +1 -1
  40. package/dist/docs/index.mjs +3 -3
  41. package/dist/{elevation-9X0lGzTQ.mjs → elevation-CZy6n50b.mjs} +4 -4
  42. package/dist/encryption/index.mjs +3 -3
  43. package/dist/{errorHandler-DI5AN2b5.d.mts → errorHandler--4rSMMvq.d.mts} +7 -1
  44. package/dist/{errorHandler-BmEGKyO9.mjs → errorHandler-By9keRvX.mjs} +3 -3
  45. package/dist/{errors-CbxCF9M0.mjs → errors-BHD3L8of.mjs} +1 -1
  46. package/dist/{eventPlugin-B1ahehZH.mjs → eventPlugin-DB26V7uX.mjs} +6 -6
  47. package/dist/{eventPlugin-B47sfCJ8.d.mts → eventPlugin-DfHaKEWQ.d.mts} +10 -1
  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 +21 -20
  52. package/dist/events/transports/redis.d.mts +1 -1
  53. package/dist/events/transports/redis.mjs +11 -8
  54. package/dist/factory/index.d.mts +4 -4
  55. package/dist/factory/index.mjs +5 -5
  56. package/dist/{fastify-augmentation-CRsNNhuo.d.mts → fastify-augmentation-HncZMmze.d.mts} +3 -3
  57. package/dist/{fields-f_MdWDl_.mjs → fields-fA-Dkou5.mjs} +37 -2
  58. package/dist/{generate-DxWn-XnM.mjs → generate-BSSdtiOy.mjs} +4 -3
  59. package/dist/{headers-DivLPMHe.mjs → headers-BFEEshDS.mjs} +2 -2
  60. package/dist/{health-W_BjgWf0.mjs → health-BlGHjkqZ.mjs} +1 -1
  61. package/dist/hooks/index.d.mts +1 -1
  62. package/dist/hooks/index.mjs +2 -2
  63. package/dist/idempotency/index.mjs +4 -4
  64. package/dist/idempotency/redis.mjs +1 -1
  65. package/dist/{index-BqRfP1kT.d.mts → index-D3sIPcD4.d.mts} +47 -11
  66. package/dist/{index-DCxxRwLC.d.mts → index-DbMglURO.d.mts} +2 -2
  67. package/dist/{index-CEmPspAB.d.mts → index-SCsOJxWB.d.mts} +2 -2
  68. package/dist/index.d.mts +3 -3
  69. package/dist/index.mjs +11 -11
  70. package/dist/{init-BJ6fdYnp.mjs → init-pl88PHzb.mjs} +9 -9
  71. package/dist/integrations/event-gateway.d.mts +1 -1
  72. package/dist/integrations/event-gateway.mjs +2 -2
  73. package/dist/integrations/index.d.mts +1 -1
  74. package/dist/integrations/index.mjs +1 -1
  75. package/dist/integrations/jobs/index.mjs +2 -2
  76. package/dist/integrations/mcp/index.d.mts +3 -46
  77. package/dist/integrations/mcp/index.mjs +2 -2
  78. package/dist/integrations/mcp/testing.d.mts +22 -2
  79. package/dist/integrations/mcp/testing.mjs +55 -33
  80. package/dist/integrations/streamline.mjs +3 -3
  81. package/dist/integrations/webhooks.d.mts +2 -2
  82. package/dist/integrations/webhooks.mjs +3 -3
  83. package/dist/integrations/websocket-pushref-redis.mjs +1 -1
  84. package/dist/integrations/websocket-redis.mjs +1 -1
  85. package/dist/integrations/websocket.mjs +13 -6
  86. package/dist/{interface-DeLndJ8G.mjs → interface-DjtFnZxH.mjs} +1 -1
  87. package/dist/{jsonBody-kApktjTc.mjs → jsonBody-Dx6jH_Nb.mjs} +2 -2
  88. package/dist/{keys-B1MgfDWi.mjs → keys-Ds3ekBiu.mjs} +1 -1
  89. package/dist/{loadResources-ma-Aaxp1.mjs → loadResources-E5UFlRrT.mjs} +2 -2
  90. package/dist/{loadResourcesFromEntry-xszlyXTs.mjs → loadResourcesFromEntry-C2jrJbWG.mjs} +2 -2
  91. package/dist/logger/index.mjs +1 -1
  92. package/dist/{mcpPlugin-97HuFA46.mjs → mcpPlugin-D-3OLxNz.mjs} +75 -31
  93. package/dist/{memory-DvASzOn3.mjs → memory-CNvjxzB2.mjs} +2 -2
  94. package/dist/{metrics-Dx-nkDE5.mjs → metrics-P37sNV5H.mjs} +2 -2
  95. package/dist/middleware/index.d.mts +1 -1
  96. package/dist/middleware/index.mjs +3 -3
  97. package/dist/migrations/index.mjs +2 -2
  98. package/dist/{module-CNKk_twm.mjs → module-CNcwCKUJ.mjs} +1 -1
  99. package/dist/{multipartBody-TDaYOHGZ.mjs → multipartBody-Bl_gU3Wg.mjs} +1 -1
  100. package/dist/{openapi-473gZ-8x.mjs → openapi-BYrL8zvY.mjs} +6 -6
  101. package/dist/outbox-admin/index.d.mts +1 -1
  102. package/dist/outbox-admin/index.mjs +4 -4
  103. package/dist/{outbox-module-DOAmyXOb.mjs → outbox-module-6DMC_WNu.mjs} +40 -21
  104. package/dist/{outbox-module-BbdaMyqy.d.mts → outbox-module-CzsKRBvO.d.mts} +11 -2
  105. package/dist/permissions/index.mjs +5 -5
  106. package/dist/{permissions-DnAc6zoZ.mjs → permissions-C0GpDsB_.mjs} +6 -6
  107. package/dist/{pipe-BoV-z4db.mjs → pipe-4_XamfxI.mjs} +2 -2
  108. package/dist/pipeline/index.d.mts +1 -1
  109. package/dist/pipeline/index.mjs +2 -2
  110. package/dist/plugins/index.d.mts +5 -5
  111. package/dist/plugins/index.mjs +17 -16
  112. package/dist/plugins/response-cache.mjs +2 -2
  113. package/dist/plugins/tracing-entry.mjs +2 -2
  114. package/dist/{pluralize-BiU5ocWw.mjs → pluralize-BaQ62hOW.mjs} +1 -1
  115. package/dist/{preloadResources-DJ7Lli0a.mjs → preloadResources-BAx5s9EF.mjs} +70 -21
  116. package/dist/{preloadResources-DHkyk3QN.d.mts → preloadResources-DVgPCNcD.d.mts} +7 -7
  117. package/dist/presets/filesUpload.d.mts +1 -1
  118. package/dist/presets/filesUpload.mjs +5 -5
  119. package/dist/presets/index.d.mts +1 -1
  120. package/dist/presets/index.mjs +2 -2
  121. package/dist/presets/multiTenant.d.mts +1 -1
  122. package/dist/presets/multiTenant.mjs +3 -3
  123. package/dist/presets/search.d.mts +1 -1
  124. package/dist/presets/search.mjs +2 -2
  125. package/dist/{presets-BMxH-Bb7.mjs → presets-CAaqVVcW.mjs} +4 -4
  126. package/dist/{projection-CRCM5S9T.mjs → projection-qbCOEvsh.mjs} +2 -2
  127. package/dist/{queryCachePlugin-Cl3zLG7g.mjs → queryCachePlugin-2Pp9w-8D.mjs} +5 -5
  128. package/dist/rateLimitKey-umrS6-vu.mjs +41 -0
  129. package/dist/{realtime-BWuHi-UI.mjs → realtime-zzoNLDtj.mjs} +9 -9
  130. package/dist/{redis-stream-mwLWlfHG.d.mts → redis-stream-DSsPyYzd.d.mts} +7 -2
  131. package/dist/{registerRoute-mvm6zY2H.mjs → registerRoute-_6zHiz0x.mjs} +10 -6
  132. package/dist/registry/index.d.mts +2 -2
  133. package/dist/registry/index.mjs +3 -3
  134. package/dist/{registry-3maEt__c.mjs → registry-CEpoRpLP.mjs} +2 -2
  135. package/dist/{renewingLease-C1-GAUpr.mjs → renewingLease-B5Grm0pI.mjs} +1 -1
  136. package/dist/{replyHelpers-DVcUoled.mjs → replyHelpers-9h-a592u.mjs} +2 -2
  137. package/dist/{requestContext-KzIdSmN2.mjs → requestContext-D4PuGhEw.mjs} +1 -1
  138. package/dist/{rolldown-runtime-NVzJrC-o.mjs → rolldown-runtime-DzE6ikSH.mjs} +1 -1
  139. package/dist/{runtimeCapabilities-OrGatf7r.mjs → runtimeCapabilities-Bo7rSKjm.mjs} +1 -1
  140. package/dist/{schedules-DeRI03eo.mjs → schedules-Dm21pqHU.mjs} +8 -4
  141. package/dist/{schemaConverter-cXTayNOW.mjs → schemaConverter-DENbixyA.mjs} +1 -1
  142. package/dist/{schemaIR-Cc9ZPVs2.mjs → schemaIR-C2qUNzC6.mjs} +2 -2
  143. package/dist/schemas/index.mjs +1 -1
  144. package/dist/scim/index.mjs +2 -2
  145. package/dist/scope/index.mjs +5 -5
  146. package/dist/{scope-C2r7_WGs.mjs → scope-CdYxQVxt.mjs} +4 -4
  147. package/dist/{simpleEqualityMatcher-Cr1F8jKZ.mjs → simpleEqualityMatcher-Cldubvul.mjs} +1 -1
  148. package/dist/{sse-BmZCVRGH.mjs → sse-DbyXoQun.mjs} +5 -5
  149. package/dist/{sseStream-nNPqvOeK.mjs → sseStream-BfZtL5-m.mjs} +2 -2
  150. package/dist/{store-helpers-C1r3-6M0.mjs → store-helpers-BfyOd5i6.mjs} +1 -1
  151. package/dist/{streaming-BxZDlH01.mjs → streaming-CFwCzEvU.mjs} +1 -1
  152. package/dist/{subscribe-helpers-Dca7Fcz2.mjs → subscribe-helpers-KgVEcn8L.mjs} +2 -2
  153. package/dist/sync/changelog.mjs +1 -1
  154. package/dist/testing/cleanupStoreContract.mjs +1 -1
  155. package/dist/testing/index.d.mts +4 -4
  156. package/dist/testing/index.mjs +10 -10
  157. package/dist/testing/outboxStoreContract.mjs +14 -3
  158. package/dist/testing/storageContract.mjs +1 -1
  159. package/dist/{transactionContext-6F7Gkbxg.mjs → transactionContext-46KyUADP.mjs} +1 -1
  160. package/dist/{typeGuards-BrXgbFi-.mjs → typeGuards-t_CVgRXN.mjs} +1 -1
  161. package/dist/types/index.d.mts +1 -1
  162. package/dist/types/index.mjs +1 -1
  163. package/dist/types/storage.mjs +1 -1
  164. package/dist/{types-rzNprqbE.d.mts → types-9rvxn5Ym.d.mts} +46 -1
  165. package/dist/{types-BMa2EPtv.d.mts → types-BVlowlm7.d.mts} +2 -2
  166. package/dist/{types-khJmBErP.mjs → types-CNQyOrLk.mjs} +4 -4
  167. package/dist/usage/index.mjs +0 -0
  168. package/dist/{userHelpers-Bi97zMEl.mjs → userHelpers-DLueLQdQ.mjs} +1 -1
  169. package/dist/utils/index.d.mts +4 -4
  170. package/dist/utils/index.mjs +11 -11
  171. package/dist/{utils-WlLDIKuw.mjs → utils-CUFBrhq-.mjs} +14 -6
  172. package/dist/{validate-pMke_boy.mjs → validate-DV3hRbsz.mjs} +2 -2
  173. package/dist/{versioning-CFK3c04-.mjs → versioning-BXwmj5SD.mjs} +3 -3
  174. package/dist/{versioning-DEs-_hFi.d.mts → versioning-P3V6ATyC.d.mts} +1 -1
  175. package/dist/workScope-CoGpuzDX.mjs +42 -0
  176. package/package.json +48 -39
  177. package/skills/arc/references/mcp.md +20 -0
  178. package/skills/arc/references/testing.md +0 -12
  179. package/skills/arc-code-review/references/anti-patterns.md +1 -1
  180. package/skills/arc-code-review/references/migration-recipes.md +0 -60
  181. package/skills/arc-code-review/references/mongokit-migration.md +0 -27
  182. package/skills/arc-module-publishing/references/package-manifest.md +3 -1
  183. package/dist/rateLimitKey-D4_rjP1K.mjs +0 -15
@@ -1,15 +1,15 @@
1
- /*! @classytic/arc v2.37.1 | MIT | https://classytic.com */
2
- import { h as SYSTEM_FIELDS, o as DEFAULT_TENANT_FIELD } from "./constants-DDKf25s4.mjs";
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";
3
3
  import { arcLog } from "./logger/index.mjs";
4
- import { a as conjoinPolicyFilters } from "./authorizationDecision-BzZi2bsf.mjs";
5
- import { d as createDomainError, f as createError, i as NotFoundError, p as isArcError, r as ForbiddenError } from "./errors-CbxCF9M0.mjs";
6
- import { n as getUserRoles, t as getUserId } from "./userHelpers-Bi97zMEl.mjs";
7
- import { b as isElevated, c as getOrgId, n as PUBLIC_SCOPE, x as isMember } from "./types-khJmBErP.mjs";
8
- import { t as simpleEqualityMatcher } from "./simpleEqualityMatcher-Cr1F8jKZ.mjs";
9
- import { t as buildQueryKey } from "./keys-B1MgfDWi.mjs";
10
- import { t as transactionContext } from "./transactionContext-6F7Gkbxg.mjs";
11
- import { A as scheduleBackground, E as ArcQueryParser } from "./utils-WlLDIKuw.mjs";
12
- import { i as resolveEffectiveRoles, n as applyFieldWritePermissions } from "./fields-f_MdWDl_.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";
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";
@@ -650,7 +650,7 @@ async function executeAfterHook(ctx, op, data, meta) {
650
650
  * Every mixin used to spell out its own narrowing cast inline:
651
651
  *
652
652
  * ```ts
653
- * const repo = this.repository as unknown as {
653
+ * const repo = this.repository as {
654
654
  * getTree?: (options?: unknown) => Promise<AnyRecord[]>;
655
655
  * };
656
656
  * ```
@@ -717,7 +717,7 @@ async function runDistinctVerb(repository, field, resolveScope) {
717
717
  const repo = withRepoFeatures(repository);
718
718
  if (typeof repo.distinct !== "function") throw createError(501, "_distinct is not supported: the resource's storage adapter does not implement repo.distinct()");
719
719
  const { filter, options } = resolveScope();
720
- return await repo.distinct(field, filter, options);
720
+ return { values: await repo.distinct(field, filter, options) };
721
721
  }
722
722
  /**
723
723
  * `?_exists=true` → `repo.exists(filter)`. Returns the RAW repo result —
@@ -789,6 +789,27 @@ function noteDeniedJoins(kind) {
789
789
  notedDeniedJoins = true;
790
790
  log.warn(`client requested ${kind} but no allowlist is configured — DENIED (2.24 default flip; it was allow-all). Set schemaOptions.query.allowedPopulate / allowedLookups to enable client-driven joins. (dev-only note, shown once)`);
791
791
  }
792
+ /**
793
+ * A `$lookup` reaches ANOTHER collection, and the tenant filter arc conjoins applies to the
794
+ * BASE one only. The joined side carries whatever predicate the lookup itself names and
795
+ * nothing more — no tenant scope, no soft-delete filter — so a resource that opens
796
+ * `allowedLookups` can return rows from a collection the caller could not query directly.
797
+ *
798
+ * Unreachable by default (2.24 denies `lookup=` with no allowlist) and no resource in this
799
+ * fleet configures one, so this is a WARNING at the moment a deployment first opts in
800
+ * rather than machinery for a door nobody has opened. Warned once per collection set: the
801
+ * decision is made when the allowlist is written, not per request.
802
+ *
803
+ * Scope the join with the lookup's own `where`, which mongokit compiles into a `$match`
804
+ * inside the lookup pipeline.
805
+ */
806
+ const notedUnscopedJoins = /* @__PURE__ */ new Set();
807
+ function noteUnscopedJoin(lookups) {
808
+ const key = lookups.map((l) => l.from).filter((f) => typeof f === "string").sort().join(",");
809
+ if (key.length === 0 || notedUnscopedJoins.has(key)) return;
810
+ notedUnscopedJoins.add(key);
811
+ log.warn(`client-driven $lookup on [${key}] — the JOINED side carries no tenant or soft-delete filter (arc scopes the base collection only). Narrow each lookup with its own \`where\`, or the join can surface rows the caller cannot query directly. (shown once)`);
812
+ }
792
813
  var QueryResolver = class {
793
814
  queryParser;
794
815
  maxLimit;
@@ -912,6 +933,12 @@ var QueryResolver = class {
912
933
  query = rest;
913
934
  }
914
935
  const parsed = this.queryParser.parse(query);
936
+ /**
937
+ * Client-supplied keys only, and BEFORE the policy conjunction below: trusted policy
938
+ * legitimately filters on hidden fields (`requireOwnership('userId')` emits exactly that),
939
+ * so checking the conjoined result would reject the framework's own restrictions.
940
+ */
941
+ this.assertNoBlockedReadKeys(parsed.filters, parsed.sort);
915
942
  const arcContext = meta ?? req.metadata;
916
943
  const limit = Math.min(Math.max(1, parsed.limit || this.defaultLimit), this.maxLimit);
917
944
  const page = parsed.after ? void 0 : parsed.page ? Math.max(1, parsed.page) : 1;
@@ -950,20 +977,14 @@ var QueryResolver = class {
950
977
  if (!select) return exclusion();
951
978
  if (typeof select === "object" && !Array.isArray(select)) {
952
979
  const sanitized = {};
953
- for (const [field, val] of Object.entries(select)) if (!blockedFields.includes(field)) sanitized[field] = val;
980
+ for (const [field, val] of Object.entries(select)) if (!this.isBlockedProjection(field, blockedFields)) sanitized[field] = val;
954
981
  return Object.keys(sanitized).length > 0 ? sanitized : exclusion();
955
982
  }
956
983
  if (Array.isArray(select)) {
957
- const sanitized = select.filter((f) => {
958
- const fieldName = f.replace(/^-/, "");
959
- return !blockedFields.includes(fieldName);
960
- });
984
+ const sanitized = select.filter((f) => !this.isBlockedProjection(f, blockedFields));
961
985
  return sanitized.length > 0 ? sanitized : exclusion();
962
986
  }
963
- const sanitized = select.split(/[\s,]+/).filter(Boolean).filter((f) => {
964
- const fieldName = f.replace(/^-/, "");
965
- return !blockedFields.includes(fieldName);
966
- });
987
+ const sanitized = select.split(/[\s,]+/).filter(Boolean).filter((f) => !this.isBlockedProjection(f, blockedFields));
967
988
  return sanitized.length > 0 ? sanitized.join(" ") : exclusion();
968
989
  }
969
990
  /** Sanitize populate fields */
@@ -1011,6 +1032,7 @@ var QueryResolver = class {
1011
1032
  if (!allowedLookups.includes(lookup.from)) return false;
1012
1033
  return true;
1013
1034
  });
1035
+ if (sanitized.length > 0) noteUnscopedJoin(sanitized);
1014
1036
  return sanitized.length > 0 ? sanitized : void 0;
1015
1037
  }
1016
1038
  /**
@@ -1023,6 +1045,68 @@ var QueryResolver = class {
1023
1045
  const blocked = collectReadBlockedFields(schemaOptions);
1024
1046
  return blocked ? Array.from(blocked) : [];
1025
1047
  }
1048
+ /**
1049
+ * Is this projection path blocked — by its own name, or by a hidden ANCESTOR?
1050
+ *
1051
+ * `hidden: { secret: true }` hides the object, and an exact-name match left its children
1052
+ * reachable: `?select=secret.value` projected the very field the rule exists to withhold.
1053
+ * A rule on a parent covers everything under it, which is what "hidden" already means to
1054
+ * whoever wrote it.
1055
+ */
1056
+ isBlockedProjection(path, blockedFields) {
1057
+ const field = path.replace(/^-/, "");
1058
+ return blockedFields.some((blocked) => field === blocked || field.startsWith(`${blocked}.`));
1059
+ }
1060
+ /**
1061
+ * Refuse a read that FILTERS or SORTS on a `hidden` field.
1062
+ *
1063
+ * `hidden` was enforced on the surfaces that RETURN a value — the response, `select=`,
1064
+ * `_distinct`, aggregations — but a filter key never returns the field, it INTERROGATES it:
1065
+ * `?passwordHash[like]=^ab` narrows the result set, so the row count answers a question about
1066
+ * a value the caller may not read. A resource with no `allowedFilterFields` was a blind
1067
+ * existence oracle over every hidden field it declared.
1068
+ *
1069
+ * Rejected rather than dropped, unlike `select`. Dropping a projection narrows what comes
1070
+ * back; dropping a filter WIDENS the rows, which is the silent-permissive shape this
1071
+ * framework fails loudly on everywhere else.
1072
+ *
1073
+ * Compound keys (`$or`, `$and`) are walked, because the offending key can be nested inside
1074
+ * one. A dotted path is blocked by its own name or by a hidden ancestor, so a rule on
1075
+ * `secret` also covers `secret.value`.
1076
+ */
1077
+ assertNoBlockedReadKeys(filters, sort) {
1078
+ const blocked = collectReadBlockedFields(this.schemaOptions);
1079
+ if (!blocked) return;
1080
+ const offenders = /* @__PURE__ */ new Set();
1081
+ const isBlocked = (key) => {
1082
+ if (blocked.has(key)) return true;
1083
+ const dot = key.indexOf(".");
1084
+ return dot > 0 && blocked.has(key.slice(0, dot));
1085
+ };
1086
+ const walk = (node, depth) => {
1087
+ if (depth > 8 || !node || typeof node !== "object") return;
1088
+ if (Array.isArray(node)) {
1089
+ for (const item of node) walk(item, depth + 1);
1090
+ return;
1091
+ }
1092
+ for (const [key, value] of Object.entries(node)) {
1093
+ if (key.startsWith("$")) {
1094
+ walk(value, depth + 1);
1095
+ continue;
1096
+ }
1097
+ if (isBlocked(key)) offenders.add(key);
1098
+ }
1099
+ };
1100
+ walk(filters, 0);
1101
+ const sortKeys = typeof sort === "string" ? sort.split(",").map((s) => s.trim().replace(/^-/, "")).filter(Boolean) : Object.keys(sort ?? {});
1102
+ for (const key of sortKeys) if (isBlocked(key)) offenders.add(key);
1103
+ if (offenders.size === 0) return;
1104
+ const fields = [...offenders];
1105
+ throw new ValidationError(`Cannot filter or sort on hidden field(s): ${fields.join(", ")}`, fields.map((field) => ({
1106
+ field,
1107
+ message: "Field is not readable"
1108
+ })));
1109
+ }
1026
1110
  };
1027
1111
  //#endregion
1028
1112
  //#region src/core/BaseCrudController.ts
@@ -1550,7 +1634,7 @@ var BaseCrudController = class {
1550
1634
  }
1551
1635
  async list(req) {
1552
1636
  const dispatch = this.dispatchResourceVerb(req);
1553
- if (dispatch) return dispatch;
1637
+ if (dispatch !== null) return dispatch;
1554
1638
  const options = this.queryResolver.resolve(req, this.meta(req));
1555
1639
  const cached = await this.withListCache(req, options);
1556
1640
  if (cached) return cached;
@@ -19,6 +19,41 @@ interface MemoryEventTransportOptions {
19
19
  * handlers must be idempotent. Every handler runs before the rejection.
20
20
  */
21
21
  onHandlerError?: "log" | "throw";
22
+ /**
23
+ * Whether independent subscribers run one at a time or together.
24
+ *
25
+ * - `'sequential'` (default) — handler N+1 starts after handler N settles.
26
+ * - `'parallel'` — all matching handlers start together; `publish()` resolves
27
+ * when the last settles.
28
+ *
29
+ * Same delivery and the same failure semantics either way: every handler
30
+ * still receives the event, every failure is still collected, and `'throw'`
31
+ * still rejects with one `AggregateError` after all of them have run.
32
+ *
33
+ * **Opting in requires an AUDIT, not an assumption.** Every other transport
34
+ * in this package runs matching handlers sequentially in registration order
35
+ * (`redis-stream.ts` states it outright; `redis.ts` implements it), so an app
36
+ * relying on that order is relying on documented behaviour — switching this
37
+ * on is what breaks it, and swapping to a broker would not have surfaced it.
38
+ * Confirm no subscriber reads another subscriber's write before enabling.
39
+ *
40
+ * Measured on one order placement: 6 subscribers, each spending most of its
41
+ * time on its own round trips, cost 2.8s sequentially — the length of the
42
+ * QUEUE, not of the work.
43
+ */
44
+ handlerDispatch?: "sequential" | "parallel";
45
+ /**
46
+ * Cap on handlers running at once under `'parallel'`. Default: unlimited.
47
+ *
48
+ * Sequential dispatch was an accidental per-publish rate limiter on whatever
49
+ * pool the handlers share; removing it converts a latency problem into a
50
+ * saturation one when several publishes overlap. `RedisStreamTransport`
51
+ * exposes `processingConcurrency` for the same reason — this is its peer, so
52
+ * an operator has a dial rather than only "queued" or "all at once".
53
+ *
54
+ * Ignored under `'sequential'`, which is already a concurrency of 1.
55
+ */
56
+ handlerConcurrency?: number;
22
57
  }
23
58
  /**
24
59
  * In-memory event transport (default).
@@ -32,8 +67,18 @@ declare class MemoryEventTransport implements EventTransport {
32
67
  private handlers;
33
68
  private logger;
34
69
  private onHandlerError;
70
+ private handlerDispatch;
71
+ private handlerConcurrency;
35
72
  constructor(options?: MemoryEventTransportOptions);
73
+ /**
74
+ * One work scope per publish, around the WHOLE handler set — so every
75
+ * handler of this event, parallel or not, shares one `requestScopedCache()`
76
+ * and one correlation id. Inherits an active request scope (a live
77
+ * in-request dispatch keeps the request's reads); a relay- or job-driven
78
+ * publish gets its own.
79
+ */
36
80
  publish(event: DomainEvent): Promise<void>;
81
+ private dispatch;
37
82
  /**
38
83
  * Reference `publishMany` implementation — delegates to `publish()` in order.
39
84
  *
@@ -1,4 +1,5 @@
1
- /*! @classytic/arc v2.37.1 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
+ import { r as workSeedFromEvent, t as runWorkScope } from "./workScope-CoGpuzDX.mjs";
2
3
  import { createEvent, matchEventPattern } from "@classytic/primitives/events";
3
4
  //#region src/events/EventTransport.ts
4
5
  /**
@@ -79,20 +80,62 @@ var MemoryEventTransport = class {
79
80
  handlers = /* @__PURE__ */ new Map();
80
81
  logger;
81
82
  onHandlerError;
83
+ handlerDispatch;
84
+ handlerConcurrency;
82
85
  constructor(options) {
83
86
  this.logger = options?.logger ?? console;
84
87
  this.onHandlerError = options?.onHandlerError ?? "log";
88
+ this.handlerDispatch = options?.handlerDispatch ?? "sequential";
89
+ const cap = options?.handlerConcurrency;
90
+ if (cap !== void 0 && (!Number.isInteger(cap) || cap < 1)) throw new TypeError(`MemoryEventTransport: handlerConcurrency must be a positive integer, received ${String(cap)}`);
91
+ this.handlerConcurrency = cap ?? Number.POSITIVE_INFINITY;
85
92
  }
86
- async publish(event) {
93
+ /**
94
+ * One work scope per publish, around the WHOLE handler set — so every
95
+ * handler of this event, parallel or not, shares one `requestScopedCache()`
96
+ * and one correlation id. Inherits an active request scope (a live
97
+ * in-request dispatch keeps the request's reads); a relay- or job-driven
98
+ * publish gets its own.
99
+ */
100
+ publish(event) {
101
+ return runWorkScope(workSeedFromEvent(event), () => this.dispatch(event));
102
+ }
103
+ async dispatch(event) {
87
104
  const allHandlers = /* @__PURE__ */ new Set();
88
105
  for (const [pattern, handlers] of this.handlers) if (matchEventPattern(pattern, event.type)) for (const h of handlers) allHandlers.add(h);
89
106
  const failures = [];
90
- for (const handler of allHandlers) try {
91
- await handler(event);
92
- } catch (err) {
93
- this.logger.error(`[EventTransport] Handler error for ${event.type}:`, err);
94
- failures.push(err);
95
- }
107
+ const run = async (handler) => {
108
+ try {
109
+ await handler(event);
110
+ } catch (err) {
111
+ failures.push(err);
112
+ try {
113
+ this.logger.error(`[EventTransport] Handler error for ${event.type}:`, err);
114
+ } catch {}
115
+ }
116
+ };
117
+ if (this.handlerDispatch === "parallel") {
118
+ /**
119
+ * `allSettled`, not `all`. Correctness must not rest on `run` never
120
+ * rejecting: `all` short-circuits on the first rejection and resolves
121
+ * `publish()` while the other handlers are still in flight — detached
122
+ * work racing the outbox relay's redelivery of the same event. `run` is
123
+ * written not to reject, and `allSettled` means the next person to add a
124
+ * timeout or a metric to it cannot silently break that.
125
+ */
126
+ const pending = [...allHandlers];
127
+ if (this.handlerConcurrency >= pending.length) await Promise.allSettled(pending.map(run));
128
+ else {
129
+ let next = 0;
130
+ const worker = async () => {
131
+ while (next < pending.length) {
132
+ const handler = pending[next++];
133
+ if (handler) await run(handler);
134
+ }
135
+ };
136
+ await Promise.allSettled(Array.from({ length: this.handlerConcurrency }, worker));
137
+ }
138
+ } else for (const handler of allHandlers) await run(handler);
96
139
  /**
97
140
  * Rejecting is what lets an OUTBOX see the failure. With this transport,
98
141
  * `publish()` IS the handling — synchronous and in-process — so resolving
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.37.1 | MIT | https://classytic.com */
2
- import { t as buildRequestScopeProjection } from "./projection-CRCM5S9T.mjs";
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
+ import { t as buildRequestScopeProjection } from "./projection-qbCOEvsh.mjs";
3
3
  //#region src/hooks/HookSystem.ts
4
4
  /**
5
5
  * Hook System
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.37.1 | MIT | https://classytic.com */
2
- import "./constants-DDKf25s4.mjs";
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
+ import "./constants-BQ2FbhPB.mjs";
3
3
  //#region src/registry/ResourceRegistry.ts
4
4
  /**
5
5
  * Resource Registry
@@ -1,9 +1,9 @@
1
- /*! @classytic/arc v2.37.1 | MIT | https://classytic.com */
2
- import { n as getUserRoles } from "./userHelpers-Bi97zMEl.mjs";
3
- import { b as isElevated, n as PUBLIC_SCOPE, x as isMember } from "./types-khJmBErP.mjs";
4
- import { i as resolveEffectiveRoles, t as applyFieldReadPermissions } from "./fields-f_MdWDl_.mjs";
5
- import { t as buildRequestScopeProjection } from "./projection-CRCM5S9T.mjs";
6
- import { t as executePipeline } from "./pipe-BoV-z4db.mjs";
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";
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() */
@@ -1,6 +1,6 @@
1
1
 
2
2
  import { d as UserBase } from "../base-C-NL2fTi.mjs";
3
- import "../index-BqRfP1kT.mjs";
3
+ import "../index-D3sIPcD4.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,5 @@
1
- /*! @classytic/arc v2.37.1 | MIT | https://classytic.com */
2
- import { t as transactionContext } from "../transactionContext-6F7Gkbxg.mjs";
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
+ import { t as transactionContext } from "../transactionContext-46KyUADP.mjs";
3
3
  import { and, anyOf, eq, gte, lt, lte } from "@classytic/repo-core/filter";
4
4
  import fp from "fastify-plugin";
5
5
  //#region src/audit/repository-audit-adapter.ts
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.37.1 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.40.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
2
  import { l as PermissionCheck } from "../base-C-NL2fTi.mjs";
3
- import { Ft as AuthPluginOptions, Pt as AuthHelpers } from "../index-BqRfP1kT.mjs";
3
+ import { Ft as AuthPluginOptions, Pt as AuthHelpers } from "../index-D3sIPcD4.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,9 @@
1
- /*! @classytic/arc v2.37.1 | MIT | https://classytic.com */
2
- import { d as createDomainError, l as UnauthorizedError, p as isArcError, t as ArcError } from "../errors-CbxCF9M0.mjs";
3
- import { n as requireSingleHeaderValue } from "../headers-DivLPMHe.mjs";
4
- import { n as getUserRoles, r as normalizeRoles } from "../userHelpers-Bi97zMEl.mjs";
5
- import { o as toJsonSchema } from "../schemaConverter-cXTayNOW.mjs";
6
- import { E as requireOrgRole, T as requireOrgMembership, k as requireTeamMembership } from "../permissions-DnAc6zoZ.mjs";
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";
7
7
  import { isProductionEnv } from "@classytic/primitives/environment";
8
8
  import { createHmac, randomUUID, timingSafeEqual } from "node:crypto";
9
9
  import fp from "fastify-plugin";
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.37.1 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.40.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.37.1 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
2
  import { arcLog } from "./logger/index.mjs";
3
- import { t as ArcError } from "./errors-CbxCF9M0.mjs";
3
+ import { t as ArcError } from "./errors-BHD3L8of.mjs";
4
4
  //#region src/permissions/filter-merge.ts
5
5
  /**
6
6
  * Policy-filter composition — logical AND, never last-writer-wins.
@@ -1,7 +1,7 @@
1
- /*! @classytic/arc v2.37.1 | MIT | https://classytic.com */
2
- import { a as conjoinPolicyFilters } from "./authorizationDecision-BzZi2bsf.mjs";
3
- import { g as toRepositoryFilter } from "./BaseController-Chkf0Aiw.mjs";
4
- import { i as compileAggRequest, t as adapterSupportsAggregate } from "./validate-pMke_boy.mjs";
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";
5
5
  //#region src/core/aggregation/buildHandler.ts
6
6
  /**
7
7
  * Framework-agnostic aggregation execution. Runs safety guards,
@@ -1,7 +1,7 @@
1
- /*! @classytic/arc v2.37.1 | MIT | https://classytic.com */
2
- import { i as versionKey, n as hashParams, r as tagVersionKey, t as buildQueryKey } from "../keys-B1MgfDWi.mjs";
3
- import { t as MemoryCacheStore } from "../memory-DvASzOn3.mjs";
4
- import { r as QueryCache, t as queryCachePlugin } from "../queryCachePlugin-Cl3zLG7g.mjs";
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";
5
5
  //#region src/cache/redis.ts
6
6
  /**
7
7
  * Redis-backed cache store.
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.37.1 | MIT | https://classytic.com */
2
- import { t as __exportAll } from "./rolldown-runtime-NVzJrC-o.mjs";
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
+ import { t as __exportAll } from "./rolldown-runtime-DzE6ikSH.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-BqRfP1kT.mjs";
2
+ import { L as RequestWithExtras } from "../index-D3sIPcD4.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-BMa2EPtv.mjs";
4
+ import { t as ArcModule } from "../types-BVlowlm7.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.37.1 | MIT | https://classytic.com */
2
- import { g as getUserId } from "../types-khJmBErP.mjs";
3
- import { t as defineResource } from "../defineResource-DS3Uj2-8.mjs";
4
- import { t as defineModule } from "../module-CNKk_twm.mjs";
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";
5
5
  import { createPurgeEvidence } from "@classytic/primitives/retention";
6
6
  import { canonicalJson, sha256Hex } from "@classytic/primitives/canonical";
7
7
  //#region src/cleanup/errors.ts
@@ -723,9 +723,25 @@ function createCleanupService(deps) {
723
723
  const logger = deps.logger;
724
724
  const generateId = deps.generateId ?? (() => globalThis.crypto.randomUUID());
725
725
  const now = deps.now ?? (() => /* @__PURE__ */ new Date());
726
+ /**
727
+ * Undefined-valued keys are DROPPED, not spread.
728
+ *
729
+ * `limits` is `Partial<CleanupLimits>`, which permits an EXPLICIT `undefined`
730
+ * — and a plain spread lets that overwrite the default rather than fall back
731
+ * to it. Every limit is then read in a comparison, and `n > undefined` is
732
+ * always `false`, so `{ limits: { maxPlanItems: undefined } }` did not raise
733
+ * the cap: it silently REMOVED it, on a framework whose whole job is deleting
734
+ * data. Same for `maxReasonLength` / `maxParamDepth`, and `maxResults` turned
735
+ * `slice(0, undefined)` into "keep everything".
736
+ *
737
+ * A host reaches this by forwarding an optional config through
738
+ * (`limits: { maxPlanItems: cfg.planCap }`) — no cast, no obvious mistake.
739
+ * `permissions/presets.ts` already filters for exactly this reason; this is
740
+ * the same rule applied to the destructive path.
741
+ */
726
742
  const limits = {
727
743
  ...DEFAULT_CLEANUP_LIMITS,
728
- ...deps.limits
744
+ ...Object.fromEntries(Object.entries(deps.limits ?? {}).filter(([, v]) => v !== void 0))
729
745
  };
730
746
  const leaseMs = deps.leaseMs ?? 3e5;
731
747
  const progressThrottleMs = deps.progressThrottleMs ?? 0;
@@ -1,5 +1,5 @@
1
1
 
2
- import { Nt as RateLimitConfig, V as ResourceDefinition, et as RouteSchemaOptions } from "../../index-BqRfP1kT.mjs";
2
+ import { Nt as RateLimitConfig, V as ResourceDefinition, et as RouteSchemaOptions } from "../../index-D3sIPcD4.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.37.1 | MIT | https://classytic.com */
2
- import { t as CRUD_OPERATIONS } from "../../constants-DDKf25s4.mjs";
3
- import { n as stringifyMeasureMap } from "../../ResourceRegistry-OQA13slI.mjs";
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";
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.37.1 | MIT | https://classytic.com */
2
- import { t as buildOpenApiSpec } from "../../openapi-473gZ-8x.mjs";
3
- import { t as loadResourcesFromEntry } from "../../loadResourcesFromEntry-xszlyXTs.mjs";
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";
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.37.1 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.40.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.37.1 | MIT | https://classytic.com */
2
- import { t as generate } from "../../generate-DxWn-XnM.mjs";
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
+ import { t as generate } from "../../generate-BSSdtiOy.mjs";
3
3
  export { generate };
@@ -1,3 +1,3 @@
1
- /*! @classytic/arc v2.37.1 | MIT | https://classytic.com */
2
- import { t as init } from "../../init-BJ6fdYnp.mjs";
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
+ import { t as init } from "../../init-pl88PHzb.mjs";
3
3
  export { init };
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.37.1 | MIT | https://classytic.com */
2
- import { t as loadResourcesFromEntry } from "../../loadResourcesFromEntry-xszlyXTs.mjs";
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
+ import { t as loadResourcesFromEntry } from "../../loadResourcesFromEntry-C2jrJbWG.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.37.1 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.40.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-DxWn-XnM.mjs";
6
- import { t as init } from "../init-BJ6fdYnp.mjs";
5
+ import { t as generate } from "../generate-BSSdtiOy.mjs";
6
+ import { t as init } from "../init-pl88PHzb.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.37.1 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.40.0 | MIT | https://classytic.com */
2
2
  //#region src/constants.ts
3
3
  /**
4
4
  * Arc Framework Constants — Single Source of Truth