@classytic/arc 2.9.1 → 2.10.3

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 +19 -90
  2. package/dist/{BaseController-Vu2yc56T.mjs → BaseController-CbKKIflT.mjs} +8 -44
  3. package/dist/{ResourceRegistry-Dq3_zBQP.mjs → ResourceRegistry-BPd6NQDm.mjs} +1 -1
  4. package/dist/adapters/index.d.mts +3 -3
  5. package/dist/adapters/index.mjs +2 -2
  6. package/dist/{adapters-BBqAVvPK.mjs → adapters-BXY4i-hw.mjs} +210 -41
  7. package/dist/audit/index.d.mts +38 -3
  8. package/dist/audit/index.mjs +41 -7
  9. package/dist/auth/index.d.mts +4 -4
  10. package/dist/auth/index.mjs +5 -5
  11. package/dist/auth/redis-session.d.mts +1 -1
  12. package/dist/cache/index.d.mts +17 -15
  13. package/dist/cache/index.mjs +15 -14
  14. package/dist/{caching-CjybdRwx.mjs → caching-CBpK_SCM.mjs} +8 -3
  15. package/dist/cli/commands/describe.mjs +1 -1
  16. package/dist/cli/commands/docs.mjs +2 -2
  17. package/dist/cli/commands/generate.mjs +1 -1
  18. package/dist/cli/commands/init.mjs +1 -1
  19. package/dist/cli/commands/introspect.mjs +1 -1
  20. package/dist/core/index.d.mts +2 -2
  21. package/dist/core/index.mjs +3 -4
  22. package/dist/{defineResource-C__jkwvs.mjs → core-CcR01lup.mjs} +44 -12
  23. package/dist/{createActionRouter-DH1YFL9m.mjs → createActionRouter-Bp_5c_2b.mjs} +1 -1
  24. package/dist/{createApp-CBJUJKGP.mjs → createApp-BuvPma24.mjs} +14 -14
  25. package/dist/docs/index.d.mts +2 -2
  26. package/dist/docs/index.mjs +2 -2
  27. package/dist/{elevation-DxQ6ACbt.mjs → elevation-C7hgL_aI.mjs} +2 -2
  28. package/dist/{errorHandler-CZDW4EXS.mjs → errorHandler-Bb49BvPD.mjs} +1 -1
  29. package/dist/{errorHandler-DixGcttC.d.mts → errorHandler-DRQ3EqfL.d.mts} +1 -1
  30. package/dist/{eventPlugin-BxvaCIZF.d.mts → eventPlugin-CxWgpd6K.d.mts} +1 -1
  31. package/dist/{eventPlugin-Dl7MoVWH.mjs → eventPlugin-DCUjuiQT.mjs} +1 -1
  32. package/dist/events/index.d.mts +8 -5
  33. package/dist/events/index.mjs +34 -17
  34. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  35. package/dist/events/transports/redis.d.mts +1 -1
  36. package/dist/factory/index.d.mts +1 -1
  37. package/dist/factory/index.mjs +2 -2
  38. package/dist/{types-DZi1aYhm.d.mts → fields-Lo1VUDpt.d.mts} +121 -1
  39. package/dist/{filesUpload-q8oHt--L.mjs → filesUpload-t21LS-py.mjs} +2 -2
  40. package/dist/hooks/index.d.mts +1 -1
  41. package/dist/hooks/index.mjs +1 -1
  42. package/dist/idempotency/index.d.mts +7 -4
  43. package/dist/idempotency/index.mjs +9 -11
  44. package/dist/idempotency/redis.d.mts +1 -1
  45. package/dist/{index-Cibkchnx.d.mts → index-8qw4y6ff.d.mts} +2 -2
  46. package/dist/{index-C-xjcA6F.d.mts → index-ChIw3776.d.mts} +283 -408
  47. package/dist/{interface-YrWsmKqE.d.mts → index-Cl0uoKd5.d.mts} +1885 -2741
  48. package/dist/{index-CtGKT0lf.d.mts → index-DStwgFUK.d.mts} +81 -7
  49. package/dist/index.d.mts +7 -8
  50. package/dist/index.mjs +11 -12
  51. package/dist/integrations/event-gateway.d.mts +1 -1
  52. package/dist/integrations/event-gateway.mjs +1 -1
  53. package/dist/integrations/index.d.mts +1 -1
  54. package/dist/integrations/mcp/index.d.mts +2 -2
  55. package/dist/integrations/mcp/index.mjs +1 -1
  56. package/dist/integrations/mcp/testing.d.mts +1 -1
  57. package/dist/integrations/mcp/testing.mjs +1 -1
  58. package/dist/interface-D218ikEo.d.mts +77 -0
  59. package/dist/{memory-BFAYkf8H.mjs → memory-B5Amv9A1.mjs} +23 -8
  60. package/dist/{openapi-CXuTG1M9.mjs → openapi-B5F8AddX.mjs} +2 -2
  61. package/dist/org/index.d.mts +2 -2
  62. package/dist/permissions/index.d.mts +3 -4
  63. package/dist/permissions/index.mjs +5 -5
  64. package/dist/{permissions-oNZawnkR.mjs → permissions-Dk6mshja.mjs} +315 -397
  65. package/dist/plugins/index.d.mts +4 -4
  66. package/dist/plugins/index.mjs +12 -14
  67. package/dist/plugins/response-cache.mjs +1 -1
  68. package/dist/plugins/tracing-entry.d.mts +1 -1
  69. package/dist/plugins/tracing-entry.mjs +1 -1
  70. package/dist/presets/filesUpload.d.mts +3 -3
  71. package/dist/presets/filesUpload.mjs +1 -1
  72. package/dist/presets/index.d.mts +1 -1
  73. package/dist/presets/index.mjs +2 -2
  74. package/dist/presets/multiTenant.d.mts +1 -1
  75. package/dist/presets/multiTenant.mjs +1 -1
  76. package/dist/presets/search.d.mts +91 -4
  77. package/dist/presets/search.mjs +1 -1
  78. package/dist/{presets-hM4WhNWY.mjs → presets-fLJVXdVn.mjs} +1 -1
  79. package/dist/{queryCachePlugin-CnTZZTC5.d.mts → queryCachePlugin-BKbWjgDG.d.mts} +1 -1
  80. package/dist/{queryCachePlugin-DbUVroUG.mjs → queryCachePlugin-DQCEfJis.mjs} +8 -8
  81. package/dist/{queryParser-Cs-6SHQK.mjs → queryParser-DBqBB6AC.mjs} +1 -1
  82. package/dist/{redis-MXLp1oOf.d.mts → redis-DqyeggCa.d.mts} +1 -1
  83. package/dist/{redis-stream-Bz-4q96t.d.mts → redis-stream-CakIQmwR.d.mts} +1 -1
  84. package/dist/registry/index.d.mts +1 -1
  85. package/dist/registry/index.mjs +2 -2
  86. package/dist/{resourceToTools-C3cWymnW.mjs → resourceToTools-BElv3xPT.mjs} +3 -3
  87. package/dist/scope/index.d.mts +1 -1
  88. package/dist/scope/index.mjs +2 -2
  89. package/dist/{sse-CJpt7LGI.mjs → sse-yBCgOLGu.mjs} +1 -1
  90. package/dist/testing/index.d.mts +6 -5
  91. package/dist/testing/index.mjs +8 -10
  92. package/dist/testing/storageContract.d.mts +1 -1
  93. package/dist/types/index.d.mts +4 -4
  94. package/dist/types/index.mjs +1 -31
  95. package/dist/types/storage.d.mts +1 -1
  96. package/dist/{types-CoSzA-s-.d.mts → types-Btdda02s.d.mts} +1 -1
  97. package/dist/{types-CunEX4UX.d.mts → types-Co8k3NyS.d.mts} +9 -9
  98. package/dist/types-Csi3FLfq.mjs +27 -0
  99. package/dist/utils/index.d.mts +207 -3
  100. package/dist/utils/index.mjs +3 -4
  101. package/dist/{utils-B7FuRr9w.mjs → utils-B2fNOD_i.mjs} +285 -2
  102. package/dist/{versioning-Cm8qoFDg.mjs → versioning-C2U_bLY0.mjs} +3 -5
  103. package/package.json +15 -18
  104. package/skills/arc/SKILL.md +7 -11
  105. package/skills/arc/references/production.md +0 -41
  106. package/dist/circuitBreaker-CvXkjfrW.d.mts +0 -206
  107. package/dist/circuitBreaker-l18oRgL5.mjs +0 -284
  108. package/dist/core-DNncu0xF.mjs +0 -34
  109. package/dist/dynamic/index.d.mts +0 -93
  110. package/dist/dynamic/index.mjs +0 -122
  111. package/dist/fields-BC7zcmI9.d.mts +0 -121
  112. package/dist/interface-DplgQO2e.d.mts +0 -54
  113. package/dist/policies/index.d.mts +0 -425
  114. package/dist/policies/index.mjs +0 -318
  115. package/dist/rpc/index.d.mts +0 -90
  116. package/dist/rpc/index.mjs +0 -248
  117. /package/dist/{EventTransport-CqZ8FyM_.d.mts → EventTransport-CUw5NNWe.d.mts} +0 -0
  118. /package/dist/{HookSystem-BjFu7zf1.mjs → HookSystem-BNYKnrXF.mjs} +0 -0
  119. /package/dist/{applyPermissionResult-bqGpo9ML.mjs → applyPermissionResult-QhV1Pa-g.mjs} +0 -0
  120. /package/dist/{betterAuthOpenApi--rdY15Ld.mjs → betterAuthOpenApi-BBRVhjQN.mjs} +0 -0
  121. /package/dist/{constants-Cxde4rpC.mjs → constants-BhY1OHoH.mjs} +0 -0
  122. /package/dist/{elevation-B6S5csVA.d.mts → elevation-C5SwtkAn.d.mts} +0 -0
  123. /package/dist/{errors-BI8kEKsO.d.mts → errors-CCSsMpXE.d.mts} +0 -0
  124. /package/dist/{errors-CqWnSqM-.mjs → errors-D5c-5BJL.mjs} +0 -0
  125. /package/dist/{externalPaths-Bapitwvd.d.mts → externalPaths-BQ8QijNH.d.mts} +0 -0
  126. /package/dist/{fields-CU6FlaDV.mjs → fields-bxkeltzz.mjs} +0 -0
  127. /package/dist/{interface-B-pe8fhj.d.mts → interface-CSbZdv_3.d.mts} +0 -0
  128. /package/dist/{loadResources-Bksk8ydA.mjs → loadResources-BAzJItAJ.mjs} +0 -0
  129. /package/dist/{logger-CDjpjySd.mjs → logger-DLg8-Ueg.mjs} +0 -0
  130. /package/dist/{metrics-TuOmguhi.mjs → metrics-DuhiSEZI.mjs} +0 -0
  131. /package/dist/{pluralize-CWP6MB39.mjs → pluralize-A0tWEl1K.mjs} +0 -0
  132. /package/dist/{registry-B0Wl7uVV.mjs → registry-B3lRFBWo.mjs} +0 -0
  133. /package/dist/{replyHelpers-BLojtuvR.mjs → replyHelpers-CXtJDAZ0.mjs} +0 -0
  134. /package/dist/{requestContext-DYtmNpm5.mjs → requestContext-xHIKedG6.mjs} +0 -0
  135. /package/dist/{sessionManager-D-oNWHz3.d.mts → sessionManager-BkzVU8h2.d.mts} +0 -0
  136. /package/dist/{storage-BwGQXUpd.d.mts → storage-CVk_SEn2.d.mts} +0 -0
  137. /package/dist/{store-helpers-DFiZl5TL.mjs → store-helpers-ZCSMJJAX.mjs} +0 -0
  138. /package/dist/{tracing-xqXzWeaf.d.mts → tracing-65B51Dw3.d.mts} +0 -0
  139. /package/dist/{types-ZUu_h0jp.mjs → types-DV9WDfeg.mjs} +0 -0
@@ -23,8 +23,12 @@ function repositoryAsAuditStore(repository) {
23
23
  };
24
24
  await repository.create(doc);
25
25
  },
26
+ async purgeOlderThan(cutoff) {
27
+ if (!repository.deleteMany) return 0;
28
+ return (await repository.deleteMany({ timestamp: { $lt: cutoff } })).deletedCount ?? 0;
29
+ },
26
30
  async query(opts = {}) {
27
- if (!repository.findAll) throw new Error("auditPlugin: repository.findAll is required for query(). mongokit ≥3.6 implements it; other kits should match.");
31
+ if (!repository.getAll) throw new Error("auditPlugin: repository.getAll is required for query(). It's on repo-core's MinimalRepo floor every kit (mongokit, sqlitekit, custom) implements it.");
28
32
  const filter = {};
29
33
  if (opts.resource) filter.resource = opts.resource;
30
34
  if (opts.documentId) filter.documentId = opts.documentId;
@@ -40,11 +44,15 @@ function repositoryAsAuditStore(repository) {
40
44
  if (opts.to) range.$lte = opts.to;
41
45
  filter.timestamp = range;
42
46
  }
43
- return (await repository.findAll(filter, {
47
+ const limit = opts.limit ?? 100;
48
+ const page = Math.floor((opts.offset ?? 0) / limit) + 1;
49
+ const result = await repository.getAll({
50
+ filters: filter,
44
51
  sort: { timestamp: -1 },
45
- skip: opts.offset ?? 0,
46
- limit: opts.limit ?? 100
47
- })).map((d) => ({
52
+ page,
53
+ limit
54
+ });
55
+ return (Array.isArray(result) ? result : result.docs ?? []).map((d) => ({
48
56
  id: String(d._id ?? d.id ?? ""),
49
57
  resource: d.resource ?? "",
50
58
  documentId: d.documentId ?? "",
@@ -145,6 +153,11 @@ var MemoryAuditStore = class {
145
153
  results = results.slice(offset, offset + limit);
146
154
  return results;
147
155
  }
156
+ async purgeOlderThan(cutoff) {
157
+ const before = this.entries.length;
158
+ this.entries = this.entries.filter((e) => e.timestamp >= cutoff);
159
+ return before - this.entries.length;
160
+ }
148
161
  async close() {
149
162
  this.entries = [];
150
163
  }
@@ -199,6 +212,11 @@ const auditPlugin = async (fastify, opts = {}) => {
199
212
  async query(options) {
200
213
  for (const store of stores) if (store.query) return store.query(options);
201
214
  return [];
215
+ },
216
+ async purge(cutoff) {
217
+ let total = 0;
218
+ for (const store of stores) if (store.purgeOlderThan) total += await store.purgeOlderThan(cutoff);
219
+ return total;
202
220
  }
203
221
  };
204
222
  fastify.decorate("audit", audit);
@@ -223,7 +241,22 @@ const auditPlugin = async (fastify, opts = {}) => {
223
241
  request.auditContext.duration = Math.round(reply.elapsedTime);
224
242
  }
225
243
  });
244
+ const retention = opts.retention;
245
+ let retentionTimer = null;
246
+ if (retention) {
247
+ const interval = retention.purgeIntervalMs ?? 864e5;
248
+ if (interval > 0) {
249
+ retentionTimer = setInterval(() => {
250
+ const cutoff = new Date(Date.now() - retention.maxAgeMs);
251
+ audit.purge(cutoff).catch((err) => {
252
+ fastify.log?.warn?.({ err }, "audit retention purge failed");
253
+ });
254
+ }, interval);
255
+ retentionTimer.unref?.();
256
+ }
257
+ }
226
258
  fastify.addHook("onClose", async () => {
259
+ if (retentionTimer) clearInterval(retentionTimer);
227
260
  await Promise.all(stores.map((store) => store.close?.()));
228
261
  });
229
262
  const autoAuditConfig = opts.autoAudit ?? true;
@@ -317,7 +350,8 @@ function createNoopLogger() {
317
350
  delete: noop,
318
351
  restore: noop,
319
352
  custom: noop,
320
- query: async () => []
353
+ query: async () => [],
354
+ purge: async () => 0
321
355
  };
322
356
  }
323
357
  var auditPlugin_default = fp(auditPlugin, {
@@ -326,4 +360,4 @@ var auditPlugin_default = fp(auditPlugin, {
326
360
  dependencies: ["arc-core"]
327
361
  });
328
362
  //#endregion
329
- export { MemoryAuditStore, auditPlugin_default as auditPlugin, auditPlugin as auditPluginFn, createAuditEntry };
363
+ export { MemoryAuditStore, auditPlugin_default as auditPlugin, auditPlugin as auditPluginFn, createAuditEntry, repositoryAsAuditStore };
@@ -1,7 +1,7 @@
1
- import { v as AuthHelpers, y as AuthPluginOptions } from "../interface-YrWsmKqE.mjs";
2
- import { t as PermissionCheck } from "../types-DZi1aYhm.mjs";
3
- import { t as ExternalOpenApiPaths } from "../externalPaths-Bapitwvd.mjs";
4
- import { a as SessionManagerOptions, c as createSessionManager, i as SessionData, n as MemorySessionStoreOptions, o as SessionManagerResult, r as SessionCookieOptions, s as SessionStore, t as MemorySessionStore } from "../sessionManager-D-oNWHz3.mjs";
1
+ import { c as PermissionCheck } from "../fields-Lo1VUDpt.mjs";
2
+ import { A as AuthHelpers, j as AuthPluginOptions } from "../index-Cl0uoKd5.mjs";
3
+ import { t as ExternalOpenApiPaths } from "../externalPaths-BQ8QijNH.mjs";
4
+ import { a as SessionManagerOptions, c as createSessionManager, i as SessionData, n as MemorySessionStoreOptions, o as SessionManagerResult, r as SessionCookieOptions, s as SessionStore, t as MemorySessionStore } from "../sessionManager-BkzVU8h2.mjs";
5
5
  import { FastifyPluginAsync, FastifyReply as FastifyReply$1, FastifyRequest } from "fastify";
6
6
 
7
7
  //#region src/auth/authPlugin.d.ts
@@ -1,7 +1,7 @@
1
- import { n as normalizeRoles, t as getUserRoles } from "../types-ZUu_h0jp.mjs";
2
- import { t as ArcError } from "../errors-CqWnSqM-.mjs";
3
- import { h as requireTeamMembership, l as requireOrgMembership, u as requireOrgRole } from "../permissions-oNZawnkR.mjs";
4
- import { n as extractBetterAuthOpenApi } from "../betterAuthOpenApi--rdY15Ld.mjs";
1
+ import { n as normalizeRoles, t as getUserRoles } from "../types-DV9WDfeg.mjs";
2
+ import { t as ArcError } from "../errors-D5c-5BJL.mjs";
3
+ import { _ as requireTeamMembership, m as requireOrgRole, p as requireOrgMembership } from "../permissions-Dk6mshja.mjs";
4
+ import { n as extractBetterAuthOpenApi } from "../betterAuthOpenApi-BBRVhjQN.mjs";
5
5
  import { createHmac, randomUUID, timingSafeEqual } from "node:crypto";
6
6
  import fp from "fastify-plugin";
7
7
  //#region src/auth/authPlugin.ts
@@ -684,7 +684,7 @@ function createBetterAuthAdapter(options) {
684
684
  if (!fastify.hasDecorator("authenticate")) fastify.decorate("authenticate", authenticate);
685
685
  if (!fastify.hasDecorator("optionalAuthenticate")) fastify.decorate("optionalAuthenticate", optionalAuthenticate);
686
686
  if (!extractedOpenApi && openapiOpt !== false && auth.api && typeof auth.api === "object") {
687
- const { extractBetterAuthOpenApi } = await import("../betterAuthOpenApi--rdY15Ld.mjs").then((n) => n.t);
687
+ const { extractBetterAuthOpenApi } = await import("../betterAuthOpenApi-BBRVhjQN.mjs").then((n) => n.t);
688
688
  extractedOpenApi = extractBetterAuthOpenApi(auth.api, {
689
689
  basePath,
690
690
  userFields
@@ -1,4 +1,4 @@
1
- import { i as SessionData, s as SessionStore } from "../sessionManager-D-oNWHz3.mjs";
1
+ import { i as SessionData, s as SessionStore } from "../sessionManager-BkzVU8h2.mjs";
2
2
 
3
3
  //#region src/auth/redis-session.d.ts
4
4
  /** Minimal Redis client interface — compatible with ioredis */
@@ -1,5 +1,5 @@
1
- import { i as CacheStore, n as CacheSetOptions, r as CacheStats, t as CacheLogger } from "../interface-DplgQO2e.mjs";
2
- import { a as CacheEnvelope, c as QueryCache, i as queryCachePlugin, l as QueryCacheConfig, n as QueryCacheDefaults, o as CacheResult, r as QueryCachePluginOptions, s as CacheStatus, t as CrossResourceRule } from "../queryCachePlugin-CnTZZTC5.mjs";
1
+ import { n as CacheStats, r as CacheStore, t as CacheLogger } from "../interface-D218ikEo.mjs";
2
+ import { a as CacheEnvelope, c as QueryCache, i as queryCachePlugin, l as QueryCacheConfig, n as QueryCacheDefaults, o as CacheResult, r as QueryCachePluginOptions, s as CacheStatus, t as CrossResourceRule } from "../queryCachePlugin-BKbWjgDG.mjs";
3
3
 
4
4
  //#region src/cache/keys.d.ts
5
5
  /**
@@ -24,8 +24,8 @@ declare function hashParams(params: Record<string, unknown>): string;
24
24
  //#endregion
25
25
  //#region src/cache/memory.d.ts
26
26
  interface MemoryCacheStoreOptions {
27
- /** Default TTL in milliseconds (default: 60_000) */
28
- defaultTtlMs?: number;
27
+ /** Default TTL in seconds (default: 60) */
28
+ defaultTtlSeconds?: number;
29
29
  /** Hard upper bound for entries (default: 1000) */
30
30
  maxEntries?: number;
31
31
  /** Background cleanup interval in milliseconds (default: 30_000) */
@@ -59,7 +59,7 @@ interface MemoryCacheStoreOptions {
59
59
  declare class MemoryCacheStore<TValue = unknown> implements CacheStore<TValue> {
60
60
  readonly name = "memory-cache";
61
61
  private readonly cache;
62
- private readonly defaultTtlMs;
62
+ private readonly defaultTtlSeconds;
63
63
  private readonly maxEntries;
64
64
  private readonly maxEntryBytes;
65
65
  private readonly maxMemoryBytes;
@@ -72,9 +72,9 @@ declare class MemoryCacheStore<TValue = unknown> implements CacheStore<TValue> {
72
72
  private _evictions;
73
73
  constructor(options?: MemoryCacheStoreOptions);
74
74
  get(key: string): Promise<TValue | undefined>;
75
- set(key: string, value: TValue, options?: CacheSetOptions): Promise<void>;
75
+ set(key: string, value: TValue, ttlSeconds?: number): Promise<void>;
76
76
  delete(key: string): Promise<void>;
77
- clear(): Promise<void>;
77
+ clear(pattern?: string): Promise<void>;
78
78
  close(): Promise<void>;
79
79
  stats(): CacheStats;
80
80
  private removeEntry;
@@ -112,8 +112,8 @@ interface RedisCacheStoreOptions {
112
112
  client: RedisCacheClient;
113
113
  /** Key prefix for namespacing (default: 'arc:cache:') */
114
114
  prefix?: string;
115
- /** Default TTL in milliseconds (default: 60_000) */
116
- defaultTtlMs?: number;
115
+ /** Default TTL in seconds (default: 60) */
116
+ defaultTtlSeconds?: number;
117
117
  /** Maximum serialized entry size in bytes. Oversized entries are skipped. */
118
118
  maxEntryBytes?: number;
119
119
  }
@@ -126,17 +126,19 @@ declare class RedisCacheStore<TValue = unknown> implements CacheStore<TValue> {
126
126
  readonly name = "redis-cache";
127
127
  private readonly client;
128
128
  private readonly prefix;
129
- private readonly defaultTtlMs;
129
+ private readonly defaultTtlSeconds;
130
130
  private readonly maxEntryBytes;
131
131
  private _hits;
132
132
  private _misses;
133
133
  constructor(options: RedisCacheStoreOptions);
134
134
  get(key: string): Promise<TValue | undefined>;
135
- set(key: string, value: TValue, options?: CacheSetOptions): Promise<void>;
135
+ set(key: string, value: TValue, ttlSeconds?: number): Promise<void>;
136
136
  delete(key: string): Promise<void>;
137
- clear(): Promise<void>;
138
- /** Delete all keys matching `this.prefix + prefix + *`. Returns count deleted. */
139
- deleteByPrefix(prefix: string): Promise<number>;
137
+ /**
138
+ * Invalidate keys. Pass a glob pattern to delete a subset (`user:*:v2`);
139
+ * omit to clear every key under this store's prefix.
140
+ */
141
+ clear(pattern?: string): Promise<void>;
140
142
  stats(): CacheStats;
141
143
  private scanAndDelete;
142
144
  private withPrefix;
@@ -212,4 +214,4 @@ interface UpstashRedisLike {
212
214
  */
213
215
  declare function upstashAsCacheClient(client: UpstashRedisLike): RedisCacheClient;
214
216
  //#endregion
215
- export { type CacheEnvelope, type CacheLogger, type CacheResult, type CacheSetOptions, type CacheStats, type CacheStatus, type CacheStore, type CrossResourceRule, type IoredisLike, MemoryCacheStore, type MemoryCacheStoreOptions, QueryCache, type QueryCacheConfig, type QueryCacheDefaults, type QueryCachePluginOptions, type RedisCacheClient, RedisCacheStore, type RedisCacheStoreOptions, type RedisPipeline, type UpstashRedisLike, buildQueryKey, hashParams, ioredisAsCacheClient, queryCachePlugin, tagVersionKey, upstashAsCacheClient, versionKey };
217
+ export { type CacheEnvelope, type CacheLogger, type CacheResult, type CacheStats, type CacheStatus, type CacheStore, type CrossResourceRule, type IoredisLike, MemoryCacheStore, type MemoryCacheStoreOptions, QueryCache, type QueryCacheConfig, type QueryCacheDefaults, type QueryCachePluginOptions, type RedisCacheClient, RedisCacheStore, type RedisCacheStoreOptions, type RedisPipeline, type UpstashRedisLike, buildQueryKey, hashParams, ioredisAsCacheClient, queryCachePlugin, tagVersionKey, upstashAsCacheClient, versionKey };
@@ -1,6 +1,6 @@
1
1
  import { i as versionKey, n as hashParams, r as tagVersionKey, t as buildQueryKey } from "../keys-qcD-TVJl.mjs";
2
- import { t as MemoryCacheStore } from "../memory-BFAYkf8H.mjs";
3
- import { r as QueryCache, t as queryCachePlugin } from "../queryCachePlugin-DbUVroUG.mjs";
2
+ import { t as MemoryCacheStore } from "../memory-B5Amv9A1.mjs";
3
+ import { r as QueryCache, t as queryCachePlugin } from "../queryCachePlugin-DQCEfJis.mjs";
4
4
  //#region src/cache/redis.ts
5
5
  /**
6
6
  * Redis-backed cache store.
@@ -11,14 +11,14 @@ var RedisCacheStore = class {
11
11
  name = "redis-cache";
12
12
  client;
13
13
  prefix;
14
- defaultTtlMs;
14
+ defaultTtlSeconds;
15
15
  maxEntryBytes;
16
16
  _hits = 0;
17
17
  _misses = 0;
18
18
  constructor(options) {
19
19
  this.client = options.client;
20
20
  this.prefix = options.prefix ?? "arc:cache:";
21
- this.defaultTtlMs = options.defaultTtlMs ?? 6e4;
21
+ this.defaultTtlSeconds = options.defaultTtlSeconds ?? 60;
22
22
  this.maxEntryBytes = options.maxEntryBytes ?? 0;
23
23
  }
24
24
  async get(key) {
@@ -36,22 +36,23 @@ var RedisCacheStore = class {
36
36
  return;
37
37
  }
38
38
  }
39
- async set(key, value, options = {}) {
40
- const ttlMs = options.ttlMs ?? this.defaultTtlMs;
41
- if (!Number.isFinite(ttlMs) || ttlMs <= 0) return;
39
+ async set(key, value, ttlSeconds) {
40
+ const effectiveTtlSeconds = ttlSeconds ?? this.defaultTtlSeconds;
41
+ if (!Number.isFinite(effectiveTtlSeconds) || effectiveTtlSeconds <= 0) return;
42
42
  const payload = JSON.stringify(value);
43
43
  if (this.maxEntryBytes > 0 && Buffer.byteLength(payload, "utf8") > this.maxEntryBytes) return;
44
- await this.client.set(this.withPrefix(key), payload, { PX: Math.ceil(ttlMs) });
44
+ await this.client.set(this.withPrefix(key), payload, { EX: Math.ceil(effectiveTtlSeconds) });
45
45
  }
46
46
  async delete(key) {
47
47
  await this.client.del(this.withPrefix(key));
48
48
  }
49
- async clear() {
50
- await this.scanAndDelete(`${this.prefix}*`);
51
- }
52
- /** Delete all keys matching `this.prefix + prefix + *`. Returns count deleted. */
53
- async deleteByPrefix(prefix) {
54
- return this.scanAndDelete(`${this.prefix}${prefix}*`);
49
+ /**
50
+ * Invalidate keys. Pass a glob pattern to delete a subset (`user:*:v2`);
51
+ * omit to clear every key under this store's prefix.
52
+ */
53
+ async clear(pattern) {
54
+ const scanPattern = pattern ? `${this.prefix}${pattern.includes("*") ? pattern : `${pattern}*`}` : `${this.prefix}*`;
55
+ await this.scanAndDelete(scanPattern);
55
56
  }
56
57
  stats() {
57
58
  return {
@@ -34,7 +34,7 @@ const cachingPlugin = async (fastify, opts = {}) => {
34
34
  if (rule?.staleWhileRevalidate) parts.push(`stale-while-revalidate=${rule.staleWhileRevalidate}`);
35
35
  return parts.join(", ");
36
36
  }
37
- fastify.addHook("onSend", async (request, reply, payload) => {
37
+ fastify.addHook("preSerialization", async (request, reply, payload) => {
38
38
  const url = request.url;
39
39
  if (exclude.some((p) => url.startsWith(p))) return payload;
40
40
  const method = request.method.toUpperCase();
@@ -48,13 +48,18 @@ const cachingPlugin = async (fastify, opts = {}) => {
48
48
  const rule = findRule(url);
49
49
  reply.header("cache-control", buildCacheControl(rule));
50
50
  }
51
- if (etag && payload) {
52
- const tag = `"${fnv1a(typeof payload === "string" ? payload : String(payload))}"`;
51
+ if (etag && payload != null) {
52
+ let body;
53
+ if (typeof payload === "string") body = payload;
54
+ else if (Buffer.isBuffer(payload)) body = payload.toString("utf-8");
55
+ else body = JSON.stringify(payload);
56
+ const tag = `"${fnv1a(body)}"`;
53
57
  reply.header("etag", tag);
54
58
  if (conditional) {
55
59
  const ifNoneMatch = request.headers["if-none-match"];
56
60
  if (ifNoneMatch && ifNoneMatch === tag) {
57
61
  reply.code(304);
62
+ reply.serializer((p) => typeof p === "string" ? p : "");
58
63
  return "";
59
64
  }
60
65
  }
@@ -1,4 +1,4 @@
1
- import { t as CRUD_OPERATIONS } from "../../constants-Cxde4rpC.mjs";
1
+ import { t as CRUD_OPERATIONS } from "../../constants-BhY1OHoH.mjs";
2
2
  import { resolve } from "node:path";
3
3
  import { pathToFileURL } from "node:url";
4
4
  //#region src/cli/commands/describe.ts
@@ -1,5 +1,5 @@
1
- import { t as ResourceRegistry } from "../../ResourceRegistry-Dq3_zBQP.mjs";
2
- import { t as buildOpenApiSpec } from "../../openapi-CXuTG1M9.mjs";
1
+ import { t as ResourceRegistry } from "../../ResourceRegistry-BPd6NQDm.mjs";
2
+ import { t as buildOpenApiSpec } from "../../openapi-B5F8AddX.mjs";
3
3
  import { dirname, resolve } from "node:path";
4
4
  import { pathToFileURL } from "node:url";
5
5
  import { mkdirSync, writeFileSync } from "node:fs";
@@ -1,4 +1,4 @@
1
- import { t as pluralize } from "../../pluralize-CWP6MB39.mjs";
1
+ import { t as pluralize } from "../../pluralize-A0tWEl1K.mjs";
2
2
  import { join } from "node:path";
3
3
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
4
  //#region src/cli/commands/generate.ts
@@ -102,7 +102,7 @@ async function installDependencies(projectPath, config, pm) {
102
102
  ];
103
103
  if (config.auth === "better-auth") deps.push("better-auth@^1.6.0", "mongodb@latest");
104
104
  else deps.push("@fastify/jwt@latest", "bcryptjs@latest");
105
- if (config.adapter === "mongokit") deps.push("@classytic/mongokit@^3.5.5", "mongoose@^9.4.1");
105
+ if (config.adapter === "mongokit") deps.push("@classytic/mongokit@^3.10.2", "@classytic/repo-core@^0.1.0", "mongoose@^9.4.1");
106
106
  const devDeps = ["vitest@latest", "pino-pretty@latest"];
107
107
  if (config.typescript) devDeps.push("typescript@latest", "@types/node@latest", "tsx@latest");
108
108
  const installCmd = getInstallCommand(pm, deps, false);
@@ -1,4 +1,4 @@
1
- import { t as ResourceRegistry } from "../../ResourceRegistry-Dq3_zBQP.mjs";
1
+ import { t as ResourceRegistry } from "../../ResourceRegistry-BPd6NQDm.mjs";
2
2
  import { resolve } from "node:path";
3
3
  import { pathToFileURL } from "node:url";
4
4
  //#region src/cli/commands/introspect.ts
@@ -1,3 +1,3 @@
1
- import { At as BaseControllerOptions, Ft as AccessControl, It as AccessControlConfig, Kt as ResourceDefinition, Mt as QueryResolverConfig, Nt as BodySanitizer, Pt as BodySanitizerConfig, jt as QueryResolver, kt as BaseController, qt as defineResource } from "../interface-YrWsmKqE.mjs";
2
- import { C as MAX_REGEX_LENGTH, D as RESERVED_QUERY_PARAMS, E as MutationOperation, O as SYSTEM_FIELDS, S as MAX_FILTER_DEPTH, T as MUTATION_OPERATIONS, _ as DEFAULT_UPDATE_METHOD, a as getControllerScope, b as HookOperation, c as createCrudRouter, d as CrudOperation, f as DEFAULT_ID_FIELD, g as DEFAULT_TENANT_FIELD, h as DEFAULT_SORT, i as getControllerContext, l as createPermissionMiddleware, m as DEFAULT_MAX_LIMIT, n as createFastifyHandler, o as sendControllerResponse, p as DEFAULT_LIMIT, r as createRequestContext, s as defineResourceVariants, t as createCrudHandlers, u as CRUD_OPERATIONS, v as HOOK_OPERATIONS, w as MAX_SEARCH_LENGTH, x as HookPhase, y as HOOK_PHASES } from "../index-Cibkchnx.mjs";
1
+ import { G as ResourceDefinition, K as defineResource, a as QueryResolverConfig, c as AccessControl, i as QueryResolver, l as AccessControlConfig, n as BaseController, o as BodySanitizer, r as BaseControllerOptions, s as BodySanitizerConfig } from "../index-Cl0uoKd5.mjs";
2
+ import { C as MAX_REGEX_LENGTH, D as RESERVED_QUERY_PARAMS, E as MutationOperation, O as SYSTEM_FIELDS, S as MAX_FILTER_DEPTH, T as MUTATION_OPERATIONS, _ as DEFAULT_UPDATE_METHOD, a as getControllerScope, b as HookOperation, c as createCrudRouter, d as CrudOperation, f as DEFAULT_ID_FIELD, g as DEFAULT_TENANT_FIELD, h as DEFAULT_SORT, i as getControllerContext, l as createPermissionMiddleware, m as DEFAULT_MAX_LIMIT, n as createFastifyHandler, o as sendControllerResponse, p as DEFAULT_LIMIT, r as createRequestContext, s as defineResourceVariants, t as createCrudHandlers, u as CRUD_OPERATIONS, v as HOOK_OPERATIONS, w as MAX_SEARCH_LENGTH, x as HookPhase, y as HOOK_PHASES } from "../index-8qw4y6ff.mjs";
3
3
  export { AccessControl, AccessControlConfig, BaseController, BaseControllerOptions, BodySanitizer, BodySanitizerConfig, CRUD_OPERATIONS, CrudOperation, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, HookOperation, HookPhase, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MutationOperation, QueryResolver, QueryResolverConfig, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, defineResourceVariants, getControllerContext, getControllerScope, sendControllerResponse };
@@ -1,5 +1,4 @@
1
- import { a as DEFAULT_SORT, c as HOOK_OPERATIONS, d as MAX_REGEX_LENGTH, f as MAX_SEARCH_LENGTH, h as SYSTEM_FIELDS, i as DEFAULT_MAX_LIMIT, l as HOOK_PHASES, m as RESERVED_QUERY_PARAMS, n as DEFAULT_ID_FIELD, o as DEFAULT_TENANT_FIELD, p as MUTATION_OPERATIONS, r as DEFAULT_LIMIT, s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS, u as MAX_FILTER_DEPTH } from "../constants-Cxde4rpC.mjs";
2
- import { i as AccessControl, n as QueryResolver, r as BodySanitizer, t as BaseController } from "../BaseController-Vu2yc56T.mjs";
3
- import { c as createCrudHandlers, d as getControllerContext, f as getControllerScope, l as createFastifyHandler, n as defineResource, o as createCrudRouter, p as sendControllerResponse, s as createPermissionMiddleware, t as ResourceDefinition, u as createRequestContext } from "../defineResource-C__jkwvs.mjs";
4
- import { t as defineResourceVariants } from "../core-DNncu0xF.mjs";
1
+ import { a as DEFAULT_SORT, c as HOOK_OPERATIONS, d as MAX_REGEX_LENGTH, f as MAX_SEARCH_LENGTH, h as SYSTEM_FIELDS, i as DEFAULT_MAX_LIMIT, l as HOOK_PHASES, m as RESERVED_QUERY_PARAMS, n as DEFAULT_ID_FIELD, o as DEFAULT_TENANT_FIELD, p as MUTATION_OPERATIONS, r as DEFAULT_LIMIT, s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS, u as MAX_FILTER_DEPTH } from "../constants-BhY1OHoH.mjs";
2
+ import { i as AccessControl, n as QueryResolver, r as BodySanitizer, t as BaseController } from "../BaseController-CbKKIflT.mjs";
3
+ import { c as createPermissionMiddleware, d as createRequestContext, f as getControllerContext, l as createCrudHandlers, m as sendControllerResponse, n as ResourceDefinition, p as getControllerScope, r as defineResource, s as createCrudRouter, t as defineResourceVariants, u as createFastifyHandler } from "../core-CcR01lup.mjs";
5
4
  export { AccessControl, BaseController, BodySanitizer, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, QueryResolver, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, defineResourceVariants, getControllerContext, getControllerScope, sendControllerResponse };
@@ -1,15 +1,15 @@
1
- import { s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS } from "./constants-Cxde4rpC.mjs";
1
+ import { s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS } from "./constants-BhY1OHoH.mjs";
2
2
  import { _ as isElevated, n as PUBLIC_SCOPE, v as isMember } from "./types-AOD8fxIw.mjs";
3
- import { t as BaseController } from "./BaseController-Vu2yc56T.mjs";
4
- import { i as resolveEffectiveRoles, t as applyFieldReadPermissions } from "./fields-CU6FlaDV.mjs";
5
- import { t as getUserRoles } from "./types-ZUu_h0jp.mjs";
6
- import { r as ForbiddenError } from "./errors-CqWnSqM-.mjs";
7
- import { t as requestContext } from "./requestContext-DYtmNpm5.mjs";
8
- import { n as normalizePermissionResult, t as applyPermissionResult } from "./applyPermissionResult-bqGpo9ML.mjs";
9
- import { i as getDefaultCrudSchemas } from "./utils-B7FuRr9w.mjs";
3
+ import { t as BaseController } from "./BaseController-CbKKIflT.mjs";
4
+ import { i as resolveEffectiveRoles, t as applyFieldReadPermissions } from "./fields-bxkeltzz.mjs";
5
+ import { t as getUserRoles } from "./types-DV9WDfeg.mjs";
6
+ import { r as ForbiddenError } from "./errors-D5c-5BJL.mjs";
7
+ import { t as requestContext } from "./requestContext-xHIKedG6.mjs";
8
+ import { n as normalizePermissionResult, t as applyPermissionResult } from "./applyPermissionResult-QhV1Pa-g.mjs";
9
+ import { i as getDefaultCrudSchemas } from "./utils-B2fNOD_i.mjs";
10
10
  import { n as convertRouteSchema, t as convertOpenApiSchemas } from "./schemaConverter-BxFDdtXu.mjs";
11
11
  import { t as hasEvents } from "./typeGuards-Cj5Rgvlg.mjs";
12
- import { r as getAvailablePresets, t as applyPresets } from "./presets-hM4WhNWY.mjs";
12
+ import { r as getAvailablePresets, t as applyPresets } from "./presets-fLJVXdVn.mjs";
13
13
  //#region src/pipeline/pipe.ts
14
14
  /**
15
15
  * Compose pipeline steps into an ordered array.
@@ -708,7 +708,7 @@ function validateResourceConfig(config, options = {}) {
708
708
  else if (!config.adapter.repository) errors.push({
709
709
  field: "adapter.repository",
710
710
  message: "Adapter must provide a repository",
711
- suggestion: "Ensure your adapter returns a valid CrudRepository"
711
+ suggestion: "Ensure your adapter returns a valid StandardRepo (see @classytic/repo-core)"
712
712
  });
713
713
  } else if (!config.adapter && !config.routes?.length) warnings.push({
714
714
  field: "config",
@@ -1287,7 +1287,7 @@ var ResourceDefinition = class {
1287
1287
  fields: self.fields
1288
1288
  });
1289
1289
  if (self.actions && Object.keys(self.actions).length > 0) {
1290
- const { createActionRouter } = await import("./createActionRouter-DH1YFL9m.mjs").then((n) => n.n);
1290
+ const { createActionRouter } = await import("./createActionRouter-Bp_5c_2b.mjs").then((n) => n.n);
1291
1291
  createActionRouter(instance, normalizeActionsToRouterConfig(self.actions, self.actionPermissions, self.tag));
1292
1292
  }
1293
1293
  if (self.events && Object.keys(self.events).length > 0) typedInstance.log?.debug?.(`Resource '${self.name}' defined ${Object.keys(self.events).length} events`);
@@ -1376,4 +1376,36 @@ function normalizeActionsToRouterConfig(actions, globalAuth, tag) {
1376
1376
  };
1377
1377
  }
1378
1378
  //#endregion
1379
- export { validateResourceConfig as a, createCrudHandlers as c, getControllerContext as d, getControllerScope as f, formatValidationErrors as i, createFastifyHandler as l, pipe as m, defineResource as n, createCrudRouter as o, sendControllerResponse as p, assertValidConfig as r, createPermissionMiddleware as s, ResourceDefinition as t, createRequestContext as u };
1379
+ //#region src/core/defineResourceVariants.ts
1380
+ /**
1381
+ * Define multiple resources from a shared base config and per-variant overrides.
1382
+ *
1383
+ * Each variant is independently passed through `defineResource()` — the
1384
+ * returned `ResourceDefinition`s are real, fully-registered resources.
1385
+ * Register each one's plugin in your app:
1386
+ *
1387
+ * ```typescript
1388
+ * await app.register(articlePublic.toPlugin());
1389
+ * await app.register(articleAdmin.toPlugin());
1390
+ * ```
1391
+ *
1392
+ * @param base Shared config — adapter, queryParser, schemaOptions, hooks, etc.
1393
+ * Must NOT include `name` or `prefix` (those are per-variant).
1394
+ * @param variants Map of variant key → override. Each variant must declare
1395
+ * its own `name` and `prefix`. Other fields override the base.
1396
+ * @returns A record where each key from `variants` maps to a real
1397
+ * `ResourceDefinition` ready for `.toPlugin()` registration.
1398
+ */
1399
+ function defineResourceVariants(base, variants) {
1400
+ const out = {};
1401
+ for (const key of Object.keys(variants)) {
1402
+ const override = variants[key];
1403
+ out[key] = defineResource({
1404
+ ...base,
1405
+ ...override
1406
+ });
1407
+ }
1408
+ return out;
1409
+ }
1410
+ //#endregion
1411
+ export { formatValidationErrors as a, createPermissionMiddleware as c, createRequestContext as d, getControllerContext as f, pipe as h, assertValidConfig as i, createCrudHandlers as l, sendControllerResponse as m, ResourceDefinition as n, validateResourceConfig as o, getControllerScope as p, defineResource as r, createCrudRouter as s, defineResourceVariants as t, createFastifyHandler as u };
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
2
- import { n as normalizePermissionResult, t as applyPermissionResult } from "./applyPermissionResult-bqGpo9ML.mjs";
2
+ import { n as normalizePermissionResult, t as applyPermissionResult } from "./applyPermissionResult-QhV1Pa-g.mjs";
3
3
  import { a as toJsonSchema } from "./schemaConverter-BxFDdtXu.mjs";
4
4
  //#region src/core/createActionRouter.ts
5
5
  var createActionRouter_exports = /* @__PURE__ */ __exportAll({
@@ -207,7 +207,7 @@ async function registerArcCore(fastify, config, trackPlugin) {
207
207
  await fastify.register(arcCorePlugin, { emitEvents: config.arcPlugins?.emitEvents !== false });
208
208
  trackPlugin("arc-core");
209
209
  if (config.arcPlugins?.events !== false) {
210
- const { default: eventPlugin } = await import("./eventPlugin-Dl7MoVWH.mjs").then((n) => n.n);
210
+ const { default: eventPlugin } = await import("./eventPlugin-DCUjuiQT.mjs").then((n) => n.n);
211
211
  const eventOpts = typeof config.arcPlugins?.events === "object" ? config.arcPlugins.events : {};
212
212
  await fastify.register(eventPlugin, {
213
213
  ...eventOpts,
@@ -243,15 +243,15 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules) {
243
243
  trackPlugin("arc-graceful-shutdown");
244
244
  }
245
245
  if (config.arcPlugins?.caching) {
246
- const { default: cachingPlugin } = await import("./caching-CjybdRwx.mjs").then((n) => n.r);
246
+ const { default: cachingPlugin } = await import("./caching-CBpK_SCM.mjs").then((n) => n.r);
247
247
  const opts = config.arcPlugins.caching === true ? {} : config.arcPlugins.caching;
248
248
  await fastify.register(cachingPlugin, opts);
249
249
  trackPlugin("arc-caching", opts);
250
250
  }
251
251
  if (config.arcPlugins?.queryCache) {
252
- const { queryCachePlugin } = await import("./queryCachePlugin-DbUVroUG.mjs").then((n) => n.n);
252
+ const { queryCachePlugin } = await import("./queryCachePlugin-DQCEfJis.mjs").then((n) => n.n);
253
253
  const opts = config.arcPlugins.queryCache === true ? {} : config.arcPlugins.queryCache;
254
- const store = config.stores?.queryCache ?? new (await (import("./memory-BFAYkf8H.mjs").then((n) => n.n))).MemoryCacheStore();
254
+ const store = config.stores?.queryCache ?? new (await (import("./memory-B5Amv9A1.mjs").then((n) => n.n))).MemoryCacheStore();
255
255
  await fastify.register(queryCachePlugin, {
256
256
  store,
257
257
  ...opts
@@ -260,19 +260,19 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules) {
260
260
  }
261
261
  if (config.arcPlugins?.sse) if (config.arcPlugins?.events === false) fastify.log.warn("SSE plugin requires events plugin (arcPlugins.events). SSE disabled.");
262
262
  else {
263
- const { default: ssePlugin } = await import("./sse-CJpt7LGI.mjs").then((n) => n.r);
263
+ const { default: ssePlugin } = await import("./sse-yBCgOLGu.mjs").then((n) => n.r);
264
264
  const opts = config.arcPlugins.sse === true ? {} : config.arcPlugins.sse;
265
265
  await fastify.register(ssePlugin, opts);
266
266
  trackPlugin("arc-sse", opts);
267
267
  }
268
268
  if (config.arcPlugins?.metrics) {
269
- const { default: metricsPlugin } = await import("./metrics-TuOmguhi.mjs").then((n) => n.r);
269
+ const { default: metricsPlugin } = await import("./metrics-DuhiSEZI.mjs").then((n) => n.r);
270
270
  const opts = config.arcPlugins.metrics === true ? {} : config.arcPlugins.metrics;
271
271
  await fastify.register(metricsPlugin, opts);
272
272
  trackPlugin("arc-metrics", opts);
273
273
  }
274
274
  if (config.arcPlugins?.versioning) {
275
- const { default: versioningPlugin } = await import("./versioning-Cm8qoFDg.mjs").then((n) => n.r);
275
+ const { default: versioningPlugin } = await import("./versioning-C2U_bLY0.mjs").then((n) => n.r);
276
276
  await fastify.register(versioningPlugin, config.arcPlugins.versioning);
277
277
  trackPlugin("arc-versioning", config.arcPlugins.versioning);
278
278
  }
@@ -340,7 +340,7 @@ async function registerAuth(fastify, config, trackPlugin) {
340
340
  */
341
341
  async function registerElevation(fastify, config, trackPlugin) {
342
342
  if (!config.elevation) return;
343
- const { elevationPlugin } = await import("./elevation-DxQ6ACbt.mjs").then((n) => n.r);
343
+ const { elevationPlugin } = await import("./elevation-C7hgL_aI.mjs").then((n) => n.r);
344
344
  await fastify.register(elevationPlugin, config.elevation);
345
345
  trackPlugin("arc-elevation", config.elevation);
346
346
  fastify.log.debug("Elevation plugin enabled");
@@ -350,7 +350,7 @@ async function registerElevation(fastify, config, trackPlugin) {
350
350
  */
351
351
  async function registerErrorHandler(fastify, config, trackPlugin) {
352
352
  if (config.errorHandler === false) return;
353
- const { errorHandlerPlugin } = await import("./errorHandler-CZDW4EXS.mjs").then((n) => n.r);
353
+ const { errorHandlerPlugin } = await import("./errorHandler-Bb49BvPD.mjs").then((n) => n.r);
354
354
  const errorOpts = typeof config.errorHandler === "object" ? config.errorHandler : { includeStack: config.preset !== "production" };
355
355
  await fastify.register(errorHandlerPlugin, errorOpts);
356
356
  trackPlugin("arc-error-handler", errorOpts);
@@ -417,7 +417,7 @@ async function registerResources(fastify, config) {
417
417
  fastify.log.debug(`${config.bootstrap.length} bootstrap function(s) executed`);
418
418
  }
419
419
  if (!config.resources?.length && config.resourceDir) {
420
- const { loadResources } = await import("./loadResources-Bksk8ydA.mjs").then((n) => n.n);
420
+ const { loadResources } = await import("./loadResources-BAzJItAJ.mjs").then((n) => n.n);
421
421
  const { resolve } = await import("node:path");
422
422
  const dir = resolve(config.resourceDir);
423
423
  config = {
@@ -643,14 +643,14 @@ function validateDistributedRuntime(options) {
643
643
  if (!events || MEMORY_STORE_NAMES.has(events.name)) missing.push("events transport");
644
644
  if (options.arcPlugins?.caching) {
645
645
  const cache = options.stores?.cache;
646
- if (!cache || MEMORY_STORE_NAMES.has(cache.name)) missing.push("cache store");
646
+ if (!cache || cache.name !== void 0 && MEMORY_STORE_NAMES.has(cache.name)) missing.push("cache store");
647
647
  }
648
648
  const idempotency = options.stores?.idempotency;
649
649
  if (idempotency && MEMORY_STORE_NAMES.has(idempotency.name)) missing.push("idempotency store (memory-backed in distributed mode)");
650
650
  else if (!idempotency) deferredWarnings.push("runtime: 'distributed' — no idempotency store configured. Write-path deduplication will be instance-local. If resources use the idempotency plugin, provide stores.idempotency with a Redis/MongoDB store.");
651
651
  if (options.arcPlugins?.queryCache) {
652
652
  const qc = options.stores?.queryCache;
653
- if (!qc || MEMORY_STORE_NAMES.has(qc.name)) missing.push("queryCache store");
653
+ if (!qc || qc.name !== void 0 && MEMORY_STORE_NAMES.has(qc.name)) missing.push("queryCache store");
654
654
  }
655
655
  if (missing.length > 0) throw new Error(`[Arc] runtime: 'distributed' requires Redis/durable adapters.\nMissing: ${missing.join(", ")}.\nProvide Redis-backed stores or use runtime: 'memory' for development.`);
656
656
  return deferredWarnings;
@@ -676,7 +676,7 @@ function validateDistributedRuntime(options) {
676
676
  */
677
677
  async function createApp(options) {
678
678
  if (options.debug !== void 0 && options.debug !== false) {
679
- const { configureArcLogger } = await import("./logger-CDjpjySd.mjs").then((n) => n.r);
679
+ const { configureArcLogger } = await import("./logger-DLg8-Ueg.mjs").then((n) => n.r);
680
680
  configureArcLogger({ debug: options.debug });
681
681
  }
682
682
  validateAuthOptions(options);
@@ -730,7 +730,7 @@ async function createApp(options) {
730
730
  await registerErrorHandler(fastify, config, trackPlugin);
731
731
  await registerResources(fastify, config);
732
732
  if (config.replyHelpers) {
733
- const { replyHelpersPlugin } = await import("./replyHelpers-BLojtuvR.mjs").then((n) => n.n);
733
+ const { replyHelpersPlugin } = await import("./replyHelpers-CXtJDAZ0.mjs").then((n) => n.n);
734
734
  await fastify.register(replyHelpersPlugin);
735
735
  }
736
736
  if (config.serializeBigInt) fastify.addHook("preSerialization", async (_request, _reply, payload) => {
@@ -1,5 +1,5 @@
1
- import { rt as RegistryEntry } from "../interface-YrWsmKqE.mjs";
2
- import { t as ExternalOpenApiPaths } from "../externalPaths-Bapitwvd.mjs";
1
+ import { x as RegistryEntry } from "../index-Cl0uoKd5.mjs";
2
+ import { t as ExternalOpenApiPaths } from "../externalPaths-BQ8QijNH.mjs";
3
3
  import { FastifyPluginAsync } from "fastify";
4
4
 
5
5
  //#region src/docs/openapi.d.ts
@@ -1,5 +1,5 @@
1
- import { t as getUserRoles } from "../types-ZUu_h0jp.mjs";
2
- import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-CXuTG1M9.mjs";
1
+ import { t as getUserRoles } from "../types-DV9WDfeg.mjs";
2
+ import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-B5F8AddX.mjs";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/docs/scalar.ts
5
5
  const scalarPlugin = async (fastify, opts = {}) => {
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
2
- import { t as getUserRoles } from "./types-ZUu_h0jp.mjs";
3
- import { t as arcLog } from "./logger-CDjpjySd.mjs";
2
+ import { t as getUserRoles } from "./types-DV9WDfeg.mjs";
3
+ import { t as arcLog } from "./logger-DLg8-Ueg.mjs";
4
4
  import fp from "fastify-plugin";
5
5
  //#region src/scope/elevation.ts
6
6
  var elevation_exports = /* @__PURE__ */ __exportAll({
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
2
- import { p as isArcError } from "./errors-CqWnSqM-.mjs";
2
+ import { p as isArcError } from "./errors-D5c-5BJL.mjs";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/plugins/errorHandler.ts
5
5
  var errorHandler_exports = /* @__PURE__ */ __exportAll({
@@ -1,4 +1,4 @@
1
- import { n as DomainEvent } from "./EventTransport-CqZ8FyM_.mjs";
1
+ import { n as DomainEvent } from "./EventTransport-CUw5NNWe.mjs";
2
2
  import { FastifyInstance, FastifyPluginAsync, FastifyRequest } from "fastify";
3
3
 
4
4
  //#region src/plugins/caching.d.ts