@classytic/arc 2.34.0 → 2.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/dist/{BaseController-CbkuhNI2.mjs → BaseController-CTJKm6Cb.mjs} +95 -14
  2. package/dist/{EventTransport-tq4CEB-q.mjs → EventTransport-D23Uvhg4.mjs} +1 -1
  3. package/dist/{HookSystem-DqXkMXkB.mjs → HookSystem-DgwxNZTx.mjs} +6 -4
  4. package/dist/{ResourceRegistry-DoALUlOO.mjs → ResourceRegistry-DNuYVbmv.mjs} +2 -2
  5. package/dist/{pipeline-q69DZzgG.mjs → actionPermissions-D97DniUQ.mjs} +30 -7
  6. package/dist/audit/index.d.mts +2 -2
  7. package/dist/audit/index.mjs +2 -2
  8. package/dist/auth/audit.mjs +1 -1
  9. package/dist/auth/index.d.mts +2 -2
  10. package/dist/auth/index.mjs +6 -6
  11. package/dist/auth/redis-session.mjs +1 -1
  12. package/dist/{authorizationDecision-CMMLWmuZ.mjs → authorizationDecision-EsiY3nUu.mjs} +2 -2
  13. package/dist/{base-Csjc2oF-.d.mts → base-C-NL2fTi.d.mts} +16 -1
  14. package/dist/{buildHandler-BrdYrG_1.mjs → buildHandler-Dohd2JuY.mjs} +4 -4
  15. package/dist/cache/index.mjs +4 -4
  16. package/dist/{caching-BcGmvnHh.mjs → caching-CP3GLJ7U.mjs} +2 -2
  17. package/dist/cleanup/index.d.mts +2 -2
  18. package/dist/cleanup/index.mjs +4 -4
  19. package/dist/cli/commands/describe.d.mts +1 -1
  20. package/dist/cli/commands/describe.mjs +3 -3
  21. package/dist/cli/commands/docs.mjs +3 -3
  22. package/dist/cli/commands/doctor.mjs +1 -1
  23. package/dist/cli/commands/generate.mjs +2 -2
  24. package/dist/cli/commands/init.mjs +2 -2
  25. package/dist/cli/commands/introspect.mjs +2 -2
  26. package/dist/cli/index.mjs +3 -3
  27. package/dist/{constants-BxCoxmiN.mjs → constants-DUoKAGYD.mjs} +1 -1
  28. package/dist/context/index.d.mts +16 -1
  29. package/dist/context/index.mjs +64 -4
  30. package/dist/core/index.d.mts +2 -2
  31. package/dist/core/index.mjs +7 -8
  32. package/dist/{core-BYKa8wHu.mjs → core-DTXsiNTJ.mjs} +3 -3
  33. package/dist/{createActionRouter-D6T0jWhS.mjs → createActionRouter-CZz6JO93.mjs} +27 -64
  34. package/dist/{createAggregationRouter-QLV2PrWP.mjs → createAggregationRouter-DKrGv_EC.mjs} +7 -7
  35. package/dist/defineAggregation-CpQfcM8R.mjs +25 -0
  36. package/dist/{defineResource-ZhuLonLm.mjs → defineResource-DWzjyxb2.mjs} +62 -66
  37. package/dist/discovery/index.mjs +1 -1
  38. package/dist/docs/index.d.mts +1 -1
  39. package/dist/docs/index.mjs +3 -3
  40. package/dist/{elevation-B0tlY8y1.mjs → elevation-D_cmo80j.mjs} +4 -4
  41. package/dist/encryption/index.mjs +3 -3
  42. package/dist/{errorHandler-C7xBqHsI.mjs → errorHandler-2RT0hLSI.mjs} +3 -3
  43. package/dist/{errors-Cd_yy7aW.mjs → errors-DDKni6Tz.mjs} +1 -1
  44. package/dist/{eventPlugin-DSNEZWfV.d.mts → eventPlugin-B47sfCJ8.d.mts} +1 -1
  45. package/dist/{eventPlugin-Dar8qRaj.mjs → eventPlugin-c3YwGzz9.mjs} +5 -5
  46. package/dist/events/index.d.mts +2 -2
  47. package/dist/events/index.mjs +5 -5
  48. package/dist/events/transports/redis-stream-entry.mjs +1 -1
  49. package/dist/events/transports/redis.mjs +1 -1
  50. package/dist/factory/index.d.mts +5 -5
  51. package/dist/factory/index.mjs +5 -6
  52. package/dist/{fastify-augmentation-DVsTAy6X.d.mts → fastify-augmentation-Bk_9PoiV.d.mts} +3 -3
  53. package/dist/{fields-CojeUkS4.mjs → fields-DdP225wt.mjs} +1 -1
  54. package/dist/{generate-DiB0nHPR.mjs → generate-B1bKdcV9.mjs} +2 -2
  55. package/dist/{headers-CveNO9gR.mjs → headers-DKslnhey.mjs} +2 -2
  56. package/dist/{health-CasG2A28.mjs → health-k6NODS8f.mjs} +1 -1
  57. package/dist/hooks/index.d.mts +1 -1
  58. package/dist/hooks/index.mjs +2 -2
  59. package/dist/idempotency/index.mjs +22 -56
  60. package/dist/idempotency/redis.mjs +1 -1
  61. package/dist/{index-B-DvUzsr.d.mts → index-BtYoMip1.d.mts} +21 -3
  62. package/dist/{index-BcR2bFZQ.d.mts → index-C01wWGJt.d.mts} +33 -105
  63. package/dist/{index-C5NnMEKF.d.mts → index-C50BUxKs.d.mts} +1 -1
  64. package/dist/{index-CFAJEWCX.d.mts → index-RdpLP71b.d.mts} +7 -30
  65. package/dist/{index-ugr1tQlW.d.mts → index-eyg5WEcy.d.mts} +1 -1
  66. package/dist/index.d.mts +5 -5
  67. package/dist/index.mjs +11 -12
  68. package/dist/{init-mdJ-v4Xp.mjs → init-LuGxIbQ_.mjs} +1 -1
  69. package/dist/integrations/event-gateway.mjs +2 -2
  70. package/dist/integrations/index.d.mts +2 -2
  71. package/dist/integrations/index.mjs +1 -1
  72. package/dist/integrations/jobs/index.d.mts +1 -1
  73. package/dist/integrations/jobs/index.mjs +2 -2
  74. package/dist/integrations/mcp/index.d.mts +4 -4
  75. package/dist/integrations/mcp/index.mjs +2 -2
  76. package/dist/integrations/mcp/testing.d.mts +1 -1
  77. package/dist/integrations/mcp/testing.mjs +3 -3
  78. package/dist/integrations/streamline.mjs +3 -3
  79. package/dist/integrations/webhooks.d.mts +4 -2
  80. package/dist/integrations/webhooks.mjs +28 -27
  81. package/dist/integrations/websocket-pushref-redis.mjs +1 -1
  82. package/dist/integrations/websocket-redis.mjs +1 -1
  83. package/dist/integrations/websocket.mjs +1 -1
  84. package/dist/{interface-DznJrm9R.mjs → interface-B7awDx3b.mjs} +1 -1
  85. package/dist/{jsonBody-CfGH-GxO.mjs → jsonBody-CiHih3ZU.mjs} +2 -2
  86. package/dist/{keys-WeKvY1dE.mjs → keys-BcNl12HN.mjs} +1 -1
  87. package/dist/{loadResources-Bj-aSsXi.mjs → loadResources-DGlfRQc9.mjs} +2 -2
  88. package/dist/{loadResourcesFromEntry-DwaxNcE2.mjs → loadResourcesFromEntry-VYPGSas8.mjs} +2 -2
  89. package/dist/logger/index.d.mts +23 -4
  90. package/dist/logger/index.mjs +50 -7
  91. package/dist/{mcpPlugin-DX3PHD7K.mjs → mcpPlugin-NxSlc-Ks.mjs} +15 -16
  92. package/dist/{memory-qYSB7rMQ.mjs → memory-BU-C-MV3.mjs} +2 -2
  93. package/dist/{metrics-D7uchLjN.mjs → metrics-7_1GbJpl.mjs} +2 -2
  94. package/dist/middleware/index.d.mts +1 -1
  95. package/dist/middleware/index.mjs +3 -3
  96. package/dist/migrations/index.mjs +7 -4
  97. package/dist/{module-CwKsgZXp.mjs → module-CQNHzE7g.mjs} +1 -1
  98. package/dist/{multipartBody-4w-S3-PU.mjs → multipartBody-Bi5yqW0M.mjs} +1 -1
  99. package/dist/{openapi-CkV5mQ53.mjs → openapi-RpNbPBL-.mjs} +6 -6
  100. package/dist/outbox-admin/index.d.mts +2 -2
  101. package/dist/outbox-admin/index.mjs +4 -4
  102. package/dist/{outbox-module-D1QfHqO4.mjs → outbox-module-ClcFrq98.mjs} +6 -4
  103. package/dist/{outbox-module-C1Bs_FXF.d.mts → outbox-module-b1TyDGGi.d.mts} +24 -1
  104. package/dist/permissions/index.d.mts +2 -2
  105. package/dist/permissions/index.mjs +5 -5
  106. package/dist/{permissions-CP47jdi7.mjs → permissions-DgPrZsJh.mjs} +36 -9
  107. package/dist/{pipe-BzzoEhHj.mjs → pipe-Cjy1UiXX.mjs} +2 -2
  108. package/dist/pipeline/index.d.mts +1 -1
  109. package/dist/pipeline/index.mjs +2 -2
  110. package/dist/plugins/index.d.mts +92 -7
  111. package/dist/plugins/index.mjs +168 -17
  112. package/dist/plugins/response-cache.mjs +2 -2
  113. package/dist/plugins/tracing-entry.mjs +2 -2
  114. package/dist/{pluralize-B7xf8qZF.mjs → pluralize-B7m0dPm8.mjs} +1 -1
  115. package/dist/{preloadResources-g07ldtzh.d.mts → preloadResources-BuutdWgr.d.mts} +54 -270
  116. package/dist/{createApp-zR-DEesr.mjs → preloadResources-CjnW4iIX.mjs} +170 -34
  117. package/dist/presets/filesUpload.d.mts +3 -3
  118. package/dist/presets/filesUpload.mjs +5 -5
  119. package/dist/presets/index.d.mts +2 -2
  120. package/dist/presets/index.mjs +2 -2
  121. package/dist/presets/multiTenant.d.mts +1 -1
  122. package/dist/presets/multiTenant.mjs +3 -3
  123. package/dist/presets/search.d.mts +9 -47
  124. package/dist/presets/search.mjs +2 -2
  125. package/dist/{presets-BAPijK_A.mjs → presets-CsGg8B58.mjs} +4 -4
  126. package/dist/{projection-BKM0Ui-s.mjs → projection-koISNyQo.mjs} +2 -2
  127. package/dist/{queryCachePlugin-DhsZ0ZIc.mjs → queryCachePlugin-DHueQT9O.mjs} +5 -5
  128. package/dist/{rateLimitKey-XngqVNEV.mjs → rateLimitKey-Bma8VXDO.mjs} +1 -1
  129. package/dist/{realtime-G1TC6Yzc.mjs → realtime-BBoC91Bz.mjs} +9 -9
  130. package/dist/{rateLimit-D4-ASwsI.mjs → registerRoute-BTgORTlR.mjs} +114 -3
  131. package/dist/registry/index.d.mts +2 -2
  132. package/dist/registry/index.mjs +3 -3
  133. package/dist/{registry-CLxCR5LF.mjs → registry-BzvRCYS6.mjs} +15 -56
  134. package/dist/{renewingLease-BnWtbA2U.mjs → renewingLease-CgIGh0Ab.mjs} +14 -2
  135. package/dist/{replyHelpers-BSBVCwL3.mjs → replyHelpers-BN16KPHr.mjs} +2 -2
  136. package/dist/{requestContext-uYE35JxI.mjs → requestContext-B93dmpf0.mjs} +1 -1
  137. package/dist/{rolldown-runtime-DNg-KNCk.mjs → rolldown-runtime-JJWfp8rp.mjs} +1 -1
  138. package/dist/{runtimeCapabilities-Dm88DaTW.mjs → runtimeCapabilities-jK99Ciw_.mjs} +1 -1
  139. package/dist/{schedules-CAcZgia0.mjs → schedules-CKKEL21P.mjs} +6 -4
  140. package/dist/{schemaConverter-XH1RZRyu.mjs → schemaConverter-gg0_aUPF.mjs} +19 -32
  141. package/dist/{schemaIR-CDvclAew.mjs → schemaIR-CngYvpCF.mjs} +2 -2
  142. package/dist/schemas/index.mjs +1 -1
  143. package/dist/scim/index.mjs +2 -2
  144. package/dist/scope/index.d.mts +1 -1
  145. package/dist/scope/index.mjs +5 -5
  146. package/dist/{scope-BaWcqBvr.mjs → scope-B1RsHdjF.mjs} +4 -4
  147. package/dist/simpleEqualityMatcher-_9NAMHUD.mjs +43 -0
  148. package/dist/{sse-Cf0jUHsh.mjs → sse-Bxt03Hk5.mjs} +5 -5
  149. package/dist/{sseStream-Bvpi-UXQ.mjs → sseStream-BMHTLlhR.mjs} +2 -2
  150. package/dist/{store-helpers-B88p99Z2.mjs → store-helpers-Brt8OxWZ.mjs} +1 -1
  151. package/dist/{streaming-DsT1B5zJ.mjs → streaming-CiTJW8kZ.mjs} +1 -1
  152. package/dist/{subscribe-helpers-CLIOHsOK.mjs → subscribe-helpers-B4fNHRNc.mjs} +21 -49
  153. package/dist/sync/changelog.mjs +1 -1
  154. package/dist/testing/cleanupStoreContract.mjs +1 -1
  155. package/dist/testing/index.d.mts +6 -6
  156. package/dist/testing/index.mjs +10 -11
  157. package/dist/testing/outboxStoreContract.mjs +1 -1
  158. package/dist/testing/storageContract.mjs +1 -1
  159. package/dist/{transactionContext-BYtWnwAS.mjs → transactionContext-D2HwJM2z.mjs} +1 -1
  160. package/dist/{typeGuards-jjKJDN13.mjs → typeGuards-IE1laMDf.mjs} +1 -1
  161. package/dist/types/index.d.mts +3 -3
  162. package/dist/types/index.mjs +1 -1
  163. package/dist/types/storage.mjs +1 -1
  164. package/dist/{types-CoqIRrkY.mjs → types-B8lwJv9Q.mjs} +10 -53
  165. package/dist/{types-BfC83KsP.d.mts → types-BXnTOsXP.d.mts} +1 -1
  166. package/dist/{types-BcTumAz_.d.mts → types-DDD5RKTu.d.mts} +30 -87
  167. package/dist/{types-ChuShpCP.d.mts → types-Ddl9OjmE.d.mts} +18 -121
  168. package/dist/usage/index.d.mts +2 -2
  169. package/dist/usage/index.mjs +0 -0
  170. package/dist/{userHelpers-CWF5pbZD.mjs → userHelpers-xQAi5bPF.mjs} +1 -1
  171. package/dist/utils/index.d.mts +16 -42
  172. package/dist/utils/index.mjs +11 -11
  173. package/dist/{utils-h1V_sT-t.mjs → utils-DgNFsJ2c.mjs} +3 -3
  174. package/dist/{validate-CdQlz52F.mjs → validate-DI3L5V9w.mjs} +2 -2
  175. package/dist/{versioning-rZbyLVD-.mjs → versioning-COpAyfpZ.mjs} +3 -3
  176. package/package.json +8 -8
  177. package/dist/actionPermissions-CUeCmpUd.mjs +0 -25
  178. package/dist/defineAggregation-Nv-DwfOf.mjs +0 -48
  179. package/dist/preloadResources-BkyqeTDz.mjs +0 -46
  180. package/dist/registerRoute-Ba8v0PCa.mjs +0 -113
  181. package/dist/repositoryFilter-BANpz6BX.mjs +0 -78
  182. package/dist/simpleEqualityMatcher-Se8VrsaP.mjs +0 -69
@@ -1,12 +1,12 @@
1
- /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
- import { t as __exportAll } from "./rolldown-runtime-DNg-KNCk.mjs";
3
- import { arcLog, configureArcLogger, createPinoWriter } from "./logger/index.mjs";
4
- import { n as PUBLIC_SCOPE } from "./types-CoqIRrkY.mjs";
5
- import { t as auditRuntimeCapabilities } from "./runtimeCapabilities-Dm88DaTW.mjs";
6
- import { t as createTenantKeyGenerator } from "./rateLimitKey-XngqVNEV.mjs";
7
- import { i as createRequestIdGenerator, r as mergeHealthChecks } from "./health-CasG2A28.mjs";
8
- import { t as parseJsonBody } from "./jsonBody-CfGH-GxO.mjs";
9
- import { r as wrapWithBoundary } from "./subscribe-helpers-CLIOHsOK.mjs";
1
+ /*! @classytic/arc v2.36.0 | MIT | https://classytic.com */
2
+ import { t as __exportAll } from "./rolldown-runtime-JJWfp8rp.mjs";
3
+ import { arcLog, configureArcLogger, createPinoWriter, enterArcLoggerScope, runWithArcLogger } from "./logger/index.mjs";
4
+ import { n as PUBLIC_SCOPE } from "./types-B8lwJv9Q.mjs";
5
+ import { t as auditRuntimeCapabilities } from "./runtimeCapabilities-jK99Ciw_.mjs";
6
+ import { t as createTenantKeyGenerator } from "./rateLimitKey-Bma8VXDO.mjs";
7
+ import { i as createRequestIdGenerator, r as mergeHealthChecks } from "./health-k6NODS8f.mjs";
8
+ import { t as parseJsonBody } from "./jsonBody-CiHih3ZU.mjs";
9
+ import { r as wrapWithBoundary } from "./subscribe-helpers-B4fNHRNc.mjs";
10
10
  import { isProductionEnv } from "@classytic/primitives/environment";
11
11
  import Fastify from "fastify";
12
12
  import qs from "qs";
@@ -48,6 +48,56 @@ const PLUGIN_REGISTRY = {
48
48
  optional: true
49
49
  }
50
50
  };
51
+ /**
52
+ * Fail ONCE with every missing package, before any plugin registers.
53
+ *
54
+ * Without this the first absent package throws and the operator installs it,
55
+ * restarts, hits the next one, and repeats — six restarts to discover a peer
56
+ * set that was pruned as a unit. These are OPTIONAL peers of arc, so nothing
57
+ * at install or build time says they are gone; the first signal is a boot
58
+ * crash naming exactly one of them.
59
+ *
60
+ * Required-ness is read from `PLUGIN_REGISTRY` (`!optional`), never a second
61
+ * list — a hand-maintained copy is what goes stale the day a plugin is added.
62
+ * Optional plugins are deliberately NOT preflighted: their absence is a
63
+ * supported configuration, and `loadPlugin` already warns and skips.
64
+ *
65
+ * A plugin the host disabled (`{ helmet: false }`) is not checked — refusing to
66
+ * boot over a package for a plugin nobody asked for would be the opposite of
67
+ * helpful.
68
+ */
69
+ async function preflightPlugins(config, options = {}) {
70
+ const { load } = options;
71
+ const required = Object.entries(PLUGIN_REGISTRY).filter(([name, entry]) => !entry.optional && config[name] !== false);
72
+ const results = await Promise.allSettled(required.map(([name, entry]) => load ? load(name) : entry.loader()));
73
+ const missing = [];
74
+ for (const [i, result] of results.entries()) {
75
+ if (result.status === "fulfilled") continue;
76
+ const [name, entry] = required[i];
77
+ if (!isModuleNotFound(result.reason)) throw new Error(`Failed to load plugin '${name}': ${result.reason.message}`);
78
+ missing.push({
79
+ name,
80
+ package: entry.package
81
+ });
82
+ }
83
+ if (missing.length === 0) return;
84
+ const packages = missing.map((m) => m.package);
85
+ throw new Error(`arc cannot start: ${missing.length} required plugin package(s) are not installed.\n` + missing.map((m) => ` - ${m.package} (plugin '${m.name}')`).join("\n") + `\n\nInstall all of them:\n npm install ${packages.join(" ")}\n\nOr disable the plugins you do not need in createApp options: ` + missing.map((m) => `${m.name}: false`).join(", "));
86
+ }
87
+ /** Shared by the preflight and the per-plugin loader so they agree on what "missing" means. */
88
+ function isModuleNotFound(err) {
89
+ /**
90
+ * CODE first, message second. Node sets `ERR_MODULE_NOT_FOUND` (ESM) or
91
+ * `MODULE_NOT_FOUND` (CJS) on a real resolution failure; the message text
92
+ * varies by Node version, loader and bundler, so matching it alone is a
93
+ * predicate that silently stops matching after an upgrade — and this one
94
+ * decides between "install a package" and "your plugin crashed".
95
+ */
96
+ const code = err?.code;
97
+ if (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") return true;
98
+ const m = err?.message ?? "";
99
+ return m.includes("Cannot find module") || m.includes("Cannot find package") || m.includes("MODULE_NOT_FOUND") || m.includes("Could not resolve");
100
+ }
51
101
  async function loadPlugin(name, logger) {
52
102
  const entry = PLUGIN_REGISTRY[name];
53
103
  if (!entry) throw new Error(`Unknown plugin: ${name}`);
@@ -55,12 +105,12 @@ async function loadPlugin(name, logger) {
55
105
  return await entry.loader();
56
106
  } catch (error) {
57
107
  const err = error;
58
- const isModuleNotFound = err.message.includes("Cannot find module") || err.message.includes("Cannot find package") || err.message.includes("MODULE_NOT_FOUND") || err.message.includes("Could not resolve");
59
- if (isModuleNotFound && entry.optional) {
108
+ const notFound = isModuleNotFound(err);
109
+ if (notFound && entry.optional) {
60
110
  logger?.warn(`Optional plugin '${name}' skipped (${entry.package} not installed)`);
61
111
  return null;
62
112
  }
63
- if (isModuleNotFound) throw new Error(`Plugin '${name}' requires package '${entry.package}' which is not installed.\nInstall it with: npm install ${entry.package}\nOr disable this plugin by setting ${name}: false in createApp options.`);
113
+ if (notFound) throw new Error(`Plugin '${name}' requires package '${entry.package}' which is not installed.\nInstall it with: npm install ${entry.package}\nOr disable this plugin by setting ${name}: false in createApp options.`);
64
114
  throw new Error(`Failed to load plugin '${name}': ${err.message}`);
65
115
  }
66
116
  }
@@ -801,7 +851,7 @@ async function registerArcCore(fastify, config, trackPlugin) {
801
851
  await fastify.register(arcCorePlugin, { emitEvents: config.arcPlugins?.emitEvents !== false });
802
852
  trackPlugin("arc-core");
803
853
  if (config.arcPlugins?.events !== false) {
804
- const { default: eventPlugin } = await import("./eventPlugin-Dar8qRaj.mjs").then((n) => n.n);
854
+ const { default: eventPlugin } = await import("./eventPlugin-c3YwGzz9.mjs").then((n) => n.n);
805
855
  const eventOpts = typeof config.arcPlugins?.events === "object" ? config.arcPlugins.events : {};
806
856
  await fastify.register(eventPlugin, {
807
857
  /**
@@ -860,15 +910,15 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules, moduleH
860
910
  trackPlugin("arc-graceful-shutdown");
861
911
  }
862
912
  if (config.arcPlugins?.caching) {
863
- const { default: cachingPlugin } = await import("./caching-BcGmvnHh.mjs").then((n) => n.r);
913
+ const { default: cachingPlugin } = await import("./caching-CP3GLJ7U.mjs").then((n) => n.r);
864
914
  const opts = config.arcPlugins.caching === true ? {} : config.arcPlugins.caching;
865
915
  await fastify.register(cachingPlugin, opts);
866
916
  trackPlugin("arc-caching", opts);
867
917
  }
868
918
  if (config.arcPlugins?.queryCache) {
869
- const { queryCachePlugin } = await import("./queryCachePlugin-DhsZ0ZIc.mjs").then((n) => n.n);
919
+ const { queryCachePlugin } = await import("./queryCachePlugin-DHueQT9O.mjs").then((n) => n.n);
870
920
  const opts = config.arcPlugins.queryCache === true ? {} : config.arcPlugins.queryCache;
871
- const store = config.stores?.queryCache ?? new (await (import("./memory-qYSB7rMQ.mjs").then((n) => n.n))).MemoryCacheStore();
921
+ const store = config.stores?.queryCache ?? new (await (import("./memory-BU-C-MV3.mjs").then((n) => n.n))).MemoryCacheStore();
872
922
  await fastify.register(queryCachePlugin, {
873
923
  store,
874
924
  ...opts
@@ -878,7 +928,7 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules, moduleH
878
928
  if (config.arcPlugins?.sse) {
879
929
  if (config.arcPlugins?.events === false) fastify.log.warn("SSE plugin requires events plugin (arcPlugins.events). SSE disabled.");
880
930
  else {
881
- const { default: ssePlugin } = await import("./sse-Cf0jUHsh.mjs").then((n) => n.r);
931
+ const { default: ssePlugin } = await import("./sse-Bxt03Hk5.mjs").then((n) => n.r);
882
932
  const opts = config.arcPlugins.sse === true ? {} : config.arcPlugins.sse;
883
933
  await fastify.register(ssePlugin, opts);
884
934
  trackPlugin("arc-sse", opts);
@@ -887,20 +937,20 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules, moduleH
887
937
  if (config.arcPlugins?.realtime) {
888
938
  if (config.arcPlugins?.events === false) fastify.log.warn("Realtime plugin requires events plugin (arcPlugins.events). Realtime disabled.");
889
939
  else {
890
- const { default: realtimePlugin } = await import("./realtime-G1TC6Yzc.mjs").then((n) => n.r);
940
+ const { default: realtimePlugin } = await import("./realtime-BBoC91Bz.mjs").then((n) => n.r);
891
941
  const opts = config.arcPlugins.realtime === true ? {} : config.arcPlugins.realtime;
892
942
  await fastify.register(realtimePlugin, opts);
893
943
  trackPlugin("arc-realtime", opts);
894
944
  }
895
945
  }
896
946
  if (config.arcPlugins?.metrics) {
897
- const { default: metricsPlugin } = await import("./metrics-D7uchLjN.mjs").then((n) => n.r);
947
+ const { default: metricsPlugin } = await import("./metrics-7_1GbJpl.mjs").then((n) => n.r);
898
948
  const opts = config.arcPlugins.metrics === true ? {} : config.arcPlugins.metrics;
899
949
  await fastify.register(metricsPlugin, opts);
900
950
  trackPlugin("arc-metrics", opts);
901
951
  }
902
952
  if (config.arcPlugins?.versioning) {
903
- const { default: versioningPlugin } = await import("./versioning-rZbyLVD-.mjs").then((n) => n.r);
953
+ const { default: versioningPlugin } = await import("./versioning-COpAyfpZ.mjs").then((n) => n.r);
904
954
  await fastify.register(versioningPlugin, config.arcPlugins.versioning);
905
955
  trackPlugin("arc-versioning", config.arcPlugins.versioning);
906
956
  }
@@ -977,7 +1027,7 @@ async function registerAuth(fastify, config, trackPlugin) {
977
1027
  */
978
1028
  async function registerElevation(fastify, config, trackPlugin) {
979
1029
  if (!config.elevation) return;
980
- const { elevationPlugin } = await import("./elevation-B0tlY8y1.mjs").then((n) => n.r);
1030
+ const { elevationPlugin } = await import("./elevation-D_cmo80j.mjs").then((n) => n.r);
981
1031
  await fastify.register(elevationPlugin, config.elevation);
982
1032
  trackPlugin("arc-elevation", config.elevation);
983
1033
  fastify.log.debug("Elevation plugin enabled");
@@ -992,7 +1042,7 @@ async function registerElevation(fastify, config, trackPlugin) {
992
1042
  */
993
1043
  async function registerErrorHandler(fastify, config, trackPlugin, moduleErrorMappers) {
994
1044
  if (config.errorHandler === false) return;
995
- const { errorHandlerPlugin } = await import("./errorHandler-C7xBqHsI.mjs").then((n) => n.r);
1045
+ const { errorHandlerPlugin } = await import("./errorHandler-2RT0hLSI.mjs").then((n) => n.r);
996
1046
  /**
997
1047
  * DISCLOSURE DEFAULTS MERGE — they used to be REPLACED, and that was two bugs.
998
1048
  *
@@ -1216,7 +1266,7 @@ async function registerResources(fastify, config, preResolvedModules) {
1216
1266
  let discoveryPath;
1217
1267
  let discoveryYieldedZero = false;
1218
1268
  if (resolvedResources === void 0 && config.resourceDir) {
1219
- const { loadResources } = await import("./loadResources-Bj-aSsXi.mjs").then((n) => n.n);
1269
+ const { loadResources } = await import("./loadResources-DGlfRQc9.mjs").then((n) => n.n);
1220
1270
  const { resolve, dirname } = await import("node:path");
1221
1271
  const { fileURLToPath } = await import("node:url");
1222
1272
  const rawDir = config.resourceDir;
@@ -1342,7 +1392,7 @@ Resources supplied by "${m.name}": ${provided}.`);
1342
1392
  if (fastify.hasDecorator("getScheduleStats")) throw new Error("[arc] modules declare scheduledJobs but schedulesPlugin was already registered manually. Configure their runner through arcPlugins.schedules so Arc can compose one schedule table.");
1343
1393
  const frozenJobs = Object.freeze(scheduledJobs.map((job) => Object.freeze({ ...job })));
1344
1394
  const scheduleOptions = typeof config.arcPlugins?.schedules === "object" ? config.arcPlugins.schedules : {};
1345
- const { default: schedulesPlugin } = await import("./schedules-CAcZgia0.mjs").then((n) => n.r);
1395
+ const { default: schedulesPlugin } = await import("./schedules-CKKEL21P.mjs").then((n) => n.r);
1346
1396
  await fastify.register(schedulesPlugin, {
1347
1397
  ...scheduleOptions,
1348
1398
  schedules: frozenJobs
@@ -1552,6 +1602,11 @@ function compilePathMatcher(patterns) {
1552
1602
  * All enabled by default — set to `false` to opt out.
1553
1603
  */
1554
1604
  async function registerSecurityPlugins(fastify, config) {
1605
+ /**
1606
+ * Resolve every enabled plugin's package FIRST, so a pruned peer set is one
1607
+ * error listing all of them rather than one restart per package.
1608
+ */
1609
+ await preflightPlugins(config);
1555
1610
  if (config.helmet !== false) {
1556
1611
  const helmet = await loadPlugin("helmet");
1557
1612
  await fastify.register(helmet, config.helmet ?? {});
@@ -1696,7 +1751,7 @@ const MEMORY_STORE_NAMES = /* @__PURE__ */ new Set(["memory", "memory-cache"]);
1696
1751
  * Hosts that need NO redaction (test fixtures, security audits) opt out
1697
1752
  * with `logger: { redact: [] }`. Hosts that need MORE redaction supply
1698
1753
  * their own `redact` and arc steps aside — this default never overrides
1699
- * an explicit setting. (2.15.1)
1754
+ * an explicit setting.
1700
1755
  */
1701
1756
  const DEFAULT_LOGGER_REDACT_PATHS = [
1702
1757
  "req.headers.authorization",
@@ -1813,11 +1868,22 @@ async function createApp(options) {
1813
1868
  */
1814
1869
  const declaredRole = options.role ?? "all";
1815
1870
  if ((declaredRole === "relay" || declaredRole === "scheduler") && (options.resources !== void 0 || options.resourceDir !== void 0)) throw new Error(`createApp: role '${declaredRole}' declares HTTP resources — a ${declaredRole} process must not serve routes. Remove \`resources\`/\`resourceDir\`, or change the role.`);
1871
+ /**
1872
+ * This app's own `arcLog` config, entered for the WHOLE boot.
1873
+ *
1874
+ * Held by reference and mutated in `buildApp` once `fastify.log` exists:
1875
+ * boot starts before Fastify does, so a copied snapshot would send every
1876
+ * post-construction boot warning to the console instead of this app's
1877
+ * logger. Scoping it per app is what stops two apps in one process from
1878
+ * overwriting each other's writer — see `src/logger/index.ts`.
1879
+ */
1880
+ const loggerScope = {};
1881
+ if (options.debug !== void 0 && options.debug !== false) loggerScope.debug = options.debug;
1816
1882
  let partial;
1817
1883
  try {
1818
- return await buildApp(options, (instance) => {
1884
+ return await runWithArcLogger(loggerScope, () => buildApp(options, loggerScope, (instance) => {
1819
1885
  partial = instance;
1820
- });
1886
+ }));
1821
1887
  } catch (err) {
1822
1888
  if (partial) try {
1823
1889
  await partial.close();
@@ -1827,8 +1893,7 @@ async function createApp(options) {
1827
1893
  throw err;
1828
1894
  }
1829
1895
  }
1830
- async function buildApp(options, onInstance) {
1831
- if (options.debug !== void 0 && options.debug !== false) configureArcLogger({ debug: options.debug });
1896
+ async function buildApp(options, loggerScope, onInstance) {
1832
1897
  validateAuthOptions(options);
1833
1898
  const deferredWarnings = validateDistributedRuntime(options);
1834
1899
  if (options.beforeBoot) await options.beforeBoot();
@@ -1837,6 +1902,25 @@ async function buildApp(options, onInstance) {
1837
1902
  ...options
1838
1903
  };
1839
1904
  const inheritedTrustProxyDefault = options.preset === "production" && options.trustProxy === void 0;
1905
+ /**
1906
+ * A NUMERIC `trustProxy` is a no-op on Fastify >= 5.12.1.
1907
+ *
1908
+ * Fastify made hop-count trust fail-closed on purpose — the comment in
1909
+ * `lib/request.js` is explicit: "Hop-count-only trust cannot validate the
1910
+ * immediate peer. Fail closed so direct clients cannot spoof X-Forwarded-*
1911
+ * values by supplying enough hops." So `trustProxy: 1` now trusts NOTHING.
1912
+ *
1913
+ * That is the right call upstream and the wrong thing to inherit silently:
1914
+ * `request.ip` becomes the proxy's address, which is the exact failure the
1915
+ * production-preset warning below describes — rate-limit keys collapse onto
1916
+ * one bucket and audit rows record the wrong client. The host asked for
1917
+ * proxy trust and got none, with no error.
1918
+ *
1919
+ * Warn rather than refuse: the app still serves, and a hard boot failure on
1920
+ * a transitive `fastify` bump would be a harsher surprise than the one being
1921
+ * reported. The replacement is named so the fix is a copy-paste.
1922
+ */
1923
+ const numericTrustProxy = typeof config.trustProxy === "number";
1840
1924
  const resolvedModules = orderModules(await Promise.all((config.modules ?? []).map((m) => resolveModule(m))));
1841
1925
  const moduleErrorMappers = resolvedModules.flatMap((m) => m.errorMappers ?? []);
1842
1926
  const moduleHealthChecks = collectModuleHealthChecks(resolvedModules);
@@ -1869,11 +1953,19 @@ async function buildApp(options, onInstance) {
1869
1953
  } }
1870
1954
  });
1871
1955
  onInstance(fastify);
1872
- if (resolvedLogger !== false) configureArcLogger({
1873
- ...options.debug !== void 0 && options.debug !== false ? { debug: options.debug } : {},
1874
- writer: createPinoWriter(fastify.log)
1956
+ if (resolvedLogger !== false) {
1957
+ const writer = createPinoWriter(fastify.log);
1958
+ loggerScope.writer = writer;
1959
+ configureArcLogger({
1960
+ ...options.debug !== void 0 && options.debug !== false ? { debug: options.debug } : {},
1961
+ writer
1962
+ });
1963
+ }
1964
+ fastify.addHook("onRequest", (_request, _reply, done) => {
1965
+ enterArcLoggerScope(loggerScope, done);
1875
1966
  });
1876
1967
  for (const warning of deferredWarnings) fastify.log.warn(warning);
1968
+ if (numericTrustProxy) fastify.log.warn(`[arc] trustProxy: ${String(config.trustProxy)} (a hop COUNT) trusts nothing on Fastify >= 5.12.1 — hop-count trust cannot validate the immediate peer, so it fails closed upstream to stop clients spoofing X-Forwarded-* with padded hops. \`request.ip\` is therefore the PROXY's address: rate-limit keys collapse onto one bucket and audit rows record the wrong client. Name the proxies instead — trustProxy: 'loopback', '10.0.0.0/8', a comma-separated list, or \`true\` if every upstream hop is genuinely trusted.`);
1877
1969
  if (inheritedTrustProxyDefault) fastify.log.warn("[arc] preset: 'production' now defaults to trustProxy: false (fail-closed; was true before 2.24). If this app runs behind a load balancer or reverse proxy, request.ip is currently the PROXY's address — rate-limit keys collapse onto one bucket and audit logs record the wrong client. Set trustProxy explicitly: a hop count (trustProxy: 1), a CIDR allow-list ('10.0.0.0/8'), a resolver function, or false if clients truly connect directly.");
1878
1970
  fastify.removeContentTypeParser("application/json");
1879
1971
  fastify.addContentTypeParser("application/json", { parseAs: "string" }, (_req, body, done) => {
@@ -1907,7 +1999,7 @@ async function buildApp(options, onInstance) {
1907
1999
  await registerErrorHandler(fastify, config, trackPlugin, moduleErrorMappers);
1908
2000
  await registerResources(fastify, config, resolvedModules);
1909
2001
  if (config.replyHelpers) {
1910
- const { replyHelpersPlugin } = await import("./replyHelpers-BSBVCwL3.mjs").then((n) => n.n);
2002
+ const { replyHelpersPlugin } = await import("./replyHelpers-BN16KPHr.mjs").then((n) => n.n);
1911
2003
  await fastify.register(replyHelpersPlugin);
1912
2004
  }
1913
2005
  if (config.serializeBigInt) {
@@ -1959,4 +2051,48 @@ const ArcFactory = {
1959
2051
  }
1960
2052
  };
1961
2053
  //#endregion
1962
- export { collectModuleScheduledJobs as _, developmentPreset as a, resolveModule as b, productionPreset as c, getModuleState as d, hasModule as f, collectModuleHealthChecks as g, describeResolvedModule as h, createApp_exports as i, testingPreset as l, subscribeModuleEventHandlers as m, DEFAULT_LOGGER_REDACT_PATHS as n, edgePreset as o, orderModules as p, createApp as r, getPreset as s, ArcFactory as t, workerPreset as u, collectModuleWorkflows as v, resolveContribution as y };
2054
+ //#region src/factory/preloadResources.ts
2055
+ /**
2056
+ * Normalize an eager `import.meta.glob` result into a `ResourceLike[]`.
2057
+ *
2058
+ * Accepts either:
2059
+ * - `{ import: 'default' }` form: values are the resource directly
2060
+ * - default form: values are the full module — picks first export with `toPlugin()`
2061
+ *
2062
+ * Throws if any module doesn't yield a valid `ResourceLike`.
2063
+ */
2064
+ function preloadResources(globResult) {
2065
+ const resources = [];
2066
+ for (const [path, value] of Object.entries(globResult)) {
2067
+ const resource = pickResource(value);
2068
+ if (!resource) throw new Error(`preloadResources: ${path} does not export a valid resource.\n Expected: a default export OR a named export with toPlugin().`);
2069
+ resources.push(resource);
2070
+ }
2071
+ return resources.sort((a, b) => (a.name ?? "").localeCompare(b.name ?? ""));
2072
+ }
2073
+ /**
2074
+ * Normalize a lazy `import.meta.glob` result into a `Promise<ResourceLike[]>`.
2075
+ *
2076
+ * Use this when resources depend on prior bootstrap (e.g., engine init) and
2077
+ * cannot be evaluated at import time of the preload file.
2078
+ */
2079
+ async function preloadResourcesAsync(globResult) {
2080
+ return (await Promise.all(Object.entries(globResult).map(async ([path, loader]) => {
2081
+ const resource = pickResource(await loader());
2082
+ if (!resource) throw new Error(`preloadResourcesAsync: ${path} does not export a valid resource.\n Expected: a default export OR a named export with toPlugin().`);
2083
+ return resource;
2084
+ }))).sort((a, b) => (a.name ?? "").localeCompare(b.name ?? ""));
2085
+ }
2086
+ function pickResource(value) {
2087
+ if (!value || typeof value !== "object") return void 0;
2088
+ if (typeof value.toPlugin === "function") return value;
2089
+ const mod = value;
2090
+ const candidates = [
2091
+ mod.default,
2092
+ mod.resource,
2093
+ ...Object.values(mod)
2094
+ ];
2095
+ for (const c of candidates) if (c && typeof c === "object" && typeof c.toPlugin === "function") return c;
2096
+ }
2097
+ //#endregion
2098
+ export { resolveModule as S, describeResolvedModule as _, createApp as a, collectModuleWorkflows as b, edgePreset as c, testingPreset as d, workerPreset as f, subscribeModuleEventHandlers as g, orderModules as h, DEFAULT_LOGGER_REDACT_PATHS as i, getPreset as l, hasModule as m, preloadResourcesAsync as n, createApp_exports as o, getModuleState as p, ArcFactory as r, developmentPreset as s, preloadResources as t, productionPreset as u, collectModuleHealthChecks as v, resolveContribution as x, collectModuleScheduledJobs as y };
@@ -1,7 +1,7 @@
1
1
 
2
- import { i as RequestScope } from "../types-ChuShpCP.mjs";
3
- import { l as PermissionCheck } from "../base-Csjc2oF-.mjs";
4
- import { Y as PresetResult } from "../index-BcR2bFZQ.mjs";
2
+ import { i as RequestScope } from "../types-Ddl9OjmE.mjs";
3
+ import { l as PermissionCheck } from "../base-C-NL2fTi.mjs";
4
+ import { Y as PresetResult } from "../index-C01wWGJt.mjs";
5
5
  import { a as StorageReadResult, i as StorageReadRange, n as StorageContext, o as StorageUploadInput, r as StorageFile, t as Storage } from "../storage-Cx9Sz3Ou.mjs";
6
6
  //#region src/presets/filesUpload.d.ts
7
7
  interface FilesUploadPresetRoutes {
@@ -1,8 +1,8 @@
1
- /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
- import { i as NotFoundError, u as ValidationError } from "../errors-Cd_yy7aW.mjs";
3
- import { c as getOrgId, g as getUserId } from "../types-CoqIRrkY.mjs";
4
- import { B as requireAuth, F as allowPublic } from "../permissions-CP47jdi7.mjs";
5
- import { t as multipartBody } from "../multipartBody-4w-S3-PU.mjs";
1
+ /*! @classytic/arc v2.36.0 | MIT | https://classytic.com */
2
+ import { i as NotFoundError, u as ValidationError } from "../errors-DDKni6Tz.mjs";
3
+ import { c as getOrgId, g as getUserId } from "../types-B8lwJv9Q.mjs";
4
+ import { B as requireAuth, F as allowPublic } from "../permissions-DgPrZsJh.mjs";
5
+ import { t as multipartBody } from "../multipartBody-Bi5yqW0M.mjs";
6
6
  //#region src/presets/filesUpload.ts
7
7
  const DEFAULT_FIELD_NAME = "file";
8
8
  const DEFAULT_MAX_FILE_SIZE = 10485760;
@@ -1,6 +1,6 @@
1
1
 
2
- import { t as AnyRecord } from "../base-Csjc2oF-.mjs";
3
- import { Fn as IControllerResponse, In as IRequestContext, U as ResourceConfig, Y as PresetResult, d as PaginationResult } from "../index-BcR2bFZQ.mjs";
2
+ import { t as AnyRecord } from "../base-C-NL2fTi.mjs";
3
+ import { Fn as IControllerResponse, In as IRequestContext, U as ResourceConfig, Y as PresetResult, d as PaginationResult } from "../index-C01wWGJt.mjs";
4
4
  import { FilesUploadPresetOptions, FilesUploadPresetPermissions, FilesUploadPresetRoutes, filesUploadPreset } from "./filesUpload.mjs";
5
5
  import { MultiTenantOptions, TenantFieldSpec, multiTenantPreset } from "./multiTenant.mjs";
6
6
  import { SearchHandler, SearchPresetOptions, SearchRouteConfig, searchPreset } from "./search.mjs";
@@ -1,6 +1,6 @@
1
- /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.36.0 | MIT | https://classytic.com */
2
2
  import { multiTenantPreset } from "./multiTenant.mjs";
3
- 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-BAPijK_A.mjs";
3
+ 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-CsGg8B58.mjs";
4
4
  import { filesUploadPreset } from "./filesUpload.mjs";
5
5
  import { searchPreset } from "./search.mjs";
6
6
  export { applyPresets, auditedPreset, bulkPreset, filesUploadPreset, flexibleMultiTenantPreset, getAvailablePresets, getPreset, multiTenantPreset, ownedByUserPreset, registerPreset, searchPreset, slugLookupPreset, softDeletePreset, treePreset };
@@ -1,5 +1,5 @@
1
1
 
2
- import { X as CrudRouteKey, Y as PresetResult } from "../index-BcR2bFZQ.mjs";
2
+ import { X as CrudRouteKey, Y as PresetResult } from "../index-C01wWGJt.mjs";
3
3
  //#region src/presets/multiTenant.d.ts
4
4
  /**
5
5
  * One tenant dimension for multi-field filtering. Discriminated by source:
@@ -1,6 +1,6 @@
1
- /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
- import "../constants-BxCoxmiN.mjs";
3
- import { b as isElevated, c as getOrgId, d as getScopeContext, m as getTeamId, u as getRequestScope, v as hasOrgAccess } from "../types-CoqIRrkY.mjs";
1
+ /*! @classytic/arc v2.36.0 | MIT | https://classytic.com */
2
+ import "../constants-DUoKAGYD.mjs";
3
+ import { b as isElevated, c as getOrgId, d as getScopeContext, m as getTeamId, u as getRequestScope, v as hasOrgAccess } from "../types-B8lwJv9Q.mjs";
4
4
  //#region src/presets/multiTenant.ts
5
5
  /**
6
6
  * Resolve a single TenantFieldSpec against the current scope.
@@ -1,6 +1,6 @@
1
1
 
2
- import { l as PermissionCheck } from "../base-Csjc2oF-.mjs";
3
- import { At as RouteDefinition, Y as PresetResult, jn as ControllerHandler, jt as RouteMcpConfig } from "../index-BcR2bFZQ.mjs";
2
+ import { l as PermissionCheck } from "../base-C-NL2fTi.mjs";
3
+ import { At as RouteDefinition, Y as PresetResult, jn as ControllerHandler, jt as RouteMcpConfig } from "../index-C01wWGJt.mjs";
4
4
  //#region src/presets/search.d.ts
5
5
  /**
6
6
  * Search Preset — backend-agnostic search / vector / embed routes
@@ -23,55 +23,17 @@ import { At as RouteDefinition, Y as PresetResult, jn as ControllerHandler, jt a
23
23
  * GET-based autocomplete, pass `path`/`method` overrides or use `routes` for
24
24
  * fully bespoke endpoints.
25
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)
26
+ * @example
51
27
  * ```typescript
52
28
  * searchPreset({
29
+ * search: { handler: (req) => repo.search(req.body.query, req.body) },
53
30
  * 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
31
+ * path: '/vector-search', // override the default path
32
+ * mcp: false, // and skip the MCP tool for this one
33
+ * handler: (req) => pinecone.query({ vector: req.body.vector }),
64
34
  * },
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
- * });
35
+ * routes: [{ method: 'GET', path: '/autocomplete', handler, permissions }],
36
+ * })
75
37
  * ```
76
38
  */
77
39
  /**
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
- import { B as requireAuth, F as allowPublic } from "../permissions-CP47jdi7.mjs";
1
+ /*! @classytic/arc v2.36.0 | MIT | https://classytic.com */
2
+ import { B as requireAuth, F as allowPublic } from "../permissions-DgPrZsJh.mjs";
3
3
  //#region src/presets/search.ts
4
4
  const BUILTINS = [
5
5
  {
@@ -1,7 +1,7 @@
1
- /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
- import { l as UnauthorizedError } from "./errors-Cd_yy7aW.mjs";
3
- import { b as isElevated, n as PUBLIC_SCOPE } from "./types-CoqIRrkY.mjs";
4
- import { B as requireAuth, F as allowPublic, U as requireRoles } from "./permissions-CP47jdi7.mjs";
1
+ /*! @classytic/arc v2.36.0 | MIT | https://classytic.com */
2
+ import { l as UnauthorizedError } from "./errors-DDKni6Tz.mjs";
3
+ import { b as isElevated, n as PUBLIC_SCOPE } from "./types-B8lwJv9Q.mjs";
4
+ import { B as requireAuth, F as allowPublic, U as requireRoles } from "./permissions-DgPrZsJh.mjs";
5
5
  import { multiTenantPreset } from "./presets/multiTenant.mjs";
6
6
  //#region src/presets/ownedByUser.ts
7
7
  /**
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
- import { c as getOrgId, f as getScopeContextMap, g as getUserId, m as getTeamId, x as isMember } from "./types-CoqIRrkY.mjs";
1
+ /*! @classytic/arc v2.36.0 | MIT | https://classytic.com */
2
+ import { c as getOrgId, f as getScopeContextMap, g as getUserId, m as getTeamId, x as isMember } from "./types-B8lwJv9Q.mjs";
3
3
  //#region src/scope/projection.ts
4
4
  /**
5
5
  * Compute the request-scope projection. Returns `undefined` when no
@@ -1,8 +1,8 @@
1
- /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
- import { t as __exportAll } from "./rolldown-runtime-DNg-KNCk.mjs";
3
- import { t as hasEvents } from "./typeGuards-jjKJDN13.mjs";
4
- import { i as versionKey, r as tagVersionKey } from "./keys-WeKvY1dE.mjs";
5
- import { t as MemoryCacheStore } from "./memory-qYSB7rMQ.mjs";
1
+ /*! @classytic/arc v2.36.0 | MIT | https://classytic.com */
2
+ import { t as __exportAll } from "./rolldown-runtime-JJWfp8rp.mjs";
3
+ import { t as hasEvents } from "./typeGuards-IE1laMDf.mjs";
4
+ import { i as versionKey, r as tagVersionKey } from "./keys-BcNl12HN.mjs";
5
+ import { t as MemoryCacheStore } from "./memory-BU-C-MV3.mjs";
6
6
  import fp from "fastify-plugin";
7
7
  //#region src/cache/QueryCache.ts
8
8
  var QueryCache = class {
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.36.0 | MIT | https://classytic.com */
2
2
  //#region src/scope/rateLimitKey.ts
3
3
  function createTenantKeyGenerator(opts) {
4
4
  if (opts?.strategy) return opts.strategy;
@@ -1,13 +1,13 @@
1
- /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
- import { t as __exportAll } from "./rolldown-runtime-DNg-KNCk.mjs";
1
+ /*! @classytic/arc v2.36.0 | MIT | https://classytic.com */
2
+ import { t as __exportAll } from "./rolldown-runtime-JJWfp8rp.mjs";
3
3
  import { arcLog } from "./logger/index.mjs";
4
- import { n as evaluateAndApplyPermission } from "./authorizationDecision-CMMLWmuZ.mjs";
5
- import { n as getUserRoles } from "./userHelpers-CWF5pbZD.mjs";
6
- import { c as getOrgId } from "./types-CoqIRrkY.mjs";
7
- import { t as simpleEqualityMatcher } from "./simpleEqualityMatcher-Se8VrsaP.mjs";
8
- import { t as applyFieldReadPermissions } from "./fields-CojeUkS4.mjs";
9
- import { a as promoteStreamTokenToHeader } from "./streaming-DsT1B5zJ.mjs";
10
- import { t as openSseStream } from "./sseStream-Bvpi-UXQ.mjs";
4
+ import { n as evaluateAndApplyPermission } from "./authorizationDecision-EsiY3nUu.mjs";
5
+ import { n as getUserRoles } from "./userHelpers-xQAi5bPF.mjs";
6
+ import { c as getOrgId } from "./types-B8lwJv9Q.mjs";
7
+ import { t as simpleEqualityMatcher } from "./simpleEqualityMatcher-_9NAMHUD.mjs";
8
+ import { t as applyFieldReadPermissions } from "./fields-DdP225wt.mjs";
9
+ import { a as promoteStreamTokenToHeader } from "./streaming-CiTJW8kZ.mjs";
10
+ import { t as openSseStream } from "./sseStream-BMHTLlhR.mjs";
11
11
  import fp from "fastify-plugin";
12
12
  //#region src/plugins/realtime.ts
13
13
  var realtime_exports = /* @__PURE__ */ __exportAll({