@classytic/arc 2.33.0 → 2.35.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 (184) hide show
  1. package/dist/{BaseController-CaQC5EXX.mjs → BaseController-C-pofd0v.mjs} +131 -16
  2. package/dist/{EventTransport-tq4CEB-q.mjs → EventTransport-BrPeGUil.mjs} +1 -1
  3. package/dist/{HookSystem-DqXkMXkB.mjs → HookSystem-LlPm3Anm.mjs} +6 -4
  4. package/dist/{ResourceRegistry-DoALUlOO.mjs → ResourceRegistry-yuD1Ra53.mjs} +2 -2
  5. package/dist/{pipeline-q69DZzgG.mjs → actionPermissions-LFuOra7W.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-B3mP_QTy.mjs → authorizationDecision-DYXBBgtg.mjs} +6 -2
  13. package/dist/{base-Csjc2oF-.d.mts → base-GZU3LlzP.d.mts} +1 -1
  14. package/dist/{buildHandler-DLE9xX-V.mjs → buildHandler-Do9aMIvL.mjs} +4 -4
  15. package/dist/cache/index.mjs +4 -4
  16. package/dist/{caching-BcGmvnHh.mjs → caching-cN5X9VEL.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-BhzLXCfN.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 +3 -3
  31. package/dist/core/index.mjs +8 -8
  32. package/dist/{core-dxhcHhUD.mjs → core-DdEvmmkY.mjs} +3 -3
  33. package/dist/{createActionRouter-DVpoA0do.mjs → createActionRouter-EYWgd0ly.mjs} +27 -64
  34. package/dist/{createAggregationRouter-B_B48JZ-.mjs → createAggregationRouter-ByOK9Iev.mjs} +7 -7
  35. package/dist/defineAggregation-DoIijIFq.mjs +25 -0
  36. package/dist/{defineResource-DR9vsUYy.mjs → defineResource-BOrGeocE.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-tGIAldco.mjs} +4 -4
  41. package/dist/encryption/index.mjs +3 -3
  42. package/dist/{errorHandler-C7xBqHsI.mjs → errorHandler-BbQ1nQdk.mjs} +3 -3
  43. package/dist/{errors-Cd_yy7aW.mjs → errors-CLid6atr.mjs} +1 -1
  44. package/dist/{eventPlugin-DSNEZWfV.d.mts → eventPlugin-B47sfCJ8.d.mts} +1 -1
  45. package/dist/{eventPlugin-Dar8qRaj.mjs → eventPlugin-ClPn5kjn.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-CMMTL3cj.d.mts} +3 -3
  53. package/dist/{fields-CojeUkS4.mjs → fields-UtpiJO5R.mjs} +1 -1
  54. package/dist/{generate-DiB0nHPR.mjs → generate-BoAVy3_b.mjs} +2 -2
  55. package/dist/{headers-CveNO9gR.mjs → headers-DODWf7aC.mjs} +2 -2
  56. package/dist/{health-CasG2A28.mjs → health-_Zs3R_Sb.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 +23 -58
  60. package/dist/idempotency/redis.mjs +1 -1
  61. package/dist/{index-C5NnMEKF.d.mts → index-C50BUxKs.d.mts} +1 -1
  62. package/dist/{index-BcR2bFZQ.d.mts → index-C5K78SXo.d.mts} +33 -105
  63. package/dist/{index-ugr1tQlW.d.mts → index-CJCcbADG.d.mts} +1 -1
  64. package/dist/{index-B-DvUzsr.d.mts → index-K7auNNW0.d.mts} +2 -2
  65. package/dist/{index-Brin0ODU.d.mts → index-h-mTgMqy.d.mts} +21 -31
  66. package/dist/index.d.mts +6 -6
  67. package/dist/index.mjs +12 -12
  68. package/dist/{init-mdJ-v4Xp.mjs → init-Ce4R0ZGK.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 +1 -1
  80. package/dist/integrations/webhooks.mjs +11 -24
  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-my7sxjw5.mjs} +1 -1
  85. package/dist/{jsonBody-CfGH-GxO.mjs → jsonBody-CVKA7C5m.mjs} +2 -2
  86. package/dist/{keys-WeKvY1dE.mjs → keys-GlU7XpmG.mjs} +1 -1
  87. package/dist/{loadResources-Bj-aSsXi.mjs → loadResources-DdQb0qgV.mjs} +2 -2
  88. package/dist/{loadResourcesFromEntry-DwaxNcE2.mjs → loadResourcesFromEntry-s6aGs6-0.mjs} +2 -2
  89. package/dist/logger/index.d.mts +23 -4
  90. package/dist/logger/index.mjs +50 -7
  91. package/dist/{mcpPlugin-aJg5TqHi.mjs → mcpPlugin-DkzZ7Nfx.mjs} +15 -16
  92. package/dist/{memory-qYSB7rMQ.mjs → memory-BwedEXau.mjs} +2 -2
  93. package/dist/{metrics-D7uchLjN.mjs → metrics-5LNPvL3P.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-Bh5OC7ww.mjs} +1 -1
  98. package/dist/{multipartBody-4w-S3-PU.mjs → multipartBody-DjilSDAT.mjs} +1 -1
  99. package/dist/{openapi-BN5cQaO2.mjs → openapi-ItLH12_L.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-CXB79bvt.mjs → outbox-module-SGIZz6oS.mjs} +14 -5
  103. package/dist/{outbox-module-D-VFq37T.d.mts → outbox-module-b1TyDGGi.d.mts} +40 -3
  104. package/dist/permissions/index.d.mts +2 -2
  105. package/dist/permissions/index.mjs +5 -5
  106. package/dist/{permissions-BAfwgBxc.mjs → permissions-CpSBlFXZ.mjs} +6 -6
  107. package/dist/{pipe-BzzoEhHj.mjs → pipe-DNOuCfAs.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-DGAQQKL8.mjs} +1 -1
  115. package/dist/{preloadResources-g07ldtzh.d.mts → preloadResources--ZtY9pe9.d.mts} +54 -270
  116. package/dist/{createApp-CLGegqiG.mjs → preloadResources-DYMzmUk1.mjs} +112 -31
  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-D-h0uWtP.mjs → presets-Bi0Z6Iq8.mjs} +4 -4
  126. package/dist/{projection-BKM0Ui-s.mjs → projection-aevMua7Q.mjs} +2 -2
  127. package/dist/{queryCachePlugin-DhsZ0ZIc.mjs → queryCachePlugin-BI7Z88Cx.mjs} +5 -5
  128. package/dist/{rateLimitKey-XngqVNEV.mjs → rateLimitKey-pyevMUVf.mjs} +1 -1
  129. package/dist/{realtime-CTkv3O59.mjs → realtime-Cfl2bVjj.mjs} +9 -9
  130. package/dist/{rateLimit-D4-ASwsI.mjs → registerRoute-u1opU66a.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-B4sf9Rfm.mjs} +15 -56
  134. package/dist/{renewingLease-BnWtbA2U.mjs → renewingLease-5ESPMxp0.mjs} +14 -2
  135. package/dist/{replyHelpers-BSBVCwL3.mjs → replyHelpers-2jfmMnnV.mjs} +2 -2
  136. package/dist/{requestContext-uYE35JxI.mjs → requestContext-DzOUGNdY.mjs} +1 -1
  137. package/dist/{rolldown-runtime-DNg-KNCk.mjs → rolldown-runtime-CEvvVXTC.mjs} +1 -1
  138. package/dist/{runtimeCapabilities-Dm88DaTW.mjs → runtimeCapabilities-BagWc3TI.mjs} +1 -1
  139. package/dist/{schedules-CAcZgia0.mjs → schedules-BLpZLWGF.mjs} +6 -4
  140. package/dist/{schemaConverter-XH1RZRyu.mjs → schemaConverter-D2_bHGil.mjs} +19 -32
  141. package/dist/{schemaIR-CDvclAew.mjs → schemaIR-s3-ouZmP.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-DgepeCv6.mjs} +4 -4
  147. package/dist/simpleEqualityMatcher-BO-sFTQf.mjs +43 -0
  148. package/dist/{sse-Cf0jUHsh.mjs → sse-DUIP1XH6.mjs} +5 -5
  149. package/dist/{sseStream-Bvpi-UXQ.mjs → sseStream-ByFGyIVr.mjs} +2 -2
  150. package/dist/{store-helpers-B88p99Z2.mjs → store-helpers-kIJCY0wI.mjs} +1 -1
  151. package/dist/{streaming-DsT1B5zJ.mjs → streaming-DOpZVht6.mjs} +1 -1
  152. package/dist/{subscribe-helpers-CLIOHsOK.mjs → subscribe-helpers-Dh2BnzJf.mjs} +12 -46
  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-BTZzEcRo.mjs} +1 -1
  160. package/dist/{typeGuards-jjKJDN13.mjs → typeGuards-B-_jqaMi.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-BcTumAz_.d.mts → types-DDD5RKTu.d.mts} +30 -87
  165. package/dist/{types-BfC83KsP.d.mts → types-DSvHH0uR.d.mts} +1 -1
  166. package/dist/{types-ChuShpCP.d.mts → types-Ddl9OjmE.d.mts} +18 -121
  167. package/dist/{types-CoqIRrkY.mjs → types-GY4kATJb.mjs} +10 -53
  168. package/dist/usage/index.d.mts +2 -2
  169. package/dist/usage/index.mjs +0 -0
  170. package/dist/{userHelpers-CWF5pbZD.mjs → userHelpers-AKcB4V03.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-CBK9HQOI.mjs} +3 -3
  174. package/dist/{validate-CdQlz52F.mjs → validate-dosAIvQU.mjs} +2 -2
  175. package/dist/{versioning-rZbyLVD-.mjs → versioning-BbTs4pwM.mjs} +3 -3
  176. package/package.json +8 -8
  177. package/skills/arc/SKILL.md +9 -9
  178. package/skills/arc/references/api-reference.md +1 -1
  179. package/dist/actionPermissions-CUeCmpUd.mjs +0 -25
  180. package/dist/defineAggregation-Nv-DwfOf.mjs +0 -48
  181. package/dist/preloadResources-BkyqeTDz.mjs +0 -46
  182. package/dist/registerRoute-DNnd3vkz.mjs +0 -113
  183. package/dist/repositoryFilter-DKny7PDn.mjs +0 -45
  184. package/dist/simpleEqualityMatcher-Se8VrsaP.mjs +0 -69
@@ -1,5 +1,5 @@
1
1
 
2
- import { Ct as PipelineStep, Fn as IControllerResponse, St as PipelineContext, _t as Guard, bt as OperationFilter, vt as Interceptor, wt as Transform, xt as PipelineConfig, yt as NextFunction } from "../index-BcR2bFZQ.mjs";
2
+ import { Ct as PipelineStep, Fn as IControllerResponse, St as PipelineContext, _t as Guard, bt as OperationFilter, vt as Interceptor, wt as Transform, xt as PipelineConfig, yt as NextFunction } from "../index-C5K78SXo.mjs";
3
3
  //#region src/pipeline/guard.d.ts
4
4
  interface GuardOptions {
5
5
  operations?: OperationFilter;
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
- import { n as pipe, t as executePipeline } from "../pipe-BzzoEhHj.mjs";
1
+ /*! @classytic/arc v2.35.0 | MIT | https://classytic.com */
2
+ import { n as pipe, t as executePipeline } from "../pipe-DNOuCfAs.mjs";
3
3
  //#region src/pipeline/guard.ts
4
4
  /**
5
5
  * Create a named guard.
@@ -1,10 +1,10 @@
1
1
 
2
- import { t as AnyRecord } from "../base-Csjc2oF-.mjs";
3
- import { At as RouteDefinition, J as PresetHook, Q as MiddlewareConfig, et as RouteSchemaOptions } from "../index-BcR2bFZQ.mjs";
2
+ import { t as AnyRecord } from "../base-GZU3LlzP.mjs";
3
+ import { At as RouteDefinition, J as PresetHook, Q as MiddlewareConfig, et as RouteSchemaOptions } from "../index-C5K78SXo.mjs";
4
4
  import { i as errorHandlerPlugin, n as ErrorMapper, r as defaultIsDuplicateKeyError, t as ErrorHandlerOptions } from "../errorHandler-DI5AN2b5.mjs";
5
- import { _ as HealthCheck, b as healthPlugin, f as ScheduleDefinition, g as schedulesPlugin, h as _default$7, m as SchedulesPluginOptions, p as ScheduleStats, v as HealthOptions, y as _default$3 } from "../types-BcTumAz_.mjs";
6
- import { a as arcCorePlugin, i as _default, n as ArcCorePluginOptions, r as PluginMeta, t as ArcCore } from "../fastify-augmentation-DVsTAy6X.mjs";
7
- import { _ as CachingRule, a as MetricsCollector, c as metricsPlugin, d as _default$5, f as realtimePlugin, g as CachingOptions, h as ssePlugin, i as MetricEntry, l as ChangeOperation, m as _default$8, n as _default$9, o as MetricsOptions, p as SSEOptions, r as versioningPlugin, s as _default$4, t as VersioningOptions, u as RealtimeOptions, v as _default$1, y as cachingPlugin } from "../versioning-DEs-_hFi.mjs";
5
+ import { _ as HealthCheck, b as healthPlugin, f as ScheduleDefinition, g as schedulesPlugin, h as _default$8, m as SchedulesPluginOptions, p as ScheduleStats, v as HealthOptions, y as _default$3 } from "../types-DDD5RKTu.mjs";
6
+ import { a as arcCorePlugin, i as _default, n as ArcCorePluginOptions, r as PluginMeta, t as ArcCore } from "../fastify-augmentation-CMMTL3cj.mjs";
7
+ import { _ as CachingRule, a as MetricsCollector, c as metricsPlugin, d as _default$6, f as realtimePlugin, g as CachingOptions, h as ssePlugin, i as MetricEntry, l as ChangeOperation, m as _default$9, n as _default$10, o as MetricsOptions, p as SSEOptions, r as versioningPlugin, s as _default$4, t as VersioningOptions, u as RealtimeOptions, v as _default$1, y as cachingPlugin } from "../versioning-DEs-_hFi.mjs";
8
8
  import { t as TracingOptions } from "../tracing-Dro5eH6j.mjs";
9
9
  import { PaginatedResult } from "@classytic/repo-core/pagination";
10
10
  import { FastifyInstance, FastifyPluginAsync } from "fastify";
@@ -89,6 +89,91 @@ declare module "fastify" {
89
89
  }
90
90
  declare const _default$2: FastifyPluginAsync<GracefulShutdownOptions>;
91
91
  //#endregion
92
+ //#region src/plugins/pressure.d.ts
93
+ /**
94
+ * One measurable source of load, normalised by whoever owns it.
95
+ *
96
+ * A throwing `read()` reports 0, never 1 — a broken thermometer is not a fire.
97
+ * Logged once per signal, not per sample.
98
+ */
99
+ interface PressureSignal {
100
+ /** Stable identity — appears in snapshots and logs. */
101
+ readonly name: string;
102
+ /** Saturation in [0, 1]. Values outside the range are clamped. */
103
+ read(): number | Promise<number>;
104
+ }
105
+ /** `ok` → serve · `degraded` → serve, shed what is optional · `saturated` → refuse. */
106
+ type PressureState = "ok" | "degraded" | "saturated";
107
+ interface PressureThresholds {
108
+ /** Enter `degraded` at or above this. Default 0.8. */
109
+ degraded?: number;
110
+ /** Enter `saturated` at or above this. Default 0.95. */
111
+ saturated?: number;
112
+ }
113
+ interface PressureSnapshot {
114
+ readonly state: PressureState;
115
+ /** Highest signal — the one that decided the state. */
116
+ readonly worst: {
117
+ name: string;
118
+ value: number;
119
+ } | undefined;
120
+ readonly signals: Readonly<Record<string, number>>;
121
+ }
122
+ interface PressureOptions {
123
+ /** Extra signals beyond the built-in ELU reader. */
124
+ signals?: PressureSignal[];
125
+ thresholds?: PressureThresholds;
126
+ /** Sampling cadence in ms. Default 1000. */
127
+ intervalMs?: number;
128
+ /** Include the built-in event-loop-utilisation signal. Default true. */
129
+ eventLoopUtilization?: boolean;
130
+ /** Fired when the state CHANGES — not on every sample. */
131
+ onStateChange?: (next: PressureState, snapshot: PressureSnapshot) => void;
132
+ /**
133
+ * Refuse with 503 while `saturated`. Default OFF — arc cannot know which
134
+ * routes are sheddable, and refusing a checkout because a dashboard drained
135
+ * the pool is worse than serving it slowly.
136
+ *
137
+ * `exclude` matches `request.url` by prefix. Health routes are ALWAYS exempt:
138
+ * a 503 on `/_health/ready` reads as "process dead", not "process full".
139
+ */
140
+ shed?: boolean | {
141
+ statusCode?: number;
142
+ retryAfterSeconds?: number;
143
+ exclude?: string[];
144
+ };
145
+ }
146
+ interface PressureApi {
147
+ state(): PressureState;
148
+ snapshot(): PressureSnapshot;
149
+ /** Register a signal after boot — for modules that resolve their source late. */
150
+ register(signal: PressureSignal): void;
151
+ /** True at `saturated`. The check a handler makes before admitting work. */
152
+ shouldShed(): boolean;
153
+ /**
154
+ * A readiness check for `healthPlugin({ checks })`. NOT auto-registered:
155
+ * flipping readiness pulls the instance from its load balancer — right in a
156
+ * fleet, a self-inflicted outage for a single instance. Unhealthy only at
157
+ * `saturated`; `degraded` still serves.
158
+ */
159
+ readinessCheck(options?: {
160
+ name?: string;
161
+ critical?: boolean;
162
+ }): HealthCheck;
163
+ }
164
+ declare module "fastify" {
165
+ interface FastifyInstance {
166
+ pressure: PressureApi;
167
+ }
168
+ }
169
+ declare const pressurePlugin: FastifyPluginAsync<PressureOptions>;
170
+ /**
171
+ * `fp()`-wrapped so `fastify.pressure` is visible to the whole app rather than
172
+ * trapped in this plugin's encapsulation context — the named export above is
173
+ * the raw plugin, matching every other arc plugin entry.
174
+ */
175
+ declare const _default$5: FastifyPluginAsync<PressureOptions>;
176
+ //#endregion
92
177
  //#region src/plugins/replyHelpers.d.ts
93
178
  declare module "fastify" {
94
179
  interface FastifyReply {
@@ -166,6 +251,6 @@ declare function createRequestIdGenerator(opts?: Pick<RequestIdOptions, "header"
166
251
  headers: Record<string, string | string[] | undefined>;
167
252
  }) => string;
168
253
  declare const requestIdPlugin: FastifyPluginAsync<RequestIdOptions>;
169
- declare const _default$6: FastifyPluginAsync<RequestIdOptions>;
254
+ declare const _default$7: FastifyPluginAsync<RequestIdOptions>;
170
255
  //#endregion
171
- export { type ArcCore, type ArcCorePluginOptions, type ArcPlugin, type CachingOptions, type CachingRule, type ChangeOperation, type CreatePluginDefinition, type ErrorHandlerOptions, type ErrorMapper, type GracefulShutdownOptions, type HealthCheck, type HealthOptions, type MetricEntry, type MetricsCollector, type MetricsOptions, type PluginMeta, type PluginResourceResult, type RealtimeOptions, type RequestIdOptions, type SSEOptions, type ScheduleDefinition, type ScheduleStats, type SchedulesPluginOptions, type TracingOptions, type VersioningOptions, _default as arcCorePlugin, arcCorePlugin as arcCorePluginFn, _default$1 as cachingPlugin, cachingPlugin as cachingPluginFn, createPlugin, createRequestIdGenerator, 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, _default$5 as realtimePlugin, realtimePlugin as realtimePluginFn, replyHelpersPlugin, _default$6 as requestIdPlugin, requestIdPlugin as requestIdPluginFn, sanitizeRequestId, _default$7 as schedulesPlugin, schedulesPlugin as schedulesPluginFn, _default$8 as ssePlugin, ssePlugin as ssePluginFn, _default$9 as versioningPlugin, versioningPlugin as versioningPluginFn };
256
+ export { type ArcCore, type ArcCorePluginOptions, type ArcPlugin, type CachingOptions, type CachingRule, type ChangeOperation, type CreatePluginDefinition, type ErrorHandlerOptions, type ErrorMapper, type GracefulShutdownOptions, type HealthCheck, type HealthOptions, type MetricEntry, type MetricsCollector, type MetricsOptions, type PluginMeta, type PluginResourceResult, type PressureApi, type PressureOptions, type PressureSignal, type PressureSnapshot, type PressureState, type PressureThresholds, type RealtimeOptions, type RequestIdOptions, type SSEOptions, type ScheduleDefinition, type ScheduleStats, type SchedulesPluginOptions, type TracingOptions, type VersioningOptions, _default as arcCorePlugin, arcCorePlugin as arcCorePluginFn, _default$1 as cachingPlugin, cachingPlugin as cachingPluginFn, createPlugin, createRequestIdGenerator, 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, _default$5 as pressurePlugin, pressurePlugin as pressurePluginFn, _default$6 as realtimePlugin, realtimePlugin as realtimePluginFn, replyHelpersPlugin, _default$7 as requestIdPlugin, requestIdPlugin as requestIdPluginFn, sanitizeRequestId, _default$8 as schedulesPlugin, schedulesPlugin as schedulesPluginFn, _default$9 as ssePlugin, ssePlugin as ssePluginFn, _default$10 as versioningPlugin, versioningPlugin as versioningPluginFn };
@@ -1,20 +1,22 @@
1
- /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
- import { p as MUTATION_OPERATIONS } from "../constants-BxCoxmiN.mjs";
3
- import { c as getOrgId } from "../types-CoqIRrkY.mjs";
4
- import { n as requestContext } from "../requestContext-uYE35JxI.mjs";
5
- import { t as hasEvents } from "../typeGuards-jjKJDN13.mjs";
6
- import { t as HookSystem } from "../HookSystem-DqXkMXkB.mjs";
7
- import { t as ResourceRegistry } from "../ResourceRegistry-DoALUlOO.mjs";
8
- import { a as requestIdPlugin, i as createRequestIdGenerator, n as health_default, o as requestId_default, s as sanitizeRequestId, t as healthPlugin } from "../health-CasG2A28.mjs";
9
- import { n as caching_default, t as cachingPlugin } from "../caching-BcGmvnHh.mjs";
10
- import { n as errorHandlerPlugin, t as defaultIsDuplicateKeyError } from "../errorHandler-C7xBqHsI.mjs";
11
- import { n as metrics_default, t as metricsPlugin } from "../metrics-D7uchLjN.mjs";
12
- import { n as realtime_default, t as realtimePlugin } from "../realtime-CTkv3O59.mjs";
13
- import { t as replyHelpersPlugin } from "../replyHelpers-BSBVCwL3.mjs";
14
- import { n as schedules_default, t as schedulesPlugin } from "../schedules-CAcZgia0.mjs";
15
- import { n as sse_default, t as ssePlugin } from "../sse-Cf0jUHsh.mjs";
16
- import { n as versioning_default, t as versioningPlugin } from "../versioning-rZbyLVD-.mjs";
1
+ /*! @classytic/arc v2.35.0 | MIT | https://classytic.com */
2
+ import { p as MUTATION_OPERATIONS } from "../constants-BhzLXCfN.mjs";
3
+ import { arcLog } from "../logger/index.mjs";
4
+ import { c as getOrgId } from "../types-GY4kATJb.mjs";
5
+ import { n as requestContext } from "../requestContext-DzOUGNdY.mjs";
6
+ import { t as hasEvents } from "../typeGuards-B-_jqaMi.mjs";
7
+ import { t as HookSystem } from "../HookSystem-LlPm3Anm.mjs";
8
+ import { t as ResourceRegistry } from "../ResourceRegistry-yuD1Ra53.mjs";
9
+ import { a as requestIdPlugin, i as createRequestIdGenerator, n as health_default, o as requestId_default, s as sanitizeRequestId, t as healthPlugin } from "../health-_Zs3R_Sb.mjs";
10
+ import { n as caching_default, t as cachingPlugin } from "../caching-cN5X9VEL.mjs";
11
+ import { n as errorHandlerPlugin, t as defaultIsDuplicateKeyError } from "../errorHandler-BbQ1nQdk.mjs";
12
+ import { n as metrics_default, t as metricsPlugin } from "../metrics-5LNPvL3P.mjs";
13
+ import { n as realtime_default, t as realtimePlugin } from "../realtime-Cfl2bVjj.mjs";
14
+ import { t as replyHelpersPlugin } from "../replyHelpers-2jfmMnnV.mjs";
15
+ import { n as schedules_default, t as schedulesPlugin } from "../schedules-BLpZLWGF.mjs";
16
+ import { n as sse_default, t as ssePlugin } from "../sse-DUIP1XH6.mjs";
17
+ import { n as versioning_default, t as versioningPlugin } from "../versioning-BbTs4pwM.mjs";
17
18
  import fp from "fastify-plugin";
19
+ import { performance as performance$1 } from "node:perf_hooks";
18
20
  //#region src/core/arcCorePlugin.ts
19
21
  const arcCorePlugin = async (fastify, opts = {}) => {
20
22
  const { emitEvents = true, hookSystem, registry } = opts;
@@ -205,4 +207,153 @@ var gracefulShutdown_default = fp(gracefulShutdownPlugin, {
205
207
  fastify: "5.x"
206
208
  });
207
209
  //#endregion
208
- export { arcCorePlugin_default as arcCorePlugin, arcCorePlugin as arcCorePluginFn, caching_default as cachingPlugin, cachingPlugin as cachingPluginFn, createPlugin, createRequestIdGenerator, 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, realtime_default as realtimePlugin, realtimePlugin as realtimePluginFn, replyHelpersPlugin, requestId_default as requestIdPlugin, requestIdPlugin as requestIdPluginFn, sanitizeRequestId, schedules_default as schedulesPlugin, schedulesPlugin as schedulesPluginFn, sse_default as ssePlugin, ssePlugin as ssePluginFn, versioning_default as versioningPlugin, versioningPlugin as versioningPluginFn };
210
+ //#region src/plugins/pressure.ts
211
+ /**
212
+ * Admission control — ONE place that decides "are we saturated?".
213
+ *
214
+ * Arc already sheds on event-loop lag (`@fastify/under-pressure`), but lag is
215
+ * LATE: by the time the loop is behind, the work causing it is already
216
+ * admitted. What actually saturates a backend — a drained pool, an undrained
217
+ * queue, an outbox falling behind — is invisible to it. Rate limiting is a
218
+ * different axis: it bounds request FREQUENCY, this bounds concurrent
219
+ * EXPENSIVE WORK.
220
+ *
221
+ * Signals are REGISTERED, not enumerated, because only ELU has a source arc
222
+ * can read today — no kit exposes pool stats, no queue exposes depth. Arc owns
223
+ * the DECISION; signals come from whoever can produce them.
224
+ *
225
+ * `read()` returns SATURATION in [0,1]. Each signal normalises itself: 90% of
226
+ * a pool is nearly fatal, 90% ELU is merely busy, and only the signal's author
227
+ * knows which.
228
+ *
229
+ * @example
230
+ * ```typescript
231
+ * await app.register(pressurePlugin, {
232
+ * signals: [{ name: 'db-pool', read: () => pool.borrowed / pool.size }],
233
+ * shed: true,
234
+ * });
235
+ * ```
236
+ */
237
+ const log = arcLog("pressure");
238
+ /**
239
+ * Event-loop utilisation as saturation — already a [0,1] ratio, and measured
240
+ * ACROSS the interval rather than instantaneously: one lag reading is a spike,
241
+ * utilisation over a second is load.
242
+ */
243
+ function eluSignal() {
244
+ let previous = performance$1.eventLoopUtilization();
245
+ return {
246
+ name: "event-loop",
247
+ read() {
248
+ const current = performance$1.eventLoopUtilization();
249
+ const delta = performance$1.eventLoopUtilization(current, previous);
250
+ previous = current;
251
+ return delta.utilization;
252
+ }
253
+ };
254
+ }
255
+ const clamp = (n) => Number.isFinite(n) ? Math.min(1, Math.max(0, n)) : 0;
256
+ const pressurePlugin = async (fastify, options) => {
257
+ const degradedAt = options.thresholds?.degraded ?? .8;
258
+ const saturatedAt = options.thresholds?.saturated ?? .95;
259
+ if (degradedAt > saturatedAt) throw new Error(`pressurePlugin: thresholds.degraded (${degradedAt}) is above thresholds.saturated (${saturatedAt}) — 'saturated' would be unreachable and the app would never shed.`);
260
+ const signals = [...options.eventLoopUtilization === false ? [] : [eluSignal()], ...options.signals ?? []];
261
+ /** Signals that threw. Logged once each — a broken reader must not spam. */
262
+ const broken = /* @__PURE__ */ new Set();
263
+ let snapshot = {
264
+ state: "ok",
265
+ worst: void 0,
266
+ signals: {}
267
+ };
268
+ async function sample() {
269
+ const values = {};
270
+ let worst;
271
+ for (const signal of signals) {
272
+ let value = 0;
273
+ try {
274
+ value = clamp(await signal.read());
275
+ broken.delete(signal.name);
276
+ } catch (error) {
277
+ if (!broken.has(signal.name)) {
278
+ broken.add(signal.name);
279
+ log.warn("pressure signal failed to read; treating as 0", {
280
+ signal: signal.name,
281
+ error
282
+ });
283
+ }
284
+ }
285
+ values[signal.name] = value;
286
+ if (!worst || value > worst.value) worst = {
287
+ name: signal.name,
288
+ value
289
+ };
290
+ }
291
+ const peak = worst?.value ?? 0;
292
+ const next = peak >= saturatedAt ? "saturated" : peak >= degradedAt ? "degraded" : "ok";
293
+ const previous = snapshot.state;
294
+ snapshot = {
295
+ state: next,
296
+ worst,
297
+ signals: values
298
+ };
299
+ if (next !== previous) {
300
+ log.info("pressure state changed", {
301
+ from: previous,
302
+ to: next,
303
+ worst
304
+ });
305
+ options.onStateChange?.(next, snapshot);
306
+ }
307
+ }
308
+ const timer = setInterval(() => {
309
+ sample();
310
+ }, options.intervalMs ?? 1e3);
311
+ timer.unref?.();
312
+ fastify.addHook("onClose", async () => clearInterval(timer));
313
+ fastify.decorate("pressure", {
314
+ state: () => snapshot.state,
315
+ snapshot: () => snapshot,
316
+ register: (signal) => {
317
+ signals.push(signal);
318
+ },
319
+ shouldShed: () => snapshot.state === "saturated",
320
+ readinessCheck: (checkOptions) => ({
321
+ name: checkOptions?.name ?? "pressure",
322
+ critical: checkOptions?.critical ?? true,
323
+ check: () => snapshot.state !== "saturated"
324
+ })
325
+ });
326
+ if (options.shed) {
327
+ const shedConfig = options.shed === true ? {} : options.shed;
328
+ const statusCode = shedConfig.statusCode ?? 503;
329
+ const retryAfter = shedConfig.retryAfterSeconds ?? 1;
330
+ const exempt = [
331
+ "/_health",
332
+ "/health",
333
+ ...shedConfig.exclude ?? []
334
+ ];
335
+ fastify.addHook("onRequest", async (request, reply) => {
336
+ if (snapshot.state !== "saturated") return;
337
+ const url = request.url;
338
+ if (exempt.some((prefix) => url.startsWith(prefix))) return;
339
+ reply.header("Retry-After", String(retryAfter));
340
+ return reply.code(statusCode).send({
341
+ code: "arc.unavailable",
342
+ message: "Server is at capacity — retry shortly.",
343
+ status: statusCode
344
+ });
345
+ });
346
+ }
347
+ await sample();
348
+ };
349
+ /**
350
+ * `fp()`-wrapped so `fastify.pressure` is visible to the whole app rather than
351
+ * trapped in this plugin's encapsulation context — the named export above is
352
+ * the raw plugin, matching every other arc plugin entry.
353
+ */
354
+ var pressure_default = fp(pressurePlugin, {
355
+ name: "arc-pressure",
356
+ fastify: "5.x"
357
+ });
358
+ //#endregion
359
+ export { arcCorePlugin_default as arcCorePlugin, arcCorePlugin as arcCorePluginFn, caching_default as cachingPlugin, cachingPlugin as cachingPluginFn, createPlugin, createRequestIdGenerator, 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, pressure_default as pressurePlugin, pressurePlugin as pressurePluginFn, realtime_default as realtimePlugin, realtimePlugin as realtimePluginFn, replyHelpersPlugin, requestId_default as requestIdPlugin, requestIdPlugin as requestIdPluginFn, sanitizeRequestId, schedules_default as schedulesPlugin, schedulesPlugin as schedulesPluginFn, sse_default as ssePlugin, ssePlugin as ssePluginFn, versioning_default as versioningPlugin, versioningPlugin as versioningPluginFn };
@@ -1,5 +1,5 @@
1
- /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
2
- import { t as hasEvents } from "../typeGuards-jjKJDN13.mjs";
1
+ /*! @classytic/arc v2.35.0 | MIT | https://classytic.com */
2
+ import { t as hasEvents } from "../typeGuards-B-_jqaMi.mjs";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/plugins/response-cache.ts
5
5
  /**
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.35.0 | MIT | https://classytic.com */
2
2
  import { createRequire } from "node:module";
3
3
  import fp from "fastify-plugin";
4
4
  //#region src/plugins/tracing.ts
@@ -59,7 +59,7 @@ try {
59
59
  function createTracerProvider(options) {
60
60
  if (!isAvailable || !NodeTracerProvider || !BatchSpanProcessor || !OTLPTraceExporter) return null;
61
61
  const { serviceName = "@classytic/arc", serviceVersion, exporterUrl = "http://localhost:4318/v1/traces" } = options;
62
- const resolvedVersion = serviceVersion ?? "2.34.0";
62
+ const resolvedVersion = serviceVersion ?? "2.35.0";
63
63
  const exporter = new OTLPTraceExporter({ url: exporterUrl });
64
64
  const provider = new NodeTracerProvider({ resource: { attributes: {
65
65
  "service.name": serviceName,
@@ -1,4 +1,4 @@
1
- /*! @classytic/arc v2.34.0 | MIT | https://classytic.com */
1
+ /*! @classytic/arc v2.35.0 | MIT | https://classytic.com */
2
2
  //#region src/utils/pluralize.ts
3
3
  /**
4
4
  * Lightweight English pluralization for the Arc CLI.