@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,7 +1,7 @@
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-CMRutPfe.mjs";
2
- import { t as ExternalOpenApiPaths } from "../externalPaths-BnkYrNzp.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-Bah5JhBd.mjs";
4
- import { t as TracingOptions } from "../tracing-DdN2-wHJ.mjs";
1
+ import { W as ResourceRegistry, at as PresetHook, dn as AnyRecord, gt as RouteSchemaOptions, nt as MiddlewareConfig, pt as RouteDefinition, tn as HookSystem } from "../index-Cl0uoKd5.mjs";
2
+ import { t as ExternalOpenApiPaths } from "../externalPaths-BQ8QijNH.mjs";
3
+ import { _ as CachingRule, a as VersioningOptions, c as MetricEntry, d as _default$4, f as metricsPlugin, g as CachingOptions, h as ssePlugin, i as errorHandlerPlugin, l as MetricsCollector, m as _default$6, n as ErrorMapper, o as _default$7, p as SSEOptions, r as defaultIsDuplicateKeyError, s as versioningPlugin, t as ErrorHandlerOptions, u as MetricsOptions, v as _default$1, y as cachingPlugin } from "../errorHandler-DRQ3EqfL.mjs";
4
+ import { t as TracingOptions } from "../tracing-65B51Dw3.mjs";
5
5
  import { FastifyInstance, FastifyPluginAsync } from "fastify";
6
6
  import * as _$node_stream0 from "node:stream";
7
7
 
@@ -42,8 +42,8 @@ declare const _default: FastifyPluginAsync<ArcCorePluginOptions>;
42
42
  //#endregion
43
43
  //#region src/plugins/createPlugin.d.ts
44
44
  interface PluginResourceResult {
45
- /** Additional routes to add to the resource */
46
- additionalRoutes?: AdditionalRoute[];
45
+ /** Additional routes to add to the resource (v2.8 `RouteDefinition` shape) */
46
+ routes?: RouteDefinition[];
47
47
  /** Middlewares per operation */
48
48
  middlewares?: MiddlewareConfig;
49
49
  /** Hooks to register */
@@ -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 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 };
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, defaultIsDuplicateKeyError, errorHandlerPlugin, errorHandlerPlugin as errorHandlerPluginFn, _default$2 as gracefulShutdownPlugin, gracefulShutdownPlugin as gracefulShutdownPluginFn, _default$3 as healthPlugin, healthPlugin as healthPluginFn, _default$4 as metricsPlugin, metricsPlugin as metricsPluginFn, replyHelpersPlugin, _default$5 as requestIdPlugin, requestIdPlugin as requestIdPluginFn, _default$6 as ssePlugin, ssePlugin as ssePluginFn, _default$7 as versioningPlugin, versioningPlugin as versioningPluginFn };
@@ -1,15 +1,15 @@
1
- import { p as MUTATION_OPERATIONS } from "../constants-Cxde4rpC.mjs";
1
+ import { p as MUTATION_OPERATIONS } from "../constants-BhY1OHoH.mjs";
2
2
  import { o as getOrgId } from "../types-AOD8fxIw.mjs";
3
- import { t as requestContext } from "../requestContext-DYvHl113.mjs";
4
- import { t as hasEvents } from "../typeGuards-CcFZXgU7.mjs";
5
- import { t as HookSystem } from "../HookSystem-HprTmvVY.mjs";
6
- import { t as ResourceRegistry } from "../ResourceRegistry-C6uXlWe3.mjs";
7
- import { n as caching_default, t as cachingPlugin } from "../caching-IMuYVjTL.mjs";
8
- import { t as errorHandlerPlugin } from "../errorHandler-f869_8PQ.mjs";
9
- import { n as metrics_default, t as metricsPlugin } from "../metrics-B-PU4-Yu.mjs";
10
- import { t as replyHelpersPlugin } from "../replyHelpers-CxkYGT81.mjs";
11
- import { n as sse_default, t as ssePlugin } from "../sse-Ad7ypl9e.mjs";
12
- import { n as versioning_default, t as versioningPlugin } from "../versioning-CDugduqI.mjs";
3
+ import { t as requestContext } from "../requestContext-xHIKedG6.mjs";
4
+ import { t as hasEvents } from "../typeGuards-Cj5Rgvlg.mjs";
5
+ import { t as HookSystem } from "../HookSystem-BNYKnrXF.mjs";
6
+ import { t as ResourceRegistry } from "../ResourceRegistry-BPd6NQDm.mjs";
7
+ import { n as caching_default, t as cachingPlugin } from "../caching-CBpK_SCM.mjs";
8
+ import { n as errorHandlerPlugin, t as defaultIsDuplicateKeyError } from "../errorHandler-Bb49BvPD.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-yBCgOLGu.mjs";
12
+ import { n as versioning_default, t as versioningPlugin } from "../versioning-C2U_bLY0.mjs";
13
13
  import { randomUUID } from "node:crypto";
14
14
  import fp from "fastify-plugin";
15
15
  //#region src/core/arcCorePlugin.ts
@@ -393,15 +393,13 @@ var health_default = fp(healthPlugin, {
393
393
  const requestIdPlugin = async (fastify, opts = {}) => {
394
394
  const { header = "x-request-id", generator = randomUUID, setResponseHeader = true } = opts;
395
395
  if (!fastify.hasRequestDecorator("requestId")) fastify.decorateRequest("requestId", "");
396
- fastify.addHook("onRequest", async (request) => {
396
+ fastify.addHook("onRequest", async (request, reply) => {
397
397
  const incomingId = request.headers[header];
398
398
  const sanitized = typeof incomingId === "string" ? incomingId.trim() : "";
399
399
  const requestId = sanitized.length > 0 && sanitized.length <= 128 && /^[\w.:-]+$/.test(sanitized) ? sanitized : generator();
400
400
  request.id = requestId;
401
401
  request.requestId = requestId;
402
- });
403
- if (setResponseHeader) fastify.addHook("onSend", async (request, reply) => {
404
- reply.header(header, request.requestId);
402
+ if (setResponseHeader) reply.header(header, requestId);
405
403
  });
406
404
  fastify.log?.debug?.("Request ID plugin registered");
407
405
  };
@@ -410,4 +408,4 @@ var requestId_default = fp(requestIdPlugin, {
410
408
  fastify: "5.x"
411
409
  });
412
410
  //#endregion
413
- export { arcCorePlugin_default as arcCorePlugin, arcCorePlugin as arcCorePluginFn, caching_default as cachingPlugin, cachingPlugin as cachingPluginFn, createPlugin, errorHandlerPlugin, errorHandlerPlugin as errorHandlerPluginFn, gracefulShutdown_default as gracefulShutdownPlugin, gracefulShutdownPlugin as gracefulShutdownPluginFn, health_default as healthPlugin, healthPlugin as healthPluginFn, metrics_default as metricsPlugin, metricsPlugin as metricsPluginFn, replyHelpersPlugin, requestId_default as requestIdPlugin, requestIdPlugin as requestIdPluginFn, sse_default as ssePlugin, ssePlugin as ssePluginFn, versioning_default as versioningPlugin, versioningPlugin as versioningPluginFn };
411
+ export { arcCorePlugin_default as arcCorePlugin, arcCorePlugin as arcCorePluginFn, caching_default as cachingPlugin, cachingPlugin as cachingPluginFn, createPlugin, defaultIsDuplicateKeyError, errorHandlerPlugin, errorHandlerPlugin as errorHandlerPluginFn, gracefulShutdown_default as gracefulShutdownPlugin, gracefulShutdownPlugin as gracefulShutdownPluginFn, health_default as healthPlugin, healthPlugin as healthPluginFn, metrics_default as metricsPlugin, metricsPlugin as metricsPluginFn, replyHelpersPlugin, requestId_default as requestIdPlugin, requestIdPlugin as requestIdPluginFn, sse_default as ssePlugin, ssePlugin as ssePluginFn, versioning_default as versioningPlugin, versioningPlugin as versioningPluginFn };
@@ -1,4 +1,4 @@
1
- import { t as hasEvents } from "../typeGuards-CcFZXgU7.mjs";
1
+ import { t as hasEvents } from "../typeGuards-Cj5Rgvlg.mjs";
2
2
  import fp from "fastify-plugin";
3
3
  //#region src/plugins/response-cache.ts
4
4
  /**
@@ -145,7 +145,7 @@ const responseCachePluginImpl = async (fastify, opts = {}) => {
145
145
  request.__arcCacheTTL = 0;
146
146
  reply.code(entry.statusCode).send(entry.body);
147
147
  };
148
- fastify.addHook("onSend", async (request, reply, payload) => {
148
+ fastify.addHook("preSerialization", async (request, reply, payload) => {
149
149
  const ttl = request.__arcCacheTTL;
150
150
  if (!ttl || ttl <= 0) return payload;
151
151
  if (request.method !== "GET" && request.method !== "HEAD") return payload;
@@ -1,2 +1,2 @@
1
- import { a as traced, i as isTracingAvailable, n as _default, r as createSpan, t as TracingOptions } from "../tracing-DdN2-wHJ.mjs";
1
+ import { a as traced, i as isTracingAvailable, n as _default, r as createSpan, t as TracingOptions } from "../tracing-65B51Dw3.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.5";
47
+ const resolvedVersion = serviceVersion ?? "2.10.3";
48
48
  const exporter = new OTLPTraceExporter({ url: exporterUrl });
49
49
  const provider = new NodeTracerProvider({ resource: { attributes: {
50
50
  "service.name": serviceName,
@@ -1,7 +1,7 @@
1
1
  import { r as RequestScope } from "../types-BD85MlEK.mjs";
2
- import { tt as PresetResult } from "../interface-CMRutPfe.mjs";
3
- import { t as PermissionCheck } from "../types-DZi1aYhm.mjs";
4
- import { a as StorageReadResult, i as StorageReadRange, n as StorageContext, o as StorageUploadInput, r as StorageFile, t as Storage } from "../storage-Dfzt4VTl.mjs";
2
+ import { c as PermissionCheck } from "../fields-Lo1VUDpt.mjs";
3
+ import { ot as PresetResult } from "../index-Cl0uoKd5.mjs";
4
+ import { a as StorageReadResult, i as StorageReadRange, n as StorageContext, o as StorageUploadInput, r as StorageFile, t as Storage } from "../storage-CVk_SEn2.mjs";
5
5
 
6
6
  //#region src/presets/filesUpload.d.ts
7
7
  interface FilesUploadPresetRoutes {
@@ -14,6 +14,20 @@ interface FilesUploadPresetPermissions {
14
14
  read?: PermissionCheck;
15
15
  delete?: PermissionCheck;
16
16
  }
17
+ /**
18
+ * Filename policy — controls how user-supplied filenames are validated before
19
+ * reaching the `Storage.upload()` adapter.
20
+ *
21
+ * - `true` (default): strict — rejects path separators, NULs, `.`/`..`, empty,
22
+ * and names >255 chars. Safe default for disk/S3/prefix-joining adapters.
23
+ * - `false` | `'*'`: accept any filename verbatim. Use when the filename is a
24
+ * user-supplied *label* and the adapter generates the storage key itself —
25
+ * typical for microservice ingress, API-server proxies, or content stores
26
+ * that use `id` for the path and treat `filename` as metadata.
27
+ * - function: custom policy. Return a string to *transform* the filename,
28
+ * `false` to reject (triggers `ValidationError`), or `true`/`void` to accept.
29
+ */
30
+ type FilenamePolicy = boolean | "*" | ((filename: string) => string | boolean | void);
17
31
  interface FilesUploadPresetOptions {
18
32
  /** Any implementation of the `Storage` interface. App owns it. */
19
33
  storage: Storage;
@@ -21,8 +35,16 @@ interface FilesUploadPresetOptions {
21
35
  fieldName?: string;
22
36
  /** Max bytes per file. Forwarded to `multipartBody`. Default: 10 MB. */
23
37
  maxFileSize?: number;
24
- /** IANA MIME allow-list. Forwarded to `multipartBody`. Default: no filter. */
38
+ /**
39
+ * IANA MIME allow-list. Forwarded to `multipartBody`. Default: no filter.
40
+ * Pass `['*']` to explicitly allow any type (equivalent to omitting).
41
+ */
25
42
  allowedMimeTypes?: string[];
43
+ /**
44
+ * Filename validation policy. Default: `true` (strict).
45
+ * See {@link FilenamePolicy}.
46
+ */
47
+ sanitizeFilename?: FilenamePolicy;
26
48
  /**
27
49
  * Per-route permissions.
28
50
  * Defaults: upload → `requireAuth()`, read → `allowPublic()`, delete → `requireAuth()`.
@@ -46,4 +68,4 @@ interface FilesUploadPresetOptions {
46
68
  */
47
69
  declare function filesUploadPreset(options: FilesUploadPresetOptions): PresetResult;
48
70
  //#endregion
49
- export { FilesUploadPresetOptions, FilesUploadPresetPermissions, FilesUploadPresetRoutes, type Storage, type StorageContext, type StorageFile, type StorageReadRange, type StorageReadResult, type StorageUploadInput, filesUploadPreset };
71
+ export { FilenamePolicy, FilesUploadPresetOptions, FilesUploadPresetPermissions, FilesUploadPresetRoutes, type Storage, type StorageContext, type StorageFile, type StorageReadRange, type StorageReadResult, type StorageUploadInput, filesUploadPreset };
@@ -1,2 +1,2 @@
1
- import { t as filesUploadPreset } from "../filesUpload-C7r7HIeA.mjs";
1
+ import { t as filesUploadPreset } from "../filesUpload-t21LS-py.mjs";
2
2
  export { filesUploadPreset };
@@ -1,6 +1,7 @@
1
- import { Ht as IControllerResponse, Ut as IRequestContext, m as AnyRecord, on as PaginationResult, tt as PresetResult, ut as ResourceConfig } from "../interface-CMRutPfe.mjs";
1
+ import { St as IRequestContext, dn as AnyRecord, lt as ResourceConfig, ot as PresetResult, u as PaginationResult, xt as IControllerResponse } from "../index-Cl0uoKd5.mjs";
2
2
  import { FilesUploadPresetOptions, FilesUploadPresetPermissions, FilesUploadPresetRoutes, filesUploadPreset } from "./filesUpload.mjs";
3
3
  import { MultiTenantOptions, TenantFieldSpec, multiTenantPreset } from "./multiTenant.mjs";
4
+ import { SearchHandler, SearchPresetOptions, SearchRouteConfig, searchPreset } from "./search.mjs";
4
5
 
5
6
  //#region src/presets/ownedByUser.d.ts
6
7
  interface OwnedByUserOptions {
@@ -272,4 +273,4 @@ type PresetInput = string | PresetResult | {
272
273
  */
273
274
  declare function applyPresets<TDoc = AnyRecord>(config: ResourceConfig<TDoc>, presets?: PresetInput[]): ResourceConfig<TDoc>;
274
275
  //#endregion
275
- export { type AuditedPresetOptions, type BulkOperation, type BulkPresetOptions, type FilesUploadPresetOptions, type FilesUploadPresetPermissions, type FilesUploadPresetRoutes, type IAuditedPreset, type IMultiTenantPreset, type IOwnedByUserPreset, type IPresetController, type ISlugLookupController, type ISoftDeleteController, type ITreeController, type MultiTenantOptions, type OwnedByUserOptions, type SlugLookupOptions, type TenantFieldSpec, type TreeOptions, applyPresets, auditedPreset, bulkPreset, filesUploadPreset, flexibleMultiTenantPreset, getAvailablePresets, getPreset, multiTenantPreset, ownedByUserPreset, registerPreset, slugLookupPreset, softDeletePreset, treePreset };
276
+ export { type AuditedPresetOptions, type BulkOperation, type BulkPresetOptions, type FilesUploadPresetOptions, type FilesUploadPresetPermissions, type FilesUploadPresetRoutes, type IAuditedPreset, type IMultiTenantPreset, type IOwnedByUserPreset, type IPresetController, type ISlugLookupController, type ISoftDeleteController, type ITreeController, type MultiTenantOptions, type OwnedByUserOptions, type SearchHandler, type SearchPresetOptions, type SearchRouteConfig, type SlugLookupOptions, type TenantFieldSpec, type TreeOptions, applyPresets, auditedPreset, bulkPreset, filesUploadPreset, flexibleMultiTenantPreset, getAvailablePresets, getPreset, multiTenantPreset, ownedByUserPreset, registerPreset, searchPreset, slugLookupPreset, softDeletePreset, treePreset };
@@ -1,4 +1,5 @@
1
1
  import { multiTenantPreset } from "./multiTenant.mjs";
2
- import { a as registerPreset, c as auditedPreset, d as ownedByUserPreset, i as getPreset, l as softDeletePreset, n as flexibleMultiTenantPreset, o as treePreset, r as getAvailablePresets, s as bulkPreset, t as applyPresets, u as slugLookupPreset } from "../presets-C2xgzW6x.mjs";
3
- import { t as filesUploadPreset } from "../filesUpload-C7r7HIeA.mjs";
4
- export { applyPresets, auditedPreset, bulkPreset, filesUploadPreset, flexibleMultiTenantPreset, getAvailablePresets, getPreset, multiTenantPreset, ownedByUserPreset, registerPreset, slugLookupPreset, softDeletePreset, treePreset };
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-fLJVXdVn.mjs";
3
+ import { t as filesUploadPreset } from "../filesUpload-t21LS-py.mjs";
4
+ import { searchPreset } from "./search.mjs";
5
+ export { applyPresets, auditedPreset, bulkPreset, filesUploadPreset, flexibleMultiTenantPreset, getAvailablePresets, getPreset, multiTenantPreset, ownedByUserPreset, registerPreset, searchPreset, slugLookupPreset, softDeletePreset, treePreset };
@@ -1,4 +1,4 @@
1
- import { E as CrudRouteKey, tt as PresetResult } from "../interface-CMRutPfe.mjs";
1
+ import { Q as CrudRouteKey, ot as PresetResult } from "../index-Cl0uoKd5.mjs";
2
2
 
3
3
  //#region src/presets/multiTenant.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import "../constants-Cxde4rpC.mjs";
1
+ import "../constants-BhY1OHoH.mjs";
2
2
  import { _ as isElevated, c as getRequestScope, f as getTeamId, h as hasOrgAccess, l as getScopeContext, o as getOrgId } from "../types-AOD8fxIw.mjs";
3
3
  //#region src/presets/multiTenant.ts
4
4
  /**
@@ -144,7 +144,7 @@ function multiTenantPreset(options = {}) {
144
144
  list: [getFilter("list")],
145
145
  get: [getFilter("get")],
146
146
  create: [tenantInjection],
147
- update: [getFilter("update")],
147
+ update: [getFilter("update"), tenantInjection],
148
148
  delete: [getFilter("delete")]
149
149
  }
150
150
  };
@@ -0,0 +1,178 @@
1
+ import { c as PermissionCheck } from "../fields-Lo1VUDpt.mjs";
2
+ import { _t as ControllerHandler, mt as RouteMcpConfig, ot as PresetResult, pt as RouteDefinition } from "../index-Cl0uoKd5.mjs";
3
+
4
+ //#region src/presets/search.d.ts
5
+ /**
6
+ * Search Preset — backend-agnostic search / vector / embed routes
7
+ *
8
+ * Arc doesn't ship a search engine. It ships the **routes** that front one.
9
+ * The preset mounts up to three standard routes on a resource:
10
+ *
11
+ * POST /search → full-text / engine-backed search (ES, OpenSearch, Algolia, Typesense, …)
12
+ * POST /search-similar → vector / semantic similarity (Atlas, Pinecone, Qdrant, Milvus, …)
13
+ * POST /embed → text / media → vector embedding
14
+ *
15
+ * Each route is OFF by default. You opt in by providing a `handler` that calls
16
+ * whatever backend you use. The preset contributes:
17
+ * - Default path + method + permissions (customisable)
18
+ * - OpenAPI description + MCP tool naming
19
+ * - Arc envelope + pipeline (permissions, audit, hooks)
20
+ * - Sensible Fastify route schema defaults
21
+ *
22
+ * Paths are fully customisable — if your product wants `/abc/search` or a
23
+ * GET-based autocomplete, pass `path`/`method` overrides or use `routes` for
24
+ * fully bespoke endpoints.
25
+ *
26
+ * @example MongoKit wiring (elasticSearchPlugin + vectorPlugin)
27
+ * ```typescript
28
+ * import { Repository, methodRegistryPlugin, elasticSearchPlugin } from '@classytic/mongokit';
29
+ * import { vectorPlugin } from '@classytic/mongokit/ai';
30
+ * import { searchPreset } from '@classytic/arc/presets/search';
31
+ *
32
+ * const productRepo = new Repository(Product, [
33
+ * methodRegistryPlugin(),
34
+ * elasticSearchPlugin({ client: esClient, indexName: 'products' }),
35
+ * vectorPlugin({ fields: [{ path: 'embedding', dimensions: 1536 }], embedFn }),
36
+ * ]);
37
+ *
38
+ * defineResource({
39
+ * name: 'product',
40
+ * adapter: createMongooseAdapter({ model: Product, repository: productRepo }),
41
+ * presets: [
42
+ * searchPreset({
43
+ * search: { handler: (req) => productRepo.search(req.body.query, req.body) },
44
+ * similar: { handler: (req) => productRepo.searchSimilar(req.body.query, req.body) },
45
+ * }),
46
+ * ],
47
+ * });
48
+ * ```
49
+ *
50
+ * @example Custom vector backend (Pinecone)
51
+ * ```typescript
52
+ * searchPreset({
53
+ * similar: {
54
+ * path: '/vector-search', // custom path
55
+ * handler: async (req) => {
56
+ * const hits = await pinecone.query({
57
+ * vector: req.body.vector,
58
+ * topK: req.body.topK ?? 10,
59
+ * });
60
+ * return hits.matches;
61
+ * },
62
+ * schema: { body: { type: 'object', properties: { vector: { type: 'array' }, topK: { type: 'integer' } } } },
63
+ * mcp: false, // no MCP tool for this one
64
+ * },
65
+ * // Extra app-specific route
66
+ * routes: [
67
+ * {
68
+ * method: 'GET',
69
+ * path: '/autocomplete',
70
+ * handler: async (req) => algolia.suggest(req.query.q as string),
71
+ * permissions: allowPublic(),
72
+ * },
73
+ * ],
74
+ * });
75
+ * ```
76
+ */
77
+ /**
78
+ * Feature-detected search surface. Arc's `RepositoryLike` is the cross-kit
79
+ * minimum (repo-core's `MinimalRepo & Partial<StandardRepo>`) and does not
80
+ * declare search/vector/embed methods — those are kit-specific (mongokit's
81
+ * `elasticSearchPlugin` + `vectorPlugin`, pgkit's `pgvector` extension,
82
+ * sqlitekit FTS5, or a standalone Pinecone/Algolia adapter). We type the
83
+ * `repository` option locally so the preset can auto-wire handlers when a
84
+ * kit happens to ship these methods, without forcing every repo to declare
85
+ * them.
86
+ */
87
+ interface SearchableRepository {
88
+ search?(query: unknown, options?: unknown): Promise<unknown>;
89
+ searchSimilar?(query: unknown, options?: unknown): Promise<unknown>;
90
+ embed?(input: unknown): Promise<number[]>;
91
+ }
92
+ /**
93
+ * Handler contract — receives arc's `IRequestContext` (same as any `actions` or
94
+ * non-raw route handler) and returns either the raw result (wrapped into
95
+ * `{ success: true, data }` by arc) or an explicit `IControllerResponse`.
96
+ */
97
+ type SearchHandler = ControllerHandler;
98
+ interface SearchRouteConfig {
99
+ /**
100
+ * User-supplied handler. When omitted, the preset auto-synthesises a handler
101
+ * from `options.repository` (calling `repo.search` / `repo.searchSimilar` /
102
+ * `repo.embed` respectively). If `repository` is also absent — or the repo
103
+ * doesn't expose the matching method — the route is NOT mounted.
104
+ */
105
+ handler?: SearchHandler;
106
+ /** HTTP path relative to the resource prefix. Defaults per-kind: `/search`, `/search-similar`, `/embed`. */
107
+ path?: string;
108
+ /** HTTP method. Default: `POST`. */
109
+ method?: "GET" | "POST";
110
+ /** Permission check. Defaults: search/similar fall back to `permissions.list ?? allowPublic()`; embed → `requireAuth()`. */
111
+ permissions?: PermissionCheck;
112
+ /** Fastify/AJV route schema (body/querystring/params/headers/response). */
113
+ schema?: RouteDefinition["schema"];
114
+ /**
115
+ * MCP tool generation.
116
+ * - omitted/true (default): auto-generate the tool from the route
117
+ * - false: skip MCP
118
+ * - object: explicit MCP config
119
+ */
120
+ mcp?: boolean | RouteMcpConfig;
121
+ /** OpenAPI summary. Defaults per-kind. */
122
+ summary?: string;
123
+ /** OpenAPI description. Defaults per-kind. */
124
+ description?: string;
125
+ /** Operation name. Defaults per-kind (`search`, `searchSimilar`, `embed`). */
126
+ operation?: string;
127
+ /** OpenAPI tags. */
128
+ tags?: string[];
129
+ }
130
+ /**
131
+ * Shorthand shape for `search` / `similar` / `embed` sections:
132
+ * - `undefined` → route not mounted
133
+ * - `true` → mount with defaults, auto-wire from `repository`
134
+ * - `SearchRouteConfig` → explicit config (and optional handler override)
135
+ */
136
+ type SearchSection = true | SearchRouteConfig;
137
+ interface SearchPresetOptions {
138
+ /**
139
+ * Repository exposing `search`/`searchSimilar`/`embed`. When provided,
140
+ * any section without an explicit `handler` is auto-wired to the matching
141
+ * repo method. Mongokit's `elasticSearchPlugin` + `vectorPlugin` register
142
+ * exactly these methods — pass the repo once and the handlers are synthesised.
143
+ *
144
+ * Sections set to `true` REQUIRE `repository` (otherwise the route is
145
+ * skipped silently). Sections with an explicit `handler` ignore this field.
146
+ */
147
+ repository?: SearchableRepository;
148
+ /** Full-text / engine-backed search route. Opt-in. */
149
+ search?: SearchSection;
150
+ /** Vector / semantic similarity route. Opt-in. */
151
+ similar?: SearchSection;
152
+ /** Embedding route (text/media → vector). Opt-in. */
153
+ embed?: SearchSection;
154
+ /**
155
+ * Fully custom routes — merged as-is into the resource's route table.
156
+ * Use this for endpoints that don't fit search/similar/embed naming,
157
+ * e.g. `/autocomplete`, `/reindex`, `/facets`, `/more-like-this`.
158
+ *
159
+ * You are responsible for permissions + schema on each entry.
160
+ */
161
+ routes?: RouteDefinition[];
162
+ }
163
+ /**
164
+ * Create a search preset bound to a resource.
165
+ *
166
+ * Mounts routes only for sections the caller opts into. A section's handler
167
+ * is either:
168
+ * 1. explicit `cfg.handler` — always wins,
169
+ * 2. `options.repository` auto-wire — if the repo exposes the matching
170
+ * method (`search` / `searchSimilar` / `embed`),
171
+ * 3. otherwise the route is silently skipped.
172
+ *
173
+ * The preset itself stays DB-agnostic: nothing is imported from mongokit —
174
+ * it only feature-detects the optional methods on whatever repo you pass.
175
+ */
176
+ declare function searchPreset(options?: SearchPresetOptions): PresetResult;
177
+ //#endregion
178
+ export { SearchHandler, SearchPresetOptions, SearchRouteConfig, SearchSection, SearchableRepository, searchPreset };
@@ -0,0 +1,150 @@
1
+ import { C as requireAuth, y as allowPublic } from "../permissions-Dk6mshja.mjs";
2
+ //#region src/presets/search.ts
3
+ const BUILTINS = [
4
+ {
5
+ key: "search",
6
+ defaultPath: "/search",
7
+ defaultOperation: "search",
8
+ defaultSummary: "Search",
9
+ defaultDescription: "Full-text / engine-backed search. Delegates to the configured backend.",
10
+ permissionFallback: (p) => p.list ?? allowPublic()
11
+ },
12
+ {
13
+ key: "similar",
14
+ defaultPath: "/search-similar",
15
+ defaultOperation: "searchSimilar",
16
+ defaultSummary: "Semantic search",
17
+ defaultDescription: "Vector / similarity search. Delegates to the configured backend.",
18
+ permissionFallback: (p) => p.list ?? allowPublic()
19
+ },
20
+ {
21
+ key: "embed",
22
+ defaultPath: "/embed",
23
+ defaultOperation: "embed",
24
+ defaultSummary: "Embed",
25
+ defaultDescription: "Return the vector embedding for a text / media input.",
26
+ permissionFallback: () => requireAuth()
27
+ }
28
+ ];
29
+ /**
30
+ * Wrap the user handler to normalise the return shape into arc's envelope.
31
+ * If the handler already returns `{ success, data }`, arc passes it through;
32
+ * otherwise we wrap the raw return value so callers don't have to.
33
+ */
34
+ function wrapEnvelope(handler) {
35
+ return async (req) => {
36
+ const out = await handler(req);
37
+ if (out !== null && typeof out === "object" && "success" in out) return out;
38
+ return {
39
+ success: true,
40
+ data: out
41
+ };
42
+ };
43
+ }
44
+ /**
45
+ * Normalise a section value — `true` → empty config, `undefined` → undefined,
46
+ * object → passthrough. Lets callers write `search: true` to mount with
47
+ * defaults + auto-wire.
48
+ */
49
+ function normaliseSection(value) {
50
+ if (value === void 0) return void 0;
51
+ if (value === true) return {};
52
+ return value;
53
+ }
54
+ /**
55
+ * Build an auto-synthesised handler that proxies the request body to
56
+ * `repo[method]` using each kit's native calling convention. Returns
57
+ * `undefined` when the method isn't present so the caller can fall back to
58
+ * an explicit `cfg.handler` or skip the route.
59
+ *
60
+ * Conventions (verified against mongokit 3.6):
61
+ *
62
+ * - **`search`** (mongokit `elasticSearchPlugin`):
63
+ * `search(query, { limit?, from?, mongoOptions? })` — positional. `query`
64
+ * is the engine-native DSL (e.g. ES `match` clause). Arc passes
65
+ * `(body.query, body)` so the rest of the body flows into options.
66
+ *
67
+ * - **`searchSimilar`** (mongokit `vectorPlugin`):
68
+ * `searchSimilar(params: VectorSearchParams)` — **single object**. `params`
69
+ * carries `query` (vector, text, or multimodal), `limit`, `filter`,
70
+ * `numCandidates`, `exact`, `field`, `minScore`, etc. Arc passes `body`
71
+ * directly so the shapes align. Passing positional args here would
72
+ * silently break (first arg becomes the whole `params`, second arg
73
+ * is ignored).
74
+ *
75
+ * - **`embed`** (mongokit `vectorPlugin`):
76
+ * `embed(input: string | EmbeddingInput)` — single arg. Arc passes
77
+ * `body.input ?? body`, so callers may wrap as `{ input: "…" }` or send
78
+ * the `EmbeddingInput` shape directly.
79
+ */
80
+ function autoHandlerFor(repo, method) {
81
+ if (!repo) return void 0;
82
+ const fn = repo[method];
83
+ if (typeof fn !== "function") return void 0;
84
+ if (method === "embed") return async (req) => {
85
+ const body = req.body ?? {};
86
+ return fn(body.input ?? body);
87
+ };
88
+ if (method === "searchSimilar") return async (req) => {
89
+ return fn(req.body ?? {});
90
+ };
91
+ return async (req) => {
92
+ const body = req.body ?? {};
93
+ return fn(body.query, body);
94
+ };
95
+ }
96
+ /**
97
+ * Create a search preset bound to a resource.
98
+ *
99
+ * Mounts routes only for sections the caller opts into. A section's handler
100
+ * is either:
101
+ * 1. explicit `cfg.handler` — always wins,
102
+ * 2. `options.repository` auto-wire — if the repo exposes the matching
103
+ * method (`search` / `searchSimilar` / `embed`),
104
+ * 3. otherwise the route is silently skipped.
105
+ *
106
+ * The preset itself stays DB-agnostic: nothing is imported from mongokit —
107
+ * it only feature-detects the optional methods on whatever repo you pass.
108
+ */
109
+ function searchPreset(options = {}) {
110
+ const sections = {
111
+ search: normaliseSection(options.search),
112
+ similar: normaliseSection(options.similar),
113
+ embed: normaliseSection(options.embed)
114
+ };
115
+ const extraRoutes = options.routes ?? [];
116
+ const repoMethodFor = {
117
+ search: "search",
118
+ similar: "searchSimilar",
119
+ embed: "embed"
120
+ };
121
+ return {
122
+ name: "search",
123
+ routes: (permissions) => {
124
+ const mounted = [];
125
+ for (const spec of BUILTINS) {
126
+ const cfg = sections[spec.key];
127
+ if (!cfg) continue;
128
+ const handler = cfg.handler ?? autoHandlerFor(options.repository, repoMethodFor[spec.key]);
129
+ if (!handler) continue;
130
+ const route = {
131
+ method: cfg.method ?? "POST",
132
+ path: cfg.path ?? spec.defaultPath,
133
+ operation: cfg.operation ?? spec.defaultOperation,
134
+ summary: cfg.summary ?? spec.defaultSummary,
135
+ description: cfg.description ?? spec.defaultDescription,
136
+ tags: cfg.tags,
137
+ permissions: cfg.permissions ?? spec.permissionFallback(permissions),
138
+ schema: cfg.schema,
139
+ mcp: cfg.mcp,
140
+ handler: wrapEnvelope(handler)
141
+ };
142
+ mounted.push(route);
143
+ }
144
+ for (const r of extraRoutes) mounted.push(r);
145
+ return mounted;
146
+ }
147
+ };
148
+ }
149
+ //#endregion
150
+ export { searchPreset };
@@ -1,6 +1,6 @@
1
1
  import { _ as isElevated, n as PUBLIC_SCOPE } from "./types-AOD8fxIw.mjs";
2
2
  import { multiTenantPreset } from "./presets/multiTenant.mjs";
3
- import { f as requireRoles, n as allowPublic, s as requireAuth } from "./permissions-CH4cNwJi.mjs";
3
+ import { C as requireAuth, T as requireRoles, y as allowPublic } from "./permissions-Dk6mshja.mjs";
4
4
  //#region src/presets/ownedByUser.ts
5
5
  /**
6
6
  * Create ownership check middleware.
@@ -1,4 +1,4 @@
1
- import { i as CacheStore } from "./interface-4y979v99.mjs";
1
+ import { r as CacheStore } from "./interface-D218ikEo.mjs";
2
2
  import { FastifyPluginAsync } from "fastify";
3
3
 
4
4
  //#region src/cache/QueryCache.d.ts
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
2
2
  import { i as versionKey, r as tagVersionKey } from "./keys-qcD-TVJl.mjs";
3
- import { t as hasEvents } from "./typeGuards-CcFZXgU7.mjs";
4
- import { t as MemoryCacheStore } from "./memory-Cp7_cAko.mjs";
3
+ import { t as hasEvents } from "./typeGuards-Cj5Rgvlg.mjs";
4
+ import { t as MemoryCacheStore } from "./memory-B5Amv9A1.mjs";
5
5
  import fp from "fastify-plugin";
6
6
  //#region src/cache/QueryCache.ts
7
7
  var QueryCache = class {
@@ -33,17 +33,17 @@ var QueryCache = class {
33
33
  };
34
34
  }
35
35
  async set(key, data, config) {
36
- const staleTimeMs = (config.staleTime ?? 0) * 1e3;
37
- const totalTtl = staleTimeMs + (config.gcTime ?? 60) * 1e3;
36
+ const staleTimeSec = config.staleTime ?? 0;
37
+ const totalTtlSec = staleTimeSec + (config.gcTime ?? 60);
38
38
  const now = Date.now();
39
39
  const envelope = {
40
40
  data,
41
41
  createdAt: now,
42
- staleAfter: now + staleTimeMs,
43
- expiresAt: now + totalTtl,
42
+ staleAfter: now + staleTimeSec * 1e3,
43
+ expiresAt: now + totalTtlSec * 1e3,
44
44
  tags: config.tags ?? []
45
45
  };
46
- await this.store.set(key, envelope, { ttlMs: totalTtl });
46
+ await this.store.set(key, envelope, totalTtlSec);
47
47
  }
48
48
  async invalidate(key) {
49
49
  await this.store.delete(key);
@@ -56,7 +56,7 @@ var QueryCache = class {
56
56
  async bumpResourceVersion(resource) {
57
57
  const key = versionKey(resource);
58
58
  const newVersion = Date.now();
59
- await this.store.set(key, newVersion, { ttlMs: 1440 * 60 * 1e3 });
59
+ await this.store.set(key, newVersion, 1440 * 60);
60
60
  }
61
61
  /** Get current version for a tag */
62
62
  async getTagVersion(tag) {
@@ -66,7 +66,7 @@ var QueryCache = class {
66
66
  async bumpTagVersion(tag) {
67
67
  const key = tagVersionKey(tag);
68
68
  const newVersion = Date.now();
69
- await this.store.set(key, newVersion, { ttlMs: 1440 * 60 * 1e3 });
69
+ await this.store.set(key, newVersion, 1440 * 60);
70
70
  }
71
71
  };
72
72
  //#endregion
@@ -1,4 +1,4 @@
1
- import { m as RESERVED_QUERY_PARAMS } from "./constants-Cxde4rpC.mjs";
1
+ import { m as RESERVED_QUERY_PARAMS } from "./constants-BhY1OHoH.mjs";
2
2
  //#region src/utils/queryParser.ts
3
3
  /**
4
4
  * Arc Query Parser - Default URL-to-Query Parser
@@ -1,4 +1,4 @@
1
- import { n as IdempotencyResult, r as IdempotencyStore } from "./interface-DfLGcus7.mjs";
1
+ import { n as IdempotencyResult, r as IdempotencyStore } from "./interface-CSbZdv_3.mjs";
2
2
 
3
3
  //#region src/idempotency/stores/redis.d.ts
4
4
  interface RedisClient {
@@ -1,4 +1,4 @@
1
- import { i as EventTransport, n as EventHandler, r as EventLogger, t as DomainEvent } from "./EventTransport-BXja8NOc.mjs";
1
+ import { i as EventLogger, n as DomainEvent, o as EventTransport, r as EventHandler } from "./EventTransport-CUw5NNWe.mjs";
2
2
 
3
3
  //#region src/events/transports/redis-stream.d.ts
4
4
  interface RedisStreamLike {