@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,7 +1,7 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { g as getUserId } from "../types-Cys0ko9Z.mjs";
3
- import { t as defineResource } from "../defineResource-Bv6EtN1x.mjs";
4
- import { t as defineModule } from "../module-0pFJA6YW.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { g as getUserId } from "../types-CoqIRrkY.mjs";
3
+ import { t as defineResource } from "../defineResource-DR9vsUYy.mjs";
4
+ import { t as defineModule } from "../module-CwKsgZXp.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
@@ -85,6 +85,18 @@ const CleanupErrors = {
85
85
  status
86
86
  });
87
87
  },
88
+ /**
89
+ * The operator's exclusion list cannot be honoured as written.
90
+ *
91
+ * A 400 rather than a filter: dropping an unrecognised exclusion leaves
92
+ * someone believing they narrowed a destructive run when they did not, and
93
+ * dropping a PROTECTIVE one would let a guard be switched off from the same
94
+ * request that starts the run. `steps` carries the offending ids so a UI can
95
+ * point at them.
96
+ */
97
+ invalidExclusion(reason, steps) {
98
+ return new CleanupError("CLEANUP_INVALID_EXCLUSION", 400, reason, { steps: [...steps] });
99
+ },
88
100
  forbidden(operation) {
89
101
  return new CleanupError("CLEANUP_FORBIDDEN", 403, `Not authorized to ${operation} cleanup.`, { operation });
90
102
  }
@@ -102,6 +114,53 @@ function stepContextOf(ctx, parameters) {
102
114
  logger: ctx.logger
103
115
  };
104
116
  }
117
+ /**
118
+ * Resolve the operator's exclusion list against the recipe's real steps.
119
+ *
120
+ * REFUSES rather than filters. Two rejections, both of which a permissive
121
+ * version would turn into a silent lie:
122
+ *
123
+ * - **unknown id** — a typo, or a step that has since been removed. Dropping
124
+ * it leaves the operator believing they narrowed a destructive run when the
125
+ * excluded domain will in fact be purged. A free-text ignore-list that
126
+ * silently tolerates unknown entries carries exactly this hazard.
127
+ * - **a protective step** — the property an ignore-list alone cannot give. A
128
+ * guard deletes nothing; it stands between the run and records that must
129
+ * never be purged. If it can be switched off from the same screen that
130
+ * starts the run, it is advice, not a guard. `destructive: false` alone is
131
+ * not the test — a projection rebuild is also non-destructive and IS
132
+ * legitimately excludable — so the marker is the step's own
133
+ * `disposition: 'protect'`.
134
+ *
135
+ * Returns the validated set; throws `CleanupErrors.invalidInput` otherwise.
136
+ */
137
+ function resolveExclusions(steps, requested) {
138
+ if (!requested || requested.length === 0) return /* @__PURE__ */ new Set();
139
+ const byId = new Map(steps.map((s) => [s.id, s]));
140
+ const unknown = [];
141
+ const protectedIds = [];
142
+ for (const id of requested) {
143
+ const step = byId.get(id);
144
+ if (!step) {
145
+ unknown.push(id);
146
+ continue;
147
+ }
148
+ if (isProtective(step)) protectedIds.push(id);
149
+ }
150
+ if (unknown.length > 0) throw CleanupErrors.invalidExclusion(`excludeSteps names step(s) this recipe does not have: ${unknown.join(", ")}. Refusing rather than ignoring — a dropped exclusion means the run touches data the operator believed they had left out.`, unknown);
151
+ if (protectedIds.length > 0) throw CleanupErrors.invalidExclusion(`excludeSteps names protective step(s): ${protectedIds.join(", ")}. A guard deletes nothing; it refuses the run when records that must never be purged are present. It cannot be switched off from the same request that starts the run.`, protectedIds);
152
+ return new Set(requested);
153
+ }
154
+ /**
155
+ * Is this step a GUARD?
156
+ *
157
+ * Asked of the step's declared disposition rather than `destructive`, because
158
+ * `destructive: false` covers guards AND projection rebuilds — and a rebuild is
159
+ * perfectly reasonable to exclude.
160
+ */
161
+ function isProtective(step) {
162
+ return step.disposition === "protect";
163
+ }
105
164
  function errMessage(err) {
106
165
  return err instanceof Error ? err.message : String(err);
107
166
  }
@@ -131,16 +190,63 @@ function recipeFromSteps(input) {
131
190
  },
132
191
  async plan(cleanupInput, ctx) {
133
192
  const stepCtx = stepContextOf(ctx, cleanupInput.parameters ?? {});
193
+ const excluded = resolveExclusions(steps, cleanupInput.excludeSteps);
134
194
  const items = [];
135
195
  const blockers = /* @__PURE__ */ new Set();
136
196
  const retains = new Set(input.retains ?? []);
137
197
  const rebuildActions = /* @__PURE__ */ new Set();
138
198
  const warnings = new Set(input.warnings ?? []);
139
199
  for (const step of steps) {
200
+ /**
201
+ * An excluded step is NOT estimated.
202
+ *
203
+ * Estimating it would run its counting queries for a line the operator
204
+ * has already taken out — cost with no consequence — and, worse, would
205
+ * surface its blockers, so leaving a domain out of a run could still be
206
+ * refused because of that domain. A line the run will not touch must not
207
+ * be able to stop the run.
208
+ */
209
+ if (excluded.has(step.id)) {
210
+ items.push({
211
+ stepId: step.id,
212
+ resource: step.resource,
213
+ estimated: 0,
214
+ excluded: true,
215
+ retained: "excluded from this run by the operator"
216
+ });
217
+ continue;
218
+ }
140
219
  const est = await step.estimate(stepCtx);
220
+ /**
221
+ * Disposition comes from the STEP, not from `step.destructive`.
222
+ *
223
+ * (See the exclusion handling above for why `'protect'` also decides
224
+ * whether a line may be left out of a run.)
225
+ *
226
+ * They are close but not the same, and conflating them is how the bug
227
+ * this fixes arose. `destructive: false` covers BOTH a protective guard
228
+ * (counts what it defends) and a projection rebuild (counts what it
229
+ * recomputes) — opposite meanings for the headline. A step that says
230
+ * nothing means `'remove'`, which is what every purge step is.
231
+ */
232
+ /**
233
+ * A step may only PROTECT if it said so on the step itself.
234
+ *
235
+ * `resolveExclusions` runs before any estimate — it has to, since it
236
+ * decides which steps to estimate at all — so it can read only
237
+ * `step.disposition`. A guard that declared `'protect'` from its
238
+ * ESTIMATE instead was therefore excludable: the plan line came back
239
+ * marked protective, looked defended, and `excludeSteps: [thatId]`
240
+ * still switched it off. That is precisely the property this feature
241
+ * exists to make impossible, so the mismatch is an authoring error
242
+ * rather than a silent downgrade.
243
+ */
244
+ if (est.disposition === "protect" && step.disposition !== "protect") throw CleanupErrors.invalidExclusion(`step '${step.id}' returned disposition 'protect' from its estimate but does not declare \`disposition: 'protect'\` on the step. Exclusions are resolved before estimates run, so a guard declared only at estimate time can be excluded — switching off the check it exists to enforce. Declare it on the step.`, [step.id]);
141
245
  items.push({
246
+ stepId: step.id,
142
247
  resource: est.resource,
143
248
  estimated: est.estimated,
249
+ ...(est.disposition ?? step.disposition) !== void 0 ? { disposition: est.disposition ?? step.disposition } : {},
144
250
  ...est.retained !== void 0 ? { retained: est.retained } : {},
145
251
  ...est.blockers && est.blockers.length > 0 ? { blockers: est.blockers } : {}
146
252
  });
@@ -161,8 +267,44 @@ function recipeFromSteps(input) {
161
267
  async execute(plan, ctx) {
162
268
  const parameters = plan.parameters ?? {};
163
269
  const results = [];
270
+ /**
271
+ * Re-resolved from the SEALED plan, never from a fresh caller input.
272
+ *
273
+ * The exclusion set is part of the digest the operator confirmed against,
274
+ * so taking it from the plan is what makes consent binding: an execute
275
+ * cannot widen the run beyond what was previewed. Re-validating here also
276
+ * means a step that has since become protective refuses rather than being
277
+ * quietly dropped.
278
+ */
279
+ const excluded = resolveExclusions(steps, plan.excludeSteps);
280
+ /**
281
+ * Lifecycle reporting is OPTIONAL on the context — a host service that
282
+ * predates it simply gets no per-step view, rather than a crash. Resolved
283
+ * once so the loop below reads as bookkeeping, not feature detection.
284
+ */
285
+ const reportState = ctx.onStepState?.bind(ctx) ?? (async () => {});
164
286
  for (const step of steps) {
165
287
  await ctx.throwIfCancelled();
288
+ if (excluded.has(step.id)) {
289
+ await reportState({
290
+ stepId: step.id,
291
+ resource: step.resource,
292
+ status: "skipped",
293
+ processed: 0,
294
+ startedAt: ctx.now,
295
+ completedAt: ctx.now,
296
+ detail: "excluded by the operator"
297
+ });
298
+ continue;
299
+ }
300
+ const startedAt = ctx.now;
301
+ await reportState({
302
+ stepId: step.id,
303
+ resource: step.resource,
304
+ status: "running",
305
+ processed: 0,
306
+ startedAt
307
+ });
166
308
  let reported = 0;
167
309
  const execCtx = {
168
310
  ...stepContextOf(ctx, parameters),
@@ -211,6 +353,25 @@ function recipeFromSteps(input) {
211
353
  ...outcome.error !== void 0 ? { error: outcome.error } : {},
212
354
  ...outcome.cursor !== void 0 ? { cursor: outcome.cursor } : {}
213
355
  });
356
+ /**
357
+ * `skipped` is a REAL outcome, not "completed with zero".
358
+ *
359
+ * A step that had nothing in scope and a step that removed 4,000 rows
360
+ * both end `ok`, and reading a bare 0 as success is how an operator
361
+ * concludes a phase ran when its scope was simply empty. Three states
362
+ * alone only CATEGORISE the outcome; the `detail` is what makes it
363
+ * answerable.
364
+ */
365
+ const isSkip = outcome.ok && outcome.processed === 0;
366
+ await reportState({
367
+ stepId: step.id,
368
+ resource: outcome.resource,
369
+ status: outcome.ok ? isSkip ? "skipped" : "completed" : "failed",
370
+ processed: outcome.processed,
371
+ startedAt,
372
+ completedAt: ctx.now,
373
+ ...outcome.ok ? isSkip ? { detail: "nothing in scope" } : {} : { detail: outcome.error ?? "step failed" }
374
+ });
214
375
  if (!outcome.ok) break;
215
376
  }
216
377
  const allOk = results.every((r) => r.ok);
@@ -465,12 +626,15 @@ function planMaterial(plan) {
465
626
  items: plan.items.map((i) => ({
466
627
  resource: i.resource,
467
628
  estimated: i.estimated,
629
+ disposition: i.disposition ?? "remove",
630
+ excluded: i.excluded ?? false,
468
631
  retained: i.retained ?? null,
469
632
  blockers: [...i.blockers ?? []].sort()
470
633
  })).sort((a, b) => a.resource < b.resource ? -1 : a.resource > b.resource ? 1 : a.estimated - b.estimated),
471
634
  retains: [...plan.retains].sort(),
472
635
  blockers: [...plan.blockers].sort(),
473
636
  rebuildActions: [...plan.rebuildActions].sort(),
637
+ excludeSteps: [...plan.excludeSteps].sort(),
474
638
  estimatedTotal: plan.estimatedTotal,
475
639
  confirmationPhrase: plan.confirmationPhrase
476
640
  };
@@ -563,7 +727,7 @@ function createCleanupService(deps) {
563
727
  ...DEFAULT_CLEANUP_LIMITS,
564
728
  ...deps.limits
565
729
  };
566
- const leaseMs = deps.leaseMs ?? 300 * 1e3;
730
+ const leaseMs = deps.leaseMs ?? 3e5;
567
731
  const progressThrottleMs = deps.progressThrottleMs ?? 0;
568
732
  const jobQueue = deps.jobQueue ?? { enqueue: async (job) => {
569
733
  queueMicrotask(() => {
@@ -586,10 +750,22 @@ function createCleanupService(deps) {
586
750
  };
587
751
  }
588
752
  async function seal(recipe, input, ctx) {
589
- const draft = await recipe.plan({ parameters: input.parameters }, ctx);
753
+ const draft = await recipe.plan({
754
+ parameters: input.parameters,
755
+ excludeSteps: input.excludeSteps
756
+ }, ctx);
590
757
  const items = draft.items;
591
758
  if (items.length > limits.maxPlanItems) throw CleanupErrors.planTooLarge(`${items.length} items > maxPlanItems ${limits.maxPlanItems}`);
592
- const estimatedTotal = items.reduce((sum, i) => sum + i.estimated, 0);
759
+ /**
760
+ * Partition by DISPOSITION — a protective guard's count is not damage.
761
+ *
762
+ * This was one `reduce` over every item, so a guard reporting the 173 posted
763
+ * journal entries it defends pushed the "records to remove" headline to 540
764
+ * on a plan that removes 367. Absent disposition means `'remove'`, so every
765
+ * pre-existing recipe is unchanged.
766
+ */
767
+ const estimatedTotal = items.reduce((sum, i) => sum + ((i.disposition ?? "remove") === "remove" ? i.estimated : 0), 0);
768
+ const protectedTotal = items.reduce((sum, i) => sum + (i.disposition === "protect" ? i.estimated : 0), 0);
593
769
  const blockers = new Set(draft.blockers ?? []);
594
770
  for (const item of items) for (const b of item.blockers ?? []) blockers.add(b);
595
771
  const unsealed = {
@@ -601,6 +777,8 @@ function createCleanupService(deps) {
601
777
  rebuildActions: [...draft.rebuildActions ?? []],
602
778
  warnings: [...draft.warnings ?? []],
603
779
  estimatedTotal,
780
+ protectedTotal,
781
+ excludeSteps: [...input.excludeSteps ?? []].sort(),
604
782
  confirmationPhrase: draft.confirmationPhrase ?? recipe.id
605
783
  };
606
784
  return {
@@ -713,6 +891,14 @@ function createCleanupService(deps) {
713
891
  let processed = 0;
714
892
  let steps = 0;
715
893
  let failed = 0;
894
+ /**
895
+ * Per-step lifecycle, keyed by `stepId` and ordered by first sight.
896
+ *
897
+ * Seeded from the run's existing progress so a RESUMED run (crash recovery,
898
+ * retry) keeps the states it already recorded instead of presenting an
899
+ * operator with a blank pipeline for work that demonstrably happened.
900
+ */
901
+ const stepStates = new Map((run.progress?.stepProgress ?? []).map((s) => [s.stepId, s]));
716
902
  let cancelled = false;
717
903
  let lastSummary = run.progress ?? EMPTY_PROGRESS;
718
904
  let lastPersistMs = 0;
@@ -745,6 +931,7 @@ function createCleanupService(deps) {
745
931
  steps,
746
932
  failed,
747
933
  currentResource: step.resource,
934
+ ...stepStates.size > 0 ? { stepProgress: [...stepStates.values()] } : {},
748
935
  ...step.cursor !== void 0 ? { lastCursor: step.cursor } : {},
749
936
  heartbeatAt: now()
750
937
  };
@@ -756,6 +943,31 @@ function createCleanupService(deps) {
756
943
  await refreshCancel();
757
944
  }
758
945
  },
946
+ /**
947
+ * Upsert one step's lifecycle state, preserving FIRST-SEEN order.
948
+ *
949
+ * A `Map` keyed by `stepId` is what keeps this bounded and idempotent: a
950
+ * step transitioning running → completed updates its entry rather than
951
+ * appending, so the array length is the step count and never the
952
+ * transition count. Insertion order is the execution order, which is what
953
+ * an operator reads down the list.
954
+ *
955
+ * Persisted on the NEXT `onStep` (or the terminal write) rather than
956
+ * immediately — a lifecycle transition is not itself a committed chunk,
957
+ * and writing on every one would defeat the progress throttle that exists
958
+ * to keep a long run from hammering the store.
959
+ */
960
+ async onStepState(state) {
961
+ stepStates.set(state.stepId, state);
962
+ lastSummary = {
963
+ ...lastSummary ?? {
964
+ processed,
965
+ steps,
966
+ failed
967
+ },
968
+ stepProgress: [...stepStates.values()]
969
+ };
970
+ },
759
971
  async throwIfCancelled() {
760
972
  if (cancelled || controller.signal.aborted || await refreshCancel()) throw new CleanupCancelled(run.id);
761
973
  }
@@ -1079,13 +1291,31 @@ const parametersSchema = {
1079
1291
  type: "object",
1080
1292
  additionalProperties: true
1081
1293
  };
1294
+ /**
1295
+ * Step ids to leave out. Bounded and unique — an unbounded list on a
1296
+ * destructive endpoint is a denial-of-service surface, and a duplicate id says
1297
+ * nothing a single one does not. Unknown or PROTECTIVE ids are refused by the
1298
+ * recipe (CLEANUP_INVALID_EXCLUSION), not stripped here: the route must not
1299
+ * decide what an operator may narrow.
1300
+ */
1301
+ const excludeStepsSchema = {
1302
+ type: "array",
1303
+ items: {
1304
+ type: "string",
1305
+ minLength: 1,
1306
+ maxLength: 200
1307
+ },
1308
+ maxItems: 200,
1309
+ uniqueItems: true
1310
+ };
1082
1311
  const previewBodySchema = {
1083
1312
  type: "object",
1084
1313
  required: ["recipe"],
1085
1314
  additionalProperties: false,
1086
1315
  properties: {
1087
1316
  recipe: recipeIdSchema,
1088
- parameters: parametersSchema
1317
+ parameters: parametersSchema,
1318
+ excludeSteps: excludeStepsSchema
1089
1319
  }
1090
1320
  };
1091
1321
  const runsBodySchema = {
@@ -1099,6 +1329,7 @@ const runsBodySchema = {
1099
1329
  properties: {
1100
1330
  recipe: recipeIdSchema,
1101
1331
  parameters: parametersSchema,
1332
+ excludeSteps: excludeStepsSchema,
1102
1333
  planDigest: {
1103
1334
  type: "string",
1104
1335
  minLength: 1,
@@ -1140,24 +1371,40 @@ const actionBodySchema = {
1140
1371
  }
1141
1372
  }
1142
1373
  };
1143
- /**
1144
- * Build the Data Cleanup Center Arc module. The module's public export is the
1145
- * live {@link CleanupService} (so other modules / tests can drive it directly).
1146
- */
1374
+ async function resolve(input) {
1375
+ return typeof input === "function" ? await input() : input;
1376
+ }
1147
1377
  function createDataCleanupModule(deps) {
1148
- const registry = createCleanupRegistry(deps.recipes);
1149
- const service = createCleanupService({
1150
- registry,
1151
- runStore: deps.runStore,
1152
- evidenceStore: deps.evidenceStore,
1153
- writeFence: deps.writeFence,
1154
- jobQueue: deps.jobQueue,
1155
- limits: deps.limits,
1156
- leaseMs: deps.leaseMs,
1157
- progressThrottleMs: deps.progressThrottleMs,
1158
- generateId: deps.generateId,
1159
- now: deps.now
1160
- });
1378
+ /**
1379
+ * Built on FIRST READ, which is `bootstrap` — never in this factory body.
1380
+ *
1381
+ * Memoized, so the recipe thunk runs exactly once and the id-uniqueness check
1382
+ * still happens at boot (arc calls bootstrap during startup); it simply happens
1383
+ * inside arc's lifecycle rather than ahead of it.
1384
+ */
1385
+ let cachedRegistry;
1386
+ const registry = async () => {
1387
+ cachedRegistry ??= createCleanupRegistry(typeof deps.recipes === "function" ? await deps.recipes() : deps.recipes);
1388
+ return cachedRegistry;
1389
+ };
1390
+ if (typeof deps.recipes !== "function") cachedRegistry = createCleanupRegistry(deps.recipes);
1391
+ let cached;
1392
+ const service = async () => {
1393
+ if (cached) return cached;
1394
+ cached = createCleanupService({
1395
+ registry: await registry(),
1396
+ runStore: await resolve(deps.runStore),
1397
+ evidenceStore: await resolve(deps.evidenceStore),
1398
+ writeFence: await resolve(deps.writeFence),
1399
+ jobQueue: await resolve(deps.jobQueue),
1400
+ limits: deps.limits,
1401
+ leaseMs: deps.leaseMs,
1402
+ progressThrottleMs: deps.progressThrottleMs,
1403
+ generateId: deps.generateId,
1404
+ now: deps.now
1405
+ });
1406
+ return cached;
1407
+ };
1161
1408
  const prefix = deps.prefix ?? "/governance/data-cleanup";
1162
1409
  const resolveActor = deps.resolveActor ?? defaultResolveActor;
1163
1410
  const resolveAmbient = deps.resolveAmbient;
@@ -1177,7 +1424,7 @@ function createDataCleanupModule(deps) {
1177
1424
  summary: "List available cleanup recipes",
1178
1425
  permissions: view,
1179
1426
  rawHandler: async (_req, reply) => {
1180
- return reply.send({ recipes: registry.introspect() });
1427
+ return reply.send({ recipes: (await registry()).introspect() });
1181
1428
  }
1182
1429
  },
1183
1430
  {
@@ -1189,9 +1436,10 @@ function createDataCleanupModule(deps) {
1189
1436
  rawHandler: async (req, reply) => {
1190
1437
  const r = req;
1191
1438
  const body = req.body;
1192
- const plan = await service.preview({
1439
+ const plan = await (await service()).preview({
1193
1440
  recipeId: body.recipe,
1194
1441
  parameters: body.parameters,
1442
+ excludeSteps: body.excludeSteps,
1195
1443
  actor: resolveActor(r),
1196
1444
  ambient: resolveAmbient?.(r)
1197
1445
  });
@@ -1207,9 +1455,10 @@ function createDataCleanupModule(deps) {
1207
1455
  rawHandler: async (req, reply) => {
1208
1456
  const r = req;
1209
1457
  const body = req.body;
1210
- const run = await service.execute({
1458
+ const run = await (await service()).execute({
1211
1459
  recipeId: body.recipe,
1212
1460
  parameters: body.parameters,
1461
+ excludeSteps: body.excludeSteps,
1213
1462
  planDigest: body.planDigest,
1214
1463
  reason: body.reason,
1215
1464
  confirmation: body.confirmation,
@@ -1227,7 +1476,7 @@ function createDataCleanupModule(deps) {
1227
1476
  schema: { params: runIdParamsSchema },
1228
1477
  rawHandler: async (req, reply) => {
1229
1478
  const { id } = req.params;
1230
- return reply.send(await service.getRun(id));
1479
+ return reply.send(await (await service()).getRun(id));
1231
1480
  }
1232
1481
  },
1233
1482
  {
@@ -1243,11 +1492,11 @@ function createDataCleanupModule(deps) {
1243
1492
  const actionActor = resolveActor(req);
1244
1493
  const { id } = req.params;
1245
1494
  const { action, reason } = req.body;
1246
- if (action === "cancel") return reply.send(await service.cancel(id, {
1495
+ if (action === "cancel") return reply.send(await (await service()).cancel(id, {
1247
1496
  actor: actionActor,
1248
1497
  reason
1249
1498
  }));
1250
- return reply.send(await service.retry(id));
1499
+ return reply.send(await (await service()).retry(id));
1251
1500
  }
1252
1501
  }
1253
1502
  ]
@@ -1255,7 +1504,7 @@ function createDataCleanupModule(deps) {
1255
1504
  return defineModule({
1256
1505
  name: deps.moduleName ?? "data-cleanup",
1257
1506
  ...deps.owns ? { owns: deps.owns } : {},
1258
- bootstrap: () => service,
1507
+ bootstrap: () => service(),
1259
1508
  resources: () => [resource]
1260
1509
  });
1261
1510
  }
@@ -1,5 +1,5 @@
1
1
 
2
- import { Nt as RateLimitConfig, V as ResourceDefinition, et as RouteSchemaOptions } from "../../index-CpzxqePp.mjs";
2
+ import { Nt as RateLimitConfig, V as ResourceDefinition, et as RouteSchemaOptions } from "../../index-BcR2bFZQ.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.31.0 | MIT | https://classytic.com */
2
- import { t as CRUD_OPERATIONS } from "../../constants-D3Dv4LAV.mjs";
3
- import { n as stringifyMeasureMap } from "../../ResourceRegistry-qq0mn2s9.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { t as CRUD_OPERATIONS } from "../../constants-BxCoxmiN.mjs";
3
+ import { n as stringifyMeasureMap } from "../../ResourceRegistry-DoALUlOO.mjs";
4
4
  import { resolve } from "node:path";
5
5
  import { pathToFileURL } from "node:url";
6
6
  //#region src/cli/commands/describe.ts
@@ -78,9 +78,7 @@ function describePipeline(pipe) {
78
78
  case "transform":
79
79
  transforms.push(desc);
80
80
  break;
81
- case "interceptor":
82
- interceptors.push(desc);
83
- break;
81
+ case "interceptor": interceptors.push(desc);
84
82
  }
85
83
  }
86
84
  return {
@@ -1,6 +1,6 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { t as buildOpenApiSpec } from "../../openapi-B2L4js1v.mjs";
3
- import { t as loadResourcesFromEntry } from "../../loadResourcesFromEntry-BAjYZonx.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { t as buildOpenApiSpec } from "../../openapi-BN5cQaO2.mjs";
3
+ import { t as loadResourcesFromEntry } from "../../loadResourcesFromEntry-DwaxNcE2.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.31.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.34.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.31.0 | MIT | https://classytic.com */
2
- import { t as generate } from "../../generate-EcA6ui4i.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { t as generate } from "../../generate-DiB0nHPR.mjs";
3
3
  export { generate };
@@ -1,3 +1,3 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { t as init } from "../../init-BEiNZBsJ.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { t as init } from "../../init-mdJ-v4Xp.mjs";
3
3
  export { init };
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { t as loadResourcesFromEntry } from "../../loadResourcesFromEntry-BAjYZonx.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { t as loadResourcesFromEntry } from "../../loadResourcesFromEntry-DwaxNcE2.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.31.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.34.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-EcA6ui4i.mjs";
6
- import { t as init } from "../init-BEiNZBsJ.mjs";
5
+ import { t as generate } from "../generate-DiB0nHPR.mjs";
6
+ import { t as init } from "../init-mdJ-v4Xp.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.31.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
2
  //#region src/constants.ts
3
3
  /**
4
4
  * Arc Framework Constants — Single Source of Truth
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { n as requestContext, t as getTraceHeaders } from "../requestContext-2TxXOJ7T.mjs";
3
- import { t as transactionContext } from "../transactionContext-dAfBVUrk.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { n as requestContext, t as getTraceHeaders } from "../requestContext-uYE35JxI.mjs";
3
+ import { t as transactionContext } from "../transactionContext-BYtWnwAS.mjs";
4
4
  export { getTraceHeaders, requestContext, transactionContext };
@@ -1,4 +1,4 @@
1
1
 
2
- import { $t as TreeMixin, An as BaseControllerOptions, B as defineResource, Fn as BodySanitizerConfig, Mn as ControllerConstructionOptions, Nn as ListResult, Pn as BodySanitizer, Qt as TreeExt, V as ResourceDefinition, Xt as SoftDeleteExt, Yt as BaseController, Zt as SoftDeleteMixin, an as QueryResolver, cn as AccessControlConfig, ct as AggMeasureShorthand, dt as AggregationDateRangeRequirement, en as SlugExt, ft as AggregationIndexHint, gt as AggregationsMap, ht as AggregationRateLimit, in as BaseCrudController, jn as ControllerConfigurableOptions, lt as AggregationCacheConfig, mt as AggregationMaterializedResult, nn as BulkExt, on as QueryResolverConfig, pt as AggregationMaterializedContext, rn as BulkMixin, sn as AccessControl, st as AggMeasureInput, tn as SlugMixin, ut as AggregationConfig } from "../index-CpzxqePp.mjs";
3
- import { A as DEFAULT_ID_FIELD, B as MAX_FILTER_DEPTH, C as DefineActionConfig, D as defineAggregation, E as createPermissionMiddleware, F as DEFAULT_UPDATE_METHOD, G as RESERVED_QUERY_PARAMS, H as MAX_SEARCH_LENGTH, I as HOOK_OPERATIONS, K as SYSTEM_FIELDS, L as HOOK_PHASES, M as DEFAULT_MAX_LIMIT, N as DEFAULT_SORT, O as CRUD_OPERATIONS, P as DEFAULT_TENANT_FIELD, R as HookOperation, S as mergeResourceConfig, T as createCrudRouter, U as MUTATION_OPERATIONS, V as MAX_REGEX_LENGTH, W as MutationOperation, _ as getEntityQuery, a as formatValidationErrors, b as ResourceSeams, c as isFieldReadable, d as createRequestContext, f as getControllerContext, g as getEntityIdField, h as getEntityId, i as assertValidConfig, j as DEFAULT_LIMIT, k as CrudOperation, l as createCrudHandlers, m as sendControllerResponse, n as ValidateOptions, o as validateResourceConfig, p as getControllerScope, r as ValidationResult, s as collectReadBlockedFields, t as ConfigError, u as createFastifyHandler, v as defineResourceVariants, w as defineAction, x as SeamedResourceConfig, y as AdapterLike, z as HookPhase } from "../index-Bc2ox8_U.mjs";
2
+ import { $t as AccessControlConfig, B as defineResource, Bt as BaseController, Cn as ControllerConstructionOptions, En as BodySanitizerConfig, Gt as SlugExt, Ht as SoftDeleteMixin, Jt as BulkMixin, Kt as SlugMixin, Qt as AccessControl, Sn as ControllerConfigurableOptions, Tn as BodySanitizer, Ut as TreeExt, V as ResourceDefinition, Vt as SoftDeleteExt, Wt as TreeMixin, Xt as QueryResolver, Yt as BaseCrudController, Zt as QueryResolverConfig, ct as AggMeasureShorthand, dt as AggregationDateRangeRequirement, ft as AggregationIndexHint, gt as AggregationsMap, ht as AggregationRateLimit, lt as AggregationCacheConfig, mt as AggregationMaterializedResult, pt as AggregationMaterializedContext, qt as BulkExt, st as AggMeasureInput, ut as AggregationConfig, wn as ListResult, xn as BaseControllerOptions } from "../index-BcR2bFZQ.mjs";
3
+ import { A as DEFAULT_ID_FIELD, B as MAX_FILTER_DEPTH, C as DefineActionConfig, D as defineAggregation, E as createPermissionMiddleware, F as DEFAULT_UPDATE_METHOD, G as RESERVED_QUERY_PARAMS, H as MAX_SEARCH_LENGTH, I as HOOK_OPERATIONS, K as SYSTEM_FIELDS, L as HOOK_PHASES, M as DEFAULT_MAX_LIMIT, N as DEFAULT_SORT, O as CRUD_OPERATIONS, P as DEFAULT_TENANT_FIELD, R as HookOperation, S as mergeResourceConfig, T as createCrudRouter, U as MUTATION_OPERATIONS, V as MAX_REGEX_LENGTH, W as MutationOperation, _ as getEntityQuery, a as formatValidationErrors, b as ResourceSeams, c as isFieldReadable, d as createRequestContext, f as getControllerContext, g as getEntityIdField, h as getEntityId, i as assertValidConfig, j as DEFAULT_LIMIT, k as CrudOperation, l as createCrudHandlers, m as sendControllerResponse, n as ValidateOptions, o as validateResourceConfig, p as getControllerScope, r as ValidationResult, s as collectReadBlockedFields, t as ConfigError, u as createFastifyHandler, v as defineResourceVariants, w as defineAction, x as SeamedResourceConfig, y as AdapterLike, z as HookPhase } from "../index-Brin0ODU.mjs";
4
4
  export { AccessControl, type AccessControlConfig, type AdapterLike, type AggMeasureInput, type AggMeasureShorthand, type AggregationCacheConfig, type AggregationConfig, type AggregationDateRangeRequirement, type AggregationIndexHint, type AggregationMaterializedContext, type AggregationMaterializedResult, type AggregationRateLimit, type AggregationsMap, BaseController, type BaseControllerOptions, BaseCrudController, BodySanitizer, type BodySanitizerConfig, type BulkExt, BulkMixin, CRUD_OPERATIONS, type ConfigError, type ControllerConfigurableOptions, type ControllerConstructionOptions, CrudOperation, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, type DefineActionConfig, HOOK_OPERATIONS, HOOK_PHASES, HookOperation, HookPhase, type ListResult, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MutationOperation, QueryResolver, type QueryResolverConfig, RESERVED_QUERY_PARAMS, ResourceDefinition, type ResourceSeams, SYSTEM_FIELDS, type SeamedResourceConfig, type SlugExt, SlugMixin, type SoftDeleteExt, SoftDeleteMixin, type TreeExt, TreeMixin, type ValidateOptions, type ValidationResult, assertValidConfig, collectReadBlockedFields, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineAction, defineAggregation, defineResource, defineResourceVariants, formatValidationErrors, getControllerContext, getControllerScope, getEntityId, getEntityIdField, getEntityQuery, isFieldReadable, mergeResourceConfig, sendControllerResponse, validateResourceConfig };
@@ -1,8 +1,8 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { a as DEFAULT_SORT, c as HOOK_OPERATIONS, d as MAX_REGEX_LENGTH, f as MAX_SEARCH_LENGTH, h as SYSTEM_FIELDS, i as DEFAULT_MAX_LIMIT, l as HOOK_PHASES, m as RESERVED_QUERY_PARAMS, n as DEFAULT_ID_FIELD, o as DEFAULT_TENANT_FIELD, p as MUTATION_OPERATIONS, r as DEFAULT_LIMIT, s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS, u as MAX_FILTER_DEPTH } from "../constants-D3Dv4LAV.mjs";
3
- import { a as BulkMixin, c as collectReadBlockedFields, f as AccessControl, i as SlugMixin, l as isFieldReadable, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, s as QueryResolver, t as BaseController, u as BodySanitizer } from "../BaseController-De7GqHck.mjs";
4
- import { a as ResourceDefinition, i as validateResourceConfig, n as assertValidConfig, o as createCrudRouter, r as formatValidationErrors, s as createPermissionMiddleware, t as defineResource } from "../defineResource-Bv6EtN1x.mjs";
5
- import { a as createFastifyHandler, c as getControllerScope, i as createCrudHandlers, l as sendControllerResponse, o as createRequestContext, s as getControllerContext } from "../pipeline-UPQFatit.mjs";
6
- import { t as defineAggregation } from "../defineAggregation-DbPPS8RI.mjs";
7
- import { a as mergeResourceConfig, i as defineResourceVariants, n as getEntityIdField, o as defineAction, r as getEntityQuery, t as getEntityId } from "../core-BGpIxINN.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { a as DEFAULT_SORT, c as HOOK_OPERATIONS, d as MAX_REGEX_LENGTH, f as MAX_SEARCH_LENGTH, h as SYSTEM_FIELDS, i as DEFAULT_MAX_LIMIT, l as HOOK_PHASES, m as RESERVED_QUERY_PARAMS, n as DEFAULT_ID_FIELD, o as DEFAULT_TENANT_FIELD, p as MUTATION_OPERATIONS, r as DEFAULT_LIMIT, s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS, u as MAX_FILTER_DEPTH } from "../constants-BxCoxmiN.mjs";
3
+ import { a as BulkMixin, c as collectReadBlockedFields, f as BodySanitizer, i as SlugMixin, l as isFieldReadable, m as AccessControl, n as TreeMixin, o as BaseCrudController, r as SoftDeleteMixin, s as QueryResolver, t as BaseController } from "../BaseController-CaQC5EXX.mjs";
4
+ import { a as ResourceDefinition, i as validateResourceConfig, n as assertValidConfig, o as createCrudRouter, r as formatValidationErrors, s as createPermissionMiddleware, t as defineResource } from "../defineResource-DR9vsUYy.mjs";
5
+ import { a as createFastifyHandler, c as getControllerScope, i as createCrudHandlers, l as sendControllerResponse, o as createRequestContext, s as getControllerContext } from "../pipeline-q69DZzgG.mjs";
6
+ import { t as defineAggregation } from "../defineAggregation-Nv-DwfOf.mjs";
7
+ import { a as mergeResourceConfig, i as defineResourceVariants, n as getEntityIdField, o as defineAction, r as getEntityQuery, t as getEntityId } from "../core-dxhcHhUD.mjs";
8
8
  export { AccessControl, BaseController, BaseCrudController, BodySanitizer, BulkMixin, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, QueryResolver, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, SlugMixin, SoftDeleteMixin, TreeMixin, assertValidConfig, collectReadBlockedFields, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineAction, defineAggregation, defineResource, defineResourceVariants, formatValidationErrors, getControllerContext, getControllerScope, getEntityId, getEntityIdField, getEntityQuery, isFieldReadable, mergeResourceConfig, sendControllerResponse, validateResourceConfig };
@@ -1,6 +1,6 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import "./constants-D3Dv4LAV.mjs";
3
- import { t as defineResource } from "./defineResource-Bv6EtN1x.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import "./constants-BxCoxmiN.mjs";
3
+ import { t as defineResource } from "./defineResource-DR9vsUYy.mjs";
4
4
  //#region src/core/defineAction.ts
5
5
  /**
6
6
  * Build an `ActionDefinition` with a typed handler. The literal schema