@classytic/arc 2.32.0 → 2.33.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 (192) hide show
  1. package/README.md +1 -1
  2. package/bin/arc.js +58 -17
  3. package/dist/{BaseController-Dk34dxhI.mjs → BaseController-CaQC5EXX.mjs} +293 -33
  4. package/dist/{EventTransport-2uVV34WU.d.mts → EventTransport-BEVP50ka.d.mts} +16 -0
  5. package/dist/{EventTransport-BV10D0oG.mjs → EventTransport-tq4CEB-q.mjs} +39 -2
  6. package/dist/{HookSystem-vimw5D7Z.mjs → HookSystem-DqXkMXkB.mjs} +2 -2
  7. package/dist/{ResourceRegistry-BVr7PgA0.mjs → ResourceRegistry-DoALUlOO.mjs} +3 -2
  8. package/dist/{actionPermissions-Dti7ebyv.mjs → actionPermissions-CUeCmpUd.mjs} +1 -1
  9. package/dist/audit/index.d.mts +2 -2
  10. package/dist/audit/index.mjs +2 -2
  11. package/dist/auth/audit.mjs +1 -1
  12. package/dist/auth/index.d.mts +2 -2
  13. package/dist/auth/index.mjs +39 -7
  14. package/dist/auth/redis-session.mjs +1 -1
  15. package/dist/{authorizationDecision-__T3EJDA.mjs → authorizationDecision-B3mP_QTy.mjs} +2 -2
  16. package/dist/{types-B7XeLEgK.d.mts → base-Csjc2oF-.d.mts} +74 -74
  17. package/dist/{buildHandler-Dn7rzUJo.mjs → buildHandler-DLE9xX-V.mjs} +4 -4
  18. package/dist/cache/index.mjs +4 -4
  19. package/dist/{caching-DFJqHyFs.mjs → caching-BcGmvnHh.mjs} +2 -2
  20. package/dist/cleanup/index.d.mts +17 -5
  21. package/dist/cleanup/index.mjs +240 -7
  22. package/dist/cli/commands/describe.d.mts +1 -1
  23. package/dist/cli/commands/describe.mjs +3 -3
  24. package/dist/cli/commands/docs.mjs +3 -3
  25. package/dist/cli/commands/doctor.mjs +1 -1
  26. package/dist/cli/commands/generate.mjs +2 -2
  27. package/dist/cli/commands/init.mjs +2 -2
  28. package/dist/cli/commands/introspect.mjs +2 -2
  29. package/dist/cli/index.mjs +3 -3
  30. package/dist/{constants-J99LGTJI.mjs → constants-BxCoxmiN.mjs} +1 -1
  31. package/dist/context/index.mjs +3 -3
  32. package/dist/core/index.d.mts +2 -2
  33. package/dist/core/index.mjs +7 -7
  34. package/dist/{core-BwwmNSp7.mjs → core-dxhcHhUD.mjs} +3 -3
  35. package/dist/{createActionRouter-DkJZWo0m.mjs → createActionRouter-DVpoA0do.mjs} +8 -8
  36. package/dist/{createAggregationRouter-B1exOVD8.mjs → createAggregationRouter-B_B48JZ-.mjs} +7 -7
  37. package/dist/{createApp-Bv0m-Q6_.mjs → createApp-CLGegqiG.mjs} +128 -24
  38. package/dist/{defineAggregation-gX4No1gt.mjs → defineAggregation-Nv-DwfOf.mjs} +1 -1
  39. package/dist/{defineResource-XFPPUu2c.mjs → defineResource-DR9vsUYy.mjs} +297 -23
  40. package/dist/discovery/index.mjs +1 -1
  41. package/dist/docs/index.d.mts +1 -1
  42. package/dist/docs/index.mjs +3 -3
  43. package/dist/{elevation-DNXXxgjl.mjs → elevation-B0tlY8y1.mjs} +4 -4
  44. package/dist/encryption/index.mjs +3 -3
  45. package/dist/{errorHandler-B2AZUJUj.mjs → errorHandler-C7xBqHsI.mjs} +42 -5
  46. package/dist/{errorHandler-CpYUJmPA.d.mts → errorHandler-DI5AN2b5.d.mts} +14 -3
  47. package/dist/{errors-Bh1KK5ps.mjs → errors-Cd_yy7aW.mjs} +1 -1
  48. package/dist/{eventPlugin-GF5nnBIq.d.mts → eventPlugin-DSNEZWfV.d.mts} +29 -1
  49. package/dist/{eventPlugin-Dk_TyXeE.mjs → eventPlugin-Dar8qRaj.mjs} +65 -9
  50. package/dist/events/index.d.mts +5 -351
  51. package/dist/events/index.mjs +5 -780
  52. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  53. package/dist/events/transports/redis-stream-entry.mjs +1 -1
  54. package/dist/events/transports/redis.d.mts +1 -1
  55. package/dist/events/transports/redis.mjs +1 -1
  56. package/dist/factory/index.d.mts +20 -5
  57. package/dist/factory/index.mjs +7 -7
  58. package/dist/{fastify-augmentation-BppG5bMT.d.mts → fastify-augmentation-DVsTAy6X.d.mts} +3 -3
  59. package/dist/{fields-DEi65pGj.mjs → fields-CojeUkS4.mjs} +1 -1
  60. package/dist/{generate-CRSG0jTv.mjs → generate-DiB0nHPR.mjs} +2 -2
  61. package/dist/{headers-BXjQYbeC.mjs → headers-CveNO9gR.mjs} +2 -2
  62. package/dist/{health-5XnTa2uo.mjs → health-CasG2A28.mjs} +1 -1
  63. package/dist/hooks/index.d.mts +1 -1
  64. package/dist/hooks/index.mjs +2 -2
  65. package/dist/idempotency/index.d.mts +45 -1
  66. package/dist/idempotency/index.mjs +91 -9
  67. package/dist/idempotency/redis.mjs +1 -1
  68. package/dist/{index-zq6VrjaB.d.mts → index-B-DvUzsr.d.mts} +12 -2
  69. package/dist/{index-CpzxqePp.d.mts → index-BcR2bFZQ.d.mts} +707 -373
  70. package/dist/{index-DXlHwvuE.d.mts → index-Brin0ODU.d.mts} +4 -4
  71. package/dist/{index-ZWhLTp_s.d.mts → index-C5NnMEKF.d.mts} +1 -1
  72. package/dist/{index-C-481Zf2.d.mts → index-ugr1tQlW.d.mts} +17 -1
  73. package/dist/index.d.mts +6 -6
  74. package/dist/index.mjs +11 -11
  75. package/dist/{init-BbfP8aky.mjs → init-mdJ-v4Xp.mjs} +18 -12
  76. package/dist/integrations/event-gateway.d.mts +1 -1
  77. package/dist/integrations/event-gateway.mjs +2 -2
  78. package/dist/integrations/index.d.mts +2 -2
  79. package/dist/integrations/index.mjs +1 -1
  80. package/dist/integrations/jobs/index.d.mts +1 -1
  81. package/dist/integrations/jobs/index.mjs +99 -97
  82. package/dist/integrations/mcp/index.d.mts +12 -3
  83. package/dist/integrations/mcp/index.mjs +2 -2
  84. package/dist/integrations/mcp/testing.d.mts +1 -1
  85. package/dist/integrations/mcp/testing.mjs +2 -2
  86. package/dist/integrations/streamline.mjs +3 -3
  87. package/dist/integrations/webhooks.d.mts +124 -1
  88. package/dist/integrations/webhooks.mjs +180 -2
  89. package/dist/integrations/websocket-pushref-redis.mjs +1 -1
  90. package/dist/integrations/websocket-redis.mjs +1 -1
  91. package/dist/integrations/websocket.mjs +1 -1
  92. package/dist/{interface-BP4IJCBO.mjs → interface-DznJrm9R.mjs} +1 -1
  93. package/dist/{jsonBody-DDSR2HFl.mjs → jsonBody-CfGH-GxO.mjs} +2 -2
  94. package/dist/{keys-B-HBTGXl.mjs → keys-WeKvY1dE.mjs} +1 -1
  95. package/dist/{loadResources-DisEAmkm.mjs → loadResources-Bj-aSsXi.mjs} +2 -2
  96. package/dist/{loadResourcesFromEntry-D1MJp13f.mjs → loadResourcesFromEntry-DwaxNcE2.mjs} +2 -2
  97. package/dist/logger/index.mjs +1 -1
  98. package/dist/{mcpPlugin-CpfVpKHE.mjs → mcpPlugin-aJg5TqHi.mjs} +60 -21
  99. package/dist/{memory-DsuWnj4T.mjs → memory-qYSB7rMQ.mjs} +2 -2
  100. package/dist/{metrics-DdQL8syd.mjs → metrics-D7uchLjN.mjs} +2 -2
  101. package/dist/middleware/index.d.mts +1 -1
  102. package/dist/middleware/index.mjs +3 -3
  103. package/dist/migrations/index.mjs +2 -2
  104. package/dist/{module-Br81am6m.mjs → module-CwKsgZXp.mjs} +1 -1
  105. package/dist/{multipartBody-BnkBLN7v.mjs → multipartBody-4w-S3-PU.mjs} +1 -1
  106. package/dist/{openapi-DIRzvxC0.mjs → openapi-BN5cQaO2.mjs} +6 -6
  107. package/dist/outbox-admin/index.d.mts +2 -2
  108. package/dist/outbox-admin/index.mjs +4 -4
  109. package/dist/outbox-module-CXB79bvt.mjs +839 -0
  110. package/dist/outbox-module-D-VFq37T.d.mts +368 -0
  111. package/dist/permissions/index.d.mts +2 -2
  112. package/dist/permissions/index.mjs +5 -5
  113. package/dist/{permissions-Dl_m0NCe.mjs → permissions-BAfwgBxc.mjs} +25 -6
  114. package/dist/{pipe-ELHCP3zj.mjs → pipe-BzzoEhHj.mjs} +2 -2
  115. package/dist/pipeline/index.d.mts +1 -1
  116. package/dist/pipeline/index.mjs +2 -2
  117. package/dist/{pipeline-CPA-jx0M.mjs → pipeline-q69DZzgG.mjs} +6 -6
  118. package/dist/plugins/index.d.mts +6 -6
  119. package/dist/plugins/index.mjs +16 -16
  120. package/dist/plugins/response-cache.mjs +2 -2
  121. package/dist/plugins/tracing-entry.mjs +2 -2
  122. package/dist/{pluralize-C2ZkKbsn.mjs → pluralize-B7xf8qZF.mjs} +1 -1
  123. package/dist/{preloadResources-CDs87fTw.mjs → preloadResources-BkyqeTDz.mjs} +1 -1
  124. package/dist/{preloadResources-T1hmlTEZ.d.mts → preloadResources-g07ldtzh.d.mts} +30 -7
  125. package/dist/presets/filesUpload.d.mts +2 -2
  126. package/dist/presets/filesUpload.mjs +5 -5
  127. package/dist/presets/index.d.mts +2 -2
  128. package/dist/presets/index.mjs +2 -2
  129. package/dist/presets/multiTenant.d.mts +1 -1
  130. package/dist/presets/multiTenant.mjs +3 -3
  131. package/dist/presets/search.d.mts +2 -2
  132. package/dist/presets/search.mjs +2 -2
  133. package/dist/{presets-Dntd_pUO.mjs → presets-D-h0uWtP.mjs} +4 -4
  134. package/dist/projection-BKM0Ui-s.mjs +42 -0
  135. package/dist/{queryCachePlugin-Dhps-Ldt.mjs → queryCachePlugin-DhsZ0ZIc.mjs} +49 -7
  136. package/dist/{rateLimit-C7mmAGs3.mjs → rateLimit-D4-ASwsI.mjs} +2 -2
  137. package/dist/{rateLimitKey-CccEFBfk.mjs → rateLimitKey-XngqVNEV.mjs} +1 -1
  138. package/dist/{realtime-DVvVZZFz.mjs → realtime-CTkv3O59.mjs} +9 -9
  139. package/dist/{redis-stream-qN6A-RFv.d.mts → redis-stream-mwLWlfHG.d.mts} +1 -1
  140. package/dist/{registerRoute-B_QrjYZS.mjs → registerRoute-DNnd3vkz.mjs} +4 -4
  141. package/dist/registry/index.d.mts +3 -3
  142. package/dist/registry/index.mjs +3 -3
  143. package/dist/{registry-DqUmzA9W.mjs → registry-CLxCR5LF.mjs} +2 -2
  144. package/dist/{renewingLease-BpP9wwj7.mjs → renewingLease-BnWtbA2U.mjs} +1 -1
  145. package/dist/{replyHelpers-DS-P0b32.mjs → replyHelpers-BSBVCwL3.mjs} +2 -2
  146. package/dist/{repositoryFilter-DotlxG3L.mjs → repositoryFilter-DKny7PDn.mjs} +1 -1
  147. package/dist/{requestContext-B6vQF-sy.mjs → requestContext-uYE35JxI.mjs} +1 -1
  148. package/dist/{rolldown-runtime-BhflRrBs.mjs → rolldown-runtime-DNg-KNCk.mjs} +1 -1
  149. package/dist/runtimeCapabilities-Dm88DaTW.mjs +49 -0
  150. package/dist/{schedules-C2Q3uv2d.mjs → schedules-CAcZgia0.mjs} +3 -3
  151. package/dist/{schemaConverter-Crjvczi_.mjs → schemaConverter-XH1RZRyu.mjs} +1 -1
  152. package/dist/{schemaIR-CnyKK_1j.mjs → schemaIR-CDvclAew.mjs} +2 -2
  153. package/dist/schemas/index.mjs +1 -1
  154. package/dist/scim/index.mjs +2 -2
  155. package/dist/scope/index.mjs +5 -5
  156. package/dist/{scope-afz_Ieek.mjs → scope-BaWcqBvr.mjs} +4 -4
  157. package/dist/{simpleEqualityMatcher-C4KiMWUa.mjs → simpleEqualityMatcher-Se8VrsaP.mjs} +1 -1
  158. package/dist/{sse-B9P4Y-UI.mjs → sse-Cf0jUHsh.mjs} +5 -5
  159. package/dist/{sseStream-B3zb_d1h.mjs → sseStream-Bvpi-UXQ.mjs} +2 -2
  160. package/dist/{store-helpers-DmEMHlPQ.mjs → store-helpers-B88p99Z2.mjs} +1 -1
  161. package/dist/{streaming-DPZdQmDz.mjs → streaming-DsT1B5zJ.mjs} +1 -1
  162. package/dist/{subscribe-helpers-sp5xTDVA.mjs → subscribe-helpers-CLIOHsOK.mjs} +2 -2
  163. package/dist/sync/changelog.mjs +1 -1
  164. package/dist/testing/cleanupStoreContract.d.mts +1 -1
  165. package/dist/testing/cleanupStoreContract.mjs +3 -1
  166. package/dist/testing/index.d.mts +24 -12
  167. package/dist/testing/index.mjs +24 -12
  168. package/dist/testing/outboxStoreContract.mjs +1 -1
  169. package/dist/testing/storageContract.mjs +1 -1
  170. package/dist/{transactionContext-BvLKvOIL.mjs → transactionContext-BYtWnwAS.mjs} +1 -1
  171. package/dist/{typeGuards-B_5-hKjJ.mjs → typeGuards-jjKJDN13.mjs} +1 -1
  172. package/dist/types/index.d.mts +3 -3
  173. package/dist/types/index.mjs +1 -1
  174. package/dist/types/storage.mjs +1 -1
  175. package/dist/{types-CT5vu6M0.d.mts → types-BcTumAz_.d.mts} +41 -7
  176. package/dist/{types-CwcUQ610.d.mts → types-BfC83KsP.d.mts} +15 -1
  177. package/dist/{types-DXYX7dIR.mjs → types-CoqIRrkY.mjs} +4 -4
  178. package/dist/{types-C4QE8qnm.d.mts → types-DVLddu2q.d.mts} +144 -1
  179. package/dist/usage/index.d.mts +1 -1
  180. package/dist/usage/index.mjs +0 -0
  181. package/dist/{userHelpers-BNsOXzOd.mjs → userHelpers-CWF5pbZD.mjs} +1 -1
  182. package/dist/utils/index.d.mts +57 -5
  183. package/dist/utils/index.mjs +12 -11
  184. package/dist/{utils-BtOha_Sp.mjs → utils-h1V_sT-t.mjs} +38 -7
  185. package/dist/{validate-PMCPR9El.mjs → validate-CdQlz52F.mjs} +2 -2
  186. package/dist/{versioning-D_rhHfZm.d.mts → versioning-DEs-_hFi.d.mts} +1 -1
  187. package/dist/{versioning-CKv2jz_U.mjs → versioning-rZbyLVD-.mjs} +3 -3
  188. package/package.json +17 -16
  189. package/skills/arc/SKILL.md +96 -4
  190. package/skills/arc/references/api-reference.md +19 -0
  191. package/skills/arc/references/production.md +2 -2
  192. package/dist/projection-CjHhM5W1.mjs +0 -18
@@ -1,11 +1,13 @@
1
- /*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
2
- import { t as __exportAll } from "./rolldown-runtime-BhflRrBs.mjs";
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
+ import { t as __exportAll } from "./rolldown-runtime-DNg-KNCk.mjs";
3
3
  import { arcLog, configureArcLogger, createPinoWriter } from "./logger/index.mjs";
4
- import { n as PUBLIC_SCOPE } from "./types-DXYX7dIR.mjs";
5
- import { t as createTenantKeyGenerator } from "./rateLimitKey-CccEFBfk.mjs";
6
- import { i as createRequestIdGenerator, r as mergeHealthChecks } from "./health-5XnTa2uo.mjs";
7
- import { t as parseJsonBody } from "./jsonBody-DDSR2HFl.mjs";
8
- import { r as wrapWithBoundary } from "./subscribe-helpers-sp5xTDVA.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";
10
+ import { isProductionEnv } from "@classytic/primitives/environment";
9
11
  import Fastify from "fastify";
10
12
  import qs from "qs";
11
13
  //#region src/factory/security/pluginLoader.ts
@@ -799,9 +801,20 @@ async function registerArcCore(fastify, config, trackPlugin) {
799
801
  await fastify.register(arcCorePlugin, { emitEvents: config.arcPlugins?.emitEvents !== false });
800
802
  trackPlugin("arc-core");
801
803
  if (config.arcPlugins?.events !== false) {
802
- const { default: eventPlugin } = await import("./eventPlugin-Dk_TyXeE.mjs").then((n) => n.n);
804
+ const { default: eventPlugin } = await import("./eventPlugin-Dar8qRaj.mjs").then((n) => n.n);
803
805
  const eventOpts = typeof config.arcPlugins?.events === "object" ? config.arcPlugins.events : {};
804
806
  await fastify.register(eventPlugin, {
807
+ /**
808
+ * An EXPLICIT `runtime: 'memory'` is the host's single-instance
809
+ * declaration (its JSDoc says exactly that), so it flows down as the
810
+ * event plugin's `singleProcess` flag — one topology axis, declared
811
+ * once, no second knob to keep in sync. The comparison is against the
812
+ * literal, not the resolved default: `runtime` UNSET also means memory
813
+ * stores, but an unstated topology must keep the forgotten-default
814
+ * warn. `eventOpts` spreads after, so a direct
815
+ * `arcPlugins.events.singleProcess` still wins either way.
816
+ */
817
+ ...config.runtime === "memory" ? { singleProcess: true } : {},
805
818
  ...eventOpts,
806
819
  transport: config.stores?.events
807
820
  });
@@ -847,15 +860,15 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules, moduleH
847
860
  trackPlugin("arc-graceful-shutdown");
848
861
  }
849
862
  if (config.arcPlugins?.caching) {
850
- const { default: cachingPlugin } = await import("./caching-DFJqHyFs.mjs").then((n) => n.r);
863
+ const { default: cachingPlugin } = await import("./caching-BcGmvnHh.mjs").then((n) => n.r);
851
864
  const opts = config.arcPlugins.caching === true ? {} : config.arcPlugins.caching;
852
865
  await fastify.register(cachingPlugin, opts);
853
866
  trackPlugin("arc-caching", opts);
854
867
  }
855
868
  if (config.arcPlugins?.queryCache) {
856
- const { queryCachePlugin } = await import("./queryCachePlugin-Dhps-Ldt.mjs").then((n) => n.n);
869
+ const { queryCachePlugin } = await import("./queryCachePlugin-DhsZ0ZIc.mjs").then((n) => n.n);
857
870
  const opts = config.arcPlugins.queryCache === true ? {} : config.arcPlugins.queryCache;
858
- const store = config.stores?.queryCache ?? new (await (import("./memory-DsuWnj4T.mjs").then((n) => n.n))).MemoryCacheStore();
871
+ const store = config.stores?.queryCache ?? new (await (import("./memory-qYSB7rMQ.mjs").then((n) => n.n))).MemoryCacheStore();
859
872
  await fastify.register(queryCachePlugin, {
860
873
  store,
861
874
  ...opts
@@ -865,7 +878,7 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules, moduleH
865
878
  if (config.arcPlugins?.sse) {
866
879
  if (config.arcPlugins?.events === false) fastify.log.warn("SSE plugin requires events plugin (arcPlugins.events). SSE disabled.");
867
880
  else {
868
- const { default: ssePlugin } = await import("./sse-B9P4Y-UI.mjs").then((n) => n.r);
881
+ const { default: ssePlugin } = await import("./sse-Cf0jUHsh.mjs").then((n) => n.r);
869
882
  const opts = config.arcPlugins.sse === true ? {} : config.arcPlugins.sse;
870
883
  await fastify.register(ssePlugin, opts);
871
884
  trackPlugin("arc-sse", opts);
@@ -874,20 +887,20 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules, moduleH
874
887
  if (config.arcPlugins?.realtime) {
875
888
  if (config.arcPlugins?.events === false) fastify.log.warn("Realtime plugin requires events plugin (arcPlugins.events). Realtime disabled.");
876
889
  else {
877
- const { default: realtimePlugin } = await import("./realtime-DVvVZZFz.mjs").then((n) => n.r);
890
+ const { default: realtimePlugin } = await import("./realtime-CTkv3O59.mjs").then((n) => n.r);
878
891
  const opts = config.arcPlugins.realtime === true ? {} : config.arcPlugins.realtime;
879
892
  await fastify.register(realtimePlugin, opts);
880
893
  trackPlugin("arc-realtime", opts);
881
894
  }
882
895
  }
883
896
  if (config.arcPlugins?.metrics) {
884
- const { default: metricsPlugin } = await import("./metrics-DdQL8syd.mjs").then((n) => n.r);
897
+ const { default: metricsPlugin } = await import("./metrics-D7uchLjN.mjs").then((n) => n.r);
885
898
  const opts = config.arcPlugins.metrics === true ? {} : config.arcPlugins.metrics;
886
899
  await fastify.register(metricsPlugin, opts);
887
900
  trackPlugin("arc-metrics", opts);
888
901
  }
889
902
  if (config.arcPlugins?.versioning) {
890
- const { default: versioningPlugin } = await import("./versioning-CKv2jz_U.mjs").then((n) => n.r);
903
+ const { default: versioningPlugin } = await import("./versioning-rZbyLVD-.mjs").then((n) => n.r);
891
904
  await fastify.register(versioningPlugin, config.arcPlugins.versioning);
892
905
  trackPlugin("arc-versioning", config.arcPlugins.versioning);
893
906
  }
@@ -895,6 +908,12 @@ async function registerArcPlugins(fastify, config, trackPlugin, modules, moduleH
895
908
  //#endregion
896
909
  //#region src/factory/registerAuth.ts
897
910
  /**
911
+ * Authentication registration for createApp.
912
+ *
913
+ * Extracted from createApp step 9: scope decoration, auth strategy,
914
+ * elevation plugin, and error handler.
915
+ */
916
+ /**
898
917
  * Decorate request.scope with PUBLIC_SCOPE default.
899
918
  * Every request starts as public; auth hooks upgrade it.
900
919
  */
@@ -958,7 +977,7 @@ async function registerAuth(fastify, config, trackPlugin) {
958
977
  */
959
978
  async function registerElevation(fastify, config, trackPlugin) {
960
979
  if (!config.elevation) return;
961
- const { elevationPlugin } = await import("./elevation-DNXXxgjl.mjs").then((n) => n.r);
980
+ const { elevationPlugin } = await import("./elevation-B0tlY8y1.mjs").then((n) => n.r);
962
981
  await fastify.register(elevationPlugin, config.elevation);
963
982
  trackPlugin("arc-elevation", config.elevation);
964
983
  fastify.log.debug("Elevation plugin enabled");
@@ -973,8 +992,51 @@ async function registerElevation(fastify, config, trackPlugin) {
973
992
  */
974
993
  async function registerErrorHandler(fastify, config, trackPlugin, moduleErrorMappers) {
975
994
  if (config.errorHandler === false) return;
976
- const { errorHandlerPlugin } = await import("./errorHandler-B2AZUJUj.mjs").then((n) => n.r);
977
- let errorOpts = typeof config.errorHandler === "object" ? config.errorHandler : { includeStack: config.preset !== "production" };
995
+ const { errorHandlerPlugin } = await import("./errorHandler-C7xBqHsI.mjs").then((n) => n.r);
996
+ /**
997
+ * DISCLOSURE DEFAULTS MERGE — they used to be REPLACED, and that was two bugs.
998
+ *
999
+ * This was a ternary: an object from the host was used verbatim, otherwise
1000
+ * `{ includeStack: config.preset !== "production" }`. Both branches leaked.
1001
+ *
1002
+ * 1. A host that passed ANY key — even just `errorMappers` — lost the preset-derived
1003
+ * `includeStack` and fell through to `errorHandlerPlugin`'s own default, which is
1004
+ * `!(process.env.NODE_ENV === "production")`. That comparison knows only the long
1005
+ * spelling, so under `NODE_ENV=prod` it yields `true` and stack traces ship to clients in
1006
+ * production. Nobody writing `errorHandler: { errorMappers: [...] }` could reasonably
1007
+ * expect it to change stack-trace exposure.
1008
+ * 2. The derived branch never set `exposeInternalMessages` AT ALL, so that switch fell
1009
+ * through to the same raw read for EVERY arc app however it was configured. A truthy value
1010
+ * is what skips `wire.message = "Internal Server Error"` for a 500, putting the raw thrown
1011
+ * message — driver text, query fragments — on the wire.
1012
+ *
1013
+ * `preset` is the right source: it is the deployment's EXPLICIT declaration, and a specific
1014
+ * setting must never be overridden by an ambient default. Host keys still win over `derived`,
1015
+ * so an operator can widen deliberately; what they can no longer do is widen by accident.
1016
+ *
1017
+ * 3. And `preset` is OPTIONAL, so its ABSENCE must not read as "not production" either.
1018
+ * `config.preset !== "production"` is true for an unset preset, and plenty of hosts set
1019
+ * only `NODE_ENV` — which turns "the operator said nothing" into "the operator said
1020
+ * development", the widest possible reading of silence, on the two switches where being
1021
+ * wrong ships stack traces and raw driver text.
1022
+ *
1023
+ * So: an explicit `preset` wins; its absence falls back to the ENVIRONMENT rather than to a
1024
+ * guess; and that fallback goes through `isProductionEnv` from the shared classifier, never a raw
1025
+ * `process.env.NODE_ENV === "production"`. The raw form recognises only the long spelling, so a
1026
+ * preset-less host on `NODE_ENV=prod` read as non-production and re-opened both switches — the
1027
+ * same defect class this fallback exists to close, one layer in. Verified against a real 500 in
1028
+ * every state, including a Mongo connection string reaching the response body before the fix
1029
+ * (`tests/factory/error-disclosure-defaults.test.ts`).
1030
+ */
1031
+ const productionEnv = config.preset !== void 0 ? config.preset === "production" : isProductionEnv(process.env.NODE_ENV);
1032
+ const derived = {
1033
+ includeStack: !productionEnv,
1034
+ exposeInternalMessages: !productionEnv
1035
+ };
1036
+ let errorOpts = typeof config.errorHandler === "object" ? {
1037
+ ...derived,
1038
+ ...config.errorHandler
1039
+ } : derived;
978
1040
  if (moduleErrorMappers && moduleErrorMappers.length > 0) errorOpts = {
979
1041
  ...errorOpts,
980
1042
  errorMappers: [...errorOpts.errorMappers ?? [], ...moduleErrorMappers]
@@ -1096,7 +1158,10 @@ async function registerResources(fastify, config, preResolvedModules) {
1096
1158
  teardown.markInitialized(m);
1097
1159
  try {
1098
1160
  const returned = await m.plugins(fastify, disposers.contextFor(m.name));
1099
- if (typeof returned === "function") disposers.contextFor(m.name).defer(returned);
1161
+ if (typeof returned === "function") {
1162
+ assertNotAReturnedPlugin(returned, m.name, fastify);
1163
+ disposers.contextFor(m.name).defer(returned);
1164
+ }
1100
1165
  } catch (err) {
1101
1166
  setModuleState(fastify, m.name, "failed");
1102
1167
  const msg = err instanceof Error ? err.message : String(err);
@@ -1151,7 +1216,7 @@ async function registerResources(fastify, config, preResolvedModules) {
1151
1216
  let discoveryPath;
1152
1217
  let discoveryYieldedZero = false;
1153
1218
  if (resolvedResources === void 0 && config.resourceDir) {
1154
- const { loadResources } = await import("./loadResources-DisEAmkm.mjs").then((n) => n.n);
1219
+ const { loadResources } = await import("./loadResources-Bj-aSsXi.mjs").then((n) => n.n);
1155
1220
  const { resolve, dirname } = await import("node:path");
1156
1221
  const { fileURLToPath } = await import("node:url");
1157
1222
  const rawDir = config.resourceDir;
@@ -1257,13 +1322,27 @@ Resources supplied by "${m.name}": ${provided}.`);
1257
1322
  }
1258
1323
  }
1259
1324
  const scheduleCounts = /* @__PURE__ */ new Map();
1260
- const scheduledJobs = await collectModuleScheduledJobs(fastify, modules, scheduleCounts);
1325
+ const collectedJobs = await collectModuleScheduledJobs(fastify, modules, scheduleCounts);
1326
+ /**
1327
+ * ROLE gate (CreateAppOptions.role). Arms a role does not run are SKIPPED
1328
+ * and logged by name, never fatal: a module legitimately declares arms
1329
+ * that a different deployment of the same codebase executes. 'relay' runs
1330
+ * only kind:'relay' arms (the outbox relays); 'api'/'worker' run none;
1331
+ * 'scheduler'/'all' run everything.
1332
+ */
1333
+ const role = config.role ?? "all";
1334
+ const scheduledJobs = role === "scheduler" || role === "all" ? collectedJobs : role === "relay" ? collectedJobs.filter((j) => j.kind === "relay") : [];
1335
+ const skipped = collectedJobs.filter((j) => !scheduledJobs.includes(j));
1336
+ if (skipped.length > 0) fastify.log.info({
1337
+ role,
1338
+ skipped: skipped.map((j) => j.name)
1339
+ }, `[arc] role '${role}': ${skipped.length} schedule arm(s) not mounted here — a deployment with the owning role runs them`);
1261
1340
  if (scheduledJobs.length > 0) {
1262
1341
  if (config.arcPlugins?.schedules === false) throw new Error("[arc] modules declare scheduledJobs but arcPlugins.schedules is false. Enable the scheduler or remove the declarations.");
1263
1342
  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.");
1264
1343
  const frozenJobs = Object.freeze(scheduledJobs.map((job) => Object.freeze({ ...job })));
1265
1344
  const scheduleOptions = typeof config.arcPlugins?.schedules === "object" ? config.arcPlugins.schedules : {};
1266
- const { default: schedulesPlugin } = await import("./schedules-C2Q3uv2d.mjs").then((n) => n.r);
1345
+ const { default: schedulesPlugin } = await import("./schedules-CAcZgia0.mjs").then((n) => n.r);
1267
1346
  await fastify.register(schedulesPlugin, {
1268
1347
  ...scheduleOptions,
1269
1348
  schedules: frozenJobs
@@ -1319,6 +1398,22 @@ Resources supplied by "${m.name}": ${provided}.`);
1319
1398
  if (closeErrors.length > 0) throw closeErrors[0];
1320
1399
  });
1321
1400
  }
1401
+ /**
1402
+ * `plugins()` is CALLED by arc, never handed to `fastify.register()` — so a
1403
+ * module author who returns a Fastify plugin expecting arc to register it
1404
+ * gets silence: nothing is registered, and the "disposer" shorthand then
1405
+ * invokes their plugin at shutdown with no arguments.
1406
+ *
1407
+ * The `fastify-plugin` case is unambiguous (its marker symbols are only ever
1408
+ * set by `fp()`), so it throws. A bare `(fastify, opts)` function is a strong
1409
+ * but not certain signal — arc's disposer contract calls it with ZERO
1410
+ * arguments, so a 2-parameter disposer is meaningless either way — and warns.
1411
+ */
1412
+ function assertNotAReturnedPlugin(returned, moduleName, fastify) {
1413
+ const fn = returned;
1414
+ if (fn[Symbol.for("skip-override")] !== void 0 || fn[Symbol.for("plugin-meta")] !== void 0 || fn[Symbol.for("fastify.display-name")] !== void 0) throw new Error(`[arc] module "${moduleName}" returned a fastify-plugin from plugins(). That slot is a SETUP function arc calls directly — it is never passed to fastify.register(), so the returned value is read as a disposer and your plugin would be invoked at shutdown instead of registered at boot. Register it yourself: \`plugins: async (fastify) => { await fastify.register(myPlugin) }\`.`);
1415
+ if (returned.length >= 2) fastify.log?.warn?.(`[arc] module "${moduleName}" returned a ${returned.length}-argument function from plugins(). Arc calls disposers with NO arguments, so this looks like a Fastify plugin that was meant to be registered (\`await fastify.register(fn)\`) rather than a teardown callback. If it really is a disposer, declare it with no parameters.`);
1416
+ }
1322
1417
  //#endregion
1323
1418
  //#region src/factory/security/cors.ts
1324
1419
  /**
@@ -1710,6 +1805,14 @@ Missing:\n${lines}\n\nFix: pass durable adapters under \`stores\`, or use runtim
1710
1805
  * instance is closed before the error propagates — see the wrapper below.
1711
1806
  */
1712
1807
  async function createApp(options) {
1808
+ /**
1809
+ * ROLE contradiction check — before anything constructs. A relay/scheduler
1810
+ * process declaring HTTP resources is a wiring error, not a preference:
1811
+ * those roles exist to NOT serve traffic, and mounting routes anyway would
1812
+ * hide the misdeployment behind a working endpoint.
1813
+ */
1814
+ const declaredRole = options.role ?? "all";
1815
+ 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.`);
1713
1816
  let partial;
1714
1817
  try {
1715
1818
  return await buildApp(options, (instance) => {
@@ -1804,7 +1907,7 @@ async function buildApp(options, onInstance) {
1804
1907
  await registerErrorHandler(fastify, config, trackPlugin, moduleErrorMappers);
1805
1908
  await registerResources(fastify, config, resolvedModules);
1806
1909
  if (config.replyHelpers) {
1807
- const { replyHelpersPlugin } = await import("./replyHelpers-DS-P0b32.mjs").then((n) => n.n);
1910
+ const { replyHelpersPlugin } = await import("./replyHelpers-BSBVCwL3.mjs").then((n) => n.n);
1808
1911
  await fastify.register(replyHelpersPlugin);
1809
1912
  }
1810
1913
  if (config.serializeBigInt) {
@@ -1821,6 +1924,7 @@ async function buildApp(options, onInstance) {
1821
1924
  });
1822
1925
  }
1823
1926
  const authMode = config.auth === false ? "none" : config.auth ? config.auth.type : "none";
1927
+ auditRuntimeCapabilities(fastify, config.runtime ?? "memory");
1824
1928
  fastify.log.info({
1825
1929
  preset: config.preset ?? "custom",
1826
1930
  runtime: config.runtime ?? "memory",
@@ -1855,4 +1959,4 @@ const ArcFactory = {
1855
1959
  }
1856
1960
  };
1857
1961
  //#endregion
1858
- export { collectModuleWorkflows as _, edgePreset as a, testingPreset as c, hasModule as d, orderModules as f, collectModuleScheduledJobs as g, collectModuleHealthChecks as h, developmentPreset as i, workerPreset as l, describeResolvedModule as m, createApp as n, getPreset as o, subscribeModuleEventHandlers as p, createApp_exports as r, productionPreset as s, ArcFactory as t, getModuleState as u, resolveContribution as v, resolveModule as y };
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 };
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.32.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
2
  //#region src/core/aggregation/defineAggregation.ts
3
3
  /**
4
4
  * Declare a single resource aggregation. Exported configs flow into