@classytic/arc 2.8.5 → 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 (155) hide show
  1. package/README.md +50 -38
  2. package/dist/{BaseController-DAGGc5Xn.mjs → BaseController-CbKKIflT.mjs} +193 -143
  3. package/dist/EventTransport-CUw5NNWe.d.mts +293 -0
  4. package/dist/{ResourceRegistry-C6uXlWe3.mjs → ResourceRegistry-BPd6NQDm.mjs} +1 -1
  5. package/dist/adapters/index.d.mts +3 -3
  6. package/dist/adapters/index.mjs +2 -2
  7. package/dist/{adapters-BBqAVvPK.mjs → adapters-BXY4i-hw.mjs} +210 -41
  8. package/dist/audit/index.d.mts +135 -11
  9. package/dist/audit/index.mjs +107 -20
  10. package/dist/auth/index.d.mts +17 -9
  11. package/dist/auth/index.mjs +14 -7
  12. package/dist/auth/redis-session.d.mts +1 -1
  13. package/dist/{betterAuthOpenApi-BuUcUEJq.mjs → betterAuthOpenApi-BBRVhjQN.mjs} +1 -1
  14. package/dist/cache/index.d.mts +17 -15
  15. package/dist/cache/index.mjs +15 -14
  16. package/dist/{caching-IMuYVjTL.mjs → caching-CBpK_SCM.mjs} +8 -3
  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 +1 -1
  21. package/dist/cli/commands/introspect.mjs +1 -1
  22. package/dist/core/index.d.mts +3 -3
  23. package/dist/core/index.mjs +4 -6
  24. package/dist/{defineResource-tcgySDo1.mjs → core-CcR01lup.mjs} +58 -61
  25. package/dist/{createActionRouter-BORM8f17.mjs → createActionRouter-Bp_5c_2b.mjs} +3 -3
  26. package/dist/{createApp-B1EY8zxa.mjs → createApp-BuvPma24.mjs} +15 -14
  27. package/dist/docs/index.d.mts +2 -2
  28. package/dist/docs/index.mjs +2 -2
  29. package/dist/{elevation-DtFxrG0s.mjs → elevation-C7hgL_aI.mjs} +22 -8
  30. package/dist/{errorHandler-f869_8PQ.mjs → errorHandler-Bb49BvPD.mjs} +59 -7
  31. package/dist/{errorHandler-Bah5JhBd.d.mts → errorHandler-DRQ3EqfL.d.mts} +37 -2
  32. package/dist/{eventPlugin-D9DKB2zM.d.mts → eventPlugin-CxWgpd6K.d.mts} +14 -2
  33. package/dist/{eventPlugin-CDjVTM82.mjs → eventPlugin-DCUjuiQT.mjs} +83 -5
  34. package/dist/events/index.d.mts +150 -36
  35. package/dist/events/index.mjs +355 -101
  36. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  37. package/dist/events/transports/redis.d.mts +1 -1
  38. package/dist/factory/index.d.mts +1 -1
  39. package/dist/factory/index.mjs +2 -2
  40. package/dist/{types-DZi1aYhm.d.mts → fields-Lo1VUDpt.d.mts} +121 -1
  41. package/dist/{fields-ipsbIRPK.mjs → fields-bxkeltzz.mjs} +18 -5
  42. package/dist/{filesUpload-C7r7HIeA.mjs → filesUpload-t21LS-py.mjs} +65 -7
  43. package/dist/hooks/index.d.mts +1 -1
  44. package/dist/hooks/index.mjs +1 -1
  45. package/dist/idempotency/index.d.mts +32 -5
  46. package/dist/idempotency/index.mjs +119 -12
  47. package/dist/idempotency/redis.d.mts +1 -1
  48. package/dist/{index-DtDzOBn8.d.mts → index-8qw4y6ff.d.mts} +4 -135
  49. package/dist/{index-BLXBmWud.d.mts → index-ChIw3776.d.mts} +283 -408
  50. package/dist/{interface-CMRutPfe.d.mts → index-Cl0uoKd5.d.mts} +1758 -2506
  51. package/dist/{index-C1meYuDn.d.mts → index-DStwgFUK.d.mts} +81 -7
  52. package/dist/index.d.mts +7 -8
  53. package/dist/index.mjs +11 -12
  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 +26 -8
  58. package/dist/integrations/mcp/index.mjs +96 -17
  59. package/dist/integrations/mcp/testing.d.mts +1 -1
  60. package/dist/integrations/mcp/testing.mjs +1 -1
  61. package/dist/integrations/webhooks.d.mts +5 -0
  62. package/dist/integrations/webhooks.mjs +6 -0
  63. package/dist/interface-D218ikEo.d.mts +77 -0
  64. package/dist/{memory-Cp7_cAko.mjs → memory-B5Amv9A1.mjs} +23 -8
  65. package/dist/{openapi-CbKUJY_m.mjs → openapi-B5F8AddX.mjs} +3 -3
  66. package/dist/org/index.d.mts +2 -2
  67. package/dist/permissions/index.d.mts +3 -4
  68. package/dist/permissions/index.mjs +5 -5
  69. package/dist/{permissions-CH4cNwJi.mjs → permissions-Dk6mshja.mjs} +315 -397
  70. package/dist/plugins/index.d.mts +7 -7
  71. package/dist/plugins/index.mjs +14 -16
  72. package/dist/plugins/response-cache.mjs +2 -2
  73. package/dist/plugins/tracing-entry.d.mts +1 -1
  74. package/dist/plugins/tracing-entry.mjs +1 -1
  75. package/dist/presets/filesUpload.d.mts +27 -5
  76. package/dist/presets/filesUpload.mjs +1 -1
  77. package/dist/presets/index.d.mts +3 -2
  78. package/dist/presets/index.mjs +4 -3
  79. package/dist/presets/multiTenant.d.mts +1 -1
  80. package/dist/presets/multiTenant.mjs +2 -2
  81. package/dist/presets/search.d.mts +178 -0
  82. package/dist/presets/search.mjs +150 -0
  83. package/dist/{presets-C2xgzW6x.mjs → presets-fLJVXdVn.mjs} +1 -1
  84. package/dist/{queryCachePlugin-BJJGBTlu.d.mts → queryCachePlugin-BKbWjgDG.d.mts} +1 -1
  85. package/dist/{queryCachePlugin-BH-fidlv.mjs → queryCachePlugin-DQCEfJis.mjs} +9 -9
  86. package/dist/{queryParser-CgCtsjti.mjs → queryParser-DBqBB6AC.mjs} +1 -1
  87. package/dist/{redis-BM00zaPB.d.mts → redis-DqyeggCa.d.mts} +1 -1
  88. package/dist/{redis-stream-CrsfUmPt.d.mts → redis-stream-CakIQmwR.d.mts} +1 -1
  89. package/dist/registry/index.d.mts +1 -1
  90. package/dist/registry/index.mjs +2 -2
  91. package/dist/{resourceToTools-8s-EsCCe.mjs → resourceToTools-BElv3xPT.mjs} +65 -48
  92. package/dist/{schemaConverter-Y7nCYaLJ.mjs → schemaConverter-BxFDdtXu.mjs} +1 -1
  93. package/dist/scope/index.d.mts +1 -1
  94. package/dist/scope/index.mjs +2 -2
  95. package/dist/{sse-Ad7ypl9e.mjs → sse-yBCgOLGu.mjs} +1 -1
  96. package/dist/store-helpers-ZCSMJJAX.mjs +57 -0
  97. package/dist/testing/index.d.mts +9 -17
  98. package/dist/testing/index.mjs +27 -83
  99. package/dist/testing/storageContract.d.mts +1 -1
  100. package/dist/types/index.d.mts +4 -4
  101. package/dist/types/index.mjs +1 -31
  102. package/dist/types/storage.d.mts +1 -1
  103. package/dist/{types-BsbNMEDR.d.mts → types-Btdda02s.d.mts} +1 -1
  104. package/dist/{types-Ch9pTQbf.d.mts → types-Co8k3NyS.d.mts} +11 -9
  105. package/dist/types-Csi3FLfq.mjs +27 -0
  106. package/dist/utils/index.d.mts +208 -4
  107. package/dist/utils/index.mjs +5 -6
  108. package/dist/{utils-yYT3HDXt.mjs → utils-B2fNOD_i.mjs} +285 -2
  109. package/dist/{versioning-CDugduqI.mjs → versioning-C2U_bLY0.mjs} +3 -5
  110. package/package.json +20 -26
  111. package/skills/arc/SKILL.md +97 -23
  112. package/skills/arc/references/auth.md +94 -0
  113. package/skills/arc/references/events.md +200 -12
  114. package/skills/arc/references/mcp.md +4 -17
  115. package/skills/arc/references/multi-tenancy.md +43 -0
  116. package/skills/arc/references/production.md +34 -60
  117. package/dist/EventTransport-BXja8NOc.d.mts +0 -135
  118. package/dist/audit/mongodb.d.mts +0 -2
  119. package/dist/audit/mongodb.mjs +0 -2
  120. package/dist/circuitBreaker-cmi5XDv5.mjs +0 -284
  121. package/dist/circuitBreaker-dTtG-UyS.d.mts +0 -206
  122. package/dist/core-F0QoWBt2.mjs +0 -34
  123. package/dist/dynamic/index.d.mts +0 -93
  124. package/dist/dynamic/index.mjs +0 -122
  125. package/dist/fields-DpZQa_Q3.d.mts +0 -109
  126. package/dist/idempotency/mongodb.d.mts +0 -2
  127. package/dist/idempotency/mongodb.mjs +0 -123
  128. package/dist/interface-4y979v99.d.mts +0 -54
  129. package/dist/mongodb-BsP-WbhN.d.mts +0 -127
  130. package/dist/mongodb-CTcp0hQZ.d.mts +0 -80
  131. package/dist/mongodb-Utc5k_-0.mjs +0 -90
  132. package/dist/policies/index.d.mts +0 -432
  133. package/dist/policies/index.mjs +0 -318
  134. package/dist/rpc/index.d.mts +0 -90
  135. package/dist/rpc/index.mjs +0 -248
  136. /package/dist/{HookSystem-HprTmvVY.mjs → HookSystem-BNYKnrXF.mjs} +0 -0
  137. /package/dist/{applyPermissionResult-D6GPMsvh.mjs → applyPermissionResult-QhV1Pa-g.mjs} +0 -0
  138. /package/dist/{constants-Cxde4rpC.mjs → constants-BhY1OHoH.mjs} +0 -0
  139. /package/dist/{elevation-B6S5csVA.d.mts → elevation-C5SwtkAn.d.mts} +0 -0
  140. /package/dist/{errors-Ck2h67pm.d.mts → errors-CCSsMpXE.d.mts} +0 -0
  141. /package/dist/{errors-BF2bIOIS.mjs → errors-D5c-5BJL.mjs} +0 -0
  142. /package/dist/{externalPaths-BnkYrNzp.d.mts → externalPaths-BQ8QijNH.d.mts} +0 -0
  143. /package/dist/{interface-DfLGcus7.d.mts → interface-CSbZdv_3.d.mts} +0 -0
  144. /package/dist/{loadResources-PWd0OCpV.mjs → loadResources-BAzJItAJ.mjs} +0 -0
  145. /package/dist/{logger-D1YrIImS.mjs → logger-DLg8-Ueg.mjs} +0 -0
  146. /package/dist/{metrics-B-PU4-Yu.mjs → metrics-DuhiSEZI.mjs} +0 -0
  147. /package/dist/{pluralize-CWP6MB39.mjs → pluralize-A0tWEl1K.mjs} +0 -0
  148. /package/dist/{registry-BiTKT1Dg.mjs → registry-B3lRFBWo.mjs} +0 -0
  149. /package/dist/{replyHelpers-CxkYGT81.mjs → replyHelpers-CXtJDAZ0.mjs} +0 -0
  150. /package/dist/{requestContext-DYvHl113.mjs → requestContext-xHIKedG6.mjs} +0 -0
  151. /package/dist/{sessionManager-DDCmiNIo.d.mts → sessionManager-BkzVU8h2.d.mts} +0 -0
  152. /package/dist/{storage-Dfzt4VTl.d.mts → storage-CVk_SEn2.d.mts} +0 -0
  153. /package/dist/{tracing-DdN2-wHJ.d.mts → tracing-65B51Dw3.d.mts} +0 -0
  154. /package/dist/{typeGuards-CcFZXgU7.mjs → typeGuards-Cj5Rgvlg.mjs} +0 -0
  155. /package/dist/{types-ZUu_h0jp.mjs → types-DV9WDfeg.mjs} +0 -0
@@ -1,4 +1,4 @@
1
- import { Gt as RegisterOptions, H as IntrospectionPluginOptions, Kt as ResourceRegistry } from "../interface-CMRutPfe.mjs";
1
+ import { O as IntrospectionPluginOptions, U as RegisterOptions, W as ResourceRegistry } from "../index-Cl0uoKd5.mjs";
2
2
  import { FastifyPluginAsync } from "fastify";
3
3
 
4
4
  //#region src/registry/introspectionPlugin.d.ts
@@ -1,3 +1,3 @@
1
- import { n as introspectionPlugin_default, t as introspectionPlugin } from "../registry-BiTKT1Dg.mjs";
2
- import { t as ResourceRegistry } from "../ResourceRegistry-C6uXlWe3.mjs";
1
+ import { n as introspectionPlugin_default, t as introspectionPlugin } from "../registry-B3lRFBWo.mjs";
2
+ import { t as ResourceRegistry } from "../ResourceRegistry-BPd6NQDm.mjs";
3
3
  export { ResourceRegistry, introspectionPlugin_default as introspectionPlugin, introspectionPlugin as introspectionPluginFn };
@@ -1,6 +1,6 @@
1
- import { t as BaseController } from "./BaseController-DAGGc5Xn.mjs";
2
- import { n as normalizePermissionResult } from "./applyPermissionResult-D6GPMsvh.mjs";
3
- import { t as pluralize } from "./pluralize-CWP6MB39.mjs";
1
+ import { t as BaseController } from "./BaseController-CbKKIflT.mjs";
2
+ import { n as normalizePermissionResult } from "./applyPermissionResult-QhV1Pa-g.mjs";
3
+ import { t as pluralize } from "./pluralize-A0tWEl1K.mjs";
4
4
  import { z } from "zod";
5
5
  //#region src/integrations/mcp/createMcpServer.ts
6
6
  /**
@@ -568,7 +568,7 @@ function resourceToTools(resource, config = {}) {
568
568
  const hasSoftDelete = resource._appliedPresets?.includes("softDelete") ?? false;
569
569
  const tools = [];
570
570
  const prefix = config.toolNamePrefix;
571
- if (!controller) {} else {
571
+ if (controller) {
572
572
  let ops = ALL_CRUD_OPS.filter((op) => {
573
573
  if (resource.disabledRoutes?.includes(op)) return false;
574
574
  return true;
@@ -595,50 +595,51 @@ function resourceToTools(resource, config = {}) {
595
595
  handler: createHandler(op, controller, resource.name, resource.permissions)
596
596
  });
597
597
  }
598
- for (const route of resource.additionalRoutes ?? []) {
599
- if (route.mcp === false) continue;
600
- const mcpHandler = route.mcpHandler;
601
- if (!route.wrapHandler && !mcpHandler) continue;
602
- if (!mcpHandler && ![
603
- "POST",
604
- "PUT",
605
- "PATCH",
606
- "DELETE"
607
- ].includes(route.method)) continue;
608
- const opName = route.operation ?? slugifyRoute(route.method, route.path);
609
- const hasId = route.path.includes(":id");
610
- const mcpConfig = typeof route.mcp === "object" && route.mcp !== null ? route.mcp : void 0;
611
- const toolDescription = mcpConfig?.description ?? route.summary ?? route.description ?? `${opName} on ${resource.displayName}`;
612
- const toolAnnotations = mcpConfig?.annotations ? { ...mcpConfig.annotations } : { openWorldHint: true };
613
- const inputShape = {};
614
- if (hasId) inputShape.id = z.string().describe("Resource ID");
615
- if (mcpHandler) tools.push({
616
- name: prefix ? `${prefix}_${opName}_${resource.name}` : `${opName}_${resource.name}`,
617
- description: toolDescription,
618
- annotations: toolAnnotations,
619
- inputSchema: inputShape,
620
- handler: async (input, _ctx) => {
621
- try {
622
- return await mcpHandler(input);
623
- } catch (err) {
624
- return {
625
- content: [{
626
- type: "text",
627
- text: `Error: ${err instanceof Error ? err.message : String(err)}`
628
- }],
629
- isError: true
630
- };
631
- }
598
+ }
599
+ for (const route of resource.routes ?? []) {
600
+ if (route.mcp === false) continue;
601
+ const mcpHandler = route.mcpHandler;
602
+ if (!!route.raw && !mcpHandler) continue;
603
+ if (!mcpHandler && ![
604
+ "POST",
605
+ "PUT",
606
+ "PATCH",
607
+ "DELETE"
608
+ ].includes(route.method)) continue;
609
+ if (!mcpHandler && typeof route.handler === "string" && !controller) continue;
610
+ const opName = route.operation ?? slugifyRoute(route.method, route.path);
611
+ const hasId = route.path.includes(":id");
612
+ const mcpConfig = typeof route.mcp === "object" && route.mcp !== null ? route.mcp : void 0;
613
+ const toolDescription = mcpConfig?.description ?? route.summary ?? route.description ?? `${opName} on ${resource.displayName}`;
614
+ const toolAnnotations = mcpConfig?.annotations ? { ...mcpConfig.annotations } : { openWorldHint: true };
615
+ const inputShape = {};
616
+ if (hasId) inputShape.id = z.string().describe("Resource ID");
617
+ if (mcpHandler) tools.push({
618
+ name: prefix ? `${prefix}_${opName}_${resource.name}` : `${opName}_${resource.name}`,
619
+ description: toolDescription,
620
+ annotations: toolAnnotations,
621
+ inputSchema: inputShape,
622
+ handler: async (input, _ctx) => {
623
+ try {
624
+ return await mcpHandler(input);
625
+ } catch (err) {
626
+ return {
627
+ content: [{
628
+ type: "text",
629
+ text: `Error: ${err instanceof Error ? err.message : String(err)}`
630
+ }],
631
+ isError: true
632
+ };
632
633
  }
633
- });
634
- else tools.push({
635
- name: prefix ? `${prefix}_${opName}_${resource.name}` : `${opName}_${resource.name}`,
636
- description: toolDescription,
637
- annotations: toolAnnotations,
638
- inputSchema: inputShape,
639
- handler: createAdditionalRouteHandler(route, controller, hasId)
640
- });
641
- }
634
+ }
635
+ });
636
+ else tools.push({
637
+ name: prefix ? `${prefix}_${opName}_${resource.name}` : `${opName}_${resource.name}`,
638
+ description: toolDescription,
639
+ annotations: toolAnnotations,
640
+ inputSchema: inputShape,
641
+ handler: createCustomRouteHandler(route, controller, hasId)
642
+ });
642
643
  }
643
644
  if (resource.actions) for (const [actionName, entry] of Object.entries(resource.actions)) {
644
645
  const def = typeof entry === "function" ? { handler: entry } : entry;
@@ -757,11 +758,27 @@ function createHandler(op, controller, resourceName, permissions) {
757
758
  }
758
759
  };
759
760
  }
760
- function createAdditionalRouteHandler(route, controller, hasId) {
761
+ function createCustomRouteHandler(route, controller, hasId) {
761
762
  const ctrl = controller;
762
763
  const handlerName = typeof route.handler === "string" ? route.handler : route.operation ?? slugifyRoute(route.method, route.path);
763
764
  return async (input, ctx) => {
764
765
  try {
766
+ if (typeof route.handler === "function") {
767
+ const reqCtx = buildRequestContext(input, ctx.session, hasId ? "update" : "create");
768
+ const fn = route.handler;
769
+ const out = await fn(reqCtx);
770
+ return toCallToolResult(out !== null && typeof out === "object" && "success" in out ? out : {
771
+ success: true,
772
+ data: out
773
+ });
774
+ }
775
+ if (!ctrl) return {
776
+ content: [{
777
+ type: "text",
778
+ text: `Handler "${handlerName}" has no controller available`
779
+ }],
780
+ isError: true
781
+ };
765
782
  const method = ctrl[handlerName];
766
783
  if (typeof method !== "function") return {
767
784
  content: [{
@@ -85,7 +85,7 @@ function convertOpenApiSchemas(schemas, target = DEFAULT_OPENAPI_TARGET) {
85
85
  *
86
86
  * JSON Schema values pass through unchanged. Only Zod schemas are converted.
87
87
  *
88
- * Used for both additionalRoutes and customSchemas (CRUD overrides).
88
+ * Used for both custom routes and customSchemas (CRUD overrides).
89
89
  *
90
90
  * Defaults to `draft-7` so Fastify v5's bundled AJV 8 accepts the output.
91
91
  * Pass `openapi-3.0` (or `openapi-3.1`) when generating OpenAPI documents.
@@ -1,5 +1,5 @@
1
+ import { i as elevationPlugin, n as ElevationOptions, r as _default, t as ElevationEvent } from "../elevation-C5SwtkAn.mjs";
1
2
  import { _ as isAuthenticated, a as getClientId, b as isOrgInScope, c as getOrgRoles, d as getScopeContextMap, f as getServiceScopes, g as hasOrgAccess, h as getUserRoles, i as getAncestorOrgIds, l as getRequestScope, m as getUserId, n as PUBLIC_SCOPE, o as getOrgContext, p as getTeamId, r as RequestScope, s as getOrgId, t as AUTHENTICATED_SCOPE, u as getScopeContext, v as isElevated, x as isService, y as isMember } from "../types-BD85MlEK.mjs";
2
- import { i as elevationPlugin, n as ElevationOptions, r as _default, t as ElevationEvent } from "../elevation-B6S5csVA.mjs";
3
3
  import { FastifyReply, FastifyRequest } from "fastify";
4
4
 
5
5
  //#region src/scope/rateLimitKey.d.ts
@@ -1,6 +1,6 @@
1
1
  import { _ as isElevated, a as getOrgContext, b as isService, c as getRequestScope, d as getServiceScopes, f as getTeamId, g as isAuthenticated, h as hasOrgAccess, i as getClientId, l as getScopeContext, m as getUserRoles, n as PUBLIC_SCOPE, o as getOrgId, p as getUserId, r as getAncestorOrgIds, s as getOrgRoles, t as AUTHENTICATED_SCOPE, u as getScopeContextMap, v as isMember, y as isOrgInScope } from "../types-AOD8fxIw.mjs";
2
- import { n as normalizeRoles } from "../types-ZUu_h0jp.mjs";
3
- import { n as elevation_default, t as elevationPlugin } from "../elevation-DtFxrG0s.mjs";
2
+ import { n as normalizeRoles } from "../types-DV9WDfeg.mjs";
3
+ import { n as elevation_default, t as elevationPlugin } from "../elevation-C7hgL_aI.mjs";
4
4
  //#region src/scope/rateLimitKey.ts
5
5
  function createTenantKeyGenerator(opts) {
6
6
  if (opts?.strategy) return opts.strategy;
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
2
2
  import { n as PUBLIC_SCOPE, o as getOrgId } from "./types-AOD8fxIw.mjs";
3
- import { t as arcLog } from "./logger-D1YrIImS.mjs";
3
+ import { t as arcLog } from "./logger-DLg8-Ueg.mjs";
4
4
  import fp from "fastify-plugin";
5
5
  //#region src/plugins/sse.ts
6
6
  var sse_exports = /* @__PURE__ */ __exportAll({
@@ -0,0 +1,57 @@
1
+ //#region src/adapters/store-helpers.ts
2
+ /**
3
+ * Classify an error thrown by `getOne` / `getById` / `update` as a
4
+ * "document not found" miss. Mongokit uses `status: 404`, Prisma uses
5
+ * `code: 'P2025'`, some kits throw `DocumentNotFoundError`. Kits that
6
+ * return `null` on miss never see this predicate fire — it only kicks in
7
+ * when a driver chose to throw.
8
+ */
9
+ function isNotFoundError(err) {
10
+ if (!err || typeof err !== "object") return false;
11
+ const e = err;
12
+ if (e.status === 404 || e.statusCode === 404) return true;
13
+ if (e.code === "P2025") return true;
14
+ if (e.name === "DocumentNotFoundError") return true;
15
+ return false;
16
+ }
17
+ /**
18
+ * Build a `safeGetOne(filter)` that papers over the throw-vs-null split
19
+ * in kit implementations. Real errors propagate; miss returns `null`.
20
+ * Throws if the repository lacks `getOne` — callers must check.
21
+ */
22
+ function createSafeGetOne(repository) {
23
+ if (typeof repository.getOne !== "function") throw new Error("createSafeGetOne: repository.getOne is required");
24
+ const getOne = repository.getOne.bind(repository);
25
+ return async (filter) => {
26
+ try {
27
+ return await getOne(filter) ?? null;
28
+ } catch (err) {
29
+ if (isNotFoundError(err)) return null;
30
+ throw err;
31
+ }
32
+ };
33
+ }
34
+ /**
35
+ * Build a dup-key predicate for the given repository. Prefers the kit's
36
+ * own `isDuplicateKeyError` (it knows its driver — Mongo `11000`, Prisma
37
+ * `P2002`, Postgres `23505`, MySQL `1062`, etc.); falls back to a
38
+ * conservative Mongo check so mongokit ≤3.8 keeps working without changes.
39
+ *
40
+ * Non-mongo kits MUST implement the predicate to participate in
41
+ * idempotency/outbox dup-handling semantics.
42
+ *
43
+ * `name === "MongoServerError"` alone is deliberately NOT matched — that
44
+ * also fires on WriteConflict / NotWritablePrimary / transient failures,
45
+ * which must propagate rather than silently become 409s.
46
+ */
47
+ function createIsDuplicateKeyError(repository) {
48
+ const repoPredicate = typeof repository.isDuplicateKeyError === "function" ? repository.isDuplicateKeyError.bind(repository) : null;
49
+ return (err) => {
50
+ if (repoPredicate) return repoPredicate(err);
51
+ if (!err || typeof err !== "object") return false;
52
+ const e = err;
53
+ return e.code === 11e3 || e.codeName === "DuplicateKey";
54
+ };
55
+ }
56
+ //#endregion
57
+ export { createSafeGetOne as n, createIsDuplicateKeyError as t };
@@ -1,9 +1,10 @@
1
- import { Zt as CrudRepository, m as AnyRecord, qt as ResourceDefinition } from "../interface-CMRutPfe.mjs";
2
- import { d as ResourceLike, r as CreateAppOptions } from "../types-Ch9pTQbf.mjs";
1
+ import { G as ResourceDefinition, dn as AnyRecord } from "../index-Cl0uoKd5.mjs";
2
+ import { d as ResourceLike, r as CreateAppOptions } from "../types-Co8k3NyS.mjs";
3
3
  import { StorageContractSetup, StorageContractSetupResult, runStorageContract } from "./storageContract.mjs";
4
4
  import Fastify, { FastifyInstance, FastifyServerOptions } from "fastify";
5
5
  import { Connection } from "mongoose";
6
6
  import { Mock } from "vitest";
7
+ import { StandardRepo } from "@classytic/repo-core/repository";
7
8
 
8
9
  //#region src/testing/authHelpers.d.ts
9
10
  interface BetterAuthTestHelpersOptions {
@@ -478,7 +479,7 @@ declare function createHttpTestHarness<T = unknown>(resource: ResourceDefinition
478
479
  /**
479
480
  * Extended repository interface for testing (includes optional preset methods)
480
481
  */
481
- interface MockRepository<T> extends CrudRepository<T> {
482
+ interface MockRepository<T> extends StandardRepo<T> {
482
483
  getBySlug?: Mock;
483
484
  getDeleted?: Mock;
484
485
  restore?: Mock;
@@ -519,8 +520,8 @@ declare function createMockReply(): unknown;
519
520
  /**
520
521
  * Create a mock controller for testing
521
522
  */
522
- declare function createMockController(repository: CrudRepository<AnyRecord>): {
523
- repository: CrudRepository<AnyRecord>;
523
+ declare function createMockController(repository: StandardRepo<AnyRecord>): {
524
+ repository: StandardRepo<AnyRecord>;
524
525
  list: Mock<(...args: any[]) => any>;
525
526
  get: Mock<(...args: any[]) => any>;
526
527
  create: Mock<(...args: any[]) => any>;
@@ -631,21 +632,12 @@ declare class TestHarness<T = unknown> {
631
632
  private _createdIds;
632
633
  constructor(resource: ResourceDefinition<unknown>, options: TestHarnessOptions<T>);
633
634
  /**
634
- * Run all baseline tests
635
+ * Run all baseline tests (schema, presets, field permissions, pipeline, events).
635
636
  *
636
- * Executes CRUD, validation, and preset tests
637
+ * For HTTP-level CRUD coverage (routes, auth, permissions), use
638
+ * {@link HttpTestHarness} instead.
637
639
  */
638
640
  runAll(): void;
639
- /**
640
- * Run CRUD operation tests (model-level)
641
- *
642
- * Tests: create, read (list + getById), update, delete
643
- *
644
- * @deprecated Use `HttpTestHarness.runCrud()` for HTTP-level CRUD tests.
645
- * This method tests Mongoose models directly and does not exercise
646
- * HTTP routes, authentication, permissions, or the Arc pipeline.
647
- */
648
- runCrud(): void;
649
641
  /**
650
642
  * Run validation tests
651
643
  *
@@ -1,5 +1,5 @@
1
- import { t as CRUD_OPERATIONS } from "../constants-Cxde4rpC.mjs";
2
- import { n as applyFieldWritePermissions, t as applyFieldReadPermissions } from "../fields-ipsbIRPK.mjs";
1
+ import { t as CRUD_OPERATIONS } from "../constants-BhY1OHoH.mjs";
2
+ import { n as applyFieldWritePermissions, t as applyFieldReadPermissions } from "../fields-bxkeltzz.mjs";
3
3
  import { runStorageContract } from "./storageContract.mjs";
4
4
  import Fastify from "fastify";
5
5
  import mongoose from "mongoose";
@@ -566,7 +566,10 @@ var HttpTestHarness = class {
566
566
  this.resource = resource;
567
567
  this.optionsOrGetter = optionsOrGetter;
568
568
  if (typeof optionsOrGetter === "function") this.eagerBaseUrl = null;
569
- else this.eagerBaseUrl = `${optionsOrGetter.apiPrefix ?? "/api"}${resource.prefix}`;
569
+ else {
570
+ const apiPrefix = optionsOrGetter.apiPrefix ?? "/api";
571
+ this.eagerBaseUrl = `${apiPrefix}${resource.prefix}`;
572
+ }
570
573
  const disabled = new Set(resource.disabledRoutes ?? []);
571
574
  this.enabledRoutes = new Set(resource.disableDefaultRoutes ? [] : CRUD_OPERATIONS.filter((op) => !disabled.has(op)));
572
575
  this.updateMethod = resource.updateMethod === "PUT" ? "PUT" : "PATCH";
@@ -877,12 +880,6 @@ function createHttpTestHarness(resource, optionsOrGetter) {
877
880
  //#endregion
878
881
  //#region src/testing/mocks.ts
879
882
  /**
880
- * Testing Utilities - Mock Factories
881
- *
882
- * Create mock repositories, controllers, and services for testing.
883
- * Uses Vitest for mocking (compatible with Jest API).
884
- */
885
- /**
886
883
  * Create a mock repository for testing
887
884
  *
888
885
  * @example
@@ -896,6 +893,7 @@ function createHttpTestHarness(resource, optionsOrGetter) {
896
893
  function createMockRepository(overrides = {}) {
897
894
  return {
898
895
  getAll: vi.fn().mockResolvedValue({
896
+ method: "offset",
899
897
  docs: [],
900
898
  total: 0,
901
899
  page: 1,
@@ -1133,8 +1131,11 @@ function pickResource(value) {
1133
1131
  * harness.runAll();
1134
1132
  *
1135
1133
  * // Or run specific test suites
1136
- * harness.runCrud();
1137
1134
  * harness.runPresets();
1135
+ * harness.runValidation();
1136
+ *
1137
+ * // For HTTP-level CRUD coverage (auth, permissions, routes), use
1138
+ * // `HttpTestHarness` from `@classytic/arc/testing`.
1138
1139
  */
1139
1140
  var TestHarness = class {
1140
1141
  resource;
@@ -1157,12 +1158,12 @@ var TestHarness = class {
1157
1158
  this.Model = model;
1158
1159
  }
1159
1160
  /**
1160
- * Run all baseline tests
1161
+ * Run all baseline tests (schema, presets, field permissions, pipeline, events).
1161
1162
  *
1162
- * Executes CRUD, validation, and preset tests
1163
+ * For HTTP-level CRUD coverage (routes, auth, permissions), use
1164
+ * {@link HttpTestHarness} instead.
1163
1165
  */
1164
1166
  runAll() {
1165
- this.runCrud();
1166
1167
  this.runValidation();
1167
1168
  this.runPresets();
1168
1169
  this.runFieldPermissions();
@@ -1170,67 +1171,6 @@ var TestHarness = class {
1170
1171
  this.runEvents();
1171
1172
  }
1172
1173
  /**
1173
- * Run CRUD operation tests (model-level)
1174
- *
1175
- * Tests: create, read (list + getById), update, delete
1176
- *
1177
- * @deprecated Use `HttpTestHarness.runCrud()` for HTTP-level CRUD tests.
1178
- * This method tests Mongoose models directly and does not exercise
1179
- * HTTP routes, authentication, permissions, or the Arc pipeline.
1180
- */
1181
- runCrud() {
1182
- const { resource, fixtures, Model } = this;
1183
- describe(`${resource.displayName} CRUD Operations`, () => {
1184
- beforeAll(async () => {
1185
- await mongoose.connect(this.mongoUri);
1186
- if (this.setupFn) await this.setupFn();
1187
- });
1188
- afterAll(async () => {
1189
- if (this._createdIds.length > 0) await Model.deleteMany({ _id: { $in: this._createdIds } });
1190
- if (this.teardownFn) await this.teardownFn();
1191
- await mongoose.disconnect();
1192
- });
1193
- describe("Create", () => {
1194
- it("should create a new document with valid data", async () => {
1195
- const doc = await Model.create(fixtures.valid);
1196
- this._createdIds.push(doc._id);
1197
- expect(doc).toBeDefined();
1198
- expect(doc._id).toBeDefined();
1199
- for (const [key, value] of Object.entries(fixtures.valid)) if (typeof value !== "object") expect(doc[key]).toEqual(value);
1200
- });
1201
- it("should have timestamps", async () => {
1202
- const doc = await Model.findById(this._createdIds[0]);
1203
- expect(doc).toBeDefined();
1204
- expect(doc?.createdAt).toBeDefined();
1205
- expect(doc?.updatedAt).toBeDefined();
1206
- });
1207
- });
1208
- describe("Read", () => {
1209
- it("should find document by ID", async () => {
1210
- expect(await Model.findById(this._createdIds[0])).toBeDefined();
1211
- });
1212
- it("should list documents", async () => {
1213
- const docs = await Model.find({});
1214
- expect(Array.isArray(docs)).toBe(true);
1215
- expect(docs.length).toBeGreaterThan(0);
1216
- });
1217
- });
1218
- describe("Update", () => {
1219
- it("should update document", async () => {
1220
- const updateData = fixtures.update || { updatedAt: /* @__PURE__ */ new Date() };
1221
- expect(await Model.findByIdAndUpdate(this._createdIds[0], updateData, { new: true })).toBeDefined();
1222
- });
1223
- });
1224
- describe("Delete", () => {
1225
- it("should delete document", async () => {
1226
- const toDelete = await Model.create(fixtures.valid);
1227
- await Model.findByIdAndDelete(toDelete._id);
1228
- expect(await Model.findById(toDelete._id)).toBeNull();
1229
- });
1230
- });
1231
- });
1232
- }
1233
- /**
1234
1174
  * Run validation tests
1235
1175
  *
1236
1176
  * Tests schema validation, required fields, etc.
@@ -1371,7 +1311,7 @@ var TestHarness = class {
1371
1311
  expect(result.otherField).toBe("visible");
1372
1312
  });
1373
1313
  it(`should strip hidden field '${field}' from writes`, () => {
1374
- const result = applyFieldWritePermissions({
1314
+ const { body: result } = applyFieldWritePermissions({
1375
1315
  [field]: "attempt",
1376
1316
  name: "test"
1377
1317
  }, fieldPerms, []);
@@ -1392,7 +1332,7 @@ var TestHarness = class {
1392
1332
  break;
1393
1333
  case "writableBy":
1394
1334
  it(`should strip field '${field}' from writes by non-privileged users`, () => {
1395
- const result = applyFieldWritePermissions({
1335
+ const { body: result } = applyFieldWritePermissions({
1396
1336
  [field]: "new-value",
1397
1337
  name: "test"
1398
1338
  }, fieldPerms, ["viewer"]);
@@ -1402,7 +1342,8 @@ var TestHarness = class {
1402
1342
  if (perm.roles && perm.roles.length > 0) {
1403
1343
  const writeRole = perm.roles[0];
1404
1344
  it(`should allow writing field '${field}' by roles: ${[...perm.roles].join(", ")}`, () => {
1405
- expect(applyFieldWritePermissions({ [field]: "new-value" }, fieldPerms, [writeRole])[field]).toBe("new-value");
1345
+ const { body: result } = applyFieldWritePermissions({ [field]: "new-value" }, fieldPerms, [writeRole]);
1346
+ expect(result[field]).toBe("new-value");
1406
1347
  });
1407
1348
  }
1408
1349
  break;
@@ -1654,10 +1595,11 @@ function runFieldPermissionTests(displayName, fieldPerms) {
1654
1595
  }, fieldPerms, [])[field]).toBeUndefined();
1655
1596
  });
1656
1597
  it(`should strip hidden field '${field}' from writes`, () => {
1657
- expect(applyFieldWritePermissions({
1598
+ const { body: result } = applyFieldWritePermissions({
1658
1599
  [field]: "attempt",
1659
1600
  name: "test"
1660
- }, fieldPerms, [])[field]).toBeUndefined();
1601
+ }, fieldPerms, []);
1602
+ expect(result[field]).toBeUndefined();
1661
1603
  });
1662
1604
  break;
1663
1605
  case "visibleTo":
@@ -1673,15 +1615,17 @@ function runFieldPermissionTests(displayName, fieldPerms) {
1673
1615
  break;
1674
1616
  case "writableBy":
1675
1617
  it(`should strip field '${field}' from writes by non-privileged users`, () => {
1676
- expect(applyFieldWritePermissions({
1618
+ const { body: result } = applyFieldWritePermissions({
1677
1619
  [field]: "v",
1678
1620
  name: "test"
1679
- }, fieldPerms, ["_no_role_"])[field]).toBeUndefined();
1621
+ }, fieldPerms, ["_no_role_"]);
1622
+ expect(result[field]).toBeUndefined();
1680
1623
  });
1681
1624
  if (perm.roles && perm.roles.length > 0) {
1682
1625
  const writeRole = perm.roles[0];
1683
1626
  it(`should allow writing field '${field}' by roles: ${[...perm.roles].join(", ")}`, () => {
1684
- expect(applyFieldWritePermissions({ [field]: "v" }, fieldPerms, [writeRole])[field]).toBe("v");
1627
+ const { body: result } = applyFieldWritePermissions({ [field]: "v" }, fieldPerms, [writeRole]);
1628
+ expect(result[field]).toBe("v");
1685
1629
  });
1686
1630
  }
1687
1631
  break;
@@ -1797,7 +1741,7 @@ function runEventTests(resourceName, displayName, events) {
1797
1741
  * ```
1798
1742
  */
1799
1743
  async function createTestApp(options = {}) {
1800
- const { createApp } = await import("../createApp-B1EY8zxa.mjs").then((n) => n.r);
1744
+ const { createApp } = await import("../createApp-BuvPma24.mjs").then((n) => n.r);
1801
1745
  const { useInMemoryDb = true, mongoUri: providedMongoUri, ...appOptions } = options;
1802
1746
  const defaultAuth = {
1803
1747
  type: "jwt",
@@ -1,4 +1,4 @@
1
- import { t as Storage } from "../storage-Dfzt4VTl.mjs";
1
+ import { t as Storage } from "../storage-CVk_SEn2.mjs";
2
2
 
3
3
  //#region src/testing/storageContract.d.ts
4
4
  interface StorageContractSetupResult {
@@ -1,5 +1,5 @@
1
+ import { n as ElevationOptions, t as ElevationEvent } from "../elevation-C5SwtkAn.mjs";
1
2
  import { _ as isAuthenticated, c as getOrgRoles, g as hasOrgAccess, n as PUBLIC_SCOPE, p as getTeamId, r as RequestScope, s as getOrgId, t as AUTHENTICATED_SCOPE, v as isElevated, y as isMember } from "../types-BD85MlEK.mjs";
2
- import { $ as PresetFunction, $t as DeleteOptions, A as EventsDecorator, B as InferResourceDoc, Bt as FastifyHandler, C as ConfigError, Ct as TypedResourceConfig, D as CrudRouterOptions, Dt as ValidationResult, E as CrudRouteKey, Et as ValidateOptions, F as GracefulShutdownOptions, G as LookupOption, H as IntrospectionPluginOptions, Ht as IControllerResponse, I as HealthCheck, J as ObjectId, K as MiddlewareConfig, L as HealthOptions, M as FastifyWithAuth, N as FastifyWithDecorators, O as CrudSchemas, Ot as envelope, P as FieldRule, Q as PopulateOption, Qt as DeleteManyResult, R as InferAdapterDoc, Rt as ControllerHandler, S as AuthenticatorContext, St as TypedRepository, T as CrudController, Tt as UserOrganization, U as JWTPayload, Ut as IRequestContext, V as IntrospectionData, Vt as IController, W as JwtContext, Wt as RouteHandler, X as OwnershipCheck, Xt as BulkWriteResult, Y as OpenApiSchemas, Yt as BulkWriteOperation, Z as ParsedQuery, Zt as CrudRepository, _ as ArcInternalMetadata, _t as RouteMcpConfig, an as PaginationParams, at as RegistryStats, b as AuthPluginOptions, bt as TokenPair, cn as RepositorySession, ct as RequestWithExtras, d as ActionHandlerFn, dt as ResourceHookContext, en as DeleteResult, et as PresetHook, f as ActionsMap, ft as ResourceHooks, g as ArcDecorator, gt as RouteHandlerMethod, h as ApiResponse, ht as RouteDefinition, in as PaginatedResult, it as RegistryEntry, j as FastifyRequestExtras, jt as BaseControllerOptions, k as EventDefinition, kt as getUserId, l as ActionDefinition, ln as UpdateManyResult, lt as ResourceCacheConfig, m as AnyRecord, mt as ResourcePermissions, nn as KeysetPaginatedResult, nt as QueryParserInterface, on as PaginationResult, ot as RequestContext, p as AdditionalRoute, pt as ResourceMetadata, q as MiddlewareHandler, rn as OffsetPaginatedResult, rt as RateLimitConfig, sn as QueryOptions, st as RequestIdOptions, tn as InferDoc, tt as PresetResult, u as ActionEntry, un as WriteOptions, ut as ResourceConfig, v as ArcRequest, vt as RouteSchemaOptions, w as ControllerQueryOptions, wt as UserLike, x as Authenticator, xt as TypedController, y as AuthHelpers, yt as ServiceContext, z as InferDocType, zt as ControllerLike } from "../interface-CMRutPfe.mjs";
3
- import { i as UserBase, n as PermissionContext, r as PermissionResult, t as PermissionCheck } from "../types-DZi1aYhm.mjs";
4
- import { n as ElevationOptions, t as ElevationEvent } from "../elevation-B6S5csVA.mjs";
5
- export { AUTHENTICATED_SCOPE, ActionDefinition, ActionEntry, ActionHandlerFn, ActionsMap, AdditionalRoute, AnyRecord, ApiResponse, ArcDecorator, ArcInternalMetadata, ArcRequest, AuthHelpers, AuthPluginOptions, Authenticator, AuthenticatorContext, BaseControllerOptions, BulkWriteOperation, BulkWriteResult, ConfigError, ControllerHandler, ControllerLike, ControllerQueryOptions, CrudController, CrudRepository, CrudRouteKey, CrudRouterOptions, CrudSchemas, DeleteManyResult, DeleteOptions, DeleteResult, ElevationEvent, ElevationOptions, EventDefinition, EventsDecorator, FastifyHandler, FastifyRequestExtras, FastifyWithAuth, FastifyWithDecorators, FieldRule, GracefulShutdownOptions, HealthCheck, HealthOptions, IController, IControllerResponse, IRequestContext, InferAdapterDoc, InferDoc, InferDocType, InferResourceDoc, IntrospectionData, IntrospectionPluginOptions, JWTPayload, JwtContext, KeysetPaginatedResult, LookupOption, MiddlewareConfig, MiddlewareHandler, ObjectId, OffsetPaginatedResult, OpenApiSchemas, OwnershipCheck, PUBLIC_SCOPE, PaginatedResult, PaginationParams, PaginationResult, ParsedQuery, PermissionCheck, PermissionContext, PermissionResult, PopulateOption, PresetFunction, PresetHook, PresetResult, QueryOptions, QueryParserInterface, RateLimitConfig, RegistryEntry, RegistryStats, RepositorySession, RequestContext, RequestIdOptions, RequestScope, RequestWithExtras, ResourceCacheConfig, ResourceConfig, ResourceHookContext, ResourceHooks, ResourceMetadata, ResourcePermissions, RouteDefinition, RouteHandler, RouteHandlerMethod, RouteMcpConfig, RouteSchemaOptions, ServiceContext, TokenPair, TypedController, TypedRepository, TypedResourceConfig, UpdateManyResult, UserBase, UserLike, UserOrganization, ValidateOptions, ValidationResult, WriteOptions, envelope, getOrgId, getOrgRoles, getTeamId, getUserId, hasOrgAccess, isAuthenticated, isElevated, isMember };
3
+ import { c as PermissionCheck, d as UserBase, l as PermissionContext, u as PermissionResult } from "../fields-Lo1VUDpt.mjs";
4
+ import { $ as CrudSchemas, A as AuthHelpers, B as FastifyWithDecorators, Bt as ArcInternalMetadata, C as ResourceMetadata, Ct as RouteHandler, D as HealthOptions, E as HealthCheck, F as TokenPair, Gt as PopulateOption, H as RequestWithExtras, Ht as LookupOption, I as ArcDecorator, J as ActionEntry, Jt as ServiceContext, Kt as QueryParserInterface, L as EventsDecorator, M as Authenticator, N as AuthenticatorContext, O as IntrospectionPluginOptions, P as JwtContext, Q as CrudRouteKey, R as FastifyRequestExtras, S as RegistryStats, St as IRequestContext, T as GracefulShutdownOptions, Ut as OwnershipCheck, V as MiddlewareHandler, Vt as ControllerQueryOptions, Wt as ParsedQuery, X as ActionsMap, Y as ActionHandlerFn, Z as CrudController, _ as ConfigError, _n as UserOrganization, _t as ControllerHandler, at as PresetHook, b as IntrospectionData, bt as IController, ct as ResourceCacheConfig, d as InferAdapterDoc, dn as AnyRecord, dt as ResourceHooks, et as EventDefinition, f as InferDocType, fn as ApiResponse, ft as ResourcePermissions, g as TypedResourceConfig, gn as UserLike, gt as RouteSchemaOptions, h as TypedRepository, hn as ObjectId, ht as RouteMethod, it as PresetFunction, j as AuthPluginOptions, k as RequestIdOptions, lt as ResourceConfig, m as TypedController, mn as JWTPayload, mt as RouteMcpConfig, nt as MiddlewareConfig, ot as PresetResult, p as InferResourceDoc, pn as ArcRequest, pt as RouteDefinition, q as ActionDefinition, qt as RequestContext, r as BaseControllerOptions, rt as OpenApiSchemas, st as RateLimitConfig, t as RouteHandlerMethod, tt as FieldRule, u as PaginationResult, ut as ResourceHookContext, v as ValidateOptions, vn as envelope, vt as ControllerLike, w as CrudRouterOptions, x as RegistryEntry, xt as IControllerResponse, y as ValidationResult, yn as getUserId, yt as FastifyHandler, z as FastifyWithAuth } from "../index-Cl0uoKd5.mjs";
5
+ export { AUTHENTICATED_SCOPE, ActionDefinition, ActionEntry, ActionHandlerFn, ActionsMap, AnyRecord, ApiResponse, ArcDecorator, ArcInternalMetadata, ArcRequest, AuthHelpers, AuthPluginOptions, Authenticator, AuthenticatorContext, BaseControllerOptions, ConfigError, ControllerHandler, ControllerLike, ControllerQueryOptions, CrudController, CrudRouteKey, CrudRouterOptions, CrudSchemas, ElevationEvent, ElevationOptions, EventDefinition, EventsDecorator, FastifyHandler, FastifyRequestExtras, FastifyWithAuth, FastifyWithDecorators, FieldRule, GracefulShutdownOptions, HealthCheck, HealthOptions, IController, IControllerResponse, IRequestContext, InferAdapterDoc, InferDocType, InferResourceDoc, IntrospectionData, IntrospectionPluginOptions, JWTPayload, JwtContext, LookupOption, MiddlewareConfig, MiddlewareHandler, ObjectId, OpenApiSchemas, OwnershipCheck, PUBLIC_SCOPE, PaginationResult, ParsedQuery, PermissionCheck, PermissionContext, PermissionResult, PopulateOption, PresetFunction, PresetHook, PresetResult, QueryParserInterface, RateLimitConfig, RegistryEntry, RegistryStats, RequestContext, RequestIdOptions, RequestScope, RequestWithExtras, ResourceCacheConfig, ResourceConfig, ResourceHookContext, ResourceHooks, ResourceMetadata, ResourcePermissions, RouteDefinition, RouteHandler, RouteHandlerMethod, RouteMcpConfig, RouteMethod, RouteSchemaOptions, ServiceContext, TokenPair, TypedController, TypedRepository, TypedResourceConfig, UserBase, UserLike, UserOrganization, ValidateOptions, ValidationResult, envelope, getOrgId, getOrgRoles, getTeamId, getUserId, hasOrgAccess, isAuthenticated, isElevated, isMember };
@@ -1,33 +1,3 @@
1
1
  import { _ as isElevated, f as getTeamId, g as isAuthenticated, h as hasOrgAccess, n as PUBLIC_SCOPE, o as getOrgId, s as getOrgRoles, t as AUTHENTICATED_SCOPE, v as isMember } from "../types-AOD8fxIw.mjs";
2
- //#region src/types/index.ts
3
- /**
4
- * Response envelope helper — wraps data in Arc's standard `{ success, data }` format.
5
- *
6
- * @example
7
- * ```typescript
8
- * import { envelope } from '@classytic/arc';
9
- *
10
- * handler: async (req, reply) => {
11
- * const data = await getResults();
12
- * return envelope(data);
13
- * // → { success: true, data }
14
- * }
15
- * ```
16
- */
17
- function envelope(data, meta) {
18
- return {
19
- success: true,
20
- data,
21
- ...meta
22
- };
23
- }
24
- /**
25
- * Extract user ID from a user object (supports both id and _id)
26
- */
27
- function getUserId(user) {
28
- if (!user) return void 0;
29
- const id = user.id ?? user._id;
30
- return id ? String(id) : void 0;
31
- }
32
- //#endregion
2
+ import { n as getUserId, t as envelope } from "../types-Csi3FLfq.mjs";
33
3
  export { AUTHENTICATED_SCOPE, PUBLIC_SCOPE, envelope, getOrgId, getOrgRoles, getTeamId, getUserId, hasOrgAccess, isAuthenticated, isElevated, isMember };
@@ -1,2 +1,2 @@
1
- import { a as StorageReadResult, i as StorageReadRange, n as StorageContext, o as StorageUploadInput, r as StorageFile, t as Storage } from "../storage-Dfzt4VTl.mjs";
1
+ import { a as StorageReadResult, i as StorageReadRange, n as StorageContext, o as StorageUploadInput, r as StorageFile, t as Storage } from "../storage-CVk_SEn2.mjs";
2
2
  export { Storage, StorageContext, StorageFile, StorageReadRange, StorageReadResult, StorageUploadInput };
@@ -1,4 +1,4 @@
1
- import { qt as ResourceDefinition } from "./interface-CMRutPfe.mjs";
1
+ import { G as ResourceDefinition } from "./index-Cl0uoKd5.mjs";
2
2
  import { z } from "zod";
3
3
 
4
4
  //#region src/integrations/mcp/types.d.ts
@@ -1,12 +1,12 @@
1
- import { x as Authenticator } from "./interface-CMRutPfe.mjs";
2
- import { n as ElevationOptions } from "./elevation-B6S5csVA.mjs";
3
- import { t as ExternalOpenApiPaths } from "./externalPaths-BnkYrNzp.mjs";
4
- import { i as CacheStore } from "./interface-4y979v99.mjs";
5
- import { r as QueryCachePluginOptions } from "./queryCachePlugin-BJJGBTlu.mjs";
6
- import { i as EventTransport } from "./EventTransport-BXja8NOc.mjs";
7
- import { t as EventPluginOptions } from "./eventPlugin-D9DKB2zM.mjs";
8
- import { f as SSEOptions, h as CachingOptions, i as VersioningOptions, l as MetricsOptions, t as ErrorHandlerOptions } from "./errorHandler-Bah5JhBd.mjs";
9
- import { r as IdempotencyStore } from "./interface-DfLGcus7.mjs";
1
+ import { n as ElevationOptions } from "./elevation-C5SwtkAn.mjs";
2
+ import { M as Authenticator } from "./index-Cl0uoKd5.mjs";
3
+ import { o as EventTransport } from "./EventTransport-CUw5NNWe.mjs";
4
+ import { t as ExternalOpenApiPaths } from "./externalPaths-BQ8QijNH.mjs";
5
+ import { r as CacheStore } from "./interface-D218ikEo.mjs";
6
+ import { r as QueryCachePluginOptions } from "./queryCachePlugin-BKbWjgDG.mjs";
7
+ import { t as EventPluginOptions } from "./eventPlugin-CxWgpd6K.mjs";
8
+ import { a as VersioningOptions, g as CachingOptions, p as SSEOptions, t as ErrorHandlerOptions, u as MetricsOptions } from "./errorHandler-DRQ3EqfL.mjs";
9
+ import { r as IdempotencyStore } from "./interface-CSbZdv_3.mjs";
10
10
  import { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest, FastifyServerOptions } from "fastify";
11
11
 
12
12
  //#region src/factory/loadResources.d.ts
@@ -409,6 +409,8 @@ interface CreateAppOptions {
409
409
  debug?: boolean | string;
410
410
  /** Trust proxy headers (X-Forwarded-For, etc.) */
411
411
  trustProxy?: boolean;
412
+ /** Fastify plugin/onReady timeout in ms (default: 10_000). Raise for slow boot work (index materialisation, WAL replay, external warm-up). */
413
+ pluginTimeout?: number;
412
414
  /**
413
415
  * Auth configuration
414
416
  *