@classytic/arc 2.8.0 → 2.8.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 (117) hide show
  1. package/README.md +10 -1
  2. package/dist/{BaseController-CpMfCXdn.mjs → BaseController-DAGGc5Xn.mjs} +76 -25
  3. package/dist/{EventTransport-n1KBxC_N.d.mts → EventTransport-CinyO7zQ.d.mts} +37 -1
  4. package/dist/{ResourceRegistry-BOtJuRCs.mjs → ResourceRegistry-Dq3_zBQP.mjs} +17 -5
  5. package/dist/adapters/index.d.mts +2 -2
  6. package/dist/adapters/index.mjs +1 -1
  7. package/dist/{adapters-BxGgSHjj.mjs → adapters-BBqAVvPK.mjs} +11 -0
  8. package/dist/audit/index.d.mts +1 -1
  9. package/dist/audit/index.mjs +1 -1
  10. package/dist/audit/mongodb.d.mts +1 -1
  11. package/dist/audit/mongodb.mjs +1 -1
  12. package/dist/auth/index.d.mts +4 -4
  13. package/dist/auth/index.mjs +3 -3
  14. package/dist/auth/redis-session.d.mts +1 -1
  15. package/dist/{betterAuthOpenApi-CHCIuA-p.mjs → betterAuthOpenApi-C5lDyRH2.mjs} +1 -1
  16. package/dist/cache/index.d.mts +2 -2
  17. package/dist/cli/commands/describe.mjs +1 -1
  18. package/dist/cli/commands/docs.mjs +2 -2
  19. package/dist/cli/commands/generate.mjs +1 -1
  20. package/dist/cli/commands/init.mjs +10 -10
  21. package/dist/cli/commands/introspect.mjs +3 -3
  22. package/dist/core/index.d.mts +3 -3
  23. package/dist/core/index.mjs +5 -5
  24. package/dist/{core-BfrfxNqO.mjs → core-DKSwNSXf.mjs} +1 -1
  25. package/dist/{createActionRouter-CbkIAaGh.mjs → createActionRouter-Df1BuawX.mjs} +87 -21
  26. package/dist/{createApp-Cy8eUNKQ.mjs → createApp-BOYjBgdI.mjs} +16 -7
  27. package/dist/{defineResource-CovBXvTB.mjs → defineResource-Bb_Bdhtw.mjs} +60 -33
  28. package/dist/docs/index.d.mts +2 -2
  29. package/dist/docs/index.mjs +1 -1
  30. package/dist/dynamic/index.d.mts +2 -2
  31. package/dist/dynamic/index.mjs +1 -1
  32. package/dist/{errorHandler-BeN-ERN7.d.mts → errorHandler-CdZDavNH.d.mts} +2 -2
  33. package/dist/{errorHandler-BW08lEiy.mjs → errorHandler-mzqk4cGl.mjs} +1 -1
  34. package/dist/{eventPlugin-CAOWMQS8.d.mts → eventPlugin-CVxlE6De.d.mts} +1 -1
  35. package/dist/{eventPlugin-x4jo3sG0.mjs → eventPlugin-D91S2YF4.mjs} +19 -1
  36. package/dist/events/index.d.mts +399 -28
  37. package/dist/events/index.mjs +345 -29
  38. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  39. package/dist/events/transports/redis-stream-entry.mjs +3 -1
  40. package/dist/events/transports/redis.d.mts +1 -1
  41. package/dist/factory/index.d.mts +1 -1
  42. package/dist/factory/index.mjs +2 -152
  43. package/dist/hooks/index.d.mts +1 -1
  44. package/dist/idempotency/index.d.mts +3 -3
  45. package/dist/idempotency/mongodb.d.mts +1 -1
  46. package/dist/idempotency/mongodb.mjs +18 -6
  47. package/dist/idempotency/redis.d.mts +1 -1
  48. package/dist/idempotency/redis.mjs +10 -1
  49. package/dist/{index-BpMhrFgn.d.mts → index-BgmMdpm8.d.mts} +1 -1
  50. package/dist/{index-CBru2y5Y.d.mts → index-CSkeivBx.d.mts} +3 -3
  51. package/dist/{index-qct60lnl.d.mts → index-CpTSDqmD.d.mts} +60 -6
  52. package/dist/index.d.mts +8 -8
  53. package/dist/index.mjs +7 -7
  54. package/dist/integrations/event-gateway.d.mts +1 -1
  55. package/dist/integrations/event-gateway.mjs +1 -1
  56. package/dist/integrations/index.d.mts +1 -1
  57. package/dist/integrations/mcp/index.d.mts +2 -2
  58. package/dist/integrations/mcp/index.mjs +1 -1
  59. package/dist/integrations/mcp/testing.d.mts +1 -1
  60. package/dist/integrations/mcp/testing.mjs +1 -1
  61. package/dist/{interface-IJqN3pXK.d.mts → interface-BVuMfeVv.d.mts} +596 -125
  62. package/dist/loadResources-Bksk8ydA.mjs +154 -0
  63. package/dist/{mongodb-B1eVtFhw.d.mts → mongodb-B8U2xaLj.d.mts} +1 -1
  64. package/dist/{mongodb-NShVZDMr.d.mts → mongodb-X7LbEjTN.d.mts} +10 -1
  65. package/dist/{openapi-AYLVjqVe.mjs → openapi-CYCuekCn.mjs} +50 -3
  66. package/dist/org/index.d.mts +2 -2
  67. package/dist/permissions/index.d.mts +3 -3
  68. package/dist/plugins/index.d.mts +5 -5
  69. package/dist/plugins/index.mjs +8 -8
  70. package/dist/plugins/tracing-entry.d.mts +1 -1
  71. package/dist/plugins/tracing-entry.mjs +1 -1
  72. package/dist/policies/index.d.mts +1 -1
  73. package/dist/presets/index.d.mts +3 -3
  74. package/dist/presets/index.mjs +1 -1
  75. package/dist/presets/multiTenant.d.mts +1 -1
  76. package/dist/{presets-BFrGvvjL.mjs → presets-C2xgzW6x.mjs} +10 -18
  77. package/dist/{queryCachePlugin-BCFVXnxK.d.mts → queryCachePlugin-CnTZZTC5.d.mts} +1 -1
  78. package/dist/{redis-stream-CF1lrKVk.d.mts → redis-stream-D54N5oXs.d.mts} +1 -1
  79. package/dist/{redis-Bunu3qWg.d.mts → redis-z3sFr1UP.d.mts} +1 -1
  80. package/dist/registry/index.d.mts +1 -1
  81. package/dist/registry/index.mjs +1 -1
  82. package/dist/{resourceToTools-C_1SMiCz.mjs → resourceToTools-O_HwWXFa.mjs} +194 -64
  83. package/dist/rpc/index.d.mts +1 -1
  84. package/dist/rpc/index.mjs +1 -1
  85. package/dist/scope/index.d.mts +2 -2
  86. package/dist/testing/index.d.mts +2 -2
  87. package/dist/testing/index.mjs +1 -1
  88. package/dist/types/index.d.mts +5 -5
  89. package/dist/{types-gUxAIZHp.d.mts → types-Bg2X42_m.d.mts} +30 -9
  90. package/dist/{types-BoaZHr-2.d.mts → types-CVC4HOKi.d.mts} +1 -1
  91. package/dist/{types-Ct0PUUSp.d.mts → types-CcG4avic.d.mts} +1 -1
  92. package/dist/utils/index.d.mts +43 -17
  93. package/dist/utils/index.mjs +5 -5
  94. package/dist/{utils-B-l6410F.mjs → utils-yYT3HDXt.mjs} +65 -13
  95. package/package.json +10 -9
  96. package/skills/arc/SKILL.md +79 -6
  97. /package/dist/{caching-CHH-iHs3.mjs → caching-CjybdRwx.mjs} +0 -0
  98. /package/dist/{circuitBreaker-BGVoB1hD.d.mts → circuitBreaker-CvXkjfrW.d.mts} +0 -0
  99. /package/dist/{circuitBreaker-l18oRgL5.mjs → circuitBreaker-cmi5XDv5.mjs} +0 -0
  100. /package/dist/{elevation-UJO3-NvX.d.mts → elevation-s5ykdNHr.d.mts} +0 -0
  101. /package/dist/{errors-Cg58SLNi.mjs → errors-BF2bIOIS.mjs} +0 -0
  102. /package/dist/{errors-BI8kEKsO.d.mts → errors-Bmn3eZT6.d.mts} +0 -0
  103. /package/dist/{externalPaths-BQ8QijNH.d.mts → externalPaths-Bapitwvd.d.mts} +0 -0
  104. /package/dist/{fields-DoeDgh2b.d.mts → fields-DC4So2M2.d.mts} +0 -0
  105. /package/dist/{interface-CkkWm5uR.d.mts → interface-B-pe8fhj.d.mts} +0 -0
  106. /package/dist/{interface-bpoLKKqx.d.mts → interface-DplgQO2e.d.mts} +0 -0
  107. /package/dist/{metrics-DuhiSEZI.mjs → metrics-TuOmguhi.mjs} +0 -0
  108. /package/dist/{mongodb-5Ff3w8jy.mjs → mongodb-B5O6xaW1.mjs} +0 -0
  109. /package/dist/{pluralize-BneOJkpi.mjs → pluralize-A0tWEl1K.mjs} +0 -0
  110. /package/dist/{replyHelpers-CXtJDAZ0.mjs → replyHelpers-BLojtuvR.mjs} +0 -0
  111. /package/dist/{requestContext-xHIKedG6.mjs → requestContext-DYvHl113.mjs} +0 -0
  112. /package/dist/{schemaConverter-Y5EejTnJ.mjs → schemaConverter-OxfCshus.mjs} +0 -0
  113. /package/dist/{sessionManager-BkzVU8h2.d.mts → sessionManager-D-oNWHz3.d.mts} +0 -0
  114. /package/dist/{sse-CD5Hghpu.mjs → sse-CJpt7LGI.mjs} +0 -0
  115. /package/dist/{tracing-xqXzWeaf.d.mts → tracing-DxjKk7eW.d.mts} +0 -0
  116. /package/dist/{types-CN6JvmYz.d.mts → types-C72d3NDn.d.mts} +0 -0
  117. /package/dist/{versioning-CPU_5Xfs.mjs → versioning-Cm8qoFDg.mjs} +0 -0
@@ -0,0 +1,154 @@
1
+ import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
2
+ import { readdir } from "node:fs/promises";
3
+ import { dirname, join, resolve } from "node:path";
4
+ import { fileURLToPath, pathToFileURL } from "node:url";
5
+ //#region src/factory/loadResources.ts
6
+ /**
7
+ * loadResources — Auto-discover resource files from a directory.
8
+ *
9
+ * Scans for `*.resource.{ts,js,mts,mjs}` files, imports each,
10
+ * and collects their default exports. No barrel file needed.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { createApp, loadResources } from '@classytic/arc/factory';
15
+ *
16
+ * // Recommended: import.meta.url — works in both src/ (dev) and dist/ (prod)
17
+ * const app = await createApp({
18
+ * resources: await loadResources(import.meta.url),
19
+ * auth: { type: 'jwt', jwt: { secret: process.env.JWT_SECRET } },
20
+ * });
21
+ *
22
+ * // Or explicit path (must match runtime layout)
23
+ * const app2 = await createApp({
24
+ * resources: await loadResources('./src/resources'),
25
+ * });
26
+ * ```
27
+ *
28
+ * File convention:
29
+ * ```
30
+ * src/resources/
31
+ * product/product.resource.ts → export default defineResource({ name: 'product', ... })
32
+ * order/order.resource.ts → export default defineResource({ name: 'order', ... })
33
+ * ```
34
+ */
35
+ var loadResources_exports = /* @__PURE__ */ __exportAll({ loadResources: () => loadResources });
36
+ /**
37
+ * Scan a directory for resource files and import their default exports.
38
+ *
39
+ * Accepts a directory path OR `import.meta.url` (file:// URL).
40
+ * When given a URL, resolves to the directory containing that file —
41
+ * so `loadResources(import.meta.url)` works in both dev (`src/`) and
42
+ * production (`dist/`) without path gymnastics.
43
+ *
44
+ * @param dir - Directory path, or `import.meta.url` (file:// URL resolved to its dirname)
45
+ * @param options - Pattern and recursion options
46
+ * @returns Array of resource definitions (anything with `.toPlugin()`)
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * // Works from both src/ and dist/ — resolves relative to the calling file
51
+ * await loadResources(import.meta.url);
52
+ *
53
+ * // Subdirectory relative to the calling file
54
+ * await loadResources(import.meta.url, { suffix: '.resource' });
55
+ *
56
+ * // Explicit path (must match runtime layout)
57
+ * await loadResources('./src/resources');
58
+ * ```
59
+ */
60
+ async function loadResources(dir, options = {}) {
61
+ const { suffix = ".resource", recursive = true, exclude, include, silent = false } = options;
62
+ const files = await collectFiles(resolve(dir.startsWith("file://") ? dirname(fileURLToPath(dir)) : dir), new RegExp(`${escapeRegex(suffix)}\\.(ts|js|mts|mjs)$`), recursive);
63
+ files.sort();
64
+ const includeSet = include ? new Set(include) : null;
65
+ const excludeSet = exclude ? new Set(exclude) : null;
66
+ const skipped = [];
67
+ const failed = [];
68
+ const isWindowsPath = (p) => /^[a-z]:[\\/]/i.test(p);
69
+ const results = await Promise.all(files.map(async (file) => {
70
+ let mod;
71
+ let primaryError;
72
+ try {
73
+ mod = await import(pathToFileURL(file).href);
74
+ return {
75
+ file,
76
+ mod
77
+ };
78
+ } catch (err) {
79
+ primaryError = err;
80
+ }
81
+ if (!isWindowsPath(file)) try {
82
+ mod = await import(file);
83
+ return {
84
+ file,
85
+ mod
86
+ };
87
+ } catch {}
88
+ const err = primaryError;
89
+ const code = err.code;
90
+ const msg = err instanceof Error ? err.message : String(err);
91
+ if (code === "ERR_MODULE_NOT_FOUND" && msg.includes(".js")) failed.push(`${file}: ${msg}\n Hint: This file uses .js extension imports (TypeScript ESM convention).
92
+ • Production: ensure your build compiles .ts→.js before loadResources() runs.
93
+ • Node.js: use tsx, ts-node/esm, or a build step.
94
+ • Vitest: nested .js→.ts resolution may fail through dynamic imports.
95
+ Workaround: use import.meta.glob to preload resources statically.
96
+ See: https://github.com/classytic/arc/blob/main/docs/production-ops/factory.mdx#vitest-limitation`);
97
+ else failed.push(`${file}: ${msg}`);
98
+ return null;
99
+ }));
100
+ const resources = [];
101
+ for (const result of results) {
102
+ if (!result) continue;
103
+ let resource = result.mod.default ?? result.mod.resource;
104
+ if (!resource || typeof resource.toPlugin !== "function") {
105
+ for (const value of Object.values(result.mod)) if (value && typeof value === "object" && typeof value.toPlugin === "function") {
106
+ resource = value;
107
+ break;
108
+ }
109
+ }
110
+ if (!resource || typeof resource.toPlugin !== "function") {
111
+ skipped.push(result.file);
112
+ continue;
113
+ }
114
+ const name = resource.name;
115
+ if (name) {
116
+ if (includeSet && !includeSet.has(name)) continue;
117
+ if (!includeSet && excludeSet?.has(name)) continue;
118
+ }
119
+ resources.push(resource);
120
+ }
121
+ const log = silent ? void 0 : options?.logger;
122
+ if (log) {
123
+ if (failed.length) {
124
+ log.warn(`[arc] loadResources: ${failed.length} file(s) failed to import:`);
125
+ for (const f of failed) log.warn(` - ${f}`);
126
+ }
127
+ if (skipped.length) {
128
+ log.warn(`[arc] loadResources: ${skipped.length} file(s) skipped (no default export with toPlugin):`);
129
+ for (const f of skipped) log.warn(` - ${f}`);
130
+ }
131
+ }
132
+ return resources;
133
+ }
134
+ async function collectFiles(dir, pattern, recursive) {
135
+ const results = [];
136
+ let entries;
137
+ try {
138
+ entries = await readdir(dir, { withFileTypes: true });
139
+ } catch {
140
+ return results;
141
+ }
142
+ for (const entry of entries) {
143
+ const name = String(entry.name);
144
+ const fullPath = join(dir, name);
145
+ if (entry.isDirectory() && recursive) results.push(...await collectFiles(fullPath, pattern, recursive));
146
+ else if (entry.isFile() && pattern.test(name)) results.push(fullPath);
147
+ }
148
+ return results;
149
+ }
150
+ function escapeRegex(str) {
151
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
152
+ }
153
+ //#endregion
154
+ export { loadResources_exports as n, loadResources as t };
@@ -1,4 +1,4 @@
1
- import { i as UserBase } from "./types-BoaZHr-2.mjs";
1
+ import { i as UserBase } from "./types-CVC4HOKi.mjs";
2
2
 
3
3
  //#region src/audit/stores/interface.d.ts
4
4
  type AuditAction = "create" | "update" | "delete" | "restore" | "custom";
@@ -1,4 +1,4 @@
1
- import { n as IdempotencyResult, r as IdempotencyStore } from "./interface-CkkWm5uR.mjs";
1
+ import { n as IdempotencyResult, r as IdempotencyStore } from "./interface-B-pe8fhj.mjs";
2
2
 
3
3
  //#region src/idempotency/stores/mongodb.d.ts
4
4
  interface MongoConnection {
@@ -15,6 +15,7 @@ interface MongoCollection {
15
15
  acknowledged: boolean;
16
16
  matchedCount: number;
17
17
  modifiedCount: number;
18
+ upsertedCount?: number;
18
19
  }>;
19
20
  deleteOne(filter: object): Promise<{
20
21
  deletedCount: number;
@@ -38,6 +39,10 @@ interface IdempotencyDocument {
38
39
  createdAt: Date;
39
40
  expiresAt: Date;
40
41
  }
42
+ /** Minimal logger interface — compatible with console, pino, fastify.log */
43
+ interface IdempotencyLogger {
44
+ warn(message: string, ...args: unknown[]): void;
45
+ }
41
46
  interface MongoIdempotencyStoreOptions {
42
47
  /** Mongoose connection or MongoDB connection object */
43
48
  connection: MongoConnection;
@@ -47,6 +52,8 @@ interface MongoIdempotencyStoreOptions {
47
52
  createIndex?: boolean;
48
53
  /** Default TTL in ms (default: 86400000 = 24 hours) */
49
54
  ttlMs?: number;
55
+ /** Logger for operational warnings (default: console) */
56
+ logger?: IdempotencyLogger;
50
57
  }
51
58
  declare class MongoIdempotencyStore implements IdempotencyStore {
52
59
  readonly name = "mongodb";
@@ -54,6 +61,8 @@ declare class MongoIdempotencyStore implements IdempotencyStore {
54
61
  private collectionName;
55
62
  private ttlMs;
56
63
  private indexCreated;
64
+ private shouldEnsureIndex;
65
+ private logger;
57
66
  constructor(options: MongoIdempotencyStoreOptions);
58
67
  private get collection();
59
68
  private ensureIndex;
@@ -1,5 +1,6 @@
1
1
  import { t as getUserRoles } from "./types-ZUu_h0jp.mjs";
2
- import { n as convertRouteSchema } from "./schemaConverter-Y5EejTnJ.mjs";
2
+ import { n as convertRouteSchema } from "./schemaConverter-OxfCshus.mjs";
3
+ import { t as buildActionBodySchema } from "./createActionRouter-Df1BuawX.mjs";
3
4
  import fp from "fastify-plugin";
4
5
  //#region src/docs/openapi.ts
5
6
  const openApiPlugin = async (fastify, opts = {}) => {
@@ -158,7 +159,7 @@ const DEFAULT_LIST_PARAMS = [
158
159
  function generateResourcePaths(resource, apiPrefix = "", additionalSecurity = []) {
159
160
  const paths = {};
160
161
  const basePath = `${apiPrefix}${resource.prefix}`;
161
- if (resource.disableDefaultRoutes && (!resource.additionalRoutes || resource.additionalRoutes.length === 0)) return paths;
162
+ if (resource.disableDefaultRoutes && (!resource.customRoutes || resource.customRoutes.length === 0) && (!resource.actions || resource.actions.length === 0)) return paths;
162
163
  if (!resource.disableDefaultRoutes) {
163
164
  const disabledSet = new Set(resource.disabledRoutes ?? []);
164
165
  const updateMethod = resource.updateMethod ?? "PATCH";
@@ -275,7 +276,7 @@ function generateResourcePaths(resource, apiPrefix = "", additionalSecurity = []
275
276
  }, void 0, additionalSecurity);
276
277
  if (Object.keys(itemPath).length > 0) paths[toOpenApiPath(`${basePath}/:id`)] = itemPath;
277
278
  }
278
- for (const route of resource.additionalRoutes || []) {
279
+ for (const route of resource.customRoutes || []) {
279
280
  const fullPath = toOpenApiPath(`${basePath}${route.path}`);
280
281
  const method = route.method.toLowerCase();
281
282
  if (!paths[fullPath]) paths[fullPath] = {};
@@ -309,6 +310,52 @@ function generateResourcePaths(resource, apiPrefix = "", additionalSecurity = []
309
310
  }
310
311
  paths[fullPath][method] = createOperation(resource, handlerName, route.summary ?? handlerName, extras, requiresAuthForRoute, additionalSecurity);
311
312
  }
313
+ if (resource.actions && resource.actions.length > 0) {
314
+ const actionPath = toOpenApiPath(`${basePath}/:id/action`);
315
+ const actionEnum = resource.actions.map((a) => a.name);
316
+ const actionSchemas = {};
317
+ for (const a of resource.actions) if (a.schema) actionSchemas[a.name] = a.schema;
318
+ const bodySchema = buildActionBodySchema(actionEnum, actionSchemas);
319
+ const descLines = [
320
+ "Unified action endpoint for state transitions.",
321
+ "",
322
+ "**Available actions:**"
323
+ ];
324
+ for (const a of resource.actions) {
325
+ const roles = a.permissions?._roles;
326
+ const roleStr = roles?.length ? ` — requires: ${roles.join(" or ")}` : "";
327
+ const descStr = a.description ? ` — ${a.description}` : "";
328
+ descLines.push(`- \`${a.name}\`${roleStr}${descStr}`);
329
+ }
330
+ const fallbackPerm = resource.actionPermissions;
331
+ const fallbackRequiresAuth = typeof fallbackPerm === "function" && !fallbackPerm._isPublic;
332
+ const anyAuthRequired = resource.actions.some((a) => {
333
+ const p = a.permissions;
334
+ if (typeof p === "function") return !p._isPublic;
335
+ return fallbackRequiresAuth;
336
+ });
337
+ if (!paths[actionPath]) paths[actionPath] = {};
338
+ paths[actionPath].post = createOperation(resource, "action", `Perform action (${actionEnum.join(" / ")})`, {
339
+ parameters: [{
340
+ name: "id",
341
+ in: "path",
342
+ required: true,
343
+ schema: { type: "string" },
344
+ description: "Resource ID"
345
+ }],
346
+ description: descLines.join("\n"),
347
+ requestBody: {
348
+ required: true,
349
+ content: { "application/json": { schema: bodySchema } }
350
+ },
351
+ responses: {
352
+ "200": { description: "Action executed successfully" },
353
+ "400": { description: "Invalid action or missing required fields" },
354
+ "401": { description: "Authentication required" },
355
+ "403": { description: "Permission denied" }
356
+ }
357
+ }, anyAuthRequired, additionalSecurity);
358
+ }
312
359
  return paths;
313
360
  }
314
361
  /**
@@ -1,5 +1,5 @@
1
- import { Wt as RouteHandler } from "../interface-IJqN3pXK.mjs";
2
- import { i as UserBase } from "../types-BoaZHr-2.mjs";
1
+ import { Wt as RouteHandler } from "../interface-BVuMfeVv.mjs";
2
+ import { i as UserBase } from "../types-CVC4HOKi.mjs";
3
3
  import { InvitationAdapter, InvitationDoc, MemberDoc, OrgAdapter, OrgDoc, OrgPermissionStatement, OrgRole, OrganizationPluginOptions } from "./types.mjs";
4
4
  import { FastifyPluginAsync, RouteHandlerMethod } from "fastify";
5
5
 
@@ -1,4 +1,4 @@
1
- import { a as applyFieldWritePermissions, i as applyFieldReadPermissions, n as FieldPermissionMap, o as fields, r as FieldPermissionType, s as resolveEffectiveRoles, t as FieldPermission } from "../fields-DoeDgh2b.mjs";
2
- import { a as getUserRoles, i as UserBase, n as PermissionContext, o as normalizeRoles, r as PermissionResult, t as PermissionCheck } from "../types-BoaZHr-2.mjs";
3
- import { A as RoleHierarchy, C as authenticated, D as publicRead, E as presets_d_exports, M as applyPermissionResult, N as normalizePermissionResult, O as publicReadAdminWrite, S as adminOnly, T as ownerWithAdminBypass, _ as requireScopeContext, a as allOf, b as roles, c as createDynamicPermissionMatrix, d as requireAuth, f as requireOrgInScope, g as requireRoles, h as requireOwnership, i as PermissionEventBus, j as createRoleHierarchy, k as readOnly, l as createOrgPermissions, m as requireOrgRole, n as DynamicPermissionMatrix, o as allowPublic, p as requireOrgMembership, r as DynamicPermissionMatrixConfig, s as anyOf, t as ConnectEventsOptions, u as denyAll, v as requireServiceScope, w as fullPublic, x as when, y as requireTeamMembership } from "../index-CBru2y5Y.mjs";
1
+ import { a as applyFieldWritePermissions, i as applyFieldReadPermissions, n as FieldPermissionMap, o as fields, r as FieldPermissionType, s as resolveEffectiveRoles, t as FieldPermission } from "../fields-DC4So2M2.mjs";
2
+ import { a as getUserRoles, i as UserBase, n as PermissionContext, o as normalizeRoles, r as PermissionResult, t as PermissionCheck } from "../types-CVC4HOKi.mjs";
3
+ import { A as RoleHierarchy, C as authenticated, D as publicRead, E as presets_d_exports, M as applyPermissionResult, N as normalizePermissionResult, O as publicReadAdminWrite, S as adminOnly, T as ownerWithAdminBypass, _ as requireScopeContext, a as allOf, b as roles, c as createDynamicPermissionMatrix, d as requireAuth, f as requireOrgInScope, g as requireRoles, h as requireOwnership, i as PermissionEventBus, j as createRoleHierarchy, k as readOnly, l as createOrgPermissions, m as requireOrgRole, n as DynamicPermissionMatrix, o as allowPublic, p as requireOrgMembership, r as DynamicPermissionMatrixConfig, s as anyOf, t as ConnectEventsOptions, u as denyAll, v as requireServiceScope, w as fullPublic, x as when, y as requireTeamMembership } from "../index-CSkeivBx.mjs";
4
4
  export { ConnectEventsOptions, DynamicPermissionMatrix, DynamicPermissionMatrixConfig, FieldPermission, FieldPermissionMap, FieldPermissionType, PermissionCheck, PermissionContext, PermissionEventBus, PermissionResult, RoleHierarchy, UserBase, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, applyPermissionResult, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizePermissionResult, normalizeRoles, ownerWithAdminBypass, presets_d_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAuth, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, resolveEffectiveRoles, roles, when };
@@ -1,7 +1,7 @@
1
- import { K as MiddlewareConfig, Kt as ResourceRegistry, et as PresetHook, m as AnyRecord, mn as HookSystem, p as AdditionalRoute, vt as RouteSchemaOptions } from "../interface-IJqN3pXK.mjs";
2
- import { t as ExternalOpenApiPaths } from "../externalPaths-BQ8QijNH.mjs";
3
- import { _ as cachingPlugin, a as versioningPlugin, c as MetricsOptions, d as SSEOptions, f as _default$6, g as _default$1, h as CachingRule, i as _default$7, l as _default$4, m as CachingOptions, n as errorHandlerPlugin, o as MetricEntry, p as ssePlugin, r as VersioningOptions, s as MetricsCollector, t as ErrorHandlerOptions, u as metricsPlugin } from "../errorHandler-BeN-ERN7.mjs";
4
- import { t as TracingOptions } from "../tracing-xqXzWeaf.mjs";
1
+ import { K as MiddlewareConfig, Kt as ResourceRegistry, Tn as HookSystem, et as PresetHook, m as AnyRecord, p as AdditionalRoute, vt as RouteSchemaOptions } from "../interface-BVuMfeVv.mjs";
2
+ import { t as ExternalOpenApiPaths } from "../externalPaths-Bapitwvd.mjs";
3
+ import { _ as _default$1, a as _default$7, c as MetricsCollector, d as metricsPlugin, f as SSEOptions, g as CachingRule, h as CachingOptions, i as VersioningOptions, l as MetricsOptions, m as ssePlugin, n as ErrorMapper, o as versioningPlugin, p as _default$6, r as errorHandlerPlugin, s as MetricEntry, t as ErrorHandlerOptions, u as _default$4, v as cachingPlugin } from "../errorHandler-CdZDavNH.mjs";
4
+ import { t as TracingOptions } from "../tracing-DxjKk7eW.mjs";
5
5
  import { FastifyInstance, FastifyPluginAsync } from "fastify";
6
6
  import * as _$node_stream0 from "node:stream";
7
7
 
@@ -213,4 +213,4 @@ declare module "fastify" {
213
213
  declare const requestIdPlugin: FastifyPluginAsync<RequestIdOptions>;
214
214
  declare const _default$5: FastifyPluginAsync<RequestIdOptions>;
215
215
  //#endregion
216
- export { type ArcCore, type ArcCorePluginOptions, type ArcPlugin, type CachingOptions, type CachingRule, type CreatePluginDefinition, type ErrorHandlerOptions, 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, 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 };
216
+ 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, 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 };
@@ -1,15 +1,15 @@
1
1
  import { p as MUTATION_OPERATIONS } from "../constants-Cxde4rpC.mjs";
2
2
  import { o as getOrgId } from "../types-AOD8fxIw.mjs";
3
- import { t as requestContext } from "../requestContext-xHIKedG6.mjs";
3
+ import { t as requestContext } from "../requestContext-DYvHl113.mjs";
4
4
  import { t as hasEvents } from "../typeGuards-CcFZXgU7.mjs";
5
5
  import { t as HookSystem } from "../HookSystem-BjFu7zf1.mjs";
6
- import { t as ResourceRegistry } from "../ResourceRegistry-BOtJuRCs.mjs";
7
- import { n as caching_default, t as cachingPlugin } from "../caching-CHH-iHs3.mjs";
8
- import { t as errorHandlerPlugin } from "../errorHandler-BW08lEiy.mjs";
9
- import { n as metrics_default, t as metricsPlugin } from "../metrics-DuhiSEZI.mjs";
10
- import { t as replyHelpersPlugin } from "../replyHelpers-CXtJDAZ0.mjs";
11
- import { n as sse_default, t as ssePlugin } from "../sse-CD5Hghpu.mjs";
12
- import { n as versioning_default, t as versioningPlugin } from "../versioning-CPU_5Xfs.mjs";
6
+ import { t as ResourceRegistry } from "../ResourceRegistry-Dq3_zBQP.mjs";
7
+ import { n as caching_default, t as cachingPlugin } from "../caching-CjybdRwx.mjs";
8
+ import { t as errorHandlerPlugin } from "../errorHandler-mzqk4cGl.mjs";
9
+ import { n as metrics_default, t as metricsPlugin } from "../metrics-TuOmguhi.mjs";
10
+ import { t as replyHelpersPlugin } from "../replyHelpers-BLojtuvR.mjs";
11
+ import { n as sse_default, t as ssePlugin } from "../sse-CJpt7LGI.mjs";
12
+ import { n as versioning_default, t as versioningPlugin } from "../versioning-Cm8qoFDg.mjs";
13
13
  import { randomUUID } from "node:crypto";
14
14
  import fp from "fastify-plugin";
15
15
  //#region src/core/arcCorePlugin.ts
@@ -1,2 +1,2 @@
1
- import { a as traced, i as isTracingAvailable, n as _default, r as createSpan, t as TracingOptions } from "../tracing-xqXzWeaf.mjs";
1
+ import { a as traced, i as isTracingAvailable, n as _default, r as createSpan, t as TracingOptions } from "../tracing-DxjKk7eW.mjs";
2
2
  export { type TracingOptions, createSpan, isTracingAvailable, traced, _default as tracingPlugin };
@@ -44,7 +44,7 @@ try {
44
44
  function createTracerProvider(options) {
45
45
  if (!isAvailable) return null;
46
46
  const { serviceName = "@classytic/arc", serviceVersion, exporterUrl = "http://localhost:4318/v1/traces" } = options;
47
- const resolvedVersion = serviceVersion ?? "2.8.0";
47
+ const resolvedVersion = serviceVersion ?? "2.8.3";
48
48
  const exporter = new OTLPTraceExporter({ url: exporterUrl });
49
49
  const provider = new NodeTracerProvider({ resource: { attributes: {
50
50
  "service.name": serviceName,
@@ -1,4 +1,4 @@
1
- import { t as PermissionCheck } from "../types-BoaZHr-2.mjs";
1
+ import { t as PermissionCheck } from "../types-CVC4HOKi.mjs";
2
2
  import { FastifyReply, FastifyRequest } from "fastify";
3
3
 
4
4
  //#region src/policies/PolicyInterface.d.ts
@@ -1,4 +1,4 @@
1
- import { Ht as IControllerResponse, Ut as IRequestContext, Zt as PaginatedResult, m as AnyRecord, tt as PresetResult, ut as ResourceConfig } from "../interface-IJqN3pXK.mjs";
1
+ import { Ht as IControllerResponse, Ut as IRequestContext, m as AnyRecord, on as PaginationResult, tt as PresetResult, ut as ResourceConfig } from "../interface-BVuMfeVv.mjs";
2
2
  import { MultiTenantOptions, TenantFieldSpec, multiTenantPreset } from "./multiTenant.mjs";
3
3
 
4
4
  //#region src/presets/ownedByUser.d.ts
@@ -57,7 +57,7 @@ declare function treePreset(options?: TreeOptions): PresetResult;
57
57
  *
58
58
  * **Repository Requirements:**
59
59
  * Your repository must implement:
60
- * - `getDeleted(options): Promise<PaginatedResult<T> | T[]>`
60
+ * - `getDeleted(params?, options?): Promise<PaginationResult<T> | T[]>`
61
61
  * - `restore(id): Promise<T | null>`
62
62
  *
63
63
  * @example
@@ -77,7 +77,7 @@ interface ISoftDeleteController<TDoc = unknown> {
77
77
  * Get all soft-deleted items
78
78
  * Called by: GET /deleted
79
79
  */
80
- getDeleted(req: IRequestContext): Promise<IControllerResponse<PaginatedResult<TDoc>>>;
80
+ getDeleted(req: IRequestContext): Promise<IControllerResponse<PaginationResult<TDoc>>>;
81
81
  /**
82
82
  * Restore a soft-deleted item by ID
83
83
  * Called by: POST /:id/restore
@@ -1,3 +1,3 @@
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-BFrGvvjL.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-C2xgzW6x.mjs";
3
3
  export { applyPresets, auditedPreset, bulkPreset, flexibleMultiTenantPreset, getAvailablePresets, getPreset, multiTenantPreset, ownedByUserPreset, registerPreset, slugLookupPreset, softDeletePreset, treePreset };
@@ -1,4 +1,4 @@
1
- import { E as CrudRouteKey, tt as PresetResult } from "../interface-IJqN3pXK.mjs";
1
+ import { E as CrudRouteKey, tt as PresetResult } from "../interface-BVuMfeVv.mjs";
2
2
 
3
3
  //#region src/presets/multiTenant.d.ts
4
4
  /**
@@ -41,13 +41,12 @@ function slugLookupPreset(options = {}) {
41
41
  const { slugField = "slug" } = options;
42
42
  return {
43
43
  name: "slugLookup",
44
- additionalRoutes: (permissions) => [{
44
+ routes: (permissions) => [{
45
45
  method: "GET",
46
46
  path: `/slug/:${slugField}`,
47
47
  handler: "getBySlug",
48
48
  summary: "Get by slug",
49
49
  permissions: permissions.get ?? allowPublic(),
50
- wrapHandler: true,
51
50
  operation: "getBySlug"
52
51
  }],
53
52
  controllerOptions: { slugField }
@@ -65,13 +64,12 @@ function slugLookupPreset(options = {}) {
65
64
  function softDeletePreset() {
66
65
  return {
67
66
  name: "softDelete",
68
- additionalRoutes: (permissions) => [{
67
+ routes: (permissions) => [{
69
68
  method: "GET",
70
69
  path: "/deleted",
71
70
  handler: "getDeleted",
72
71
  summary: "Get soft-deleted items",
73
72
  permissions: permissions.list ?? requireRoles(["admin"]),
74
- wrapHandler: true,
75
73
  operation: "listDeleted"
76
74
  }, {
77
75
  method: "POST",
@@ -79,7 +77,6 @@ function softDeletePreset() {
79
77
  handler: "restore",
80
78
  summary: "Restore soft-deleted item",
81
79
  permissions: permissions.update ?? requireRoles(["admin"]),
82
- wrapHandler: true,
83
80
  operation: "restore"
84
81
  }]
85
82
  };
@@ -153,13 +150,12 @@ function bulkPreset(opts) {
153
150
  const maxCreateItems = opts?.maxCreateItems ?? 1e3;
154
151
  return {
155
152
  name: "bulk",
156
- additionalRoutes: (permissions) => {
153
+ routes: (permissions) => {
157
154
  const routes = [];
158
155
  if (operations.includes("createMany")) routes.push({
159
156
  method: "POST",
160
157
  path: "/bulk",
161
158
  handler: "bulkCreate",
162
- wrapHandler: true,
163
159
  operation: "bulkCreate",
164
160
  summary: "Create multiple items",
165
161
  permissions: permissions.create ?? requireAuth(),
@@ -190,7 +186,6 @@ function bulkPreset(opts) {
190
186
  method: "PATCH",
191
187
  path: "/bulk",
192
188
  handler: "bulkUpdate",
193
- wrapHandler: true,
194
189
  operation: "bulkUpdate",
195
190
  summary: "Update multiple items matching filter",
196
191
  permissions: permissions.update ?? requireAuth(),
@@ -222,7 +217,6 @@ function bulkPreset(opts) {
222
217
  method: "DELETE",
223
218
  path: "/bulk",
224
219
  handler: "bulkDelete",
225
- wrapHandler: true,
226
220
  operation: "bulkDelete",
227
221
  summary: "Delete multiple items matching filter",
228
222
  permissions: permissions.delete ?? requireAuth(),
@@ -259,13 +253,12 @@ function treePreset(options = {}) {
259
253
  const { parentField = "parent" } = options;
260
254
  return {
261
255
  name: "tree",
262
- additionalRoutes: (permissions) => [{
256
+ routes: (permissions) => [{
263
257
  method: "GET",
264
258
  path: "/tree",
265
259
  handler: "getTree",
266
260
  summary: "Get hierarchical tree",
267
261
  permissions: permissions.list ?? allowPublic(),
268
- wrapHandler: true,
269
262
  operation: "getTree"
270
263
  }, {
271
264
  method: "GET",
@@ -273,7 +266,6 @@ function treePreset(options = {}) {
273
266
  handler: "getChildren",
274
267
  summary: "Get children of parent",
275
268
  permissions: permissions.list ?? allowPublic(),
276
- wrapHandler: true,
277
269
  operation: "getChildren"
278
270
  }],
279
271
  controllerOptions: { parentField }
@@ -341,8 +333,8 @@ function validatePresetCombination(presets) {
341
333
  const routeMap = /* @__PURE__ */ new Map();
342
334
  for (const preset of presets) {
343
335
  const name = preset.name ?? "unknown";
344
- const routes = typeof preset.additionalRoutes === "function" ? preset.additionalRoutes({}) : preset.additionalRoutes ?? [];
345
- for (const route of routes) {
336
+ const presetRoutes = preset.routes ? typeof preset.routes === "function" ? preset.routes({}) : preset.routes : [];
337
+ for (const route of presetRoutes) {
346
338
  const key = `${route.method} ${route.path}`;
347
339
  const existing = routeMap.get(key);
348
340
  if (existing) conflicts.push({
@@ -371,7 +363,7 @@ function applyPresets(config, presets = []) {
371
363
  * Resolve preset input to PresetResult
372
364
  */
373
365
  function resolvePresetInput(preset) {
374
- if (typeof preset === "object" && ("middlewares" in preset || "additionalRoutes" in preset)) return preset;
366
+ if (typeof preset === "object" && ("middlewares" in preset || "routes" in preset)) return preset;
375
367
  if (typeof preset === "object" && "name" in preset) {
376
368
  const { name, ...options } = preset;
377
369
  return resolvePreset(name, options);
@@ -383,9 +375,9 @@ function resolvePresetInput(preset) {
383
375
  */
384
376
  function mergePreset(config, preset) {
385
377
  const result = { ...config };
386
- if (preset.additionalRoutes) {
387
- const routes = typeof preset.additionalRoutes === "function" ? preset.additionalRoutes(config.permissions ?? {}) : preset.additionalRoutes;
388
- result.additionalRoutes = [...result.additionalRoutes ?? [], ...routes];
378
+ if (preset.routes) {
379
+ const resolved = typeof preset.routes === "function" ? preset.routes(config.permissions ?? {}) : preset.routes;
380
+ result.routes = [...result.routes ?? [], ...resolved];
389
381
  }
390
382
  if (preset.middlewares) {
391
383
  result.middlewares = result.middlewares ?? {};
@@ -1,4 +1,4 @@
1
- import { i as CacheStore } from "./interface-bpoLKKqx.mjs";
1
+ import { i as CacheStore } from "./interface-DplgQO2e.mjs";
2
2
  import { FastifyPluginAsync } from "fastify";
3
3
 
4
4
  //#region src/cache/QueryCache.d.ts
@@ -1,4 +1,4 @@
1
- import { i as EventTransport, n as EventHandler, r as EventLogger, t as DomainEvent } from "./EventTransport-n1KBxC_N.mjs";
1
+ import { i as EventTransport, n as EventHandler, r as EventLogger, t as DomainEvent } from "./EventTransport-CinyO7zQ.mjs";
2
2
 
3
3
  //#region src/events/transports/redis-stream.d.ts
4
4
  interface RedisStreamLike {
@@ -1,4 +1,4 @@
1
- import { n as IdempotencyResult, r as IdempotencyStore } from "./interface-CkkWm5uR.mjs";
1
+ import { n as IdempotencyResult, r as IdempotencyStore } from "./interface-B-pe8fhj.mjs";
2
2
 
3
3
  //#region src/idempotency/stores/redis.d.ts
4
4
  interface RedisClient {
@@ -1,4 +1,4 @@
1
- import { Gt as RegisterOptions, H as IntrospectionPluginOptions, Kt as ResourceRegistry } from "../interface-IJqN3pXK.mjs";
1
+ import { Gt as RegisterOptions, H as IntrospectionPluginOptions, Kt as ResourceRegistry } from "../interface-BVuMfeVv.mjs";
2
2
  import { FastifyPluginAsync } from "fastify";
3
3
 
4
4
  //#region src/registry/introspectionPlugin.d.ts
@@ -1,3 +1,3 @@
1
1
  import { n as introspectionPlugin_default, t as introspectionPlugin } from "../registry-B0Wl7uVV.mjs";
2
- import { t as ResourceRegistry } from "../ResourceRegistry-BOtJuRCs.mjs";
2
+ import { t as ResourceRegistry } from "../ResourceRegistry-Dq3_zBQP.mjs";
3
3
  export { ResourceRegistry, introspectionPlugin_default as introspectionPlugin, introspectionPlugin as introspectionPluginFn };