@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,6 +1,6 @@
1
1
 
2
- import { n as DomainEvent, r as EventHandler } from "./EventTransport-2uVV34WU.mjs";
3
- import { n as ErrorMapper } from "./errorHandler-CpYUJmPA.mjs";
2
+ import { n as DomainEvent, r as EventHandler } from "./EventTransport-BEVP50ka.mjs";
3
+ import { n as ErrorMapper } from "./errorHandler-DI5AN2b5.mjs";
4
4
  import { FastifyInstance, FastifyPluginAsync } from "fastify";
5
5
  import { LockAdapter } from "@classytic/repo-core/lock";
6
6
  //#region src/plugins/health.d.ts
@@ -49,6 +49,12 @@ interface ScheduleDefinition {
49
49
  handler: (fastify: FastifyInstance) => void | Promise<void>;
50
50
  /** Fire once immediately when the app becomes ready (default: false). */
51
51
  runOnStart?: boolean;
52
+ /**
53
+ * Topology tag: `'relay'` marks an arm a `role: 'relay'` process runs
54
+ * (outbox relays); everything else is `'job'` (default). See
55
+ * `CreateAppOptions.role`.
56
+ */
57
+ kind?: "relay" | "job";
52
58
  /**
53
59
  * Random extra delay in `[0, jitterMs)` added to the FIRST tick only.
54
60
  * Spreads boot-aligned jobs so multiple same-cadence schedules don't all
@@ -320,6 +326,26 @@ interface LoadResourcesOptions<TContext = unknown> {
320
326
  */
321
327
  declare function loadResources<TContext = unknown>(dir: string, options?: LoadResourcesOptions<TContext>): Promise<ResourceLike[]>;
322
328
  //#endregion
329
+ //#region src/factory/module/disposers.d.ts
330
+ /** Teardown callback registered by a setup phase via `defer`. */
331
+ type ModuleDisposer = () => void | Promise<void>;
332
+ /**
333
+ * Second argument to a module's setup phases (`plugins`, `bootstrap`,
334
+ * `afterResources`).
335
+ */
336
+ interface ModuleSetupContext {
337
+ /**
338
+ * Register a teardown callback for the resource just acquired. Call it
339
+ * IMMEDIATELY after acquisition — that is what makes partial-init teardown
340
+ * exact rather than defensive.
341
+ *
342
+ * Disposers run LIFO, after this module's `onClose`, on both the rollback
343
+ * and shutdown paths, and exactly once. A throwing disposer is logged and
344
+ * never blocks the ones behind it.
345
+ */
346
+ defer(disposer: ModuleDisposer): void;
347
+ }
348
+ //#endregion
323
349
  //#region src/factory/module/types.d.ts
324
350
  /**
325
351
  * A module's contribution of some arm (event handlers, scheduled jobs, …).
@@ -420,18 +446,56 @@ interface ArcModule<TExports = unknown> {
420
446
  */
421
447
  readonly dependsOn?: readonly string[];
422
448
  /**
423
- * Fastify plugins / decorators this module needs — the module-level analog
424
- * of the app's `plugins()` slot. Runs in the plugins phase: AFTER the app's
425
- * own `plugins()` (so module infra can build on app foundations like a DB
426
- * connection) and in `dependsOn` order, but BEFORE any module `bootstrap` —
427
- * so engines initialised in `bootstrap` can rely on what's registered here.
449
+ * Infra SETUP function — the module-level analog of the app's `plugins()`
450
+ * slot. Runs in the plugins phase: AFTER the app's own `plugins()` (so
451
+ * module infra can build on app foundations like a DB connection) and in
452
+ * `dependsOn` order, but BEFORE any module `bootstrap` — so engines
453
+ * initialised in `bootstrap` can rely on what's registered here.
454
+ *
455
+ * ## ⚠ This is NOT itself a Fastify plugin
456
+ *
457
+ * Despite the name, arc CALLS this function directly — it is never handed
458
+ * to `fastify.register()`. Two consequences, both of which bite module
459
+ * authors coming from ordinary Fastify plugins:
460
+ *
461
+ * - **You must register plugins yourself.** `await fastify.register(x)`,
462
+ * not `return x`. A returned function is read as a DISPOSER (below),
463
+ * so returning a plugin silently registers nothing and then invokes
464
+ * your plugin as a teardown callback. Arc detects the `fastify-plugin`
465
+ * case and throws; the bare-function case warns.
466
+ * - **There is no encapsulation and no prefix here.** Decorators and
467
+ * hooks you add land on the instance arc passes you — the same
468
+ * instance every other module sees. Fastify's encapsulation applies
469
+ * only inside a `register()` call you make yourself. See
470
+ * https://fastify.dev/docs/latest/Reference/Plugins/
471
+ *
472
+ * ```ts
473
+ * plugins: async (fastify) => {
474
+ * await fastify.register(somePlugin, { prefix: '/x' }); // ✅ register
475
+ * fastify.decorate('thing', thing); // ✅ root-visible
476
+ * // return somePlugin // ❌ never registered
477
+ * },
478
+ * ```
479
+ *
480
+ * The name is kept for the 2.x line; v3 renames the slot to `setup` and
481
+ * REMOVES `plugins` outright — v3 ships no compatibility aliases (v3.md).
428
482
  *
429
483
  * Separating this from `bootstrap` keeps lifecycle intent explicit for
430
484
  * published ecosystem packages: `plugins` = "register infra"; `bootstrap` =
431
485
  * "initialise engines (and return the public export)". Registering a plugin
432
486
  * inside `bootstrap` still works — this slot just makes the two distinct.
487
+ *
488
+ * Receives `{ defer }` to register teardown for anything it acquires, and
489
+ * may RETURN a single disposer as shorthand for the one-resource case:
490
+ *
491
+ * ```ts
492
+ * plugins: async (fastify) => {
493
+ * const conn = await connect();
494
+ * return () => conn.close(); // equivalent to defer(...)
495
+ * },
496
+ * ```
433
497
  */
434
- plugins?: (fastify: FastifyInstance) => void | Promise<void>;
498
+ plugins?: (fastify: FastifyInstance, context: ModuleSetupContext) => ModuleDisposer | undefined | Promise<ModuleDisposer | undefined>;
435
499
  /**
436
500
  * Domain error mappers this module ships (see `defineErrorMapper`). Merged
437
501
  * into the app's error handler at boot, AFTER any host-declared mappers —
@@ -468,8 +532,23 @@ interface ArcModule<TExports = unknown> {
468
532
  * // arc-invoice bootstrap, composed AFTER arc-accounting:
469
533
  * const acct = getModuleExports<AccountingEngine>(fastify, "accounting");
470
534
  * ```
535
+ *
536
+ * The return value is the module's export, so teardown here goes through
537
+ * `defer` (the second argument) rather than a returned disposer — register
538
+ * each resource the moment it exists and partial-init cleanup becomes exact
539
+ * instead of a chain of `?.` guards:
540
+ *
541
+ * ```ts
542
+ * bootstrap: async (fastify, { defer }) => {
543
+ * const client = await openClient();
544
+ * defer(() => client.close());
545
+ * const engine = await createEngine(client); // if this throws, only
546
+ * defer(() => engine.stop()); // the client is released
547
+ * return engine;
548
+ * },
549
+ * ```
471
550
  */
472
- bootstrap?: (fastify: FastifyInstance) => TExports | Promise<TExports>;
551
+ bootstrap?: (fastify: FastifyInstance, context: ModuleSetupContext) => TExports | Promise<TExports>;
473
552
  /**
474
553
  * App-level resource NAMES this module authoritatively SUPERSEDES. When the
475
554
  * host also lists (or `resourceDir`-discovers) a resource of the same name,
@@ -489,18 +568,37 @@ interface ArcModule<TExports = unknown> {
489
568
  * any fork exists.
490
569
  * - Collected across ALL modules; the app-side supersession is their union.
491
570
  *
492
- * **Contract (ENFORCED at boot): if you `owns` a name, PROVIDE it** — in
493
- * THIS module's own `resources`. Arc resolves module resources first and
494
- * fails boot when a claimed name is not among them, naming the module, the
495
- * unmet names, and what it did supply. Without that check, a typo or a
496
- * resource deleted without updating `owns` booted "successfully" with the
497
- * app's route silently removed and nothing serving it.
571
+ * **Prefer `owns: "provided"`** (2.32) — arc derives the list from the
572
+ * resources this module actually returned, so the claim and the reality
573
+ * cannot disagree:
574
+ *
575
+ * ```ts
576
+ * defineModule({ name: "order", owns: "provided", resources: () => [...] })
577
+ * ```
578
+ *
579
+ * That is the whole arm for most modules. Resources are resolved exactly
580
+ * once, names are validated (duplicates within a module are rejected), the
581
+ * effective `owns` is derived, and supersession runs afterward — one atomic
582
+ * phase arc owns, rather than a rule each module re-states.
583
+ *
584
+ * **The explicit-array form is ENFORCED at boot: if you `owns` a name,
585
+ * PROVIDE it** — in THIS module's own `resources`. Arc fails boot when a
586
+ * claimed name is not among them, naming the module, the unmet names, and
587
+ * what it did supply. Without that check, a typo or a resource deleted
588
+ * without updating the list booted "successfully" with the app's route
589
+ * silently removed and nothing serving it. Two real cases, both silent 404s:
590
+ * a POS module claiming a checkout resource it mounted only when the host
591
+ * supplied a pipeline, and a device gateway claiming a name it never
592
+ * provided at all.
593
+ *
594
+ * Keep the explicit array only when the list is genuinely NOT the module's
595
+ * own resource set — e.g. pre-declaring a name before the fork exists.
498
596
  *
499
597
  * A sibling module supplying the name does NOT satisfy the claim — ownership
500
598
  * is local to the module that declares it, which is the colocation this arm
501
599
  * exists for.
502
600
  */
503
- readonly owns?: readonly string[];
601
+ readonly owns?: readonly string[] | "provided";
504
602
  /**
505
603
  * The module's resources. Array or factory — the factory form runs AFTER all
506
604
  * bootstraps, so `defineResource(...)` receives fully-booted engines. Flows
@@ -512,8 +610,12 @@ interface ArcModule<TExports = unknown> {
512
610
  * Post-registration wiring — runs in the `afterResources` phase, once this
513
611
  * module's routes are mounted. Use for cross-resource event subscriptions the
514
612
  * module owns.
613
+ *
614
+ * Receives `{ defer }`, and may return a disposer, on the same terms as
615
+ * `plugins` — handy for wiring that must be unwound (a subscription, a
616
+ * listener) without hoisting a handle into module scope.
515
617
  */
516
- afterResources?: (fastify: FastifyInstance) => void | Promise<void>;
618
+ afterResources?: (fastify: FastifyInstance, context: ModuleSetupContext) => ModuleDisposer | undefined | Promise<ModuleDisposer | undefined>;
517
619
  /**
518
620
  * Readiness checks this module contributes to the app's
519
621
  * `healthPlugin` (`/_health/ready`). Collected across ALL modules in
@@ -611,6 +713,14 @@ interface ArcModule<TExports = unknown> {
611
713
  * onClose: async () => { await client?.close(); }, // still runs
612
714
  * });
613
715
  * ```
716
+ *
717
+ * Prefer `defer` (the setup phases' second argument) for anything acquired
718
+ * step-by-step: it registers each teardown at the point of acquisition, so
719
+ * the runtime knows exactly what was reached and the `?.` guards above
720
+ * disappear. `onClose` remains the right slot for tearing down what
721
+ * `bootstrap` RETURNED — the module's engine — and runs FIRST, ahead of the
722
+ * module's deferred disposers (see `disposers.ts` for the ordering rule).
723
+ * The two compose; either alone is complete.
614
724
  */
615
725
  onClose?: (fastify: FastifyInstance) => void | Promise<void>;
616
726
  }
@@ -657,4 +767,4 @@ type ArcModuleInput<TExports = unknown> = ArcModule<TExports> | Promise<ArcModul
657
767
  */
658
768
  interface ArcModuleRegistry {}
659
769
  //#endregion
660
- export { _default$1 as _, ModuleContribution as a, ResourceModule as c, ScheduleStats as d, SchedulesPluginOptions as f, HealthOptions as g, HealthCheck as h, EventHandlerDefinition as i, loadResources as l, schedulesPlugin as m, ArcModuleInput as n, LoadResourcesOptions as o, _default as p, ArcModuleRegistry as r, ResourceLike as s, ArcModule as t, ScheduleDefinition as u, healthPlugin as v };
770
+ export { HealthCheck as _, ModuleContribution as a, healthPlugin as b, LoadResourcesOptions as c, loadResources as d, ScheduleDefinition as f, schedulesPlugin as g, _default as h, EventHandlerDefinition as i, ResourceLike as l, SchedulesPluginOptions as m, ArcModuleInput as n, ModuleDisposer as o, ScheduleStats as p, ArcModuleRegistry as r, ModuleSetupContext as s, ArcModule as t, ResourceModule as u, HealthOptions as v, _default$1 as y };
@@ -1,5 +1,5 @@
1
1
 
2
- import { V as ResourceDefinition } from "./index-CpzxqePp.mjs";
2
+ import { V as ResourceDefinition } from "./index-BcR2bFZQ.mjs";
3
3
  import { z } from "zod";
4
4
  //#region src/integrations/mcp/types.d.ts
5
5
  /** Behavioral hints for MCP clients (tool annotations per MCP spec) */
@@ -377,6 +377,20 @@ interface McpAuthResult {
377
377
  * Carried on the `service` RequestScope for fine-grained permission checks.
378
378
  */
379
379
  scopes?: readonly string[];
380
+ /**
381
+ * Active team — carried onto a `member` scope so `getTeamId()` answers the
382
+ * same on MCP as on HTTP. Member-only, like the HTTP surface.
383
+ */
384
+ teamId?: string;
385
+ /**
386
+ * Host-defined scope dimensions (`branchId`, `projectId`, `region`, …),
387
+ * carried onto `member` / `service` scopes.
388
+ *
389
+ * Declared explicitly because `requireScopeContext()` AUTHORISES against
390
+ * these: a resource gated on `branchId` denies every MCP call until the
391
+ * resolver supplies it. Non-string entries are dropped rather than coerced.
392
+ */
393
+ context?: Record<string, string>;
380
394
  /** Any extra metadata from the auth resolver */
381
395
  [key: string]: unknown;
382
396
  }
@@ -1,7 +1,7 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { l as UnauthorizedError, o as OrgRequiredError } from "./errors-Cj42AntO.mjs";
3
- import { n as requireSingleHeaderValue } from "./headers-3zvE0rM3.mjs";
4
- import { t as getUserId$1 } from "./userHelpers-ChYJ6CdK.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { l as UnauthorizedError, o as OrgRequiredError } from "./errors-Cd_yy7aW.mjs";
3
+ import { n as requireSingleHeaderValue } from "./headers-CveNO9gR.mjs";
4
+ import { t as getUserId$1 } from "./userHelpers-CWF5pbZD.mjs";
5
5
  //#region src/scope/types.ts
6
6
  /**
7
7
  * Request Scope — The One Standard
@@ -40,6 +40,18 @@ interface CleanupExecutionContext extends CleanupContext {
40
40
  * commits, call this so the executor learns of a cancel request promptly.
41
41
  */
42
42
  onStep(step: CleanupStepResult): Promise<void>;
43
+ /**
44
+ * Report a STEP LIFECYCLE transition — running / completed / skipped / failed.
45
+ *
46
+ * Separate from {@link onStep}, which reports a committed CHUNK and drives the
47
+ * aggregate counters. Folding both into one call would double-count `steps`
48
+ * and conflate "a batch landed" with "this phase is now done" — two different
49
+ * facts an operator reads differently.
50
+ *
51
+ * OPTIONAL on the context so a recipe that does not model discrete steps is
52
+ * unaffected; `recipeFromSteps` drives it for every composed recipe.
53
+ */
54
+ onStepState?(state: CleanupStepProgress): Promise<void>;
43
55
  /**
44
56
  * Throw `CleanupCancelled` if a cancel has been requested for this run. Cheap
45
57
  * to call between chunks; backed by the durable `cancelRequested` flag (the
@@ -56,13 +68,72 @@ interface Availability {
56
68
  /** Operator-supplied recipe parameters (branch, module set, before-date, …). */
57
69
  interface CleanupInput {
58
70
  readonly parameters?: Readonly<Record<string, unknown>> | undefined;
71
+ /**
72
+ * Step ids the operator chose to LEAVE OUT of this run.
73
+ *
74
+ * The obvious shape for this is a free-text ignore-list, which carries one
75
+ * dangerous gap: anything can be ignored, including the checks. Here a step
76
+ * that PROTECTS is not excludable — see
77
+ * {@link CleanupPlanItem.excluded} — because being able to switch off the
78
+ * thing standing between you and a statutory record makes the guard advisory.
79
+ * An unknown or unexcludable id REFUSES the plan rather than being dropped: a
80
+ * silently-ignored exclusion is an operator believing they narrowed a
81
+ * destructive run when they did not.
82
+ *
83
+ * SEALED INTO THE DIGEST. The exclusion set is part of what was consented to,
84
+ * so a plan previewed with accounting excluded cannot be executed as one that
85
+ * includes it.
86
+ *
87
+ * Framework-level and deliberately NOT smuggled through `parameters`:
88
+ * parameters are the recipe's domain scope, this is the composition.
89
+ */
90
+ readonly excludeSteps?: readonly string[] | undefined;
59
91
  }
92
+ /**
93
+ * What a line's `estimated` COUNTS. Absent ⇒ `'remove'`, so every existing
94
+ * recipe keeps its meaning.
95
+ *
96
+ * A protective guard step reports the records it DEFENDS, not records it would
97
+ * touch — and summing those into a "records to remove" headline overstates the
98
+ * damage by exactly the protected count. That is not cosmetic: a pre-live reset
99
+ * showed **540 records to remove** when 173 of them were posted journal entries
100
+ * the run would refuse to touch. The number was plausible, internally
101
+ * consistent, and wrong — this codebase's signature failure, in the one place an
102
+ * operator reads before authorising a destructive act.
103
+ *
104
+ * The count cannot be inferred from `blockers`: a guard that finds nothing still
105
+ * reports zero protected records, and a REMOVING line can carry a blocker too.
106
+ * The line has to say which quantity it is.
107
+ */
108
+ type CleanupPlanItemDisposition = "remove" | "protect" | "rebuild";
60
109
  /** One logical line in the preview — a business record class, never a collection. */
61
110
  interface CleanupPlanItem {
111
+ /**
112
+ * The contributing step, when the recipe is composed from steps.
113
+ *
114
+ * Without it the exclusion list is enforceable but not DISCOVERABLE: a UI
115
+ * showing `resource` labels has no id to send, so the capability exists and
116
+ * nothing can reach it. Absent for a recipe that is not step-composed.
117
+ */
118
+ readonly stepId?: string | undefined;
62
119
  /** Logical module / resource label, e.g. `'orders'`, `'journal entries'`. */
63
120
  readonly resource: string;
64
121
  /** Estimated records affected. */
65
122
  readonly estimated: number;
123
+ /**
124
+ * Whether `estimated` counts records this line REMOVES, PROTECTS, or REBUILDS.
125
+ * Defaults to `'remove'` — only a line that does something else must say so.
126
+ */
127
+ readonly disposition?: CleanupPlanItemDisposition | undefined;
128
+ /**
129
+ * The operator excluded this line from the run.
130
+ *
131
+ * It still appears in the plan — showing what was left out is the point; a
132
+ * line that vanishes is indistinguishable from one that was never in scope.
133
+ * Its `estimated` is kept out of both totals, and at execute time the step is
134
+ * reported `skipped` with the reason rather than silently not run.
135
+ */
136
+ readonly excluded?: boolean | undefined;
66
137
  /** What is retained for this line (e.g. `'measures kept, PII redacted'`). */
67
138
  readonly retained?: string | undefined;
68
139
  /** Domain blockers preventing this line (e.g. `'OPEN_TRANSFER'`). */
@@ -101,7 +172,26 @@ interface CleanupPlan {
101
172
  readonly blockers: readonly string[];
102
173
  readonly rebuildActions: readonly string[];
103
174
  readonly warnings: readonly string[];
175
+ /**
176
+ * Records this plan would REMOVE — the headline an operator authorises against.
177
+ *
178
+ * Counts only `disposition: 'remove'` lines. It used to sum every line, so a
179
+ * protective guard's count landed in the removal total (see
180
+ * {@link CleanupPlanItemDisposition}).
181
+ */
104
182
  readonly estimatedTotal: number;
183
+ /**
184
+ * Records a guard step is DEFENDING in this plan, reported separately so it
185
+ * can be shown as reassurance rather than as damage. Zero when no line
186
+ * protects anything.
187
+ */
188
+ readonly protectedTotal: number;
189
+ /**
190
+ * Step ids the operator left out, SEALED. re-resolves from here,
191
+ * never from a fresh caller input, so a run cannot be widened past what was
192
+ * previewed and confirmed.
193
+ */
194
+ readonly excludeSteps: readonly string[];
105
195
  readonly confirmationPhrase: string;
106
196
  /** Deterministic checksum of the plan's material content — see `computePlanDigest`. */
107
197
  readonly digest: string;
@@ -122,11 +212,64 @@ interface CleanupStepResult {
122
212
  * fixed-size aggregate, never an unbounded per-chunk array. Detailed steps, if a
123
213
  * host wants them, go to a separate capped sink — not this document.
124
214
  */
215
+ /**
216
+ * One step's lifecycle within a run.
217
+ *
218
+ * `skipped` and `failed` are DISTINCT from each other and from `completed`,
219
+ * because collapsing them is what makes a long destructive run unreadable: an
220
+ * operator watching "1,204 processed" cannot tell whether accounting ran, was
221
+ * deliberately not applicable, or blew up and left the rest half-done.
222
+ */
223
+ type CleanupStepRunStatus = "pending" | "running" | "completed" | "skipped" | "failed";
224
+ /**
225
+ * Per-step progress — the readable half of a run.
226
+ *
227
+ * The conventional shape is one FIXED COLUMN per phase, each holding
228
+ * `Pending | Completed | Skipped`. That works for a fixed pipeline and breaks
229
+ * the moment the pipeline is composed: adding a phase means a schema migration,
230
+ * and a recipe assembled from contributed steps has no fixed phase list at all.
231
+ *
232
+ * So this is a bounded LIST keyed by step id rather than columns. Two further
233
+ * properties, both deliberate:
234
+ *
235
+ * - a `Skipped` with no reason is unreadable — "nothing to do" and
236
+ * "deliberately excluded" are opposite facts, and a bare status enum cannot
237
+ * tell them apart. {@link detail} is REQUIRED for `skipped` and `failed`.
238
+ * - per-step `processed` and timings, so a stalled step is visible while it is
239
+ * still running instead of after the run ends.
240
+ *
241
+ * Bounded by construction: one entry per step in the SEALED plan, and the plan
242
+ * is already capped at `maxPlanItems`. This is not the unbounded per-chunk array
243
+ * the progress summary exists to avoid.
244
+ */
245
+ interface CleanupStepProgress {
246
+ /** Stable id of the contributing step — survives relabelling of `resource`. */
247
+ readonly stepId: string;
248
+ /** Human-facing record class, e.g. `'journal entries'`. */
249
+ readonly resource: string;
250
+ readonly status: CleanupStepRunStatus;
251
+ /** Records this step has processed so far. */
252
+ readonly processed: number;
253
+ readonly startedAt?: Date | undefined;
254
+ readonly completedAt?: Date | undefined;
255
+ /**
256
+ * WHY, for any non-`completed` terminal state. Required for `skipped` and
257
+ * `failed`: an unexplained non-completion is the thing this field exists to
258
+ * prevent.
259
+ */
260
+ readonly detail?: string | undefined;
261
+ }
125
262
  interface CleanupProgressSummary {
126
263
  /** Running total of processed records across all steps. */
127
264
  readonly processed: number;
128
265
  /** Count of steps reported so far. */
129
266
  readonly steps: number;
267
+ /**
268
+ * Per-step lifecycle. Bounded by the sealed plan's step count — see
269
+ * {@link CleanupStepProgress}. Absent on runs recorded before this existed,
270
+ * so a reader must treat it as optional rather than assume an empty run.
271
+ */
272
+ readonly stepProgress?: readonly CleanupStepProgress[] | undefined;
130
273
  /** Resource the last step touched. */
131
274
  readonly currentResource?: string | undefined;
132
275
  /** Last resume cursor reported. */
@@ -448,4 +591,4 @@ interface CleanupLimits {
448
591
  }
449
592
  declare const DEFAULT_CLEANUP_LIMITS: CleanupLimits;
450
593
  //#endregion
451
- export { CleanupWriteFence as A, CleanupResult as C, CleanupRunStore as D, CleanupRunStatus as E, PurgeStrategyKind$1 as F, PurgeVerificationSummary as I, VerificationCheck as L, PurgeActor as M, PurgeEvidence as N, CleanupRunTransitionPatch as O, PurgeResourceResult as P, VerificationResult as R, CleanupRecipe as S, CleanupRunCreateResult as T, CleanupPermissions as _, CleanupEvidenceStore as a, CleanupPlanItem as b, CleanupInput as c, CleanupLease as d, CleanupLimits as f, CleanupPermissionCheck as g, CleanupOutcomeStatus as h, CleanupContext as i, DEFAULT_CLEANUP_LIMITS as j, CleanupStepResult as k, CleanupJob as l, CleanupManifest as m, CLEANUP_TERMINAL_STATUSES as n, CleanupExecutionContext as o, CleanupLogger as p, CleanupCancelRequest as r, CleanupFinalizationPayload as s, Availability as t, CleanupJobQueue as u, CleanupPlan as v, CleanupRun as w, CleanupProgressSummary as x, CleanupPlanDraft as y };
594
+ export { CleanupStepResult as A, VerificationResult as B, CleanupResult as C, CleanupRunStore as D, CleanupRunStatus as E, PurgeEvidence as F, PurgeResourceResult as I, PurgeStrategyKind$1 as L, CleanupWriteFence as M, DEFAULT_CLEANUP_LIMITS as N, CleanupRunTransitionPatch as O, PurgeActor as P, PurgeVerificationSummary as R, CleanupRecipe as S, CleanupRunCreateResult as T, CleanupPermissions as _, CleanupEvidenceStore as a, CleanupPlanItem as b, CleanupInput as c, CleanupLease as d, CleanupLimits as f, CleanupPermissionCheck as g, CleanupOutcomeStatus as h, CleanupContext as i, CleanupStepRunStatus as j, CleanupStepProgress as k, CleanupJob as l, CleanupManifest as m, CLEANUP_TERMINAL_STATUSES as n, CleanupExecutionContext as o, CleanupLogger as p, CleanupCancelRequest as r, CleanupFinalizationPayload as s, Availability as t, CleanupJobQueue as u, CleanupPlan as v, CleanupRun as w, CleanupProgressSummary as x, CleanupPlanDraft as y, VerificationCheck as z };
@@ -1,6 +1,6 @@
1
1
 
2
2
  import { i as RequestScope } from "../types-ChuShpCP.mjs";
3
- import { i as PermissionContext, r as PermissionCheck } from "../types-B7XeLEgK.mjs";
3
+ import { l as PermissionCheck, u as PermissionContext } from "../base-Csjc2oF-.mjs";
4
4
  import { UsageBucket, UsageStore, usagePeriod } from "@classytic/repo-core/usage";
5
5
  import { FastifyPluginAsync, FastifyRequest } from "fastify";
6
6
  //#region src/usage/requireQuota.d.ts
Binary file
@@ -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/userHelpers.ts
3
3
  /**
4
4
  * Extract a user ID from a user object. Accepts `id` or `_id` — returns
@@ -1,8 +1,8 @@
1
1
 
2
- import { $ as OpenApiSchemas, S as QueryParserInterface, b as ParsedQuery } from "../index-CpzxqePp.mjs";
3
2
  import { F as getHeader, I as requireSingleHeaderValue, P as ArcHeaders } from "../types-ChuShpCP.mjs";
4
- import { c as normalizeRoles, l as AnyRecord, o as getUserId, s as getUserRoles } from "../types-B7XeLEgK.mjs";
5
- import { n as ErrorMapper } from "../errorHandler-CpYUJmPA.mjs";
3
+ import { f as getUserId, m as normalizeRoles, p as getUserRoles, t as AnyRecord } from "../base-Csjc2oF-.mjs";
4
+ import { $ as OpenApiSchemas, S as QueryParserInterface, b as ParsedQuery } from "../index-BcR2bFZQ.mjs";
5
+ import { n as ErrorMapper } from "../errorHandler-DI5AN2b5.mjs";
6
6
  import { a as NotFoundError, c as RateLimitError, d as ValidationError, f as createDomainError, i as ForbiddenError, l as ServiceUnavailableError, m as isArcError, n as ConflictError, o as OrgAccessDeniedError, p as createError, r as ErrorOptions, s as OrgRequiredError, t as ArcError, u as UnauthorizedError } from "../errors-BGdVwP25.mjs";
7
7
  import { errorContractSchema, errorDetailSchema } from "@classytic/repo-core/errors";
8
8
  import { scheduleBackground } from "@classytic/repo-core/cache";
@@ -478,6 +478,29 @@ interface ArcQueryParserOptions {
478
478
  * Also used by MCP to auto-derive filterable fields in tool schemas.
479
479
  */
480
480
  allowedFilterFields?: string[];
481
+ /**
482
+ * REFUSE a filter key that is not in {@link allowedFilterFields}, instead of
483
+ * dropping it (default: `false` — today's drop behaviour, kept because arc
484
+ * is published and an unconditional throw would reject requests that work).
485
+ *
486
+ * Dropping a filter does not fail, it **WIDENS**: the caller asked for a
487
+ * narrower set and is silently answered with a broader one, HTTP 200. Two
488
+ * live instances:
489
+ *
490
+ * `?filters[status]=pending` → 200, every row `status:"verified"`
491
+ * `?productId=…` (the param is `skuRef`) → a different product's 75 units,
492
+ * filed for weeks as "quant leakage"
493
+ *
494
+ * Turn this on per-parser, or fleet-wide via `ARC_STRICT_QUERY_PARAMS`.
495
+ * Mirrors the `ARC_STRICT_PERMISSIONS` precedent: off by default here, and
496
+ * the HOST opts in from its env-loader so a forgotten `.env` line cannot
497
+ * silently disable enforcement.
498
+ *
499
+ * Only the FILTER whitelist is covered. `allowedSortFields` /
500
+ * `allowedOperators` keep dropping: a rejected sort or operator degrades
501
+ * ordering, it does not widen the row set.
502
+ */
503
+ strictFilterFields?: boolean;
481
504
  /**
482
505
  * Whitelist of fields that can be sorted on.
483
506
  * When set, sort fields not in this list are silently dropped.
@@ -527,7 +550,12 @@ interface ArcQueryParserOptions {
527
550
  * For advanced MongoDB features ($lookup, aggregations), use MongoKit's QueryParser.
528
551
  */
529
552
  declare class ArcQueryParser implements QueryParserInterface {
530
- private readonly maxLimit;
553
+ /**
554
+ * PUBLIC, deliberately: `QueryResolver` reads it so it does not apply a second cap
555
+ * on top of this one. Three layers capping independently, lowest winning silently,
556
+ * is what made a 696-row chart of accounts render as 100.
557
+ */
558
+ readonly maxLimit: number;
531
559
  private readonly defaultLimit;
532
560
  private readonly maxRegexLength;
533
561
  private readonly maxSearchLength;
@@ -535,6 +563,7 @@ declare class ArcQueryParser implements QueryParserInterface {
535
563
  private readonly _allowedFilterFields?;
536
564
  private readonly _allowedSortFields?;
537
565
  private readonly _allowedOperators?;
566
+ private readonly strictFilterFields;
538
567
  /** Allowed filter fields (used by MCP for auto-derive) */
539
568
  readonly allowedFilterFields?: readonly string[];
540
569
  /** Allowed sort fields (used by MCP for sort descriptions) */
@@ -1105,6 +1134,29 @@ declare function getListQueryParams(): AnyRecord;
1105
1134
  */
1106
1135
  declare function getDefaultCrudSchemas(): Record<string, Record<string, unknown>>;
1107
1136
  //#endregion
1137
+ //#region src/utils/runtimeCapabilities.d.ts
1138
+ /** What a subsystem declares about the state it holds. */
1139
+ interface RuntimeCapabilityDeclaration {
1140
+ /** Dotted subsystem id, e.g. `'webhooks.subscriptions'`, `'events.transport'`. */
1141
+ subsystem: string;
1142
+ /** Where the state lives: `'memory'` = this process only; `'shared'` = external/durable. */
1143
+ durability: "memory" | "shared";
1144
+ /**
1145
+ * `'memory'` durability that is CORRECT by design (per-process micro-cache,
1146
+ * declared single-process topology). Audited as info, never an error —
1147
+ * acceptance must be stated by the declarant, not inferred by the audit.
1148
+ */
1149
+ accepted?: boolean;
1150
+ /** One line for the audit output: what breaks multi-replica, or why accepted. */
1151
+ detail?: string;
1152
+ }
1153
+ /**
1154
+ * Declare a runtime capability. Callable from ANY registration context —
1155
+ * arc's own plugins, host `plugins()` callbacks, module `plugins` phases —
1156
+ * which is the point: the audit sees what the constructor-time guard cannot.
1157
+ */
1158
+ declare function declareRuntimeCapability(fastify: FastifyInstance, decl: RuntimeCapabilityDeclaration): void;
1159
+ //#endregion
1108
1160
  //#region src/utils/schemaConverter.d.ts
1109
1161
  /**
1110
1162
  * Supported JSON Schema output targets for Zod v4's `toJSONSchema()`.
@@ -1514,4 +1566,4 @@ declare function hasEvents(instance: FastifyInstance): instance is FastifyInstan
1514
1566
  events: EventsDecorator;
1515
1567
  };
1516
1568
  //#endregion
1517
- export { ArcError, type ArcHeaders, ArcQueryParser, type ArcQueryParserOptions, CircuitBreaker, CircuitBreakerError, type CircuitBreakerOptions, CircuitBreakerRegistry, type CircuitBreakerStats, CircuitState, type CompensationDefinition, type CompensationError, type CompensationHooks, type CompensationResult, type CompensationStep, ConflictError, type ErrorOptions, type EventsDecorator, type FilterDialect, ForbiddenError, type Guard, type GuardConfig, type JsonSchema, type JsonSchemaTarget, MONGO_DIALECT, NEUTRAL_DIALECT, NotFoundError, OrgAccessDeniedError, OrgRequiredError, type PipeUIMessageStreamOptions, RateLimitError, type SchemaIo, ServiceUnavailableError, type SseStream, type SseStreamOptions, type StateMachine, type TransitionConfig, UI_MESSAGE_STREAM_HEADERS, UnauthorizedError, ValidationError, aggregateListResponse, bareListResponse, convertOpenApiSchemas, convertRouteSchema, createCircuitBreaker, createCircuitBreakerRegistry, createDomainError, createError, createQueryParser, createStateMachine, defineCompensation, defineErrorMapper, defineGuard, deleteResponse, errorContractSchema, errorDetailSchema, forwardedStreamHeaders, getDefaultCrudSchemas, getHeader, getListQueryParams, getUserId, getUserRoles, handleRaw, hasEvents, isArcError, isJsonSchema, isReadableStream, isZodSchema, keysetListResponse, listResponse, normalizeRoles, offsetListResponse, openSseStream, paginationSchema, pipeUIMessageStreamToReply, promoteStreamTokenToHeader, queryParams, requireSingleHeaderValue, responses, scheduleBackground, simpleEqualityMatcher, toJsonSchema, withCompensation };
1569
+ export { ArcError, type ArcHeaders, ArcQueryParser, type ArcQueryParserOptions, CircuitBreaker, CircuitBreakerError, type CircuitBreakerOptions, CircuitBreakerRegistry, type CircuitBreakerStats, CircuitState, type CompensationDefinition, type CompensationError, type CompensationHooks, type CompensationResult, type CompensationStep, ConflictError, type ErrorOptions, type EventsDecorator, type FilterDialect, ForbiddenError, type Guard, type GuardConfig, type JsonSchema, type JsonSchemaTarget, MONGO_DIALECT, NEUTRAL_DIALECT, NotFoundError, OrgAccessDeniedError, OrgRequiredError, type PipeUIMessageStreamOptions, RateLimitError, type RuntimeCapabilityDeclaration, type SchemaIo, ServiceUnavailableError, type SseStream, type SseStreamOptions, type StateMachine, type TransitionConfig, UI_MESSAGE_STREAM_HEADERS, UnauthorizedError, ValidationError, aggregateListResponse, bareListResponse, convertOpenApiSchemas, convertRouteSchema, createCircuitBreaker, createCircuitBreakerRegistry, createDomainError, createError, createQueryParser, createStateMachine, declareRuntimeCapability, defineCompensation, defineErrorMapper, defineGuard, deleteResponse, errorContractSchema, errorDetailSchema, forwardedStreamHeaders, getDefaultCrudSchemas, getHeader, getListQueryParams, getUserId, getUserRoles, handleRaw, hasEvents, isArcError, isJsonSchema, isReadableStream, isZodSchema, keysetListResponse, listResponse, normalizeRoles, offsetListResponse, openSseStream, paginationSchema, pipeUIMessageStreamToReply, promoteStreamTokenToHeader, queryParams, requireSingleHeaderValue, responses, scheduleBackground, simpleEqualityMatcher, toJsonSchema, withCompensation };
@@ -1,11 +1,12 @@
1
- /*! @classytic/arc v2.31.0 | MIT | https://classytic.com */
2
- import { a as OrgAccessDeniedError, c as ServiceUnavailableError, d as createDomainError, f as createError, i as NotFoundError, l as UnauthorizedError, n as ConflictError, o as OrgRequiredError, p as isArcError, r as ForbiddenError, s as RateLimitError, t as ArcError, u as ValidationError } from "../errors-Cj42AntO.mjs";
3
- import { n as requireSingleHeaderValue, t as getHeader } from "../headers-3zvE0rM3.mjs";
4
- import { n as getUserRoles, r as normalizeRoles, t as getUserId } from "../userHelpers-ChYJ6CdK.mjs";
5
- import { t as simpleEqualityMatcher } from "../simpleEqualityMatcher-DjQJ7FKA.mjs";
6
- import { A as createCircuitBreakerRegistry, C as defineCompensation, D as CircuitBreakerRegistry, E as CircuitBreakerError, O as CircuitState, S as defineErrorMapper, T as CircuitBreaker, _ as createQueryParser, a as deleteResponse, b as NEUTRAL_DIALECT, c as getDefaultCrudSchemas, d as listResponse, f as offsetListResponse, g as ArcQueryParser, h as responses, i as bareListResponse, k as createCircuitBreaker, l as getListQueryParams, m as queryParams, n as scheduleBackground, o as errorContractSchema, p as paginationSchema, r as aggregateListResponse, s as errorDetailSchema, t as createStateMachine, u as keysetListResponse, v as handleRaw, w as withCompensation, x as defineGuard, y as MONGO_DIALECT } from "../utils-vL8BrDE2.mjs";
7
- import { a as isZodSchema, i as isJsonSchema, n as convertRouteSchema, o as toJsonSchema, t as convertOpenApiSchemas } from "../schemaConverter-D--wdJM-.mjs";
8
- import { a as promoteStreamTokenToHeader, i as pipeUIMessageStreamToReply, n as forwardedStreamHeaders, r as isReadableStream, t as UI_MESSAGE_STREAM_HEADERS } from "../streaming-PSZwi8JV.mjs";
9
- import { t as openSseStream } from "../sseStream-B_5XcVVd.mjs";
10
- import { t as hasEvents } from "../typeGuards-B0ryPo3I.mjs";
11
- export { ArcError, ArcQueryParser, CircuitBreaker, CircuitBreakerError, CircuitBreakerRegistry, CircuitState, ConflictError, ForbiddenError, MONGO_DIALECT, NEUTRAL_DIALECT, NotFoundError, OrgAccessDeniedError, OrgRequiredError, RateLimitError, ServiceUnavailableError, UI_MESSAGE_STREAM_HEADERS, UnauthorizedError, ValidationError, aggregateListResponse, bareListResponse, convertOpenApiSchemas, convertRouteSchema, createCircuitBreaker, createCircuitBreakerRegistry, createDomainError, createError, createQueryParser, createStateMachine, defineCompensation, defineErrorMapper, defineGuard, deleteResponse, errorContractSchema, errorDetailSchema, forwardedStreamHeaders, getDefaultCrudSchemas, getHeader, getListQueryParams, getUserId, getUserRoles, handleRaw, hasEvents, isArcError, isJsonSchema, isReadableStream, isZodSchema, keysetListResponse, listResponse, normalizeRoles, offsetListResponse, openSseStream, paginationSchema, pipeUIMessageStreamToReply, promoteStreamTokenToHeader, queryParams, requireSingleHeaderValue, responses, scheduleBackground, simpleEqualityMatcher, toJsonSchema, withCompensation };
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { a as OrgAccessDeniedError, c as ServiceUnavailableError, d as createDomainError, f as createError, i as NotFoundError, l as UnauthorizedError, n as ConflictError, o as OrgRequiredError, p as isArcError, r as ForbiddenError, s as RateLimitError, t as ArcError, u as ValidationError } from "../errors-Cd_yy7aW.mjs";
3
+ import { n as requireSingleHeaderValue, t as getHeader } from "../headers-CveNO9gR.mjs";
4
+ import { n as getUserRoles, r as normalizeRoles, t as getUserId } from "../userHelpers-CWF5pbZD.mjs";
5
+ import { t as simpleEqualityMatcher } from "../simpleEqualityMatcher-Se8VrsaP.mjs";
6
+ import { A as createCircuitBreakerRegistry, C as defineCompensation, D as CircuitBreakerRegistry, E as CircuitBreakerError, O as CircuitState, S as defineErrorMapper, T as CircuitBreaker, _ as createQueryParser, a as deleteResponse, b as NEUTRAL_DIALECT, c as getDefaultCrudSchemas, d as listResponse, f as offsetListResponse, g as ArcQueryParser, h as responses, i as bareListResponse, k as createCircuitBreaker, l as getListQueryParams, m as queryParams, n as scheduleBackground, o as errorContractSchema, p as paginationSchema, r as aggregateListResponse, s as errorDetailSchema, t as createStateMachine, u as keysetListResponse, v as handleRaw, w as withCompensation, x as defineGuard, y as MONGO_DIALECT } from "../utils-h1V_sT-t.mjs";
7
+ import { n as declareRuntimeCapability } from "../runtimeCapabilities-Dm88DaTW.mjs";
8
+ import { a as isZodSchema, i as isJsonSchema, n as convertRouteSchema, o as toJsonSchema, t as convertOpenApiSchemas } from "../schemaConverter-XH1RZRyu.mjs";
9
+ import { a as promoteStreamTokenToHeader, i as pipeUIMessageStreamToReply, n as forwardedStreamHeaders, r as isReadableStream, t as UI_MESSAGE_STREAM_HEADERS } from "../streaming-DsT1B5zJ.mjs";
10
+ import { t as openSseStream } from "../sseStream-Bvpi-UXQ.mjs";
11
+ import { t as hasEvents } from "../typeGuards-jjKJDN13.mjs";
12
+ export { ArcError, ArcQueryParser, CircuitBreaker, CircuitBreakerError, CircuitBreakerRegistry, CircuitState, ConflictError, ForbiddenError, MONGO_DIALECT, NEUTRAL_DIALECT, NotFoundError, OrgAccessDeniedError, OrgRequiredError, RateLimitError, ServiceUnavailableError, UI_MESSAGE_STREAM_HEADERS, UnauthorizedError, ValidationError, aggregateListResponse, bareListResponse, convertOpenApiSchemas, convertRouteSchema, createCircuitBreaker, createCircuitBreakerRegistry, createDomainError, createError, createQueryParser, createStateMachine, declareRuntimeCapability, defineCompensation, defineErrorMapper, defineGuard, deleteResponse, errorContractSchema, errorDetailSchema, forwardedStreamHeaders, getDefaultCrudSchemas, getHeader, getListQueryParams, getUserId, getUserRoles, handleRaw, hasEvents, isArcError, isJsonSchema, isReadableStream, isZodSchema, keysetListResponse, listResponse, normalizeRoles, offsetListResponse, openSseStream, paginationSchema, pipeUIMessageStreamToReply, promoteStreamTokenToHeader, queryParams, requireSingleHeaderValue, responses, scheduleBackground, simpleEqualityMatcher, toJsonSchema, withCompensation };