@classytic/arc 2.19.0 → 2.21.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 (139) hide show
  1. package/README.md +1 -1
  2. package/bin/arc.js +37 -0
  3. package/dist/{BaseController-Dy6EQHjM.mjs → BaseController-BnLYgE9A.mjs} +4 -4
  4. package/dist/{EventTransport-IEn7Tn-Q.d.mts → EventTransport-QmY7A258.d.mts} +0 -1
  5. package/dist/{QueryCache-TRfXau3W.d.mts → QueryCache-Z1B38koh.d.mts} +0 -1
  6. package/dist/{ResourceRegistry-5fKZwhK_.mjs → ResourceRegistry-7RnrEWNP.mjs} +1 -1
  7. package/dist/{actionPermissions-D7NGwcAR.mjs → actionPermissions-ze70xXJi.mjs} +1 -1
  8. package/dist/audit/index.d.mts +9 -5
  9. package/dist/audit/index.mjs +1 -1
  10. package/dist/auth/audit.d.mts +7 -4
  11. package/dist/auth/audit.mjs +5 -0
  12. package/dist/auth/index.d.mts +7 -14
  13. package/dist/auth/index.mjs +7 -5
  14. package/dist/auth/redis-session.d.mts +1 -2
  15. package/dist/{buildHandler-B0qvAguf.mjs → buildHandler-D_2ULWxZ.mjs} +3 -3
  16. package/dist/cache/index.d.mts +2 -3
  17. package/dist/cache/index.mjs +2 -2
  18. package/dist/cli/commands/describe.d.mts +1 -2
  19. package/dist/cli/commands/describe.mjs +2 -2
  20. package/dist/cli/commands/docs.mjs +2 -2
  21. package/dist/cli/commands/generate.mjs +1 -1
  22. package/dist/cli/commands/init.mjs +1 -1
  23. package/dist/cli/commands/introspect.mjs +4 -13
  24. package/dist/cli/index.mjs +2 -2
  25. package/dist/{constants-gaEeMlz-.mjs → constants-DNre0wRg.mjs} +1 -1
  26. package/dist/context/index.d.mts +2 -2
  27. package/dist/core/index.d.mts +3 -3
  28. package/dist/core/index.mjs +5 -5
  29. package/dist/{core-Ba-6Sue6.mjs → core-DZ6Xe1jR.mjs} +182 -55
  30. package/dist/{createActionRouter-B_WzBFyf.mjs → createActionRouter-BWMDW-dL.mjs} +4 -4
  31. package/dist/{createAggregationRouter-B_G_nIjm.mjs → createAggregationRouter-l5mNdYrZ.mjs} +5 -4
  32. package/dist/{createApp--703hQE1.mjs → createApp-Bi61XxqU.mjs} +229 -24
  33. package/dist/discovery/index.d.mts +0 -1
  34. package/dist/docs/index.d.mts +1 -2
  35. package/dist/docs/index.mjs +1 -1
  36. package/dist/{elevation-xGUBq6p_.d.mts → elevation-C9s5hFP_.d.mts} +0 -1
  37. package/dist/encryption/index.d.mts +2 -144
  38. package/dist/{errorHandler-BtUUDPEa.d.mts → errorHandler-B0e-bq-O.d.mts} +0 -1
  39. package/dist/{errors-DOHkjQlD.d.mts → errors-DHcHVAgk.d.mts} +0 -1
  40. package/dist/{eventPlugin-DbBFd3x_.d.mts → eventPlugin-A6EbthXR.d.mts} +10 -6
  41. package/dist/events/index.d.mts +9 -6
  42. package/dist/events/index.mjs +9 -6
  43. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  44. package/dist/events/transports/redis.d.mts +1 -2
  45. package/dist/factory/index.d.mts +5 -4
  46. package/dist/factory/index.mjs +3 -3
  47. package/dist/{fastify-augmentation-D-5_yQJi.d.mts → fastify-augmentation-DafigGQp.d.mts} +12 -2
  48. package/dist/{fields-C7ahdGYf.d.mts → fields-BGqrAa_u.d.mts} +1 -2
  49. package/dist/{generate-Brans3fW.mjs → generate-usRSdQmP.mjs} +4 -3
  50. package/dist/hooks/index.d.mts +1 -1
  51. package/dist/idempotency/index.d.mts +4 -3
  52. package/dist/idempotency/index.mjs +1 -1
  53. package/dist/idempotency/redis.d.mts +1 -1
  54. package/dist/{index-CP6A1Ffj.d.mts → index-B5N-NaHs.d.mts} +88 -7
  55. package/dist/{index-CRKiiP5o.d.mts → index-B5PoNbfu.d.mts} +41 -7
  56. package/dist/{index-CUTG2Cuo.d.mts → index-Dtrj6XZk.d.mts} +90 -29
  57. package/dist/index.d.mts +7 -7
  58. package/dist/index.mjs +7 -7
  59. package/dist/{init-Bqpt1Hxf.mjs → init-0YhHkXGk.mjs} +239 -140
  60. package/dist/integrations/event-gateway.d.mts +2 -3
  61. package/dist/integrations/index.d.mts +2 -2
  62. package/dist/integrations/jobs.d.mts +0 -1
  63. package/dist/integrations/mcp/index.d.mts +6 -7
  64. package/dist/integrations/mcp/index.mjs +1 -1
  65. package/dist/integrations/mcp/testing.d.mts +1 -2
  66. package/dist/integrations/mcp/testing.mjs +1 -1
  67. package/dist/integrations/streamline.d.mts +19 -7
  68. package/dist/integrations/streamline.mjs +9 -5
  69. package/dist/integrations/webhooks.d.mts +0 -1
  70. package/dist/integrations/websocket-pushref-redis.d.mts +1 -2
  71. package/dist/integrations/websocket-redis.d.mts +1 -2
  72. package/dist/integrations/websocket.d.mts +2 -2
  73. package/dist/{loadResources-B8UmpITt.mjs → loadResources-DpU8pfjV.mjs} +4 -3
  74. package/dist/{loadResourcesFromEntry-BTlFEx05.mjs → loadResourcesFromEntry-OMCvIEE7.mjs} +1 -1
  75. package/dist/{mcpPlugin-C088Nd-G.mjs → mcpPlugin-B9XjjNVG.mjs} +148 -49
  76. package/dist/middleware/index.d.mts +1 -2
  77. package/dist/middleware/index.mjs +1 -1
  78. package/dist/module-WeuU5jfd.d.mts +429 -0
  79. package/dist/{openapi-DZ-5a5Op.mjs → openapi-Kyod_di6.mjs} +3 -3
  80. package/dist/permissions/index.d.mts +3 -3
  81. package/dist/permissions/index.mjs +2 -2
  82. package/dist/{permissions-BPB1xqGf.mjs → permissions-BJMuKMl7.mjs} +43 -3
  83. package/dist/pipeline/index.d.mts +1 -2
  84. package/dist/plugins/index.d.mts +87 -10
  85. package/dist/plugins/index.mjs +91 -4
  86. package/dist/plugins/response-cache.d.mts +5 -3
  87. package/dist/plugins/tracing-entry.d.mts +1 -1
  88. package/dist/plugins/tracing-entry.mjs +1 -1
  89. package/dist/{pluralize-DccFV9R7.mjs → pluralize-BhrgwZb9.mjs} +3 -3
  90. package/dist/presets/filesUpload.d.mts +4 -5
  91. package/dist/presets/filesUpload.mjs +1 -1
  92. package/dist/presets/index.d.mts +16 -3
  93. package/dist/presets/index.mjs +1 -1
  94. package/dist/presets/multiTenant.d.mts +1 -2
  95. package/dist/presets/multiTenant.mjs +1 -1
  96. package/dist/presets/search.d.mts +2 -3
  97. package/dist/presets/search.mjs +3 -2
  98. package/dist/{presets-BtyFwTO4.mjs → presets-gw0ciIUD.mjs} +1 -1
  99. package/dist/{pushref-registry-DnCqL3aa.d.mts → pushref-registry-BbcnpNTm.d.mts} +4 -2
  100. package/dist/{queryCachePlugin-xzFyKAjT.d.mts → queryCachePlugin-CfYWq-Ak.d.mts} +1 -2
  101. package/dist/{queryCachePlugin-emHb0CuX.mjs → queryCachePlugin-DzqLN904.mjs} +2 -2
  102. package/dist/{redis-C3W0qbz8.d.mts → redis-UDtLaNj6.d.mts} +0 -1
  103. package/dist/{redis-stream-DsP1vqZB.d.mts → redis-stream-iVR2l7aS.d.mts} +1 -2
  104. package/dist/{registerRoute-BdV8DDwU.mjs → registerRoute-oGAl0oA8.mjs} +1 -1
  105. package/dist/registry/index.d.mts +2 -2
  106. package/dist/registry/index.mjs +2 -2
  107. package/dist/{registry-Bm9LjWKs.mjs → registry-vcOCtPij.mjs} +1 -1
  108. package/dist/{schemaIR-D1MJwqmp.mjs → schemaIR-ajetw3Fv.mjs} +1 -42
  109. package/dist/schemas/index.d.mts +0 -1
  110. package/dist/scim/index.d.mts +0 -1
  111. package/dist/scim/index.mjs +2 -2
  112. package/dist/scope/index.d.mts +2 -3
  113. package/dist/{sessionManager-BXG-HGwG.d.mts → sessionManager-BHOM3N_0.d.mts} +10 -6
  114. package/dist/{storage-Co_PQpeQ.d.mts → storage-DLUZ04kK.d.mts} +8 -4
  115. package/dist/sync/changelog.d.mts +2 -0
  116. package/dist/sync/changelog.mjs +2 -0
  117. package/dist/testing/index.d.mts +2 -3
  118. package/dist/testing/index.mjs +6 -3
  119. package/dist/testing/storageContract.d.mts +1 -2
  120. package/dist/{tracing-D8jlGXP7.d.mts → tracing-CsGKQJGg.d.mts} +0 -1
  121. package/dist/types/index.d.mts +4 -4
  122. package/dist/types/storage.d.mts +1 -1
  123. package/dist/types-Cc91nXuA.d.mts +132 -0
  124. package/dist/{types-LNebCoJx.d.mts → types-DH0GupI7.d.mts} +8 -4
  125. package/dist/{types-DpvSF5Hh.d.mts → types-DRj-Ut4n.d.mts} +1 -2
  126. package/dist/{types-9_wtNPsI.d.mts → types-DpxoNX5v.d.mts} +112 -214
  127. package/dist/utils/index.d.mts +182 -128
  128. package/dist/utils/index.mjs +2 -2
  129. package/dist/{utils-C6QQ9-hd.mjs → utils-CO8a3B_1.mjs} +1435 -1391
  130. package/dist/{validate-CRcaWzp2.mjs → validate-C2mGgSXg.mjs} +3 -3
  131. package/dist/{versioning-D_eBCfNr.d.mts → versioning-DQ4mCvg0.d.mts} +1 -2
  132. package/dist/{websocket-MlYlrYq0.d.mts → websocket-uuWqM6UY.d.mts} +5 -4
  133. package/package.json +18 -13
  134. package/skills/arc/SKILL.md +10 -0
  135. package/skills/arc/references/mcp.md +2 -0
  136. package/skills/arc-module-publishing/SKILL.md +242 -0
  137. package/skills/arc-module-publishing/references/authoring-modules.md +272 -0
  138. package/skills/arc-module-publishing/references/package-manifest.md +155 -0
  139. package/skills/arc-module-publishing/references/publishing-workflow.md +182 -0
@@ -1,11 +1,10 @@
1
- import { Q as MiddlewareConfig, ft as RouteDefinition, ht as RouteSchemaOptions, nt as PresetHook, qt as AnyRecord } from "../index-CUTG2Cuo.mjs";
2
- import { a as arcCorePlugin, i as _default, n as ArcCorePluginOptions, r as PluginMeta, t as ArcCore } from "../fastify-augmentation-D-5_yQJi.mjs";
3
- import { _ as HealthOptions, a as MetricsCollector, c as metricsPlugin, d as ssePlugin, f as CachingOptions, g as HealthCheck, h as cachingPlugin, i as MetricEntry, l as SSEOptions, m as _default$1, n as _default$7, o as MetricsOptions, p as CachingRule, r as versioningPlugin, s as _default$4, t as VersioningOptions, u as _default$6, v as _default$3, y as healthPlugin } from "../versioning-D_eBCfNr.mjs";
4
- import { i as errorHandlerPlugin, n as ErrorMapper, r as defaultIsDuplicateKeyError, t as ErrorHandlerOptions } from "../errorHandler-BtUUDPEa.mjs";
5
- import { t as TracingOptions } from "../tracing-D8jlGXP7.mjs";
1
+ import { Q as MiddlewareConfig, ft as RouteDefinition, ht as RouteSchemaOptions, nt as PresetHook, qt as AnyRecord } from "../index-Dtrj6XZk.mjs";
2
+ import { i as errorHandlerPlugin, n as ErrorMapper, r as defaultIsDuplicateKeyError, t as ErrorHandlerOptions } from "../errorHandler-B0e-bq-O.mjs";
3
+ import { a as arcCorePlugin, i as _default, n as ArcCorePluginOptions, r as PluginMeta, t as ArcCore } from "../fastify-augmentation-DafigGQp.mjs";
4
+ import { _ as HealthOptions, a as MetricsCollector, c as metricsPlugin, d as ssePlugin, f as CachingOptions, g as HealthCheck, h as cachingPlugin, i as MetricEntry, l as SSEOptions, m as _default$1, n as _default$8, o as MetricsOptions, p as CachingRule, r as versioningPlugin, s as _default$4, t as VersioningOptions, u as _default$7, v as _default$3, y as healthPlugin } from "../versioning-DQ4mCvg0.mjs";
5
+ import { t as TracingOptions } from "../tracing-CsGKQJGg.mjs";
6
6
  import { PaginatedResult } from "@classytic/repo-core/pagination";
7
7
  import { FastifyInstance, FastifyPluginAsync } from "fastify";
8
-
9
8
  //#region src/plugins/createPlugin.d.ts
10
9
  interface PluginResourceResult {
11
10
  /** Additional routes to add to the resource (v2.8 `RouteDefinition` shape) */
@@ -24,10 +23,15 @@ interface CreatePluginDefinition<TRootOpts extends AnyRecord = AnyRecord, TResou
24
23
  */
25
24
  forRoot?: (fastify: FastifyInstance, opts: TRootOpts) => void | Promise<void>;
26
25
  /**
27
- * Per-resource configuration function. Called for each resource that uses this plugin.
28
- * Returns hooks, routes, middlewares, etc. to merge into the resource config.
26
+ * Per-resource configuration function. Called (via `plugin.forResource(opts)`)
27
+ * to PRODUCE a partial resource config — hooks, routes, middlewares — that the
28
+ * host spreads into `defineResource(...)`. It receives only the plugin's own
29
+ * `opts`: the resource does not exist yet at this call site, so it cannot be
30
+ * inspected here (that was a false promise pre-2.20; the unused `resourceConfig`
31
+ * parameter is removed). For behavior that must vary by resource, key off the
32
+ * plugin's `opts` the host passes per resource.
29
33
  */
30
- forResource?: (resourceConfig: AnyRecord, opts: TResourceOpts) => PluginResourceResult;
34
+ forResource?: (opts: TResourceOpts) => PluginResourceResult;
31
35
  }
32
36
  interface ArcPlugin<TRootOpts extends AnyRecord = AnyRecord, TResourceOpts extends AnyRecord = AnyRecord> {
33
37
  /** Plugin name */
@@ -144,4 +148,77 @@ declare module "fastify" {
144
148
  declare const requestIdPlugin: FastifyPluginAsync<RequestIdOptions>;
145
149
  declare const _default$5: FastifyPluginAsync<RequestIdOptions>;
146
150
  //#endregion
147
- export { type ArcCore, type ArcCorePluginOptions, type ArcPlugin, type CachingOptions, type CachingRule, type CreatePluginDefinition, type ErrorHandlerOptions, type ErrorMapper, type GracefulShutdownOptions, type HealthCheck, type HealthOptions, type MetricEntry, type MetricsCollector, type MetricsOptions, type PluginMeta, type PluginResourceResult, type RequestIdOptions, type SSEOptions, type TracingOptions, type VersioningOptions, _default as arcCorePlugin, arcCorePlugin as arcCorePluginFn, _default$1 as cachingPlugin, cachingPlugin as cachingPluginFn, createPlugin, defaultIsDuplicateKeyError, errorHandlerPlugin, errorHandlerPlugin as errorHandlerPluginFn, _default$2 as gracefulShutdownPlugin, gracefulShutdownPlugin as gracefulShutdownPluginFn, _default$3 as healthPlugin, healthPlugin as healthPluginFn, _default$4 as metricsPlugin, metricsPlugin as metricsPluginFn, replyHelpersPlugin, _default$5 as requestIdPlugin, requestIdPlugin as requestIdPluginFn, _default$6 as ssePlugin, ssePlugin as ssePluginFn, _default$7 as versioningPlugin, versioningPlugin as versioningPluginFn };
151
+ //#region src/plugins/schedules.d.ts
152
+ /**
153
+ * Structural view of the ecosystem lock contract — matches
154
+ * `LockAdapter` from `@classytic/repo-core/lock` (and every kit
155
+ * implementation) WITHOUT importing the subpath, so arc's emitted
156
+ * declarations carry no repo-core@>=0.8 subpath reference and the
157
+ * peer floor stays honest. Any conforming adapter assigns.
158
+ */
159
+ interface ScheduleLockLike {
160
+ tryAcquire(name: string, holderId: string, leaseMs: number): Promise<boolean> | boolean;
161
+ release(name: string, holderId: string): Promise<boolean> | boolean;
162
+ }
163
+ interface ScheduleDefinition {
164
+ /** Unique name — also the lock key (`arc:schedule:<name>`). */
165
+ name: string;
166
+ /** Interval in milliseconds between the END of one run and the next tick. */
167
+ every: number;
168
+ /** The work. Receives the Fastify instance; errors are logged, never fatal. */
169
+ handler: (fastify: FastifyInstance) => void | Promise<void>;
170
+ /** Fire once immediately when the app becomes ready (default: false). */
171
+ runOnStart?: boolean;
172
+ /**
173
+ * Random extra delay in `[0, jitterMs)` added to the FIRST tick only.
174
+ * Spreads boot-aligned jobs so multiple same-cadence schedules don't all
175
+ * fire at exactly `boot + every` after every restart (and, with a lock,
176
+ * de-synchronizes replicas competing for the same lease). Ignored when
177
+ * `runOnStart` is true.
178
+ */
179
+ jitterMs?: number;
180
+ /**
181
+ * Lease duration when a `lock` is configured. Default: `every * 0.9`
182
+ * (capped at 5 minutes) — long enough that other replicas skip the same
183
+ * tick, short enough that a crashed leader fails over within one cycle.
184
+ */
185
+ leaseMs?: number;
186
+ /** Per-schedule kill switch (default: true). */
187
+ enabled?: boolean;
188
+ }
189
+ interface SchedulesPluginOptions {
190
+ schedules: ScheduleDefinition[];
191
+ /**
192
+ * Ecosystem lock adapter for multi-replica deployments. Omit for
193
+ * single-instance apps — every tick runs locally.
194
+ */
195
+ lock?: ScheduleLockLike;
196
+ /**
197
+ * Identity of this replica for lease ownership. Default: a random id per
198
+ * process (repo-core's `getInstanceId()` is a good explicit value).
199
+ */
200
+ holderId?: string;
201
+ /**
202
+ * Master switch — `false` registers a typed no-op (config-gated
203
+ * environments), same pattern as `idempotencyPlugin`.
204
+ */
205
+ enabled?: boolean;
206
+ }
207
+ /** Per-schedule runtime counters, readable via `fastify.getScheduleStats()`. */
208
+ interface ScheduleStats {
209
+ name: string;
210
+ runs: number;
211
+ failures: number;
212
+ skippedByLock: number;
213
+ lastRunAt: string | null;
214
+ lastError: string | null;
215
+ }
216
+ declare module "fastify" {
217
+ interface FastifyInstance {
218
+ getScheduleStats?: () => ScheduleStats[];
219
+ }
220
+ }
221
+ declare const schedulesPlugin: FastifyPluginAsync<SchedulesPluginOptions>;
222
+ declare const _default$6: FastifyPluginAsync<SchedulesPluginOptions>;
223
+ //#endregion
224
+ export { type ArcCore, type ArcCorePluginOptions, type ArcPlugin, type CachingOptions, type CachingRule, type CreatePluginDefinition, type ErrorHandlerOptions, type ErrorMapper, type GracefulShutdownOptions, type HealthCheck, type HealthOptions, type MetricEntry, type MetricsCollector, type MetricsOptions, type PluginMeta, type PluginResourceResult, type RequestIdOptions, type SSEOptions, type ScheduleDefinition, type ScheduleLockLike, type ScheduleStats, type SchedulesPluginOptions, type TracingOptions, type VersioningOptions, _default as arcCorePlugin, arcCorePlugin as arcCorePluginFn, _default$1 as cachingPlugin, cachingPlugin as cachingPluginFn, createPlugin, defaultIsDuplicateKeyError, errorHandlerPlugin, errorHandlerPlugin as errorHandlerPluginFn, _default$2 as gracefulShutdownPlugin, gracefulShutdownPlugin as gracefulShutdownPluginFn, _default$3 as healthPlugin, healthPlugin as healthPluginFn, _default$4 as metricsPlugin, metricsPlugin as metricsPluginFn, replyHelpersPlugin, _default$5 as requestIdPlugin, requestIdPlugin as requestIdPluginFn, _default$6 as schedulesPlugin, schedulesPlugin as schedulesPluginFn, _default$7 as ssePlugin, ssePlugin as ssePluginFn, _default$8 as versioningPlugin, versioningPlugin as versioningPluginFn };
@@ -1,9 +1,9 @@
1
- import { p as MUTATION_OPERATIONS } from "../constants-gaEeMlz-.mjs";
1
+ import { p as MUTATION_OPERATIONS } from "../constants-DNre0wRg.mjs";
2
2
  import { c as getOrgId } from "../types-bHblZ9YN.mjs";
3
3
  import { n as requestContext } from "../requestContext-BZKOr13H.mjs";
4
4
  import { t as hasEvents } from "../typeGuards-C9KXUly6.mjs";
5
5
  import { t as HookSystem } from "../HookSystem-C1vB_Gc9.mjs";
6
- import { t as ResourceRegistry } from "../ResourceRegistry-5fKZwhK_.mjs";
6
+ import { t as ResourceRegistry } from "../ResourceRegistry-7RnrEWNP.mjs";
7
7
  import { n as caching_default, t as cachingPlugin } from "../caching-_NJeDd1_.mjs";
8
8
  import { n as errorHandlerPlugin, t as defaultIsDuplicateKeyError } from "../errorHandler-Dxf6P_kV.mjs";
9
9
  import { n as metrics_default, t as metricsPlugin } from "../metrics-fdxI5mn_.mjs";
@@ -131,7 +131,7 @@ function createPlugin(name, definition) {
131
131
  },
132
132
  forResource(opts) {
133
133
  if (!definition.forResource) return {};
134
- return definition.forResource({}, opts ?? {});
134
+ return definition.forResource(opts ?? {});
135
135
  }
136
136
  };
137
137
  }
@@ -469,4 +469,91 @@ var requestId_default = fp(requestIdPlugin, {
469
469
  fastify: "5.x"
470
470
  });
471
471
  //#endregion
472
- export { arcCorePlugin_default as arcCorePlugin, arcCorePlugin as arcCorePluginFn, caching_default as cachingPlugin, cachingPlugin as cachingPluginFn, createPlugin, defaultIsDuplicateKeyError, errorHandlerPlugin, errorHandlerPlugin as errorHandlerPluginFn, gracefulShutdown_default as gracefulShutdownPlugin, gracefulShutdownPlugin as gracefulShutdownPluginFn, health_default as healthPlugin, healthPlugin as healthPluginFn, metrics_default as metricsPlugin, metricsPlugin as metricsPluginFn, replyHelpersPlugin, requestId_default as requestIdPlugin, requestIdPlugin as requestIdPluginFn, sse_default as ssePlugin, ssePlugin as ssePluginFn, versioning_default as versioningPlugin, versioningPlugin as versioningPluginFn };
472
+ //#region src/plugins/schedules.ts
473
+ const MIN_SAFE_INTERVAL_MS = 1e3;
474
+ const MAX_DEFAULT_LEASE_MS = 3e5;
475
+ const schedulesPlugin = async (fastify, opts) => {
476
+ const { schedules, lock, enabled = true } = opts;
477
+ const holderId = opts.holderId ?? `arc-${process.pid}-${Math.random().toString(36).slice(2, 10)}`;
478
+ const stats = /* @__PURE__ */ new Map();
479
+ fastify.decorate("getScheduleStats", () => [...stats.values()].map((s) => ({ ...s })));
480
+ if (!enabled) {
481
+ fastify.log.debug("schedulesPlugin disabled — registered as no-op");
482
+ return;
483
+ }
484
+ const seen = /* @__PURE__ */ new Set();
485
+ for (const s of schedules) {
486
+ if (!s.name) throw new TypeError("[arc-schedules] every schedule needs a name");
487
+ if (seen.has(s.name)) throw new TypeError(`[arc-schedules] duplicate schedule name "${s.name}"`);
488
+ seen.add(s.name);
489
+ if (!Number.isFinite(s.every) || s.every <= 0) throw new TypeError(`[arc-schedules] "${s.name}": \`every\` must be a positive number of ms`);
490
+ if (s.every < MIN_SAFE_INTERVAL_MS) fastify.log.warn(`[arc-schedules] "${s.name}" runs every ${s.every}ms — sub-second schedules are almost always a bug in production (DB pressure, lock churn). Intended for tests only.`);
491
+ }
492
+ const timers = /* @__PURE__ */ new Map();
493
+ const inFlight = /* @__PURE__ */ new Map();
494
+ let closing = false;
495
+ async function tick(s) {
496
+ const stat = stats.get(s.name);
497
+ if (!stat) return;
498
+ try {
499
+ if (lock) {
500
+ const leaseMs = s.leaseMs ?? Math.min(Math.floor(s.every * .9), MAX_DEFAULT_LEASE_MS);
501
+ if (!await lock.tryAcquire(`arc:schedule:${s.name}`, holderId, leaseMs)) {
502
+ stat.skippedByLock++;
503
+ return;
504
+ }
505
+ }
506
+ stat.runs++;
507
+ stat.lastRunAt = (/* @__PURE__ */ new Date()).toISOString();
508
+ await s.handler(fastify);
509
+ stat.lastError = null;
510
+ } catch (err) {
511
+ stat.failures++;
512
+ stat.lastError = err instanceof Error ? err.message : String(err);
513
+ fastify.log.error({
514
+ err,
515
+ schedule: s.name
516
+ }, "[arc-schedules] schedule run failed");
517
+ }
518
+ }
519
+ function scheduleNext(s, delay) {
520
+ if (closing) return;
521
+ const timer = setTimeout(() => {
522
+ const run = tick(s).finally(() => {
523
+ inFlight.delete(s.name);
524
+ scheduleNext(s, s.every);
525
+ });
526
+ inFlight.set(s.name, run);
527
+ }, delay);
528
+ timer.unref?.();
529
+ timers.set(s.name, timer);
530
+ }
531
+ fastify.addHook("onReady", async () => {
532
+ for (const s of schedules) {
533
+ if (s.enabled === false) continue;
534
+ stats.set(s.name, {
535
+ name: s.name,
536
+ runs: 0,
537
+ failures: 0,
538
+ skippedByLock: 0,
539
+ lastRunAt: null,
540
+ lastError: null
541
+ });
542
+ const jitter = !s.runOnStart && s.jitterMs ? Math.floor(Math.random() * s.jitterMs) : 0;
543
+ scheduleNext(s, s.runOnStart ? 0 : s.every + jitter);
544
+ }
545
+ if (stats.size > 0) fastify.log.debug(`[arc-schedules] ${stats.size} schedule(s) armed${lock ? ` (leader-safe, holder ${holderId})` : ""}`);
546
+ });
547
+ fastify.addHook("onClose", async () => {
548
+ closing = true;
549
+ for (const timer of timers.values()) clearTimeout(timer);
550
+ timers.clear();
551
+ await Promise.allSettled([...inFlight.values()]);
552
+ });
553
+ };
554
+ var schedules_default = fp(schedulesPlugin, {
555
+ name: "arc-schedules",
556
+ fastify: "5.x"
557
+ });
558
+ //#endregion
559
+ export { arcCorePlugin_default as arcCorePlugin, arcCorePlugin as arcCorePluginFn, caching_default as cachingPlugin, cachingPlugin as cachingPluginFn, createPlugin, defaultIsDuplicateKeyError, errorHandlerPlugin, errorHandlerPlugin as errorHandlerPluginFn, gracefulShutdown_default as gracefulShutdownPlugin, gracefulShutdownPlugin as gracefulShutdownPluginFn, health_default as healthPlugin, healthPlugin as healthPluginFn, metrics_default as metricsPlugin, metricsPlugin as metricsPluginFn, replyHelpersPlugin, requestId_default as requestIdPlugin, requestIdPlugin as requestIdPluginFn, schedules_default as schedulesPlugin, schedulesPlugin as schedulesPluginFn, sse_default as ssePlugin, ssePlugin as ssePluginFn, versioning_default as versioningPlugin, versioningPlugin as versioningPluginFn };
@@ -1,5 +1,4 @@
1
1
  import { FastifyPluginAsync, FastifyRequest } from "fastify";
2
-
3
2
  //#region src/plugins/response-cache.d.ts
4
3
  interface ResponseCacheRule {
5
4
  /** Path prefix to match (e.g., '/api/products') */
@@ -57,8 +56,11 @@ interface ResponseCacheStats {
57
56
  declare module "fastify" {
58
57
  interface FastifyInstance {
59
58
  responseCache: {
60
- /** Invalidate all cached responses matching a path prefix */invalidate: (pathPrefix: string) => number; /** Clear the entire cache */
61
- invalidateAll: () => void; /** Get cache statistics */
59
+ /** Invalidate all cached responses matching a path prefix */
60
+ invalidate: (pathPrefix: string) => number;
61
+ /** Clear the entire cache */
62
+ invalidateAll: () => void;
63
+ /** Get cache statistics */
62
64
  stats: () => ResponseCacheStats;
63
65
  /**
64
66
  * Route-level preHandler for cache lookup.
@@ -1,2 +1,2 @@
1
- import { a as traced, i as isTracingAvailable, n as _default, r as createSpan, t as TracingOptions } from "../tracing-D8jlGXP7.mjs";
1
+ import { a as traced, i as isTracingAvailable, n as _default, r as createSpan, t as TracingOptions } from "../tracing-CsGKQJGg.mjs";
2
2
  export { type TracingOptions, createSpan, isTracingAvailable, traced, _default as tracingPlugin };
@@ -58,7 +58,7 @@ try {
58
58
  function createTracerProvider(options) {
59
59
  if (!isAvailable || !NodeTracerProvider || !BatchSpanProcessor || !OTLPTraceExporter) return null;
60
60
  const { serviceName = "@classytic/arc", serviceVersion, exporterUrl = "http://localhost:4318/v1/traces" } = options;
61
- const resolvedVersion = serviceVersion ?? "2.19.0";
61
+ const resolvedVersion = serviceVersion ?? "2.21.0";
62
62
  const exporter = new OTLPTraceExporter({ url: exporterUrl });
63
63
  const provider = new NodeTracerProvider({ resource: { attributes: {
64
64
  "service.name": serviceName,
@@ -34,7 +34,7 @@ const IRREGULARS = {
34
34
  vertex: "vertices",
35
35
  criterion: "criteria"
36
36
  };
37
- const UNCOUNTABLES = new Set([
37
+ const UNCOUNTABLES = /* @__PURE__ */ new Set([
38
38
  "sheep",
39
39
  "fish",
40
40
  "deer",
@@ -65,7 +65,7 @@ function pluralize(word) {
65
65
  if (lower.endsWith("f") && !lower.endsWith("ff") && !lower.endsWith("roof") && !lower.endsWith("chief") && !lower.endsWith("belief")) return `${word.slice(0, -1)}ves`;
66
66
  if (lower.endsWith("y") && !/[aeiou]y$/i.test(lower)) return `${word.slice(0, -1)}ies`;
67
67
  if (lower.endsWith("is")) return `${word.slice(0, -2)}es`;
68
- if (new Set([
68
+ if ((/* @__PURE__ */ new Set([
69
69
  "cactus",
70
70
  "stimulus",
71
71
  "focus",
@@ -76,7 +76,7 @@ function pluralize(word) {
76
76
  "alumnus",
77
77
  "terminus",
78
78
  "bacillus"
79
- ]).has(lower)) return `${word.slice(0, -2)}i`;
79
+ ])).has(lower)) return `${word.slice(0, -2)}i`;
80
80
  if (lower.endsWith("z") && !lower.endsWith("zz")) return `${word}zes`;
81
81
  if (/(?:s|sh|ch|x|zz)$/i.test(lower)) return `${word}es`;
82
82
  if (lower.endsWith("o") && !/[aeiou]o$/i.test(lower)) return `${word}es`;
@@ -1,8 +1,7 @@
1
- import { rt as PresetResult } from "../index-CUTG2Cuo.mjs";
2
- import { i as RequestScope } from "../types-LNebCoJx.mjs";
3
- import { c as PermissionCheck } from "../fields-C7ahdGYf.mjs";
4
- import { a as StorageReadResult, i as StorageReadRange, n as StorageContext, o as StorageUploadInput, r as StorageFile, t as Storage } from "../storage-Co_PQpeQ.mjs";
5
-
1
+ import { rt as PresetResult } from "../index-Dtrj6XZk.mjs";
2
+ import { i as RequestScope } from "../types-DH0GupI7.mjs";
3
+ import { c as PermissionCheck } from "../fields-BGqrAa_u.mjs";
4
+ import { a as StorageReadResult, i as StorageReadRange, n as StorageContext, o as StorageUploadInput, r as StorageFile, t as Storage } from "../storage-DLUZ04kK.mjs";
6
5
  //#region src/presets/filesUpload.d.ts
7
6
  interface FilesUploadPresetRoutes {
8
7
  upload?: boolean;
@@ -1,6 +1,6 @@
1
1
  import { i as NotFoundError, u as ValidationError } from "../errors-DkO8Nk6-.mjs";
2
2
  import { c as getOrgId, g as getUserId } from "../types-bHblZ9YN.mjs";
3
- import { C as requireAuth, y as allowPublic } from "../permissions-BPB1xqGf.mjs";
3
+ import { b as allowPublic, w as requireAuth } from "../permissions-BJMuKMl7.mjs";
4
4
  import { t as multipartBody } from "../multipartBody-CHEQSZ6G.mjs";
5
5
  //#region src/presets/filesUpload.ts
6
6
  const DEFAULT_FIELD_NAME = "file";
@@ -1,8 +1,7 @@
1
- import { bt as IControllerResponse, d as PaginationResult, qt as AnyRecord, rt as PresetResult, st as ResourceConfig, xt as IRequestContext } from "../index-CUTG2Cuo.mjs";
1
+ import { bt as IControllerResponse, d as PaginationResult, qt as AnyRecord, rt as PresetResult, st as ResourceConfig, xt as IRequestContext } from "../index-Dtrj6XZk.mjs";
2
2
  import { FilesUploadPresetOptions, FilesUploadPresetPermissions, FilesUploadPresetRoutes, filesUploadPreset } from "./filesUpload.mjs";
3
3
  import { MultiTenantOptions, TenantFieldSpec, multiTenantPreset } from "./multiTenant.mjs";
4
4
  import { SearchHandler, SearchPresetOptions, SearchRouteConfig, searchPreset } from "./search.mjs";
5
-
6
5
  //#region src/presets/ownedByUser.d.ts
7
6
  interface OwnedByUserOptions {
8
7
  ownerField?: string;
@@ -237,7 +236,21 @@ type IAuditedPreset = never;
237
236
  * }
238
237
  * ```
239
238
  */
240
- type IPresetController<TDoc = unknown, TPresets extends "softDelete" | "slugLookup" | "tree" | never = never> = TPresets extends "softDelete" ? ISoftDeleteController<TDoc> : TPresets extends "slugLookup" ? ISlugLookupController<TDoc> : TPresets extends "tree" ? ITreeController<TDoc> : unknown;
239
+ /** Preset name → controller contract. Lookup table for {@link IPresetController}. */
240
+ interface PresetControllerContracts<TDoc> {
241
+ softDelete: ISoftDeleteController<TDoc>;
242
+ slugLookup: ISlugLookupController<TDoc>;
243
+ tree: ITreeController<TDoc>;
244
+ }
245
+ /**
246
+ * Collapse a union into an intersection. The pre-2.20 implementation used a
247
+ * distributive conditional, so `IPresetController<T, 'softDelete' | 'tree'>`
248
+ * produced a UNION of contracts — which a class cannot `implements`; the
249
+ * documented multi-preset example didn't compile. An indexed lookup over the
250
+ * union followed by this fold yields the intersection the example promises.
251
+ */
252
+ type UnionToIntersection<U> = (U extends unknown ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never;
253
+ type IPresetController<TDoc = unknown, TPresets extends keyof PresetControllerContracts<TDoc> = never> = UnionToIntersection<PresetControllerContracts<TDoc>[TPresets]>;
241
254
  //#endregion
242
255
  //#region src/presets/index.d.ts
243
256
  /**
@@ -1,5 +1,5 @@
1
1
  import { multiTenantPreset } from "./multiTenant.mjs";
2
- import { a as registerPreset, c as auditedPreset, d as ownedByUserPreset, i as getPreset, l as softDeletePreset, n as flexibleMultiTenantPreset, o as treePreset, r as getAvailablePresets, s as bulkPreset, t as applyPresets, u as slugLookupPreset } from "../presets-BtyFwTO4.mjs";
2
+ import { a as registerPreset, c as auditedPreset, d as ownedByUserPreset, i as getPreset, l as softDeletePreset, n as flexibleMultiTenantPreset, o as treePreset, r as getAvailablePresets, s as bulkPreset, t as applyPresets, u as slugLookupPreset } from "../presets-gw0ciIUD.mjs";
3
3
  import { filesUploadPreset } from "./filesUpload.mjs";
4
4
  import { searchPreset } from "./search.mjs";
5
5
  export { applyPresets, auditedPreset, bulkPreset, filesUploadPreset, flexibleMultiTenantPreset, getAvailablePresets, getPreset, multiTenantPreset, ownedByUserPreset, registerPreset, searchPreset, slugLookupPreset, softDeletePreset, treePreset };
@@ -1,5 +1,4 @@
1
- import { J as CrudRouteKey, rt as PresetResult } from "../index-CUTG2Cuo.mjs";
2
-
1
+ import { J as CrudRouteKey, rt as PresetResult } from "../index-Dtrj6XZk.mjs";
3
2
  //#region src/presets/multiTenant.d.ts
4
3
  /**
5
4
  * One tenant dimension for multi-field filtering. Discriminated by source:
@@ -1,4 +1,4 @@
1
- import "../constants-gaEeMlz-.mjs";
1
+ import "../constants-DNre0wRg.mjs";
2
2
  import { b as isElevated, c as getOrgId, d as getScopeContext, m as getTeamId, u as getRequestScope, v as hasOrgAccess } from "../types-bHblZ9YN.mjs";
3
3
  //#region src/presets/multiTenant.ts
4
4
  /**
@@ -1,6 +1,5 @@
1
- import { ft as RouteDefinition, gt as ControllerHandler, pt as RouteMcpConfig, rt as PresetResult } from "../index-CUTG2Cuo.mjs";
2
- import { c as PermissionCheck } from "../fields-C7ahdGYf.mjs";
3
-
1
+ import { ft as RouteDefinition, gt as ControllerHandler, pt as RouteMcpConfig, rt as PresetResult } from "../index-Dtrj6XZk.mjs";
2
+ import { c as PermissionCheck } from "../fields-BGqrAa_u.mjs";
4
3
  //#region src/presets/search.d.ts
5
4
  /**
6
5
  * Search Preset — backend-agnostic search / vector / embed routes
@@ -1,4 +1,4 @@
1
- import { C as requireAuth, y as allowPublic } from "../permissions-BPB1xqGf.mjs";
1
+ import { b as allowPublic, w as requireAuth } from "../permissions-BJMuKMl7.mjs";
2
2
  //#region src/presets/search.ts
3
3
  const BUILTINS = [
4
4
  {
@@ -84,7 +84,8 @@ function autoHandlerFor(repo, method) {
84
84
  return fn(body.input ?? body);
85
85
  };
86
86
  if (method === "searchSimilar") return async (req) => {
87
- return fn(req.body ?? {});
87
+ const body = req.body ?? {};
88
+ return fn(body);
88
89
  };
89
90
  return async (req) => {
90
91
  const body = req.body ?? {};
@@ -1,5 +1,5 @@
1
1
  import { b as isElevated, n as PUBLIC_SCOPE } from "./types-bHblZ9YN.mjs";
2
- import { C as requireAuth, T as requireRoles, y as allowPublic } from "./permissions-BPB1xqGf.mjs";
2
+ import { E as requireRoles, b as allowPublic, w as requireAuth } from "./permissions-BJMuKMl7.mjs";
3
3
  import { multiTenantPreset } from "./presets/multiTenant.mjs";
4
4
  //#region src/presets/ownedByUser.ts
5
5
  /**
@@ -244,8 +244,10 @@ interface PushRefStore {
244
244
  * pre-compute it without re-introducing the very race we're closing.
245
245
  */
246
246
  stageIfInactive(args: {
247
- pushRef: string; /** Raw payload (NOT pre-wrapped). The store assigns seq + wraps atomically. */
248
- payload: unknown; /** Server timestamp (ms) — passed in so tests can pin the clock. */
247
+ pushRef: string;
248
+ /** Raw payload (NOT pre-wrapped). The store assigns seq + wraps atomically. */
249
+ payload: unknown;
250
+ /** Server timestamp (ms) — passed in so tests can pin the clock. */
249
251
  timestamp: number;
250
252
  expiresAt: number;
251
253
  }): Promise<"ok" | "missing" | "active" | "raw">;
@@ -1,7 +1,6 @@
1
1
  import { r as CacheStore } from "./interface-C1_WLTMK.mjs";
2
- import { i as QueryCache } from "./QueryCache-TRfXau3W.mjs";
2
+ import { i as QueryCache } from "./QueryCache-Z1B38koh.mjs";
3
3
  import { FastifyPluginAsync } from "fastify";
4
-
5
4
  //#region src/cache/queryCachePlugin.d.ts
6
5
  interface QueryCachePluginOptions {
7
6
  /** CacheStore instance. Default: MemoryCacheStore with default options. */
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
2
- import { i as versionKey, r as tagVersionKey } from "./keys-Cd316u_y.mjs";
3
2
  import { t as MemoryCacheStore } from "./memory-CLXA2VeJ.mjs";
4
3
  import { t as hasEvents } from "./typeGuards-C9KXUly6.mjs";
4
+ import { i as versionKey, r as tagVersionKey } from "./keys-Cd316u_y.mjs";
5
5
  import fp from "fastify-plugin";
6
6
  //#region src/cache/QueryCache.ts
7
7
  var QueryCache = class {
@@ -72,7 +72,7 @@ var QueryCache = class {
72
72
  //#endregion
73
73
  //#region src/cache/queryCachePlugin.ts
74
74
  var queryCachePlugin_exports = /* @__PURE__ */ __exportAll({ queryCachePlugin: () => queryCachePlugin });
75
- const CRUD_SUFFIXES = new Set([
75
+ const CRUD_SUFFIXES = /* @__PURE__ */ new Set([
76
76
  "created",
77
77
  "updated",
78
78
  "deleted"
@@ -1,5 +1,4 @@
1
1
  import { n as IdempotencyResult, r as IdempotencyStore } from "./interface-Uk8ONJv7.mjs";
2
-
3
2
  //#region src/idempotency/stores/redis.d.ts
4
3
  interface RedisClient {
5
4
  get(key: string): Promise<string | null>;
@@ -1,5 +1,4 @@
1
- import { a as EventTransport, i as EventLogger, n as DomainEvent, r as EventHandler } from "./EventTransport-IEn7Tn-Q.mjs";
2
-
1
+ import { a as EventTransport, i as EventLogger, n as DomainEvent, r as EventHandler } from "./EventTransport-QmY7A258.mjs";
3
2
  //#region src/events/transports/redis-stream.d.ts
4
3
  interface RedisStreamLike {
5
4
  xadd(key: string, id: string, ...fieldValues: string[]): Promise<string | null>;
@@ -1,6 +1,6 @@
1
1
  import { f as createError } from "./errors-DkO8Nk6-.mjs";
2
- import { M as evaluateAndApplyPermission } from "./permissions-BPB1xqGf.mjs";
3
2
  import { n as requestContext } from "./requestContext-BZKOr13H.mjs";
3
+ import { N as evaluateAndApplyPermission } from "./permissions-BJMuKMl7.mjs";
4
4
  //#region src/core/middlewares/arcDecorator.ts
5
5
  /**
6
6
  * Build the `arcDecorator` preHandler for a resource.
@@ -1,7 +1,7 @@
1
- import { J as CrudRouteKey, R as RegisterOptions, V as ResourceDefinition, at as ResolvedTenantPurge, k as IntrospectionPluginOptions, p as RegistryEntry, z as ResourceRegistry } from "../index-CUTG2Cuo.mjs";
1
+ import { J as CrudRouteKey, R as RegisterOptions, V as ResourceDefinition, at as ResolvedTenantPurge, k as IntrospectionPluginOptions, p as RegistryEntry, z as ResourceRegistry } from "../index-Dtrj6XZk.mjs";
2
+ import "../fastify-augmentation-DafigGQp.mjs";
2
3
  import { FastifyPluginAsync } from "fastify";
3
4
  import { TenantPurgeProgress, TenantPurgeStrategy } from "@classytic/repo-core/repository";
4
-
5
5
  //#region src/registry/assertNoTenantData.d.ts
6
6
  interface AssertNoTenantDataOptions {
7
7
  readonly organizationId: string;
@@ -1,3 +1,3 @@
1
- import { a as cascadeDeleteForOrganization, c as assertNoTenantData, i as introspectionPlugin_default, n as buildResourceManifestFromRegistry, o as getCascadingResources, r as introspectionPlugin, s as getCascadingResourcesWithMetadata, t as buildResourceManifest } from "../registry-Bm9LjWKs.mjs";
2
- import { t as ResourceRegistry } from "../ResourceRegistry-5fKZwhK_.mjs";
1
+ import { a as cascadeDeleteForOrganization, c as assertNoTenantData, i as introspectionPlugin_default, n as buildResourceManifestFromRegistry, o as getCascadingResources, r as introspectionPlugin, s as getCascadingResourcesWithMetadata, t as buildResourceManifest } from "../registry-vcOCtPij.mjs";
2
+ import { t as ResourceRegistry } from "../ResourceRegistry-7RnrEWNP.mjs";
3
3
  export { ResourceRegistry, assertNoTenantData, buildResourceManifest, buildResourceManifestFromRegistry, cascadeDeleteForOrganization, getCascadingResources, getCascadingResourcesWithMetadata, introspectionPlugin_default as introspectionPlugin, introspectionPlugin as introspectionPluginFn };
@@ -1,4 +1,4 @@
1
- import { t as CRUD_OPERATIONS } from "./constants-gaEeMlz-.mjs";
1
+ import { t as CRUD_OPERATIONS } from "./constants-DNre0wRg.mjs";
2
2
  import fp from "fastify-plugin";
3
3
  //#region src/registry/assertNoTenantData.ts
4
4
  /**
@@ -1,5 +1,4 @@
1
1
  import { a as toJsonSchema } from "./schemaConverter-U0MnO9vd.mjs";
2
- import { z } from "zod";
3
2
  //#region src/core/schemaIR.ts
4
3
  /**
5
4
  * Schema IR — one canonical representation, two adapters.
@@ -98,27 +97,6 @@ function schemaIRToJsonSchemaBranch(ir, extras = {}) {
98
97
  };
99
98
  }
100
99
  /**
101
- * Emit a flat Zod shape from the IR. The MCP SDK wraps the returned record
102
- * in `z.object()` internally, so we return the bare shape (same contract
103
- * as `ToolDefinition.inputSchema`).
104
- *
105
- * `additionalProperties: false` is honored at the MCP handler layer rather
106
- * than baked into the Zod shape — the SDK's input validation happens before
107
- * the handler runs, and flat shapes can't express `.strict()` mode.
108
- * `strictAdditionalProperties(ir)` returns the flag so callers can gate
109
- * their handler on it.
110
- */
111
- function schemaIRToZodShape(ir) {
112
- const requiredSet = new Set(ir.required);
113
- const result = {};
114
- for (const [name, prop] of Object.entries(ir.properties)) {
115
- const desc = typeof prop.description === "string" && prop.description.length > 0 ? prop.description : name;
116
- const base = jsonSchemaPropToZod(prop);
117
- result[name] = requiredSet.has(name) ? base.describe(desc) : base.optional().describe(desc);
118
- }
119
- return result;
120
- }
121
- /**
122
100
  * Returns `true` when the IR declares `additionalProperties: false`. MCP
123
101
  * tool handlers should reject inputs with unknown keys when this is true,
124
102
  * matching HTTP's AJV-level strict enforcement.
@@ -126,24 +104,5 @@ function schemaIRToZodShape(ir) {
126
104
  function shouldRejectAdditionalProperties(ir) {
127
105
  return ir.additionalProperties === false;
128
106
  }
129
- /**
130
- * Convert a single JSON Schema property to a Zod type. Understands enum,
131
- * numeric/integer/boolean/array/object, and falls back to string for
132
- * unrecognized types (matches MCP's "strings for opaque fields" convention).
133
- *
134
- * Internal — use `schemaIRToZodShape` which wires this up with required/optional
135
- * + description handling.
136
- */
137
- function jsonSchemaPropToZod(schema) {
138
- if (Array.isArray(schema.enum) && schema.enum.length > 0) return z.enum(schema.enum);
139
- switch (typeof schema.type === "string" ? schema.type : "string") {
140
- case "number":
141
- case "integer": return z.number();
142
- case "boolean": return z.boolean();
143
- case "array": return z.array(z.unknown());
144
- case "object": return z.record(z.string(), z.unknown());
145
- default: return z.string();
146
- }
147
- }
148
107
  //#endregion
149
- export { shouldRejectAdditionalProperties as i, schemaIRToJsonSchemaBranch as n, schemaIRToZodShape as r, normalizeSchemaIR as t };
108
+ export { schemaIRToJsonSchemaBranch as n, shouldRejectAdditionalProperties as r, normalizeSchemaIR as t };
@@ -1,7 +1,6 @@
1
1
  import { ErrorContract, ErrorDetail } from "@classytic/repo-core/errors";
2
2
  import { FastifyPluginAsyncTypebox, FastifyPluginCallbackTypebox, TypeBoxTypeProvider, TypeBoxValidatorCompiler } from "@fastify/type-provider-typebox";
3
3
  import { Static, TObject, TSchema, TSchema as TSchema$1, Type } from "@sinclair/typebox";
4
-
5
4
  //#region src/schemas/index.d.ts
6
5
  /**
7
6
  * Paginated list response — full union of every wire shape `toCanonicalList`
@@ -1,6 +1,5 @@
1
1
  import { FastifyPluginAsync, FastifyRequest } from "fastify";
2
2
  import { RepositoryLike } from "@classytic/repo-core/adapter";
3
-
4
3
  //#region src/scim/mapping.d.ts
5
4
  /**
6
5
  * SCIM 2.0 ↔ arc resource mapping
@@ -381,7 +381,7 @@ function resourceToScim(resource, mapping, baseUrl) {
381
381
  * parseScimFilter('active eq true and name.familyName sw "S"')
382
382
  * → { $and: [{ active: true }, { 'name.familyName': { $regex: '^S' } }] }
383
383
  */
384
- const COMPARISON_OPS = new Set([
384
+ const COMPARISON_OPS = /* @__PURE__ */ new Set([
385
385
  "eq",
386
386
  "ne",
387
387
  "co",
@@ -393,7 +393,7 @@ const COMPARISON_OPS = new Set([
393
393
  "le",
394
394
  "pr"
395
395
  ]);
396
- const LOGICAL_OPS = new Set([
396
+ const LOGICAL_OPS = /* @__PURE__ */ new Set([
397
397
  "and",
398
398
  "or",
399
399
  "not"
@@ -1,7 +1,6 @@
1
- import { C as isMember, D as requireOrgId, E as requireClientId, O as requireTeamId, S as isElevated, T as isService, _ as getTenantFromRequest, a as getAncestorOrgIds, b as hasOrgAccess, c as getMandate, d as getOrgRoles, f as getRequestScope, g as getTeamId, h as getServiceScopes, i as RequestScope, k as requireUserId, l as getOrgContext, m as getScopeContextMap, n as Mandate, o as getClientId, p as getScopeContext, r as PUBLIC_SCOPE, s as getDPoPJkt, t as AUTHENTICATED_SCOPE, u as getOrgId, v as getUserId, w as isOrgInScope, x as isAuthenticated, y as getUserRoles } from "../types-LNebCoJx.mjs";
2
- import { i as elevationPlugin, n as ElevationOptions, r as _default, t as ElevationEvent } from "../elevation-xGUBq6p_.mjs";
1
+ import { C as isMember, D as requireOrgId, E as requireClientId, O as requireTeamId, S as isElevated, T as isService, _ as getTenantFromRequest, a as getAncestorOrgIds, b as hasOrgAccess, c as getMandate, d as getOrgRoles, f as getRequestScope, g as getTeamId, h as getServiceScopes, i as RequestScope, k as requireUserId, l as getOrgContext, m as getScopeContextMap, n as Mandate, o as getClientId, p as getScopeContext, r as PUBLIC_SCOPE, s as getDPoPJkt, t as AUTHENTICATED_SCOPE, u as getOrgId, v as getUserId, w as isOrgInScope, x as isAuthenticated, y as getUserRoles } from "../types-DH0GupI7.mjs";
2
+ import { i as elevationPlugin, n as ElevationOptions, r as _default, t as ElevationEvent } from "../elevation-C9s5hFP_.mjs";
3
3
  import { FastifyReply, FastifyRequest } from "fastify";
4
-
5
4
  //#region src/scope/rateLimitKey.d.ts
6
5
  interface RateLimitKeyContext {
7
6
  ip: string;