@classytic/arc 2.31.0 → 2.33.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 (194) hide show
  1. package/README.md +1 -1
  2. package/bin/arc.js +58 -17
  3. package/dist/{BaseController-De7GqHck.mjs → BaseController-CaQC5EXX.mjs} +298 -35
  4. package/dist/{EventTransport-2uVV34WU.d.mts → EventTransport-BEVP50ka.d.mts} +16 -0
  5. package/dist/{EventTransport-9mlTgqzE.mjs → EventTransport-tq4CEB-q.mjs} +39 -2
  6. package/dist/{HookSystem-BcmPyq5I.mjs → HookSystem-DqXkMXkB.mjs} +2 -2
  7. package/dist/{ResourceRegistry-qq0mn2s9.mjs → ResourceRegistry-DoALUlOO.mjs} +18 -15
  8. package/dist/{actionPermissions-BE5NwaQk.mjs → actionPermissions-CUeCmpUd.mjs} +1 -1
  9. package/dist/audit/index.d.mts +2 -2
  10. package/dist/audit/index.mjs +2 -2
  11. package/dist/auth/audit.mjs +1 -1
  12. package/dist/auth/index.d.mts +2 -2
  13. package/dist/auth/index.mjs +44 -11
  14. package/dist/auth/redis-session.mjs +1 -1
  15. package/dist/{authorizationDecision-ChvUQGG1.mjs → authorizationDecision-B3mP_QTy.mjs} +2 -2
  16. package/dist/{types-B7XeLEgK.d.mts → base-Csjc2oF-.d.mts} +74 -74
  17. package/dist/{buildHandler-CDrCJzmB.mjs → buildHandler-DLE9xX-V.mjs} +6 -5
  18. package/dist/cache/index.mjs +4 -4
  19. package/dist/{caching-BFHA6Scf.mjs → caching-BcGmvnHh.mjs} +2 -2
  20. package/dist/cleanup/index.d.mts +52 -18
  21. package/dist/cleanup/index.mjs +281 -32
  22. package/dist/cli/commands/describe.d.mts +1 -1
  23. package/dist/cli/commands/describe.mjs +4 -6
  24. package/dist/cli/commands/docs.mjs +3 -3
  25. package/dist/cli/commands/doctor.mjs +1 -1
  26. package/dist/cli/commands/generate.mjs +2 -2
  27. package/dist/cli/commands/init.mjs +2 -2
  28. package/dist/cli/commands/introspect.mjs +2 -2
  29. package/dist/cli/index.mjs +3 -3
  30. package/dist/{constants-D3Dv4LAV.mjs → constants-BxCoxmiN.mjs} +1 -1
  31. package/dist/context/index.mjs +3 -3
  32. package/dist/core/index.d.mts +2 -2
  33. package/dist/core/index.mjs +7 -7
  34. package/dist/{core-BGpIxINN.mjs → core-dxhcHhUD.mjs} +3 -3
  35. package/dist/{createActionRouter-CDXEdasl.mjs → createActionRouter-DVpoA0do.mjs} +14 -11
  36. package/dist/{createAggregationRouter-KrQDzx-k.mjs → createAggregationRouter-B_B48JZ-.mjs} +10 -8
  37. package/dist/{createApp-Df89BEni.mjs → createApp-CLGegqiG.mjs} +287 -62
  38. package/dist/{defineAggregation-DbPPS8RI.mjs → defineAggregation-Nv-DwfOf.mjs} +1 -1
  39. package/dist/{defineResource-Bv6EtN1x.mjs → defineResource-DR9vsUYy.mjs} +318 -35
  40. package/dist/discovery/index.mjs +1 -1
  41. package/dist/docs/index.d.mts +1 -1
  42. package/dist/docs/index.mjs +3 -3
  43. package/dist/{elevation-D2l1mh4g.mjs → elevation-B0tlY8y1.mjs} +4 -4
  44. package/dist/encryption/index.mjs +5 -4
  45. package/dist/{errorHandler-C5NeD6bT.mjs → errorHandler-C7xBqHsI.mjs} +42 -5
  46. package/dist/{errorHandler-CpYUJmPA.d.mts → errorHandler-DI5AN2b5.d.mts} +14 -3
  47. package/dist/{errors-Cj42AntO.mjs → errors-Cd_yy7aW.mjs} +1 -1
  48. package/dist/{eventPlugin-GF5nnBIq.d.mts → eventPlugin-DSNEZWfV.d.mts} +29 -1
  49. package/dist/{eventPlugin-CkffEihm.mjs → eventPlugin-Dar8qRaj.mjs} +68 -11
  50. package/dist/events/index.d.mts +18 -297
  51. package/dist/events/index.mjs +7 -758
  52. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  53. package/dist/events/transports/redis-stream-entry.mjs +14 -10
  54. package/dist/events/transports/redis.d.mts +1 -1
  55. package/dist/events/transports/redis.mjs +1 -1
  56. package/dist/factory/index.d.mts +20 -5
  57. package/dist/factory/index.mjs +131 -8
  58. package/dist/fastify-augmentation-DVsTAy6X.d.mts +179 -0
  59. package/dist/{fields-CB5Cuzk9.mjs → fields-CojeUkS4.mjs} +6 -11
  60. package/dist/{generate-EcA6ui4i.mjs → generate-DiB0nHPR.mjs} +2 -2
  61. package/dist/{headers-3zvE0rM3.mjs → headers-CveNO9gR.mjs} +2 -2
  62. package/dist/{health-DjZYjM7H.mjs → health-CasG2A28.mjs} +1 -1
  63. package/dist/hooks/index.d.mts +1 -1
  64. package/dist/hooks/index.mjs +2 -2
  65. package/dist/idempotency/index.d.mts +45 -1
  66. package/dist/idempotency/index.mjs +95 -11
  67. package/dist/idempotency/redis.mjs +1 -1
  68. package/dist/{index-CEJNZFtX.d.mts → index-B-DvUzsr.d.mts} +82 -3
  69. package/dist/{index-CpzxqePp.d.mts → index-BcR2bFZQ.d.mts} +707 -373
  70. package/dist/{index-Bc2ox8_U.d.mts → index-Brin0ODU.d.mts} +4 -4
  71. package/dist/{index-CFThn1K9.d.mts → index-C5NnMEKF.d.mts} +70 -4
  72. package/dist/{index-C-481Zf2.d.mts → index-ugr1tQlW.d.mts} +17 -1
  73. package/dist/index.d.mts +6 -6
  74. package/dist/index.mjs +11 -11
  75. package/dist/{init-BEiNZBsJ.mjs → init-mdJ-v4Xp.mjs} +24 -16
  76. package/dist/integrations/event-gateway.d.mts +1 -1
  77. package/dist/integrations/event-gateway.mjs +2 -2
  78. package/dist/integrations/index.d.mts +2 -2
  79. package/dist/integrations/index.mjs +1 -1
  80. package/dist/integrations/jobs/index.d.mts +1 -1
  81. package/dist/integrations/jobs/index.mjs +100 -98
  82. package/dist/integrations/mcp/index.d.mts +12 -3
  83. package/dist/integrations/mcp/index.mjs +2 -2
  84. package/dist/integrations/mcp/testing.d.mts +1 -1
  85. package/dist/integrations/mcp/testing.mjs +2 -2
  86. package/dist/integrations/streamline.mjs +3 -3
  87. package/dist/integrations/webhooks.d.mts +124 -1
  88. package/dist/integrations/webhooks.mjs +180 -2
  89. package/dist/integrations/websocket-pushref-redis.mjs +1 -1
  90. package/dist/integrations/websocket-redis.mjs +1 -1
  91. package/dist/integrations/websocket.mjs +38 -35
  92. package/dist/{interface-DYzM0q-u.mjs → interface-DznJrm9R.mjs} +1 -1
  93. package/dist/{jsonBody-BYbLDi5D.mjs → jsonBody-CfGH-GxO.mjs} +2 -2
  94. package/dist/{keys-C0_pa1tY.mjs → keys-WeKvY1dE.mjs} +1 -1
  95. package/dist/{loadResources-yawi9tAE.mjs → loadResources-Bj-aSsXi.mjs} +4 -3
  96. package/dist/{loadResourcesFromEntry-BAjYZonx.mjs → loadResourcesFromEntry-DwaxNcE2.mjs} +2 -2
  97. package/dist/logger/index.mjs +1 -1
  98. package/dist/{mcpPlugin-B_es0hiF.mjs → mcpPlugin-aJg5TqHi.mjs} +76 -36
  99. package/dist/{memory-DR6wpa9F.mjs → memory-qYSB7rMQ.mjs} +5 -5
  100. package/dist/{metrics-CUdw_wLB.mjs → metrics-D7uchLjN.mjs} +2 -2
  101. package/dist/middleware/index.d.mts +1 -1
  102. package/dist/middleware/index.mjs +3 -3
  103. package/dist/migrations/index.mjs +3 -3
  104. package/dist/{module-0pFJA6YW.mjs → module-CwKsgZXp.mjs} +1 -1
  105. package/dist/{multipartBody-wOgj_fnj.mjs → multipartBody-4w-S3-PU.mjs} +3 -3
  106. package/dist/{openapi-B2L4js1v.mjs → openapi-BN5cQaO2.mjs} +6 -6
  107. package/dist/outbox-admin/index.d.mts +85 -0
  108. package/dist/outbox-admin/index.mjs +115 -0
  109. package/dist/outbox-module-CXB79bvt.mjs +839 -0
  110. package/dist/outbox-module-D-VFq37T.d.mts +368 -0
  111. package/dist/permissions/index.d.mts +3 -3
  112. package/dist/permissions/index.mjs +6 -6
  113. package/dist/{permissions-L--QDAir.mjs → permissions-BAfwgBxc.mjs} +120 -8
  114. package/dist/{pipe-DRDNsI2T.mjs → pipe-BzzoEhHj.mjs} +3 -5
  115. package/dist/pipeline/index.d.mts +1 -1
  116. package/dist/pipeline/index.mjs +2 -2
  117. package/dist/{pipeline-UPQFatit.mjs → pipeline-q69DZzgG.mjs} +17 -15
  118. package/dist/plugins/index.d.mts +6 -6
  119. package/dist/plugins/index.mjs +16 -16
  120. package/dist/plugins/response-cache.mjs +2 -2
  121. package/dist/plugins/tracing-entry.mjs +2 -2
  122. package/dist/{pluralize-O0FZgESl.mjs → pluralize-B7xf8qZF.mjs} +1 -1
  123. package/dist/{preloadResources-Dz6BjzM6.mjs → preloadResources-BkyqeTDz.mjs} +1 -1
  124. package/dist/{preloadResources-CyoJMSiO.d.mts → preloadResources-g07ldtzh.d.mts} +30 -7
  125. package/dist/presets/filesUpload.d.mts +2 -2
  126. package/dist/presets/filesUpload.mjs +6 -6
  127. package/dist/presets/index.d.mts +2 -2
  128. package/dist/presets/index.mjs +2 -2
  129. package/dist/presets/multiTenant.d.mts +1 -1
  130. package/dist/presets/multiTenant.mjs +3 -3
  131. package/dist/presets/search.d.mts +2 -2
  132. package/dist/presets/search.mjs +2 -2
  133. package/dist/{presets-C4-g4_4P.mjs → presets-D-h0uWtP.mjs} +6 -5
  134. package/dist/projection-BKM0Ui-s.mjs +42 -0
  135. package/dist/{queryCachePlugin-BZr8v46E.mjs → queryCachePlugin-DhsZ0ZIc.mjs} +50 -8
  136. package/dist/{rateLimit-CMPY5Qms.mjs → rateLimit-D4-ASwsI.mjs} +2 -2
  137. package/dist/{rateLimitKey-Dn5JNmkj.mjs → rateLimitKey-XngqVNEV.mjs} +1 -1
  138. package/dist/{realtime-C5NoxWFY.mjs → realtime-CTkv3O59.mjs} +10 -10
  139. package/dist/{redis-stream-qN6A-RFv.d.mts → redis-stream-mwLWlfHG.d.mts} +1 -1
  140. package/dist/{registerRoute-CBN84fc7.mjs → registerRoute-DNnd3vkz.mjs} +10 -8
  141. package/dist/registry/index.d.mts +3 -3
  142. package/dist/registry/index.mjs +3 -3
  143. package/dist/{registry-4213U4zb.mjs → registry-CLxCR5LF.mjs} +2 -2
  144. package/dist/{renewingLease-Dll8mGgc.mjs → renewingLease-BnWtbA2U.mjs} +1 -1
  145. package/dist/{replyHelpers-DIiZKGUt.mjs → replyHelpers-BSBVCwL3.mjs} +2 -2
  146. package/dist/{repositoryFilter-f9eAfq_l.mjs → repositoryFilter-DKny7PDn.mjs} +1 -1
  147. package/dist/{requestContext-2TxXOJ7T.mjs → requestContext-uYE35JxI.mjs} +1 -1
  148. package/dist/{rolldown-runtime-CUsjNX9R.mjs → rolldown-runtime-DNg-KNCk.mjs} +1 -1
  149. package/dist/runtimeCapabilities-Dm88DaTW.mjs +49 -0
  150. package/dist/{schedules-DdtlICTf.mjs → schedules-CAcZgia0.mjs} +3 -3
  151. package/dist/{schemaConverter-D--wdJM-.mjs → schemaConverter-XH1RZRyu.mjs} +1 -1
  152. package/dist/{schemaIR-Bm2enbnh.mjs → schemaIR-CDvclAew.mjs} +2 -2
  153. package/dist/schemas/index.mjs +1 -1
  154. package/dist/scim/index.mjs +2 -2
  155. package/dist/scope/index.mjs +5 -5
  156. package/dist/{scope-DHx5Fous.mjs → scope-BaWcqBvr.mjs} +4 -4
  157. package/dist/{simpleEqualityMatcher-DjQJ7FKA.mjs → simpleEqualityMatcher-Se8VrsaP.mjs} +1 -1
  158. package/dist/{sse-CUTo9y0X.mjs → sse-Cf0jUHsh.mjs} +7 -6
  159. package/dist/{sseStream-B_5XcVVd.mjs → sseStream-Bvpi-UXQ.mjs} +2 -2
  160. package/dist/{store-helpers-D1MP_gRG.mjs → store-helpers-B88p99Z2.mjs} +1 -1
  161. package/dist/{streaming-PSZwi8JV.mjs → streaming-DsT1B5zJ.mjs} +1 -1
  162. package/dist/{subscribe-helpers-C0Tb2aUp.mjs → subscribe-helpers-CLIOHsOK.mjs} +2 -2
  163. package/dist/sync/changelog.mjs +1 -1
  164. package/dist/testing/cleanupStoreContract.d.mts +1 -1
  165. package/dist/testing/cleanupStoreContract.mjs +12 -6
  166. package/dist/testing/index.d.mts +52 -13
  167. package/dist/testing/index.mjs +110 -40
  168. package/dist/testing/outboxStoreContract.d.mts +11 -2
  169. package/dist/testing/outboxStoreContract.mjs +110 -21
  170. package/dist/testing/storageContract.mjs +11 -6
  171. package/dist/{transactionContext-dAfBVUrk.mjs → transactionContext-BYtWnwAS.mjs} +1 -1
  172. package/dist/{typeGuards-B0ryPo3I.mjs → typeGuards-jjKJDN13.mjs} +1 -1
  173. package/dist/types/index.d.mts +3 -3
  174. package/dist/types/index.mjs +1 -1
  175. package/dist/types/storage.mjs +1 -1
  176. package/dist/{types-CBgvkp8O.d.mts → types-BcTumAz_.d.mts} +128 -18
  177. package/dist/{types-CwcUQ610.d.mts → types-BfC83KsP.d.mts} +15 -1
  178. package/dist/{types-Cys0ko9Z.mjs → types-CoqIRrkY.mjs} +4 -4
  179. package/dist/{types-C4QE8qnm.d.mts → types-DVLddu2q.d.mts} +144 -1
  180. package/dist/usage/index.d.mts +1 -1
  181. package/dist/usage/index.mjs +0 -0
  182. package/dist/{userHelpers-ChYJ6CdK.mjs → userHelpers-CWF5pbZD.mjs} +1 -1
  183. package/dist/utils/index.d.mts +57 -5
  184. package/dist/utils/index.mjs +12 -11
  185. package/dist/{utils-vL8BrDE2.mjs → utils-h1V_sT-t.mjs} +38 -7
  186. package/dist/{validate-_KbifpHF.mjs → validate-CdQlz52F.mjs} +2 -2
  187. package/dist/{versioning-D_rhHfZm.d.mts → versioning-DEs-_hFi.d.mts} +1 -1
  188. package/dist/{versioning-CHDTor3P.mjs → versioning-rZbyLVD-.mjs} +4 -4
  189. package/package.json +31 -20
  190. package/skills/arc/SKILL.md +96 -4
  191. package/skills/arc/references/api-reference.md +19 -0
  192. package/skills/arc/references/production.md +2 -2
  193. package/dist/fastify-augmentation-zh0_AYHa.d.mts +0 -85
  194. package/dist/projection-BHw6xlOQ.mjs +0 -18
@@ -1,9 +1,9 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { n as getUserRoles } from "./userHelpers-ChYJ6CdK.mjs";
3
- import { b as isElevated, n as PUBLIC_SCOPE, x as isMember } from "./types-Cys0ko9Z.mjs";
4
- import { i as resolveEffectiveRoles, t as applyFieldReadPermissions } from "./fields-CB5Cuzk9.mjs";
5
- import { t as executePipeline } from "./pipe-DRDNsI2T.mjs";
6
- import { t as buildRequestScopeProjection } from "./projection-BHw6xlOQ.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { n as getUserRoles } from "./userHelpers-CWF5pbZD.mjs";
3
+ import { b as isElevated, n as PUBLIC_SCOPE, x as isMember } from "./types-CoqIRrkY.mjs";
4
+ import { i as resolveEffectiveRoles, t as applyFieldReadPermissions } from "./fields-CojeUkS4.mjs";
5
+ import { t as executePipeline } from "./pipe-BzzoEhHj.mjs";
6
+ import { t as buildRequestScopeProjection } from "./projection-BKM0Ui-s.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() */
@@ -122,9 +122,7 @@ function computeFieldCapabilities(fieldPerms, effectiveRoles) {
122
122
  case "visibleTo":
123
123
  readable = perm.roles?.some((r) => effectiveRoles.includes(r)) ?? false;
124
124
  break;
125
- case "writableBy":
126
- writable = perm.roles?.some((r) => effectiveRoles.includes(r)) ?? false;
127
- break;
125
+ case "writableBy": writable = perm.roles?.some((r) => effectiveRoles.includes(r)) ?? false;
128
126
  }
129
127
  caps[field] = {
130
128
  readable,
@@ -172,8 +170,10 @@ function sendControllerResponse(reply, response, request) {
172
170
  /** Apply both field mask and field-level permissions to a data item */
173
171
  const applyPermissions = (data) => {
174
172
  let result = fieldMaskConfig ? applyFieldMask(data, fieldMaskConfig) : data;
175
- if (fieldPerms && result && typeof result === "object") if (Array.isArray(result)) result = result.map((item) => applyFieldReadPermissions(item, fieldPerms, effectiveRoles));
176
- else result = applyFieldReadPermissions(result, fieldPerms, effectiveRoles);
173
+ if (fieldPerms && result && typeof result === "object") {
174
+ if (Array.isArray(result)) result = result.map((item) => applyFieldReadPermissions(item, fieldPerms, effectiveRoles));
175
+ else result = applyFieldReadPermissions(result, fieldPerms, effectiveRoles);
176
+ }
177
177
  return result;
178
178
  };
179
179
  if (response.headers) for (const [key, value] of Object.entries(response.headers)) reply.header(key, value);
@@ -281,11 +281,12 @@ function resolvePipelineSteps(pipeline, operation) {
281
281
  */
282
282
  function buildPipelineHandler(controllerMethod, steps, operation, resourceName) {
283
283
  return async (req, reply) => {
284
- sendControllerResponse(reply, await executePipeline(steps, {
284
+ const pipeCtx = {
285
285
  ...createRequestContext(req),
286
286
  resource: resourceName,
287
287
  operation
288
- }, (ctx) => controllerMethod(ctx), operation), req);
288
+ };
289
+ sendControllerResponse(reply, await executePipeline(steps, pipeCtx, (ctx) => controllerMethod(ctx), operation), req);
289
290
  };
290
291
  }
291
292
  /**
@@ -310,11 +311,12 @@ function buildActionPipelineHandler(handler, steps, operation, resourceName) {
310
311
  data: await handler(id, data, req)
311
312
  });
312
313
  return async (id, data, req) => {
313
- return executePipeline(steps, {
314
+ const pipeCtx = {
314
315
  ...createRequestContext(req),
315
316
  resource: resourceName,
316
317
  operation
317
- }, async (_ctx) => ({
318
+ };
319
+ return executePipeline(steps, pipeCtx, async (_ctx) => ({
318
320
  status: 200,
319
321
  data: await handler(id, data, req)
320
322
  }), operation);
@@ -1,10 +1,10 @@
1
1
 
2
- import { At as RouteDefinition, J as PresetHook, Q as MiddlewareConfig, et as RouteSchemaOptions } from "../index-CpzxqePp.mjs";
3
- import { l as AnyRecord } from "../types-B7XeLEgK.mjs";
4
- import { i as errorHandlerPlugin, n as ErrorMapper, r as defaultIsDuplicateKeyError, t as ErrorHandlerOptions } from "../errorHandler-CpYUJmPA.mjs";
5
- import { _ as _default$3, d as ScheduleStats, f as SchedulesPluginOptions, g as HealthOptions, h as HealthCheck, m as schedulesPlugin, p as _default$7, u as ScheduleDefinition, v as healthPlugin } from "../types-CBgvkp8O.mjs";
6
- import { a as arcCorePlugin, i as _default, n as ArcCorePluginOptions, r as PluginMeta, t as ArcCore } from "../fastify-augmentation-zh0_AYHa.mjs";
7
- import { _ as CachingRule, a as MetricsCollector, c as metricsPlugin, d as _default$5, f as realtimePlugin, g as CachingOptions, h as ssePlugin, i as MetricEntry, l as ChangeOperation, m as _default$8, n as _default$9, o as MetricsOptions, p as SSEOptions, r as versioningPlugin, s as _default$4, t as VersioningOptions, u as RealtimeOptions, v as _default$1, y as cachingPlugin } from "../versioning-D_rhHfZm.mjs";
2
+ import { t as AnyRecord } from "../base-Csjc2oF-.mjs";
3
+ import { At as RouteDefinition, J as PresetHook, Q as MiddlewareConfig, et as RouteSchemaOptions } from "../index-BcR2bFZQ.mjs";
4
+ import { i as errorHandlerPlugin, n as ErrorMapper, r as defaultIsDuplicateKeyError, t as ErrorHandlerOptions } from "../errorHandler-DI5AN2b5.mjs";
5
+ import { _ as HealthCheck, b as healthPlugin, f as ScheduleDefinition, g as schedulesPlugin, h as _default$7, m as SchedulesPluginOptions, p as ScheduleStats, v as HealthOptions, y as _default$3 } from "../types-BcTumAz_.mjs";
6
+ import { a as arcCorePlugin, i as _default, n as ArcCorePluginOptions, r as PluginMeta, t as ArcCore } from "../fastify-augmentation-DVsTAy6X.mjs";
7
+ import { _ as CachingRule, a as MetricsCollector, c as metricsPlugin, d as _default$5, f as realtimePlugin, g as CachingOptions, h as ssePlugin, i as MetricEntry, l as ChangeOperation, m as _default$8, n as _default$9, o as MetricsOptions, p as SSEOptions, r as versioningPlugin, s as _default$4, t as VersioningOptions, u as RealtimeOptions, v as _default$1, y as cachingPlugin } from "../versioning-DEs-_hFi.mjs";
8
8
  import { t as TracingOptions } from "../tracing-Dro5eH6j.mjs";
9
9
  import { PaginatedResult } from "@classytic/repo-core/pagination";
10
10
  import { FastifyInstance, FastifyPluginAsync } from "fastify";
@@ -1,19 +1,19 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { p as MUTATION_OPERATIONS } from "../constants-D3Dv4LAV.mjs";
3
- import { c as getOrgId } from "../types-Cys0ko9Z.mjs";
4
- import { n as requestContext } from "../requestContext-2TxXOJ7T.mjs";
5
- import { t as hasEvents } from "../typeGuards-B0ryPo3I.mjs";
6
- import { t as HookSystem } from "../HookSystem-BcmPyq5I.mjs";
7
- import { t as ResourceRegistry } from "../ResourceRegistry-qq0mn2s9.mjs";
8
- import { a as requestIdPlugin, i as createRequestIdGenerator, n as health_default, o as requestId_default, s as sanitizeRequestId, t as healthPlugin } from "../health-DjZYjM7H.mjs";
9
- import { n as caching_default, t as cachingPlugin } from "../caching-BFHA6Scf.mjs";
10
- import { n as errorHandlerPlugin, t as defaultIsDuplicateKeyError } from "../errorHandler-C5NeD6bT.mjs";
11
- import { n as metrics_default, t as metricsPlugin } from "../metrics-CUdw_wLB.mjs";
12
- import { n as realtime_default, t as realtimePlugin } from "../realtime-C5NoxWFY.mjs";
13
- import { t as replyHelpersPlugin } from "../replyHelpers-DIiZKGUt.mjs";
14
- import { n as schedules_default, t as schedulesPlugin } from "../schedules-DdtlICTf.mjs";
15
- import { n as sse_default, t as ssePlugin } from "../sse-CUTo9y0X.mjs";
16
- import { n as versioning_default, t as versioningPlugin } from "../versioning-CHDTor3P.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { p as MUTATION_OPERATIONS } from "../constants-BxCoxmiN.mjs";
3
+ import { c as getOrgId } from "../types-CoqIRrkY.mjs";
4
+ import { n as requestContext } from "../requestContext-uYE35JxI.mjs";
5
+ import { t as hasEvents } from "../typeGuards-jjKJDN13.mjs";
6
+ import { t as HookSystem } from "../HookSystem-DqXkMXkB.mjs";
7
+ import { t as ResourceRegistry } from "../ResourceRegistry-DoALUlOO.mjs";
8
+ import { a as requestIdPlugin, i as createRequestIdGenerator, n as health_default, o as requestId_default, s as sanitizeRequestId, t as healthPlugin } from "../health-CasG2A28.mjs";
9
+ import { n as caching_default, t as cachingPlugin } from "../caching-BcGmvnHh.mjs";
10
+ import { n as errorHandlerPlugin, t as defaultIsDuplicateKeyError } from "../errorHandler-C7xBqHsI.mjs";
11
+ import { n as metrics_default, t as metricsPlugin } from "../metrics-D7uchLjN.mjs";
12
+ import { n as realtime_default, t as realtimePlugin } from "../realtime-CTkv3O59.mjs";
13
+ import { t as replyHelpersPlugin } from "../replyHelpers-BSBVCwL3.mjs";
14
+ import { n as schedules_default, t as schedulesPlugin } from "../schedules-CAcZgia0.mjs";
15
+ import { n as sse_default, t as ssePlugin } from "../sse-Cf0jUHsh.mjs";
16
+ import { n as versioning_default, t as versioningPlugin } from "../versioning-rZbyLVD-.mjs";
17
17
  import fp from "fastify-plugin";
18
18
  //#region src/core/arcCorePlugin.ts
19
19
  const arcCorePlugin = async (fastify, opts = {}) => {
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { t as hasEvents } from "../typeGuards-B0ryPo3I.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { t as hasEvents } from "../typeGuards-jjKJDN13.mjs";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/plugins/response-cache.ts
5
5
  /**
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
2
  import { createRequire } from "node:module";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/plugins/tracing.ts
@@ -59,7 +59,7 @@ try {
59
59
  function createTracerProvider(options) {
60
60
  if (!isAvailable || !NodeTracerProvider || !BatchSpanProcessor || !OTLPTraceExporter) return null;
61
61
  const { serviceName = "@classytic/arc", serviceVersion, exporterUrl = "http://localhost:4318/v1/traces" } = options;
62
- const resolvedVersion = serviceVersion ?? "2.31.0";
62
+ const resolvedVersion = serviceVersion ?? "2.34.0";
63
63
  const exporter = new OTLPTraceExporter({ url: exporterUrl });
64
64
  const provider = new NodeTracerProvider({ resource: { attributes: {
65
65
  "service.name": serviceName,
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
2
  //#region src/utils/pluralize.ts
3
3
  /**
4
4
  * Lightweight English pluralization for the Arc CLI.
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
2
  //#region src/factory/preloadResources.ts
3
3
  /**
4
4
  * Normalize an eager `import.meta.glob` result into a `ResourceLike[]`.
@@ -1,15 +1,15 @@
1
1
 
2
- import { Gt as Authenticator } from "./index-CpzxqePp.mjs";
2
+ import { It as Authenticator } from "./index-BcR2bFZQ.mjs";
3
3
  import { r as CacheStore } from "./interface-BOk3YnTz.mjs";
4
4
  import { n as ElevationOptions } from "./elevation-BXCfVcNG.mjs";
5
- import { a as EventTransport } from "./EventTransport-2uVV34WU.mjs";
5
+ import { a as EventTransport } from "./EventTransport-BEVP50ka.mjs";
6
6
  import { t as ExternalOpenApiPaths } from "./externalPaths-CmGOxOtD.mjs";
7
7
  import { r as QueryCachePluginOptions } from "./queryCachePlugin-BzqxconG.mjs";
8
- import { t as ErrorHandlerOptions } from "./errorHandler-CpYUJmPA.mjs";
9
- import { f as SchedulesPluginOptions, g as HealthOptions, n as ArcModuleInput, s as ResourceLike } from "./types-CBgvkp8O.mjs";
10
- import "./index-CFThn1K9.mjs";
11
- import { t as EventPluginOptions } from "./eventPlugin-GF5nnBIq.mjs";
12
- import { g as CachingOptions, o as MetricsOptions, p as SSEOptions, t as VersioningOptions, u as RealtimeOptions } from "./versioning-D_rhHfZm.mjs";
8
+ import { t as ErrorHandlerOptions } from "./errorHandler-DI5AN2b5.mjs";
9
+ import { l as ResourceLike, m as SchedulesPluginOptions, n as ArcModuleInput, v as HealthOptions } from "./types-BcTumAz_.mjs";
10
+ import "./index-C5NnMEKF.mjs";
11
+ import { t as EventPluginOptions } from "./eventPlugin-DSNEZWfV.mjs";
12
+ import { g as CachingOptions, o as MetricsOptions, p as SSEOptions, t as VersioningOptions, u as RealtimeOptions } from "./versioning-DEs-_hFi.mjs";
13
13
  import { r as IdempotencyStore } from "./interface-DEWNOMza.mjs";
14
14
  import { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest, FastifyServerOptions } from "fastify";
15
15
  //#region src/factory/types/assets.d.ts
@@ -463,6 +463,29 @@ interface CreateAppOptions {
463
463
  * would be instance-local.
464
464
  */
465
465
  runtime?: "memory" | "distributed";
466
+ /**
467
+ * Deployment ROLE of this process (topology plan, Phase 2). Decides which
468
+ * async machinery mounts; default `'all'` is the single-process case and
469
+ * changes nothing.
470
+ *
471
+ * - `'api'` / `'worker'` — no module schedule arms run here (the outbox
472
+ * relay arm included); a worker fleet or scheduler deployment owns them.
473
+ * Register `jobsPlugin({ mode })` to match ('api' → 'producer').
474
+ * - `'relay'` — ONLY `kind: 'relay'` schedule arms run (the outbox
475
+ * relays); declaring HTTP `resources` is boot-fatal.
476
+ * - `'scheduler'` — every schedule arm runs; HTTP resources boot-fatal.
477
+ * - `'all'` — everything (default).
478
+ *
479
+ * A skipped arm is logged by name at boot so a misdeployed process is
480
+ * legible from its first lines.
481
+ *
482
+ * `createWorker` is the paved road for headless processes and forwards
483
+ * this option untouched — one axis, not two mechanisms. Its default stays
484
+ * `'all'` (its 2.23 contract: the headless process runs everything
485
+ * non-HTTP); pass `role: 'worker'` there when a dedicated scheduler/relay
486
+ * deployment owns the arms.
487
+ */
488
+ role?: "api" | "worker" | "relay" | "scheduler" | "all";
466
489
  /**
467
490
  * Store and transport instances for runtime profile validation.
468
491
  * When `runtime` is `'distributed'`, Arc validates that these are
@@ -1,7 +1,7 @@
1
1
 
2
- import { Y as PresetResult } from "../index-CpzxqePp.mjs";
3
2
  import { i as RequestScope } from "../types-ChuShpCP.mjs";
4
- import { r as PermissionCheck } from "../types-B7XeLEgK.mjs";
3
+ import { l as PermissionCheck } from "../base-Csjc2oF-.mjs";
4
+ import { Y as PresetResult } from "../index-BcR2bFZQ.mjs";
5
5
  import { a as StorageReadResult, i as StorageReadRange, n as StorageContext, o as StorageUploadInput, r as StorageFile, t as Storage } from "../storage-Cx9Sz3Ou.mjs";
6
6
  //#region src/presets/filesUpload.d.ts
7
7
  interface FilesUploadPresetRoutes {
@@ -1,11 +1,11 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { i as NotFoundError, u as ValidationError } from "../errors-Cj42AntO.mjs";
3
- import { c as getOrgId, g as getUserId } from "../types-Cys0ko9Z.mjs";
4
- import { I as requireAuth, j as allowPublic } from "../permissions-L--QDAir.mjs";
5
- import { t as multipartBody } from "../multipartBody-wOgj_fnj.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { i as NotFoundError, u as ValidationError } from "../errors-Cd_yy7aW.mjs";
3
+ import { c as getOrgId, g as getUserId } from "../types-CoqIRrkY.mjs";
4
+ import { B as requireAuth, F as allowPublic } from "../permissions-BAfwgBxc.mjs";
5
+ import { t as multipartBody } from "../multipartBody-4w-S3-PU.mjs";
6
6
  //#region src/presets/filesUpload.ts
7
7
  const DEFAULT_FIELD_NAME = "file";
8
- const DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;
8
+ const DEFAULT_MAX_FILE_SIZE = 10485760;
9
9
  function defaultContextFrom(scope) {
10
10
  if (!scope) return {};
11
11
  const userId = getUserId(scope);
@@ -1,6 +1,6 @@
1
1
 
2
- import { Rt as IControllerResponse, U as ResourceConfig, Y as PresetResult, d as PaginationResult, zt as IRequestContext } from "../index-CpzxqePp.mjs";
3
- import { l as AnyRecord } from "../types-B7XeLEgK.mjs";
2
+ import { t as AnyRecord } from "../base-Csjc2oF-.mjs";
3
+ import { Fn as IControllerResponse, In as IRequestContext, U as ResourceConfig, Y as PresetResult, d as PaginationResult } from "../index-BcR2bFZQ.mjs";
4
4
  import { FilesUploadPresetOptions, FilesUploadPresetPermissions, FilesUploadPresetRoutes, filesUploadPreset } from "./filesUpload.mjs";
5
5
  import { MultiTenantOptions, TenantFieldSpec, multiTenantPreset } from "./multiTenant.mjs";
6
6
  import { SearchHandler, SearchPresetOptions, SearchRouteConfig, searchPreset } from "./search.mjs";
@@ -1,6 +1,6 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
2
  import { multiTenantPreset } from "./multiTenant.mjs";
3
- import { a as registerPreset, c as auditedPreset, d as ownedByUserPreset, i as getPreset, l as softDeletePreset, n as flexibleMultiTenantPreset, o as treePreset, r as getAvailablePresets, s as bulkPreset, t as applyPresets, u as slugLookupPreset } from "../presets-C4-g4_4P.mjs";
3
+ import { a as registerPreset, c as auditedPreset, d as ownedByUserPreset, i as getPreset, l as softDeletePreset, n as flexibleMultiTenantPreset, o as treePreset, r as getAvailablePresets, s as bulkPreset, t as applyPresets, u as slugLookupPreset } from "../presets-D-h0uWtP.mjs";
4
4
  import { filesUploadPreset } from "./filesUpload.mjs";
5
5
  import { searchPreset } from "./search.mjs";
6
6
  export { applyPresets, auditedPreset, bulkPreset, filesUploadPreset, flexibleMultiTenantPreset, getAvailablePresets, getPreset, multiTenantPreset, ownedByUserPreset, registerPreset, searchPreset, slugLookupPreset, softDeletePreset, treePreset };
@@ -1,5 +1,5 @@
1
1
 
2
- import { X as CrudRouteKey, Y as PresetResult } from "../index-CpzxqePp.mjs";
2
+ import { X as CrudRouteKey, Y as PresetResult } from "../index-BcR2bFZQ.mjs";
3
3
  //#region src/presets/multiTenant.d.ts
4
4
  /**
5
5
  * One tenant dimension for multi-field filtering. Discriminated by source:
@@ -1,6 +1,6 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import "../constants-D3Dv4LAV.mjs";
3
- import { b as isElevated, c as getOrgId, d as getScopeContext, m as getTeamId, u as getRequestScope, v as hasOrgAccess } from "../types-Cys0ko9Z.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import "../constants-BxCoxmiN.mjs";
3
+ import { b as isElevated, c as getOrgId, d as getScopeContext, m as getTeamId, u as getRequestScope, v as hasOrgAccess } from "../types-CoqIRrkY.mjs";
4
4
  //#region src/presets/multiTenant.ts
5
5
  /**
6
6
  * Resolve a single TenantFieldSpec against the current scope.
@@ -1,6 +1,6 @@
1
1
 
2
- import { At as RouteDefinition, Pt as ControllerHandler, Y as PresetResult, jt as RouteMcpConfig } from "../index-CpzxqePp.mjs";
3
- import { r as PermissionCheck } from "../types-B7XeLEgK.mjs";
2
+ import { l as PermissionCheck } from "../base-Csjc2oF-.mjs";
3
+ import { At as RouteDefinition, Y as PresetResult, jn as ControllerHandler, jt as RouteMcpConfig } from "../index-BcR2bFZQ.mjs";
4
4
  //#region src/presets/search.d.ts
5
5
  /**
6
6
  * Search Preset — backend-agnostic search / vector / embed routes
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { I as requireAuth, j as allowPublic } from "../permissions-L--QDAir.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { B as requireAuth, F as allowPublic } from "../permissions-BAfwgBxc.mjs";
3
3
  //#region src/presets/search.ts
4
4
  const BUILTINS = [
5
5
  {
@@ -1,7 +1,7 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { l as UnauthorizedError } from "./errors-Cj42AntO.mjs";
3
- import { b as isElevated, n as PUBLIC_SCOPE } from "./types-Cys0ko9Z.mjs";
4
- import { I as requireAuth, j as allowPublic, z as requireRoles } from "./permissions-L--QDAir.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { l as UnauthorizedError } from "./errors-Cd_yy7aW.mjs";
3
+ import { b as isElevated, n as PUBLIC_SCOPE } from "./types-CoqIRrkY.mjs";
4
+ import { B as requireAuth, F as allowPublic, U as requireRoles } from "./permissions-BAfwgBxc.mjs";
5
5
  import { multiTenantPreset } from "./presets/multiTenant.mjs";
6
6
  //#region src/presets/ownedByUser.ts
7
7
  /**
@@ -14,7 +14,8 @@ import { multiTenantPreset } from "./presets/multiTenant.mjs";
14
14
  */
15
15
  function createOwnershipCheck(ownerField, missingOwner) {
16
16
  return async (request, _reply) => {
17
- if (isElevated(request.scope ?? PUBLIC_SCOPE)) return;
17
+ const scope = request.scope ?? PUBLIC_SCOPE;
18
+ if (isElevated(scope)) return;
18
19
  const user = request.user;
19
20
  if (!user) throw new UnauthorizedError("Authentication required for this operation");
20
21
  const userWithId = user;
@@ -0,0 +1,42 @@
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { c as getOrgId, f as getScopeContextMap, g as getUserId, m as getTeamId, x as isMember } from "./types-CoqIRrkY.mjs";
3
+ //#region src/scope/projection.ts
4
+ /**
5
+ * Compute the request-scope projection. Returns `undefined` when no
6
+ * scope is attached (public / unscoped routes) so hosts can idiomatically
7
+ * write `ctx.scope?.organizationId` without a double-null check.
8
+ */
9
+ function buildRequestScopeProjection(scope) {
10
+ if (!scope) return void 0;
11
+ return {
12
+ organizationId: getOrgId(scope),
13
+ userId: getUserId(scope),
14
+ orgRoles: isMember(scope) ? scope.orgRoles : void 0,
15
+ teamId: getTeamId(scope),
16
+ context: freezeContext(getScopeContextMap(scope))
17
+ };
18
+ }
19
+ /**
20
+ * Hand out a FROZEN COPY of the scope's context, never the live map.
21
+ *
22
+ * `Readonly<Record<string, string>>` is erased at runtime, so the annotation
23
+ * alone protected nothing: `getScopeContextMap` returns the scope's own
24
+ * object, and a hook doing `ctx.scope.context.branchId = 'other'` mutated the
25
+ * caller's REAL scope. That matters because `requireScopeContext()` authorises
26
+ * against exactly these values — a later permission check in the same request
27
+ * would read the tampered dimension and allow what it should refuse.
28
+ *
29
+ * A copy rather than freezing in place: the map belongs to whoever built the
30
+ * scope (a host auth function), and freezing someone else's object as a side
31
+ * effect of reading it is a surprise a library should not spring. Copying also
32
+ * makes the guarantee deterministic instead of "frozen once something happens
33
+ * to call the accessor".
34
+ *
35
+ * ESM is always strict mode, so a write to the frozen copy THROWS rather than
36
+ * failing silently — the mistake surfaces where it is made.
37
+ */
38
+ function freezeContext(ctx) {
39
+ return ctx === void 0 ? void 0 : Object.freeze({ ...ctx });
40
+ }
41
+ //#endregion
42
+ export { buildRequestScopeProjection as t };
@@ -1,8 +1,8 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { t as __exportAll } from "./rolldown-runtime-CUsjNX9R.mjs";
3
- import { t as hasEvents } from "./typeGuards-B0ryPo3I.mjs";
4
- import { i as versionKey, r as tagVersionKey } from "./keys-C0_pa1tY.mjs";
5
- import { t as MemoryCacheStore } from "./memory-DR6wpa9F.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { t as __exportAll } from "./rolldown-runtime-DNg-KNCk.mjs";
3
+ import { t as hasEvents } from "./typeGuards-jjKJDN13.mjs";
4
+ import { i as versionKey, r as tagVersionKey } from "./keys-WeKvY1dE.mjs";
5
+ import { t as MemoryCacheStore } from "./memory-qYSB7rMQ.mjs";
6
6
  import fp from "fastify-plugin";
7
7
  //#region src/cache/QueryCache.ts
8
8
  var QueryCache = class {
@@ -100,7 +100,7 @@ var QueryCache = class {
100
100
  }
101
101
  };
102
102
  /** See `bumpVersion` — effectively non-expiring, refreshed on every bump. */
103
- const VERSION_TTL_SECONDS = 365 * 24 * 60 * 60;
103
+ const VERSION_TTL_SECONDS = 31536e3;
104
104
  //#endregion
105
105
  //#region src/cache/queryCachePlugin.ts
106
106
  var queryCachePlugin_exports = /* @__PURE__ */ __exportAll({ queryCachePlugin: () => queryCachePlugin });
@@ -110,6 +110,7 @@ const CRUD_SUFFIXES = /* @__PURE__ */ new Set([
110
110
  "deleted"
111
111
  ]);
112
112
  const queryCachePluginImpl = async (fastify, opts = {}) => {
113
+ const ownsStore = opts.store === void 0;
113
114
  const store = opts.store ?? new MemoryCacheStore();
114
115
  const queryCache = new QueryCache(store);
115
116
  const defaults = {
@@ -124,20 +125,61 @@ const queryCachePluginImpl = async (fastify, opts = {}) => {
124
125
  });
125
126
  fastify.addHook("onReady", async () => {
126
127
  if (!hasEvents(fastify)) return;
128
+ /**
129
+ * Auto-invalidate on CRUD events — `product.created` bumps `product`, and
130
+ * `catalog:category.created` bumps BOTH `catalog:category` and `category`.
131
+ *
132
+ * ## Why the namespace has to be stripped
133
+ *
134
+ * This derived the resource as "everything before the last dot", which is right for
135
+ * an arc-native event (`product.created`) and wrong for every NAMESPACED one. Each
136
+ * `@classytic/*` kernel publishes `<domain>:<entity>.<verb>` —
137
+ * `catalog:category.created`, `revenue:payment.verified`,
138
+ * `access:entitlement.granted` — so the resource came out as `catalog:category` and
139
+ * the version bumped at `arc:ver:catalog:category`.
140
+ *
141
+ * Readers use the arc RESOURCE NAME: `buildQueryKey(resource, …)` folds in
142
+ * `getResourceVersion("category")`, i.e. `arc:ver:category`. Bump and read
143
+ * therefore used different keys and **auto-invalidation never fired for any
144
+ * kernel-backed resource** — no error, no warning, just caches serving stale data
145
+ * for a full `staleTime`. It was invisible precisely because the feature looks
146
+ * wired: the plugin is registered, events flow, a version does get bumped.
147
+ *
148
+ * ## Both names are bumped, on purpose
149
+ *
150
+ * Two namespaces could each own an `<entity>` of the same name (`catalog:category`
151
+ * and a hypothetical `cms:category`), so stripping is ambiguous. The asymmetry
152
+ * decides it: **over-invalidation costs a cache miss, under-invalidation serves
153
+ * wrong data.** Bumping both the qualified and the bare name means an unrelated
154
+ * namespace can at worst force an extra reload, and never a stale read. That is the
155
+ * same reasoning applied everywhere else here — a permissive default is only
156
+ * acceptable when the failure it causes is loud and cheap.
157
+ *
158
+ * By the same argument the split is UNCONDITIONAL: any `:` in the qualified
159
+ * name yields a bare candidate, including when the prefix itself contains a
160
+ * dot (`some.thing:entity` bumps `entity` too). Narrowing that would remove
161
+ * invalidations, which is the one direction that can serve wrong data.
162
+ */
127
163
  await fastify.events.subscribe("*", async (event) => {
128
164
  const type = event.type;
129
165
  const dotIdx = type.lastIndexOf(".");
130
166
  if (dotIdx === -1) return;
131
167
  const suffix = type.slice(dotIdx + 1);
132
168
  if (!CRUD_SUFFIXES.has(suffix)) return;
133
- const resource = type.slice(0, dotIdx);
134
- await queryCache.bumpResourceVersion(resource);
169
+ const qualified = type.slice(0, dotIdx);
170
+ await queryCache.bumpResourceVersion(qualified);
171
+ const colonIdx = qualified.lastIndexOf(":");
172
+ if (colonIdx === -1) return;
173
+ const bare = qualified.slice(colonIdx + 1);
174
+ if (bare.length === 0 || bare === qualified) return;
175
+ await queryCache.bumpResourceVersion(bare);
135
176
  });
136
177
  for (const rule of crossResourceRules) await fastify.events.subscribe(rule.pattern, async () => {
137
178
  for (const tag of rule.tags) await queryCache.bumpTagVersion(tag);
138
179
  });
139
180
  });
140
181
  fastify.addHook("onClose", async () => {
182
+ if (!ownsStore) return;
141
183
  if ("close" in store && typeof store.close === "function") await store.close();
142
184
  });
143
185
  };
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { n as requestContext } from "./requestContext-2TxXOJ7T.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { n as requestContext } from "./requestContext-uYE35JxI.mjs";
3
3
  //#region src/core/middlewares/arcDecorator.ts
4
4
  /**
5
5
  * Build the `arcDecorator` preHandler for a resource.
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
2
  //#region src/scope/rateLimitKey.ts
3
3
  function createTenantKeyGenerator(opts) {
4
4
  if (opts?.strategy) return opts.strategy;
@@ -1,13 +1,13 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { t as __exportAll } from "./rolldown-runtime-CUsjNX9R.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { t as __exportAll } from "./rolldown-runtime-DNg-KNCk.mjs";
3
3
  import { arcLog } from "./logger/index.mjs";
4
- import { n as evaluateAndApplyPermission } from "./authorizationDecision-ChvUQGG1.mjs";
5
- import { n as getUserRoles } from "./userHelpers-ChYJ6CdK.mjs";
6
- import { c as getOrgId } from "./types-Cys0ko9Z.mjs";
7
- import { t as simpleEqualityMatcher } from "./simpleEqualityMatcher-DjQJ7FKA.mjs";
8
- import { t as applyFieldReadPermissions } from "./fields-CB5Cuzk9.mjs";
9
- import { a as promoteStreamTokenToHeader } from "./streaming-PSZwi8JV.mjs";
10
- import { t as openSseStream } from "./sseStream-B_5XcVVd.mjs";
4
+ import { n as evaluateAndApplyPermission } from "./authorizationDecision-B3mP_QTy.mjs";
5
+ import { n as getUserRoles } from "./userHelpers-CWF5pbZD.mjs";
6
+ import { c as getOrgId } from "./types-CoqIRrkY.mjs";
7
+ import { t as simpleEqualityMatcher } from "./simpleEqualityMatcher-Se8VrsaP.mjs";
8
+ import { t as applyFieldReadPermissions } from "./fields-CojeUkS4.mjs";
9
+ import { a as promoteStreamTokenToHeader } from "./streaming-DsT1B5zJ.mjs";
10
+ import { t as openSseStream } from "./sseStream-Bvpi-UXQ.mjs";
11
11
  import fp from "fastify-plugin";
12
12
  //#region src/plugins/realtime.ts
13
13
  var realtime_exports = /* @__PURE__ */ __exportAll({
@@ -47,7 +47,7 @@ const MAX_TIMER_MS = 2147483647;
47
47
  * churning connections. A host that truly wants a longer-lived feed sets
48
48
  * `maxConnectionMs` explicitly (up to `MAX_TIMER_MS`).
49
49
  */
50
- const DEFAULT_MAX_CONNECTION_MS = 30 * 6e4;
50
+ const DEFAULT_MAX_CONNECTION_MS = 18e5;
51
51
  /**
52
52
  * Milliseconds from `now` until the feed should force-close to bound
53
53
  * permission staleness — `min(auth-token exp, maxConnectionMs)`. Returns
@@ -1,5 +1,5 @@
1
1
 
2
- import { a as EventTransport, i as EventLogger, n as DomainEvent, r as EventHandler } from "./EventTransport-2uVV34WU.mjs";
2
+ import { a as EventTransport, i as EventLogger, n as DomainEvent, r as EventHandler } from "./EventTransport-BEVP50ka.mjs";
3
3
  //#region src/events/transports/redis-stream.d.ts
4
4
  interface RedisStreamLike {
5
5
  xadd(key: string, id: string, ...fieldValues: string[]): Promise<string | null>;
@@ -1,7 +1,7 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { n as evaluateAndApplyPermission } from "./authorizationDecision-ChvUQGG1.mjs";
3
- import { f as createError } from "./errors-Cj42AntO.mjs";
4
- import { u as getRequestScope } from "./types-Cys0ko9Z.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { n as evaluateAndApplyPermission } from "./authorizationDecision-B3mP_QTy.mjs";
3
+ import { f as createError } from "./errors-Cd_yy7aW.mjs";
4
+ import { u as getRequestScope } from "./types-CoqIRrkY.mjs";
5
5
  //#region src/core/middlewares/permissions.ts
6
6
  /**
7
7
  * Build a PermissionContext from a Fastify request. Extracted so the CRUD
@@ -32,10 +32,11 @@ function buildPermissionContext(req, opts) {
32
32
  function buildCrudPermissionMw(permissionCheck, resourceName, action) {
33
33
  if (!permissionCheck) return null;
34
34
  return async (req, reply) => {
35
- await evaluateAndApplyPermission(permissionCheck, buildPermissionContext(req, {
35
+ const context = buildPermissionContext(req, {
36
36
  resource: resourceName,
37
37
  action
38
- }), req, reply);
38
+ });
39
+ await evaluateAndApplyPermission(permissionCheck, context, req, reply);
39
40
  };
40
41
  }
41
42
  /**
@@ -64,12 +65,13 @@ function buildActionPermissionMw(actionEnum, actionPermissions, globalAuth, reso
64
65
  if (!permissionCheck) return;
65
66
  const { action: _discard, ...data } = body;
66
67
  const params = req.params;
67
- await evaluateAndApplyPermission(permissionCheck, buildPermissionContext(req, {
68
+ const context = buildPermissionContext(req, {
68
69
  resource: resourceName,
69
70
  action,
70
71
  resourceId: params?.id,
71
72
  data
72
- }), req, reply, { defaultDenialMessage: (user) => user ? `Permission denied for '${action}'` : "Authentication required" });
73
+ });
74
+ await evaluateAndApplyPermission(permissionCheck, context, req, reply, { defaultDenialMessage: (user) => user ? `Permission denied for '${action}'` : "Authentication required" });
73
75
  };
74
76
  }
75
77
  //#endregion
@@ -1,8 +1,8 @@
1
1
 
2
- import { K as ResolvedTenantPurge, R as RegisterOptions, V as ResourceDefinition, X as CrudRouteKey, k as IntrospectionPluginOptions, p as RegistryEntry, z as ResourceRegistry } from "../index-CpzxqePp.mjs";
3
- import "../fastify-augmentation-zh0_AYHa.mjs";
4
- import { FastifyPluginAsync } from "fastify";
2
+ import { K as ResolvedTenantPurge, R as RegisterOptions, V as ResourceDefinition, X as CrudRouteKey, k as IntrospectionPluginOptions, p as RegistryEntry, z as ResourceRegistry } from "../index-BcR2bFZQ.mjs";
3
+ import "../fastify-augmentation-DVsTAy6X.mjs";
5
4
  import { TenantPurgeProgress, TenantPurgeStrategy } from "@classytic/repo-core/repository";
5
+ import { FastifyPluginAsync } from "fastify";
6
6
  //#region src/registry/assertNoTenantData.d.ts
7
7
  interface AssertNoTenantDataOptions {
8
8
  readonly organizationId: string;
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { a as cascadeDeleteForOrganization, c as assertNoTenantData, i as introspectionPlugin_default, n as buildResourceManifestFromRegistry, o as getCascadingResources, r as introspectionPlugin, s as getCascadingResourcesWithMetadata, t as buildResourceManifest } from "../registry-4213U4zb.mjs";
3
- import { t as ResourceRegistry } from "../ResourceRegistry-qq0mn2s9.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { a as cascadeDeleteForOrganization, c as assertNoTenantData, i as introspectionPlugin_default, n as buildResourceManifestFromRegistry, o as getCascadingResources, r as introspectionPlugin, s as getCascadingResourcesWithMetadata, t as buildResourceManifest } from "../registry-CLxCR5LF.mjs";
3
+ import { t as ResourceRegistry } from "../ResourceRegistry-DoALUlOO.mjs";
4
4
  export { ResourceRegistry, assertNoTenantData, buildResourceManifest, buildResourceManifestFromRegistry, cascadeDeleteForOrganization, getCascadingResources, getCascadingResourcesWithMetadata, introspectionPlugin_default as introspectionPlugin, introspectionPlugin as introspectionPluginFn };
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { t as CRUD_OPERATIONS } from "./constants-D3Dv4LAV.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { t as CRUD_OPERATIONS } from "./constants-BxCoxmiN.mjs";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/registry/assertNoTenantData.ts
5
5
  /**
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
2
  //#region src/lock/renewingLease.ts
3
3
  /**
4
4
  * Start renewing an ALREADY-ACQUIRED lease. The caller performed the