brass-runtime 1.17.0 → 1.18.1

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 (120) hide show
  1. package/README.md +36 -3
  2. package/dist/agent/cli/main.cjs +31 -32
  3. package/dist/agent/cli/main.js +3 -4
  4. package/dist/agent/cli/main.mjs +3 -4
  5. package/dist/agent/index.cjs +4 -5
  6. package/dist/agent/index.d.ts +1 -1
  7. package/dist/agent/index.js +3 -4
  8. package/dist/agent/index.mjs +3 -4
  9. package/dist/{chunk-7X3K5RMS.js → chunk-22HZQG5F.js} +9 -11
  10. package/dist/{chunk-GLE2WY7Z.cjs → chunk-2JHJ4YHS.cjs} +417 -124
  11. package/dist/{chunk-Q2I37RP3.cjs → chunk-2OW6IFY2.cjs} +44 -323
  12. package/dist/{chunk-7ZPEZ57L.cjs → chunk-5LC7V2OZ.cjs} +18 -20
  13. package/dist/{chunk-AGR5B2BC.cjs → chunk-5RZ7YITF.cjs} +564 -12
  14. package/dist/{chunk-DNFJLJMW.mjs → chunk-6MLAZPBL.mjs} +48 -24
  15. package/dist/{chunk-EJ6BPYVR.mjs → chunk-6V2AWT4R.mjs} +1 -1
  16. package/dist/{chunk-3AYM6WPJ.js → chunk-7DU7IQHK.js} +20 -299
  17. package/dist/{chunk-SK7UZRNI.mjs → chunk-7GBJYOX7.mjs} +528 -23
  18. package/dist/chunk-7TKI527D.cjs +123 -0
  19. package/dist/{chunk-52OB2ROS.js → chunk-7VQLEN37.js} +2 -4
  20. package/dist/{chunk-KH4SYAOS.mjs → chunk-B5FKOLTB.mjs} +20 -299
  21. package/dist/{chunk-FHQGHPMO.mjs → chunk-BC6Q6BCO.mjs} +2 -4
  22. package/dist/{chunk-4P2HHGAX.mjs → chunk-COOW7BJX.mjs} +32 -11
  23. package/dist/{chunk-2HQTDLHF.mjs → chunk-EEN5OTCR.mjs} +555 -3
  24. package/dist/{chunk-KZJQ723N.cjs → chunk-EICAJDNX.cjs} +13 -15
  25. package/dist/chunk-ELIECDYN.cjs +33 -0
  26. package/dist/{chunk-GYM3LLGS.mjs → chunk-H626ZTDZ.mjs} +399 -106
  27. package/dist/{chunk-C3MDXTRZ.js → chunk-HCJ4S3YB.js} +48 -24
  28. package/dist/{chunk-7JIJOVCT.js → chunk-IPSMXUWA.js} +2 -4
  29. package/dist/{chunk-4ROBZFL6.cjs → chunk-J6DUHITE.cjs} +6 -8
  30. package/dist/{chunk-6RY2FFN4.mjs → chunk-JWIEMBE6.mjs} +9 -11
  31. package/dist/{chunk-PD4EJTQC.cjs → chunk-KNTJ7FQB.cjs} +5 -5
  32. package/dist/chunk-KTGDLBLD.mjs +123 -0
  33. package/dist/chunk-LSYQ3C2M.js +33 -0
  34. package/dist/{chunk-RKGKFN2A.js → chunk-OW5VHAOE.js} +1 -1
  35. package/dist/{chunk-EOC4UHBS.mjs → chunk-RBHNOKH4.mjs} +2 -2
  36. package/dist/{chunk-6IXXWIUM.js → chunk-S4HXADU4.js} +555 -3
  37. package/dist/{chunk-FH2X7BVP.js → chunk-TTSPIU3U.js} +399 -106
  38. package/dist/{chunk-5QC7LRZ3.js → chunk-UAKAF32U.js} +2 -2
  39. package/dist/{chunk-CZIVE6NT.cjs → chunk-UUMKZJRJ.cjs} +48 -24
  40. package/dist/{chunk-MBEJI5HF.mjs → chunk-WCBNXPN6.mjs} +2 -4
  41. package/dist/{chunk-52PPNNI4.cjs → chunk-WGE2FEZE.cjs} +2 -2
  42. package/dist/{chunk-WBGRHGBP.cjs → chunk-WI7GZF3B.cjs} +114 -93
  43. package/dist/chunk-WUDHOZIH.js +6234 -0
  44. package/dist/{chunk-F6XWZQY4.cjs → chunk-WVSZOPGQ.cjs} +583 -78
  45. package/dist/chunk-XPIMJQYS.cjs +6234 -0
  46. package/dist/{chunk-VWIPB6I5.js → chunk-YGR2IN4R.js} +528 -23
  47. package/dist/chunk-YM3EDNYD.js +123 -0
  48. package/dist/chunk-YWLLH27R.mjs +33 -0
  49. package/dist/{chunk-BKK77SBA.js → chunk-YZ5LQ32F.js} +32 -11
  50. package/dist/chunk-Z3ZZMQUZ.mjs +6234 -0
  51. package/dist/core/index.cjs +37 -9
  52. package/dist/core/index.d.ts +19 -152
  53. package/dist/core/index.js +86 -58
  54. package/dist/core/index.mjs +86 -58
  55. package/dist/defaultClient-Cid0JoUR.d.ts +1648 -0
  56. package/dist/{effect-DIUHZ9IN.d.ts → effect-DnGUuhw6.d.ts} +22 -1
  57. package/dist/http/index.cjs +206 -59
  58. package/dist/http/index.d.ts +55 -819
  59. package/dist/http/index.js +220 -73
  60. package/dist/http/index.mjs +220 -73
  61. package/dist/http/testing.cjs +31 -10
  62. package/dist/http/testing.d.ts +16 -5
  63. package/dist/http/testing.js +29 -8
  64. package/dist/http/testing.mjs +29 -8
  65. package/dist/index.cjs +116 -88
  66. package/dist/index.d.ts +9 -8
  67. package/dist/index.js +87 -59
  68. package/dist/index.mjs +87 -59
  69. package/dist/{schedule-CK3Ml_7p.d.ts → layer-D2LFcBVx.d.ts} +176 -2
  70. package/dist/observability/index.cjs +20 -7
  71. package/dist/observability/index.d.ts +32 -8
  72. package/dist/observability/index.js +19 -6
  73. package/dist/observability/index.mjs +19 -6
  74. package/dist/perf/cli.cjs +26 -28
  75. package/dist/perf/cli.js +11 -13
  76. package/dist/perf/cli.mjs +11 -13
  77. package/dist/perf/index.cjs +13 -15
  78. package/dist/perf/index.js +11 -13
  79. package/dist/perf/index.mjs +11 -13
  80. package/dist/schema/index.cjs +2 -2
  81. package/dist/schema/index.js +1 -1
  82. package/dist/schema/index.mjs +1 -1
  83. package/dist/{server-D6JZ15_e.d.ts → server-Bf1zNYZk.d.ts} +5 -5
  84. package/dist/{stream-B4oK9JFP.d.ts → stream-I7bkvF7a.d.ts} +1 -1
  85. package/dist/{tracer-Hwt1cl7h.d.ts → tracer-DF83nLn6.d.ts} +2 -2
  86. package/dist/{tracing-DqbTKGcf.d.ts → tracing-CWV4gT0u.d.ts} +1 -1
  87. package/docs/README.md +2 -0
  88. package/docs/ai/PUBLIC_API.md +28 -7
  89. package/docs/articles/brass-runtime-http-observability.md +467 -0
  90. package/docs/frameworks/angular.md +51 -0
  91. package/docs/frameworks/express.md +58 -0
  92. package/docs/frameworks/fastify.md +49 -0
  93. package/docs/frameworks/nestjs.md +53 -0
  94. package/docs/frameworks/nextjs.md +55 -0
  95. package/docs/frameworks/react.md +44 -0
  96. package/docs/frameworks/vanilla.md +56 -0
  97. package/docs/guides/layers.md +130 -0
  98. package/docs/http-recipes.md +31 -1
  99. package/docs/http.md +50 -1
  100. package/docs/observability.md +132 -0
  101. package/docs/performance-profiler.md +6 -2
  102. package/docs/recipes/layers.md +46 -2
  103. package/docs/recipes/testing.md +25 -0
  104. package/package.json +6 -2
  105. package/dist/chunk-3LOYJFRR.cjs +0 -300
  106. package/dist/chunk-3Y2RIUMM.js +0 -300
  107. package/dist/chunk-5EC274J5.cjs +0 -2874
  108. package/dist/chunk-5VRJNBLZ.mjs +0 -2874
  109. package/dist/chunk-62AZW6UT.cjs +0 -313
  110. package/dist/chunk-74ZTY6CP.js +0 -2871
  111. package/dist/chunk-7CMJS3QE.mjs +0 -2871
  112. package/dist/chunk-A2OM6NEH.mjs +0 -194
  113. package/dist/chunk-B33ICAKP.js +0 -313
  114. package/dist/chunk-JF5WGYJJ.cjs +0 -194
  115. package/dist/chunk-KN32XNTH.mjs +0 -313
  116. package/dist/chunk-KQLYONSE.cjs +0 -2871
  117. package/dist/chunk-L2SYFEBS.js +0 -194
  118. package/dist/chunk-MIIYDLGM.js +0 -2874
  119. package/dist/chunk-PWC3RBQE.mjs +0 -300
  120. package/dist/client-CZHU674n.d.ts +0 -820
@@ -1,2874 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5;
2
-
3
- var _chunkL6VB5N7Qcjs = require('./chunk-L6VB5N7Q.cjs');
4
-
5
-
6
- var _chunkKZJQ723Ncjs = require('./chunk-KZJQ723N.cjs');
7
-
8
-
9
-
10
- var _chunkAGR5B2BCcjs = require('./chunk-AGR5B2BC.cjs');
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
- var _chunk3LOYJFRRcjs = require('./chunk-3LOYJFRR.cjs');
19
-
20
-
21
-
22
- var _chunkGLE2WY7Zcjs = require('./chunk-GLE2WY7Z.cjs');
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
- var _chunkMVGUEJ5Zcjs = require('./chunk-MVGUEJ5Z.cjs');
31
-
32
-
33
-
34
- var _chunkCZIVE6NTcjs = require('./chunk-CZIVE6NT.cjs');
35
-
36
- // src/http/retry/wasmRetryPlanner.ts
37
- var WasmRetryPlannerBridge = class {
38
-
39
- constructor(Ctor) {
40
- this.planner = new Ctor();
41
- }
42
- start(options) {
43
- return this.planner.start(
44
- options.nowMs,
45
- options.maxRetries,
46
- options.baseDelayMs,
47
- options.maxDelayMs,
48
- _nullishCoalesce(options.maxElapsedMs, () => ( -1)),
49
- BigInt(this.seed())
50
- );
51
- }
52
- nextDelayMs(retryId, options) {
53
- const delay = this.planner.next_delay_ms(retryId, options.nowMs, options.retryable, _nullishCoalesce(options.retryAfterMs, () => ( -1)));
54
- return delay < 0 ? void 0 : delay;
55
- }
56
- drop(retryId) {
57
- this.planner.drop_state(retryId);
58
- }
59
- stats() {
60
- return {
61
- live: this.planner.metric_u64(0),
62
- planned: this.planner.metric_u64(1),
63
- exhausted: this.planner.metric_u64(2),
64
- dropped: this.planner.metric_u64(3)
65
- };
66
- }
67
- seed() {
68
- return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
69
- }
70
- };
71
- function makeWasmRetryPlanner() {
72
- const mod = _chunkGLE2WY7Zcjs.resolveWasmModule.call(void 0, );
73
- const Ctor = _optionalChain([mod, 'optionalAccess', _ => _.BrassWasmRetryPlanner]);
74
- if (!Ctor) throw new Error("brass-runtime wasm retry planner is not available. Run npm run build:wasm first.");
75
- return new WasmRetryPlannerBridge(Ctor);
76
- }
77
-
78
- // src/http/retry/retry.ts
79
- var defaultRetryableMethods = ["GET", "HEAD", "OPTIONS"];
80
- var defaultRetryOnStatus = (s) => s === 408 || s === 429 || s === 500 || s === 502 || s === 503 || s === 504;
81
- var defaultRetryOnError = (e) => _chunk3LOYJFRRcjs.isRetryableHttpError.call(void 0, e, { retryOnStatus: defaultRetryOnStatus });
82
- var clamp = (n, min, max) => Math.max(min, Math.min(max, n));
83
- var backoffDelayMs = (attempt, base, cap) => {
84
- const b = Math.max(0, base);
85
- const c = Math.max(0, cap);
86
- const exp = b * Math.pow(2, attempt);
87
- const lim = clamp(exp, 0, c);
88
- return Math.floor(Math.random() * lim);
89
- };
90
- var headerCI = (h, name) => {
91
- const k = Object.keys(h).find((x) => x.toLowerCase() === name.toLowerCase());
92
- return k ? h[k] : void 0;
93
- };
94
- var retryAfterMs = (headers) => {
95
- const v = _optionalChain([headerCI, 'call', _2 => _2(headers, "retry-after"), 'optionalAccess', _3 => _3.trim, 'call', _4 => _4()]);
96
- if (!v) return void 0;
97
- const secs = Number(v);
98
- if (Number.isFinite(secs)) return Math.max(0, Math.floor(secs * 1e3));
99
- const t = Date.parse(v);
100
- if (Number.isFinite(t)) return Math.max(0, t - Date.now());
101
- return void 0;
102
- };
103
- var normalizeRetryBudget = (ms) => {
104
- if (ms === void 0 || !Number.isFinite(ms)) return void 0;
105
- return Math.max(0, Math.floor(ms));
106
- };
107
- var resolveEffectivePolicy = (req, basePolicy) => {
108
- const override = _chunk3LOYJFRRcjs.getHttpRequestPolicy.call(void 0, req).retry;
109
- if (override === false) return null;
110
- if (override === void 0) return basePolicy;
111
- return {
112
- ...basePolicy,
113
- ...override.maxRetries !== void 0 && { maxRetries: override.maxRetries },
114
- ...override.baseDelayMs !== void 0 && { baseDelayMs: override.baseDelayMs },
115
- ...override.maxDelayMs !== void 0 && { maxDelayMs: override.maxDelayMs },
116
- ...override.schedule !== void 0 && { schedule: override.schedule },
117
- ...override.retryOnStatus !== void 0 && { retryOnStatus: override.retryOnStatus }
118
- };
119
- };
120
- var resolveRetryEngine = (p) => {
121
- if (p.engine !== void 0) {
122
- if (p.engine === "ts" || p.engine === "wasm") return p.engine;
123
- throw new Error(`brass-runtime retry engine must be 'ts' or 'wasm'; received '${String(p.engine)}'`);
124
- }
125
- if (p.wasm === true) return "wasm";
126
- if (p.wasm === false) return "ts";
127
- return "ts";
128
- };
129
- var withRetry = (p) => (next) => {
130
- const retryOnMethods = _nullishCoalesce(p.retryOnMethods, () => ( defaultRetryableMethods));
131
- const retryEngine = resolveRetryEngine(p);
132
- const wasmPlanner = retryEngine === "wasm" ? makeWasmRetryPlanner() : void 0;
133
- const isMethodRetryable = (req) => retryOnMethods.includes(req.method);
134
- const nextDelay = (ep, epMaxElapsedMs, retryId, attempt, startedAt, retryable, scheduleDriver, input) => {
135
- if (!retryable) return void 0;
136
- const remainingBudget = epMaxElapsedMs === void 0 ? Number.POSITIVE_INFINITY : epMaxElapsedMs - (performance.now() - startedAt);
137
- if (remainingBudget <= 0) return void 0;
138
- if (scheduleDriver) {
139
- const decision = scheduleDriver.next(input);
140
- if (!decision.continue) return void 0;
141
- const rawDelay2 = input.retryAfterMs === void 0 ? decision.delayMs : Math.min(input.retryAfterMs, ep.maxDelayMs);
142
- return {
143
- delayMs: Math.max(0, Math.min(rawDelay2, remainingBudget))
144
- };
145
- }
146
- if (wasmPlanner && retryId !== void 0) {
147
- const delay = wasmPlanner.nextDelayMs(retryId, {
148
- nowMs: performance.now(),
149
- retryable,
150
- retryAfterMs: input.retryAfterMs
151
- });
152
- return delay === void 0 ? void 0 : { delayMs: delay };
153
- }
154
- const rawDelay = input.retryAfterMs === void 0 ? backoffDelayMs(attempt, ep.baseDelayMs, ep.maxDelayMs) : Math.min(input.retryAfterMs, ep.maxDelayMs);
155
- return { delayMs: Math.max(0, Math.min(rawDelay, remainingBudget)) };
156
- };
157
- const sleepWithCleanup = (ms, onCancel) => {
158
- return _chunkMVGUEJ5Zcjs.asyncEffect.call(void 0, (_env, cb) => {
159
- const delay = Math.max(0, Math.floor(ms));
160
- const id = setTimeout(() => cb({ _tag: "Success", value: void 0 }), delay);
161
- return () => {
162
- clearTimeout(id);
163
- onCancel();
164
- };
165
- });
166
- };
167
- const loop = (req, attempt, startedAt, retryId, ep, epMaxElapsedMs, epRetryOnStatus, epRetryOnError, originalPriority, safeDrop, scheduleDriver) => {
168
- if (!isMethodRetryable(req)) return next(req);
169
- const effectiveReq = attempt > 0 ? _chunk3LOYJFRRcjs.withHttpRequestPolicy.call(void 0, req, { priority: Math.max(0, originalPriority - 1) }) : req;
170
- const remainingBudget = () => epMaxElapsedMs === void 0 ? Number.POSITIVE_INFINITY : epMaxElapsedMs - (performance.now() - startedAt);
171
- return _chunkMVGUEJ5Zcjs.asyncFold.call(void 0,
172
- next(effectiveReq),
173
- (e) => {
174
- if (e._tag === "Abort" || e._tag === "BadUrl" || e._tag === "PoolRejected" || e._tag === "PoolClosed" || e._tag === "CircuitBreakerOpen") {
175
- safeDrop(retryId);
176
- return _chunkMVGUEJ5Zcjs.asyncFail.call(void 0, e);
177
- }
178
- const retryable = attempt < ep.maxRetries && epRetryOnError(e) && remainingBudget() > 0;
179
- const retryDecision = nextDelay(ep, epMaxElapsedMs, retryId, attempt, startedAt, retryable, scheduleDriver, {
180
- attempt,
181
- elapsedMs: performance.now() - startedAt,
182
- request: req,
183
- error: e
184
- });
185
- if (retryDecision === void 0 || retryDecision.delayMs <= 0 && epMaxElapsedMs !== void 0) {
186
- safeDrop(retryId);
187
- return _chunkMVGUEJ5Zcjs.asyncFail.call(void 0, e);
188
- }
189
- if (ep.onRetry) {
190
- ep.onRetry({
191
- attempt,
192
- delayMs: retryDecision.delayMs,
193
- error: e,
194
- status: void 0,
195
- url: req.url,
196
- method: req.method,
197
- timestamp: Date.now()
198
- });
199
- }
200
- return _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0, sleepWithCleanup(retryDecision.delayMs, () => safeDrop(retryId)), () => loop(req, attempt + 1, startedAt, retryId, ep, epMaxElapsedMs, epRetryOnStatus, epRetryOnError, originalPriority, safeDrop, scheduleDriver));
201
- },
202
- (w) => {
203
- const retryable = attempt < ep.maxRetries && epRetryOnStatus(w.status) && remainingBudget() > 0;
204
- const ra = ep.respectRetryAfter === false ? void 0 : retryAfterMs(w.headers);
205
- const retryDecision = nextDelay(ep, epMaxElapsedMs, retryId, attempt, startedAt, retryable, scheduleDriver, {
206
- attempt,
207
- elapsedMs: performance.now() - startedAt,
208
- request: req,
209
- status: w.status,
210
- retryAfterMs: ra
211
- });
212
- if (retryDecision === void 0 || retryDecision.delayMs <= 0 && epMaxElapsedMs !== void 0) {
213
- safeDrop(retryId);
214
- return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, w);
215
- }
216
- if (ep.onRetry) {
217
- ep.onRetry({
218
- attempt,
219
- delayMs: retryDecision.delayMs,
220
- error: void 0,
221
- status: w.status,
222
- url: req.url,
223
- method: req.method,
224
- timestamp: Date.now()
225
- });
226
- }
227
- return _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0, sleepWithCleanup(retryDecision.delayMs, () => safeDrop(retryId)), () => loop(req, attempt + 1, startedAt, retryId, ep, epMaxElapsedMs, epRetryOnStatus, epRetryOnError, originalPriority, safeDrop, scheduleDriver));
228
- }
229
- );
230
- };
231
- return (req) => {
232
- const effectivePolicy = resolveEffectivePolicy(req, p);
233
- if (effectivePolicy === null) return next(req);
234
- if (!isMethodRetryable(req)) return next(req);
235
- const epRetryOnStatus = _nullishCoalesce(effectivePolicy.retryOnStatus, () => ( defaultRetryOnStatus));
236
- const epRetryOnError = _nullishCoalesce(effectivePolicy.retryOnError, () => ( defaultRetryOnError));
237
- const epMaxElapsedMs = normalizeRetryBudget(effectivePolicy.maxElapsedMs);
238
- const originalPriority = _nullishCoalesce(_chunk3LOYJFRRcjs.getHttpRequestPolicy.call(void 0, req).priority, () => ( 5));
239
- const startedAt = performance.now();
240
- const retryId = _optionalChain([wasmPlanner, 'optionalAccess', _5 => _5.start, 'call', _6 => _6({
241
- nowMs: startedAt,
242
- maxRetries: effectivePolicy.maxRetries,
243
- baseDelayMs: effectivePolicy.baseDelayMs,
244
- maxDelayMs: effectivePolicy.maxDelayMs,
245
- maxElapsedMs: epMaxElapsedMs
246
- })]);
247
- let plannerDropped = false;
248
- const safeDrop = (id) => {
249
- if (id !== void 0 && !plannerDropped) {
250
- plannerDropped = true;
251
- _optionalChain([wasmPlanner, 'optionalAccess', _7 => _7.drop, 'call', _8 => _8(id)]);
252
- }
253
- };
254
- const scheduleDriver = effectivePolicy.schedule ? _chunkAGR5B2BCcjs.makeScheduleDriver.call(void 0, effectivePolicy.schedule, {
255
- name: _nullishCoalesce(effectivePolicy.schedule.name, () => ( "http.retry")),
256
- startedAtMs: startedAt,
257
- onDecision: effectivePolicy.onScheduleDecision
258
- }) : void 0;
259
- return loop(req, 0, startedAt, retryId, effectivePolicy, epMaxElapsedMs, epRetryOnStatus, epRetryOnError, originalPriority, safeDrop, scheduleDriver);
260
- };
261
- };
262
-
263
- // src/http/wasmPermitPool.ts
264
- var DECISION_RUN_NOW = 0;
265
- var DECISION_QUEUED = 1;
266
- var WasmHttpPermitPoolBridge = (_class = class {
267
-
268
- __init() {this.keyCache = /* @__PURE__ */ new Map()}
269
- constructor(Ctor, options) {;_class.prototype.__init.call(this);
270
- this.pool = new Ctor(options.concurrency, options.maxQueue, toU64(options.queueTimeoutMs));
271
- }
272
- acquire(key, subjectId, nowMs2 = Date.now()) {
273
- const keyId = this.internKey(key);
274
- const decision = this.pool.acquire(subjectId, keyId, toU64(nowMs2));
275
- const permitId = this.pool.last_permit_id();
276
- if (decision === DECISION_RUN_NOW) return { kind: "run", keyId, permitId };
277
- if (decision === DECISION_QUEUED) return { kind: "queued", keyId, permitId };
278
- return { kind: "rejected", keyId, permitId };
279
- }
280
- release(keyId, nowMs2 = Date.now()) {
281
- const ptr = this.pool.release(keyId, toU64(nowMs2));
282
- return this.readEvents(ptr, this.pool.permit_events_len());
283
- }
284
- cancel(permitId) {
285
- this.pool.cancel(permitId);
286
- }
287
- advanceTime(nowMs2 = Date.now()) {
288
- const ptr = this.pool.advance_time(toU64(nowMs2));
289
- return this.readEvents(ptr, this.pool.permit_events_len());
290
- }
291
- nextDeadlineMs() {
292
- return this.pool.next_deadline_ms();
293
- }
294
- stats() {
295
- return {
296
- running: this.pool.metric_u64(0),
297
- queued: this.pool.metric_u64(1),
298
- acquired: this.pool.metric_u64(2),
299
- released: this.pool.metric_u64(3),
300
- rejected: this.pool.metric_u64(4),
301
- queueTimeouts: this.pool.metric_u64(5),
302
- keys: this.pool.metric_u64(6)
303
- };
304
- }
305
- internKey(key) {
306
- const normalized = key.trim().slice(0, 160) || "global";
307
- let id = this.keyCache.get(normalized);
308
- if (id === void 0) {
309
- id = this.pool.intern_key(normalized);
310
- this.keyCache.set(normalized, id);
311
- }
312
- return id;
313
- }
314
- readEvents(ptr, len) {
315
- if (ptr === 0 || len <= 1) return [];
316
- const words = new Uint32Array(this.pool.memory().buffer, ptr, len);
317
- const count = words[0] >>> 0;
318
- const out = [];
319
- for (let i = 0; i < count; i++) {
320
- const base = 1 + i * 3;
321
- if (base + 2 >= words.length) break;
322
- out.push({
323
- subjectId: words[base] >>> 0,
324
- permitId: words[base + 1] >>> 0,
325
- keyId: words[base + 2] >>> 0
326
- });
327
- }
328
- return out;
329
- }
330
- }, _class);
331
- function makeWasmHttpPermitPool(options) {
332
- const mod = _chunkGLE2WY7Zcjs.resolveWasmModule.call(void 0, );
333
- const Ctor = _optionalChain([mod, 'optionalAccess', _9 => _9.BrassWasmHttpPermitPool]);
334
- if (!Ctor) throw new Error("brass-runtime wasm HTTP permit pool is not available. Run npm run build:wasm first.");
335
- return new WasmHttpPermitPoolBridge(Ctor, options);
336
- }
337
- function toU64(value) {
338
- return BigInt(Math.max(0, Math.floor(value)));
339
- }
340
-
341
- // src/http/pool.ts
342
- var DEFAULT_CONCURRENCY = 64;
343
- var DEFAULT_MAX_QUEUE = 256;
344
- var clampInt = (n, fallback, min) => {
345
- if (n === void 0 || !Number.isFinite(n)) return fallback;
346
- return Math.max(min, Math.floor(n));
347
- };
348
- var queueTimeoutError = (key, timeoutMs) => ({
349
- _tag: "PoolTimeout",
350
- key,
351
- timeoutMs,
352
- message: `HTTP pool '${key}' did not grant a slot within ${timeoutMs}ms`
353
- });
354
- var poolRejectedError = (key, maxQueue) => ({
355
- _tag: "PoolRejected",
356
- key,
357
- limit: maxQueue,
358
- message: `HTTP pool '${key}' queue is full`
359
- });
360
- var abortError = () => ({ _tag: "Abort" });
361
- function resolveHttpPoolEngine(config) {
362
- if (config.engine !== void 0) {
363
- if (config.engine === "ts" || config.engine === "wasm") return config.engine;
364
- throw new Error(`brass-runtime HTTP pool engine must be 'ts' or 'wasm'; received '${String(config.engine)}'`);
365
- }
366
- if (config.wasm === true) return "wasm";
367
- if (config.wasm === false) return "ts";
368
- return "ts";
369
- }
370
- function resolveHttpPoolKey(resolver, req, url) {
371
- const custom = _optionalChain([_chunk3LOYJFRRcjs.getHttpRequestPolicy.call(void 0, req), 'access', _10 => _10.poolKey, 'optionalAccess', _11 => _11.trim, 'call', _12 => _12()]);
372
- if (custom) return custom.slice(0, 160);
373
- const r = _nullishCoalesce(resolver, () => ( "origin"));
374
- if (typeof r === "function") return r(req, url).trim().slice(0, 160) || "global";
375
- if (r === "global") return "global";
376
- if (r === "host") return url.host;
377
- return url.origin;
378
- }
379
- var HttpConcurrencyPool = (_class2 = class {
380
- __init2() {this.states = /* @__PURE__ */ new Map()}
381
-
382
-
383
-
384
-
385
-
386
- __init3() {this.wasmWaiters = /* @__PURE__ */ new Map()}
387
-
388
- __init4() {this.nextSubjectId = 1}
389
- constructor(config = {}) {;_class2.prototype.__init2.call(this);_class2.prototype.__init3.call(this);_class2.prototype.__init4.call(this);
390
- this.concurrency = clampInt(config.concurrency, DEFAULT_CONCURRENCY, 1);
391
- this.maxQueue = clampInt(config.maxQueue, DEFAULT_MAX_QUEUE, 0);
392
- this.queueTimeoutMs = config.queueTimeoutMs !== void 0 && Number.isFinite(config.queueTimeoutMs) ? Math.max(0, Math.floor(config.queueTimeoutMs)) : void 0;
393
- this.keyResolver = config.key;
394
- const engine = resolveHttpPoolEngine(config);
395
- this.wasm = engine === "wasm" ? makeWasmHttpPermitPool({
396
- concurrency: this.concurrency,
397
- maxQueue: this.maxQueue,
398
- queueTimeoutMs: _nullishCoalesce(this.queueTimeoutMs, () => ( 0))
399
- }) : void 0;
400
- }
401
- acquire(key, signal) {
402
- return this.wasm ? this.acquireWasm(key, signal) : this.acquireJs(key, signal);
403
- }
404
- stats() {
405
- const keys = Array.from(this.states.values()).map((state) => ({
406
- key: state.key,
407
- running: state.running,
408
- queued: state.queue.length,
409
- concurrency: this.concurrency,
410
- maxQueue: this.maxQueue,
411
- acquired: state.acquired,
412
- released: state.released,
413
- rejected: state.rejected,
414
- queueTimeouts: state.queueTimeouts,
415
- abortedWhileQueued: state.abortedWhileQueued
416
- })).sort((a, b) => b.running + b.queued - (a.running + a.queued) || a.key.localeCompare(b.key));
417
- return keys.reduce((acc, key) => ({
418
- running: acc.running + key.running,
419
- queued: acc.queued + key.queued,
420
- acquired: acc.acquired + key.acquired,
421
- released: acc.released + key.released,
422
- rejected: acc.rejected + key.rejected,
423
- queueTimeouts: acc.queueTimeouts + key.queueTimeouts,
424
- abortedWhileQueued: acc.abortedWhileQueued + key.abortedWhileQueued,
425
- wasm: _optionalChain([this, 'access', _13 => _13.wasm, 'optionalAccess', _14 => _14.stats, 'call', _15 => _15()]),
426
- keys: acc.keys.concat(key)
427
- }), {
428
- running: 0,
429
- queued: 0,
430
- acquired: 0,
431
- released: 0,
432
- rejected: 0,
433
- queueTimeouts: 0,
434
- abortedWhileQueued: 0,
435
- ...this.wasm ? { wasm: this.wasm.stats() } : {},
436
- keys: []
437
- });
438
- }
439
- acquireJs(key, signal) {
440
- const state = this.getState(key);
441
- if (signal.aborted) return Promise.reject(abortError());
442
- if (state.running < this.concurrency) {
443
- state.running++;
444
- state.acquired++;
445
- return Promise.resolve(this.makeLease(state));
446
- }
447
- if (state.queue.length >= this.maxQueue) {
448
- state.rejected++;
449
- return Promise.reject(poolRejectedError(key, this.maxQueue));
450
- }
451
- return new Promise((resolve, reject) => {
452
- const waiter = { signal, resolve, reject };
453
- const removeWaiter = () => this.removeWaiter(state, waiter);
454
- const cleanup = () => this.cleanupWaiter(waiter);
455
- waiter.abort = () => {
456
- cleanup();
457
- removeWaiter();
458
- state.abortedWhileQueued++;
459
- reject(abortError());
460
- };
461
- signal.addEventListener("abort", waiter.abort, { once: true });
462
- if (this.queueTimeoutMs !== void 0 && this.queueTimeoutMs > 0) {
463
- waiter.timer = setTimeout(() => {
464
- cleanup();
465
- removeWaiter();
466
- state.queueTimeouts++;
467
- reject(queueTimeoutError(key, this.queueTimeoutMs));
468
- }, this.queueTimeoutMs);
469
- }
470
- state.queue.push(waiter);
471
- });
472
- }
473
- acquireWasm(key, signal) {
474
- const wasm = this.wasm;
475
- const state = this.getState(key);
476
- if (signal.aborted) return Promise.reject(abortError());
477
- const subjectId = this.allocateSubjectId();
478
- const decision = wasm.acquire(key, subjectId);
479
- if (decision.kind === "run") {
480
- state.running++;
481
- state.acquired++;
482
- return Promise.resolve(this.makeLease(state, decision.keyId));
483
- }
484
- if (decision.kind === "rejected") {
485
- state.rejected++;
486
- return Promise.reject(poolRejectedError(key, this.maxQueue));
487
- }
488
- return new Promise((resolve, reject) => {
489
- const waiter = { signal, resolve, reject };
490
- const removeWaiter = () => this.removeWaiter(state, waiter);
491
- const cleanup = () => this.cleanupWaiter(waiter);
492
- waiter.abort = () => {
493
- cleanup();
494
- removeWaiter();
495
- wasm.cancel(decision.permitId);
496
- this.wasmWaiters.delete(decision.permitId);
497
- state.abortedWhileQueued++;
498
- reject(abortError());
499
- };
500
- signal.addEventListener("abort", waiter.abort, { once: true });
501
- state.queue.push(waiter);
502
- this.wasmWaiters.set(decision.permitId, { waiter, state, keyId: decision.keyId });
503
- this.scheduleWasmTimeoutPump();
504
- });
505
- }
506
- getState(key) {
507
- const k = key.trim().slice(0, 160) || "global";
508
- const existing = this.states.get(k);
509
- if (existing) return existing;
510
- const created = {
511
- key: k,
512
- running: 0,
513
- queue: [],
514
- acquired: 0,
515
- released: 0,
516
- rejected: 0,
517
- queueTimeouts: 0,
518
- abortedWhileQueued: 0
519
- };
520
- this.states.set(k, created);
521
- return created;
522
- }
523
- makeLease(state, wasmKeyId) {
524
- let released = false;
525
- return {
526
- key: state.key,
527
- release: () => {
528
- if (released) return;
529
- released = true;
530
- if (state.running > 0) state.running--;
531
- state.released++;
532
- if (this.wasm && wasmKeyId !== void 0) {
533
- this.handleWasmGrants(this.wasm.release(wasmKeyId));
534
- this.scheduleWasmTimeoutPump();
535
- return;
536
- }
537
- this.drain(state);
538
- }
539
- };
540
- }
541
- drain(state) {
542
- while (state.running < this.concurrency && state.queue.length > 0) {
543
- const waiter = state.queue.shift();
544
- this.cleanupWaiter(waiter);
545
- if (waiter.signal.aborted) {
546
- state.abortedWhileQueued++;
547
- waiter.reject(abortError());
548
- continue;
549
- }
550
- state.running++;
551
- state.acquired++;
552
- waiter.resolve(this.makeLease(state));
553
- }
554
- }
555
- handleWasmGrants(events) {
556
- for (const event of events) {
557
- const pending = this.wasmWaiters.get(event.permitId);
558
- if (!pending) continue;
559
- this.wasmWaiters.delete(event.permitId);
560
- this.cleanupWaiter(pending.waiter);
561
- this.removeWaiter(pending.state, pending.waiter);
562
- if (pending.waiter.signal.aborted) {
563
- pending.state.abortedWhileQueued++;
564
- pending.waiter.reject(abortError());
565
- continue;
566
- }
567
- pending.state.running++;
568
- pending.state.acquired++;
569
- pending.waiter.resolve(this.makeLease(pending.state, event.keyId));
570
- }
571
- }
572
- handleWasmTimeouts(events) {
573
- for (const event of events) {
574
- const pending = this.wasmWaiters.get(event.permitId);
575
- if (!pending) continue;
576
- this.wasmWaiters.delete(event.permitId);
577
- this.cleanupWaiter(pending.waiter);
578
- this.removeWaiter(pending.state, pending.waiter);
579
- pending.state.queueTimeouts++;
580
- pending.waiter.reject(queueTimeoutError(pending.state.key, _nullishCoalesce(this.queueTimeoutMs, () => ( 0))));
581
- }
582
- }
583
- scheduleWasmTimeoutPump() {
584
- if (!this.wasm) return;
585
- if (this.wasmTimer !== void 0) clearTimeout(this.wasmTimer);
586
- this.wasmTimer = void 0;
587
- const next = this.wasm.nextDeadlineMs();
588
- if (!Number.isFinite(next) || next < 0) return;
589
- const delay = Math.max(0, Math.min(2 ** 31 - 1, Math.floor(next - Date.now())));
590
- this.wasmTimer = setTimeout(() => {
591
- this.wasmTimer = void 0;
592
- if (!this.wasm) return;
593
- this.handleWasmTimeouts(this.wasm.advanceTime());
594
- this.scheduleWasmTimeoutPump();
595
- }, delay);
596
- if (typeof this.wasmTimer.unref === "function") this.wasmTimer.unref();
597
- }
598
- cleanupWaiter(waiter) {
599
- if (waiter.timer !== void 0) {
600
- clearTimeout(waiter.timer);
601
- waiter.timer = void 0;
602
- }
603
- if (waiter.abort) {
604
- waiter.signal.removeEventListener("abort", waiter.abort);
605
- waiter.abort = void 0;
606
- }
607
- }
608
- removeWaiter(state, waiter) {
609
- const idx = state.queue.indexOf(waiter);
610
- if (idx >= 0) state.queue.splice(idx, 1);
611
- }
612
- allocateSubjectId() {
613
- const id = this.nextSubjectId >>> 0;
614
- this.nextSubjectId = this.nextSubjectId + 1 >>> 0;
615
- if (this.nextSubjectId === 0) this.nextSubjectId = 1;
616
- return id === 0 ? this.allocateSubjectId() : id;
617
- }
618
- }, _class2);
619
-
620
- // src/http/adaptiveLimiter/latencyWindow.ts
621
- var LatencyWindow = (_class3 = class {
622
-
623
- __init5() {this.sorted = []}
624
-
625
- __init6() {this.head = 0}
626
- __init7() {this.count = 0}
627
- constructor(size) {;_class3.prototype.__init5.call(this);_class3.prototype.__init6.call(this);_class3.prototype.__init7.call(this);
628
- this.size = Math.max(2, Math.floor(size));
629
- this.buffer = new Array(this.size);
630
- }
631
- /**
632
- * Record a latency sample. Discards non-positive, NaN, and Infinity values.
633
- * Evicts the oldest sample when the buffer is full.
634
- */
635
- record(latencyMs) {
636
- if (!Number.isFinite(latencyMs) || latencyMs <= 0) return;
637
- const evicted = this.buffer[this.head];
638
- if (evicted !== void 0 && this.count === this.size) {
639
- this.removeSorted(evicted);
640
- }
641
- this.buffer[this.head] = latencyMs;
642
- this.insertSorted(latencyMs);
643
- this.head = (this.head + 1) % this.size;
644
- if (this.count < this.size) this.count++;
645
- }
646
- /**
647
- * Returns the minimum latency in the current window, or undefined if empty.
648
- */
649
- min() {
650
- return this.sorted[0];
651
- }
652
- /**
653
- * Computes the percentile using the nearest-rank method.
654
- * Returns undefined if fewer than 2 samples are present.
655
- * @param p - Percentile value in [0, 100]
656
- */
657
- percentile(p) {
658
- if (this.count < 2) return void 0;
659
- const rank = Math.ceil(p / 100 * this.sorted.length);
660
- return this.sorted[Math.min(rank, this.sorted.length) - 1];
661
- }
662
- /**
663
- * Computes a percentile where newer samples receive exponentially higher
664
- * weight. A decay of 1 is identical to `percentile`; lower values adapt
665
- * faster to recent latency shifts.
666
- */
667
- weightedPercentile(p, decay) {
668
- if (this.count < 2) return void 0;
669
- if (!Number.isFinite(decay) || decay >= 1) return this.percentile(p);
670
- const samples = this.samples();
671
- const weighted = samples.map((value, index) => ({
672
- value,
673
- weight: Math.pow(decay, samples.length - 1 - index)
674
- }));
675
- weighted.sort((a, b) => a.value - b.value);
676
- const total = weighted.reduce((sum, sample) => sum + sample.weight, 0);
677
- const target = Math.max(0, Math.min(100, p)) / 100 * total;
678
- let cumulative = 0;
679
- for (const sample of weighted) {
680
- cumulative += sample.weight;
681
- if (cumulative >= target) return sample.value;
682
- }
683
- return _optionalChain([weighted, 'access', _16 => _16[weighted.length - 1], 'optionalAccess', _17 => _17.value]);
684
- }
685
- /** Number of samples currently in the window. */
686
- get length() {
687
- return this.count;
688
- }
689
- /** Maximum capacity of the window. */
690
- get capacity() {
691
- return this.size;
692
- }
693
- /** Returns a copy of the current samples (oldest to newest). */
694
- samples() {
695
- const result = new Array(this.count);
696
- for (let i = 0; i < this.count; i++) {
697
- const idx = (this.head - this.count + i + this.size) % this.size;
698
- result[i] = this.buffer[idx];
699
- }
700
- return result;
701
- }
702
- insertSorted(value) {
703
- const idx = this.lowerBound(value);
704
- this.sorted.splice(idx, 0, value);
705
- }
706
- removeSorted(value) {
707
- let idx = this.lowerBound(value);
708
- while (idx < this.sorted.length && this.sorted[idx] === value) {
709
- this.sorted.splice(idx, 1);
710
- return;
711
- }
712
- }
713
- lowerBound(value) {
714
- let lo = 0;
715
- let hi = this.sorted.length;
716
- while (lo < hi) {
717
- const mid = lo + hi >>> 1;
718
- if (this.sorted[mid] < value) lo = mid + 1;
719
- else hi = mid;
720
- }
721
- return lo;
722
- }
723
- }, _class3);
724
-
725
- // src/http/adaptiveLimiter/ema.ts
726
- var EmaComputer = (_class4 = class {
727
-
728
- __init8() {this.current = void 0}
729
- /**
730
- * @param alpha - Smoothing factor in (0, 1]. Higher values weight recent samples more.
731
- */
732
- constructor(alpha) {;_class4.prototype.__init8.call(this);
733
- this.alpha = alpha;
734
- }
735
- /**
736
- * Update the EMA with a new sample and return the new EMA value.
737
- * On the first sample, the EMA is initialized to that sample.
738
- */
739
- update(sample) {
740
- if (this.current === void 0) {
741
- this.current = sample;
742
- } else {
743
- this.current = this.alpha * sample + (1 - this.alpha) * this.current;
744
- }
745
- return this.current;
746
- }
747
- /** Returns the current EMA value, or undefined if no samples have been recorded. */
748
- get value() {
749
- return this.current;
750
- }
751
- /** Resets the EMA state. */
752
- reset() {
753
- this.current = void 0;
754
- }
755
- }, _class4);
756
-
757
- // src/http/adaptiveLimiter/gradient.ts
758
- function computeGradient(minLatency, currentLatency) {
759
- if (currentLatency <= 0) return 1;
760
- return minLatency / currentLatency;
761
- }
762
- function computeNewLimit(currentLimit, gradient, headroom, minBound, maxBound, options = {}) {
763
- const decreaseThreshold = _nullishCoalesce(options.decreaseThreshold, () => ( 1));
764
- const increaseThreshold = _nullishCoalesce(options.increaseThreshold, () => ( 1));
765
- const maxDecreaseRatio = _nullishCoalesce(options.maxDecreaseRatio, () => ( 1));
766
- let newLimit;
767
- if (gradient < decreaseThreshold) {
768
- const rawLimit = Math.floor(currentLimit * gradient);
769
- const maxDecrease = Math.max(1, Math.floor(currentLimit * maxDecreaseRatio));
770
- newLimit = Math.max(rawLimit, currentLimit - maxDecrease);
771
- } else if (gradient >= increaseThreshold) {
772
- newLimit = currentLimit + headroom;
773
- } else {
774
- newLimit = currentLimit;
775
- }
776
- return Math.max(minBound, Math.min(maxBound, newLimit));
777
- }
778
-
779
- // src/http/adaptiveLimiter/types.ts
780
- var adaptiveLimiterPresets = Object.freeze({
781
- conservative: Object.freeze({
782
- initialLimit: 8,
783
- minLimit: 2,
784
- maxLimit: 64,
785
- maxQueue: 256,
786
- queueTimeoutMs: 3e4,
787
- smoothingFactor: 0.3,
788
- probeInterval: 40,
789
- probeJitterRatio: 0.2,
790
- windowSize: 100,
791
- minSamples: 80,
792
- baselineStrategy: "p5",
793
- windowDecayFactor: 0.99,
794
- errorWeight: 0.2,
795
- decreaseThreshold: 0.65,
796
- maxDecreaseRatio: 0.08,
797
- headroomStrategy: "fixed",
798
- queueStrategy: "priority",
799
- queueLoadShedding: "priority-evict",
800
- rejectionBackoffThreshold: 2,
801
- rejectionBackoffMs: 150,
802
- percentile: "p50"
803
- }),
804
- balanced: Object.freeze({
805
- initialLimit: 16,
806
- minLimit: 4,
807
- maxLimit: 128,
808
- maxQueue: 512,
809
- queueTimeoutMs: 3e4,
810
- smoothingFactor: 0.35,
811
- probeInterval: 25,
812
- probeJitterRatio: 0.2,
813
- windowSize: 100,
814
- minSamples: 50,
815
- baselineStrategy: "p5",
816
- windowDecayFactor: 0.98,
817
- errorWeight: 0.25,
818
- decreaseThreshold: 0.5,
819
- maxDecreaseRatio: 0.1,
820
- headroomStrategy: { type: "proportional", ratio: 0.05 },
821
- queueStrategy: "priority",
822
- queueLoadShedding: "priority-evict",
823
- rejectionBackoffThreshold: 3,
824
- rejectionBackoffMs: 100,
825
- percentile: "p50"
826
- }),
827
- aggressive: Object.freeze({
828
- initialLimit: 32,
829
- minLimit: 8,
830
- maxLimit: 256,
831
- maxQueue: 1024,
832
- queueTimeoutMs: 3e4,
833
- smoothingFactor: 0.35,
834
- probeInterval: 20,
835
- probeJitterRatio: 0.2,
836
- windowSize: 160,
837
- minSamples: 100,
838
- baselineStrategy: "p5",
839
- windowDecayFactor: 0.98,
840
- errorWeight: 0.25,
841
- decreaseThreshold: 0.5,
842
- maxDecreaseRatio: 0.1,
843
- headroomStrategy: { type: "proportional", ratio: 0.05 },
844
- queueStrategy: "priority",
845
- queueLoadShedding: "priority-evict",
846
- rejectionBackoffThreshold: 3,
847
- rejectionBackoffMs: 100,
848
- percentile: "p50"
849
- })
850
- });
851
- function makeAdaptiveLimiterConfig(preset, overrides = {}) {
852
- return {
853
- ...adaptiveLimiterPresets[preset],
854
- ...overrides,
855
- preset
856
- };
857
- }
858
- function validateConfig(config) {
859
- if (config.preset !== void 0 && config.preset !== "conservative" && config.preset !== "balanced" && config.preset !== "aggressive") {
860
- throw new Error(
861
- `AdaptiveLimiter: preset must be "conservative", "balanced", or "aggressive", got ${config.preset}`
862
- );
863
- }
864
- if (config.smoothingFactor !== void 0) {
865
- if (config.smoothingFactor <= 0 || config.smoothingFactor > 1) {
866
- throw new Error(
867
- `AdaptiveLimiter: smoothingFactor must be in (0, 1], got ${config.smoothingFactor}`
868
- );
869
- }
870
- }
871
- if (config.windowSize !== void 0) {
872
- if (config.windowSize < 2) {
873
- throw new Error(
874
- `AdaptiveLimiter: windowSize must be >= 2, got ${config.windowSize}`
875
- );
876
- }
877
- }
878
- if (config.probeInterval !== void 0) {
879
- if (config.probeInterval < 1) {
880
- throw new Error(
881
- `AdaptiveLimiter: probeInterval must be >= 1, got ${config.probeInterval}`
882
- );
883
- }
884
- }
885
- if (config.probeJitterRatio !== void 0) {
886
- if (config.probeJitterRatio < 0 || config.probeJitterRatio > 1) {
887
- throw new Error(
888
- `AdaptiveLimiter: probeJitterRatio must be in [0, 1], got ${config.probeJitterRatio}`
889
- );
890
- }
891
- }
892
- if (config.minSamples !== void 0 && config.minSamples < 1) {
893
- throw new Error(
894
- `AdaptiveLimiter: minSamples must be >= 1, got ${config.minSamples}`
895
- );
896
- }
897
- if (config.baselineStrategy !== void 0 && config.baselineStrategy !== "min" && config.baselineStrategy !== "p5" && config.baselineStrategy !== "ema-low") {
898
- throw new Error(
899
- `AdaptiveLimiter: baselineStrategy must be "min", "p5", or "ema-low", got ${config.baselineStrategy}`
900
- );
901
- }
902
- if (config.decreaseCooldownSamples !== void 0 && (!Number.isFinite(config.decreaseCooldownSamples) || config.decreaseCooldownSamples < 0)) {
903
- throw new Error(
904
- `AdaptiveLimiter: decreaseCooldownSamples must be >= 0, got ${config.decreaseCooldownSamples}`
905
- );
906
- }
907
- if (config.historySize !== void 0 && (!Number.isFinite(config.historySize) || config.historySize < 0)) {
908
- throw new Error(
909
- `AdaptiveLimiter: historySize must be >= 0, got ${config.historySize}`
910
- );
911
- }
912
- if (config.windowDecayFactor !== void 0) {
913
- if (!Number.isFinite(config.windowDecayFactor) || config.windowDecayFactor <= 0 || config.windowDecayFactor > 1) {
914
- throw new Error(
915
- `AdaptiveLimiter: windowDecayFactor must be in (0, 1], got ${config.windowDecayFactor}`
916
- );
917
- }
918
- }
919
- if (config.errorWeight !== void 0) {
920
- if (!Number.isFinite(config.errorWeight) || config.errorWeight < 0 || config.errorWeight > 1) {
921
- throw new Error(
922
- `AdaptiveLimiter: errorWeight must be in [0, 1], got ${config.errorWeight}`
923
- );
924
- }
925
- }
926
- if (config.errorSmoothingFactor !== void 0) {
927
- if (!Number.isFinite(config.errorSmoothingFactor) || config.errorSmoothingFactor <= 0 || config.errorSmoothingFactor > 1) {
928
- throw new Error(
929
- `AdaptiveLimiter: errorSmoothingFactor must be in (0, 1], got ${config.errorSmoothingFactor}`
930
- );
931
- }
932
- }
933
- if (config.errorStatusThreshold !== void 0) {
934
- if (!Number.isFinite(config.errorStatusThreshold) || config.errorStatusThreshold < 100 || config.errorStatusThreshold > 599) {
935
- throw new Error(
936
- `AdaptiveLimiter: errorStatusThreshold must be in [100, 599], got ${config.errorStatusThreshold}`
937
- );
938
- }
939
- }
940
- if (config.queueStrategy !== void 0 && config.queueStrategy !== "fifo" && config.queueStrategy !== "priority") {
941
- throw new Error(
942
- `AdaptiveLimiter: queueStrategy must be "fifo" or "priority", got ${config.queueStrategy}`
943
- );
944
- }
945
- if (config.queueLoadShedding !== void 0 && config.queueLoadShedding !== "reject-new" && config.queueLoadShedding !== "priority-evict") {
946
- throw new Error(
947
- `AdaptiveLimiter: queueLoadShedding must be "reject-new" or "priority-evict", got ${config.queueLoadShedding}`
948
- );
949
- }
950
- if (config.rejectionBackoffThreshold !== void 0 && (!Number.isFinite(config.rejectionBackoffThreshold) || config.rejectionBackoffThreshold < 1)) {
951
- throw new Error(
952
- `AdaptiveLimiter: rejectionBackoffThreshold must be >= 1, got ${config.rejectionBackoffThreshold}`
953
- );
954
- }
955
- if (config.rejectionBackoffMs !== void 0 && (!Number.isFinite(config.rejectionBackoffMs) || config.rejectionBackoffMs < 1)) {
956
- throw new Error(
957
- `AdaptiveLimiter: rejectionBackoffMs must be >= 1, got ${config.rejectionBackoffMs}`
958
- );
959
- }
960
- if (config.stateTtlMs !== void 0 && config.stateTtlMs !== false) {
961
- if (config.stateTtlMs < 1) {
962
- throw new Error(
963
- `AdaptiveLimiter: stateTtlMs must be >= 1ms or false, got ${config.stateTtlMs}`
964
- );
965
- }
966
- }
967
- if (config.warmupRequests !== void 0 && config.warmupRequests < 0) {
968
- throw new Error(
969
- `AdaptiveLimiter: warmupRequests must be >= 0, got ${config.warmupRequests}`
970
- );
971
- }
972
- if (config.decreaseThreshold !== void 0) {
973
- if (config.decreaseThreshold <= 0 || config.decreaseThreshold > 1) {
974
- throw new Error(
975
- `AdaptiveLimiter: decreaseThreshold must be in (0, 1], got ${config.decreaseThreshold}`
976
- );
977
- }
978
- }
979
- if (config.increaseThreshold !== void 0 && config.increaseThreshold < 1) {
980
- throw new Error(
981
- `AdaptiveLimiter: increaseThreshold must be >= 1, got ${config.increaseThreshold}`
982
- );
983
- }
984
- if (config.maxDecreaseRatio !== void 0) {
985
- if (config.maxDecreaseRatio <= 0 || config.maxDecreaseRatio > 1) {
986
- throw new Error(
987
- `AdaptiveLimiter: maxDecreaseRatio must be in (0, 1], got ${config.maxDecreaseRatio}`
988
- );
989
- }
990
- }
991
- if (config.initialLimit !== void 0 && config.initialLimit < 1) {
992
- throw new Error(
993
- `AdaptiveLimiter: initialLimit must be >= 1, got ${config.initialLimit}`
994
- );
995
- }
996
- if (config.minLimit !== void 0 && config.minLimit < 1) {
997
- throw new Error(
998
- `AdaptiveLimiter: minLimit must be >= 1, got ${config.minLimit}`
999
- );
1000
- }
1001
- if (config.maxLimit !== void 0 && config.maxLimit < 1) {
1002
- throw new Error(
1003
- `AdaptiveLimiter: maxLimit must be >= 1, got ${config.maxLimit}`
1004
- );
1005
- }
1006
- validateHeadroomStrategy(config.headroomStrategy);
1007
- if (config.slowStartSaturationThreshold !== void 0) {
1008
- if (config.slowStartSaturationThreshold <= 0 || config.slowStartSaturationThreshold > 1) {
1009
- throw new Error(
1010
- `AdaptiveLimiter: slowStartSaturationThreshold must be in (0, 1], got ${config.slowStartSaturationThreshold}`
1011
- );
1012
- }
1013
- }
1014
- if (config.slowStartSaturationSamples !== void 0 && config.slowStartSaturationSamples < 1) {
1015
- throw new Error(
1016
- `AdaptiveLimiter: slowStartSaturationSamples must be >= 1, got ${config.slowStartSaturationSamples}`
1017
- );
1018
- }
1019
- }
1020
- function validatePositiveNumber(name, value) {
1021
- if (value !== void 0 && (!Number.isFinite(value) || value <= 0)) {
1022
- throw new Error(`AdaptiveLimiter: ${name} must be > 0, got ${value}`);
1023
- }
1024
- }
1025
- function validateHeadroomStrategy(strategy) {
1026
- if (strategy === void 0) return;
1027
- if (typeof strategy === "function") return;
1028
- if (typeof strategy === "number") {
1029
- validatePositiveNumber("headroomStrategy", strategy);
1030
- return;
1031
- }
1032
- if (strategy === "fixed" || strategy === "proportional") return;
1033
- if (typeof strategy !== "object" || strategy === null) {
1034
- throw new Error("AdaptiveLimiter: headroomStrategy must be a number, function, 'fixed', 'proportional', or strategy object");
1035
- }
1036
- if (strategy.type === "fixed") {
1037
- validatePositiveNumber("headroomStrategy.value", strategy.value);
1038
- return;
1039
- }
1040
- if (strategy.type === "proportional") {
1041
- validatePositiveNumber("headroomStrategy.ratio", strategy.ratio);
1042
- validatePositiveNumber("headroomStrategy.min", strategy.min);
1043
- validatePositiveNumber("headroomStrategy.max", strategy.max);
1044
- return;
1045
- }
1046
- throw new Error("AdaptiveLimiter: headroomStrategy.type must be 'fixed' or 'proportional'");
1047
- }
1048
- var DEFAULTS = {
1049
- preset: void 0,
1050
- initialLimit: 10,
1051
- minLimit: 1,
1052
- maxLimit: 200,
1053
- smoothingFactor: 0.5,
1054
- probeInterval: 10,
1055
- probeJitterRatio: 0.2,
1056
- windowSize: 100,
1057
- minSamples: 10,
1058
- baselineStrategy: "min",
1059
- decreaseCooldownSamples: 0,
1060
- historySize: 32,
1061
- windowDecayFactor: 1,
1062
- errorWeight: 0,
1063
- errorSmoothingFactor: 0.5,
1064
- errorStatusThreshold: 500,
1065
- queueStrategy: "fifo",
1066
- queueLoadShedding: "reject-new",
1067
- rejectionBackoffThreshold: 3,
1068
- rejectionBackoffMs: void 0,
1069
- stateTtlMs: 3e5,
1070
- warmupRequests: 0,
1071
- decreaseThreshold: 0.75,
1072
- increaseThreshold: 1,
1073
- maxDecreaseRatio: 0.2,
1074
- headroomStrategy: 1,
1075
- slowStartRecovery: true,
1076
- slowStartSaturationThreshold: 0.5,
1077
- slowStartSaturationSamples: 3,
1078
- key: "origin",
1079
- maxQueue: 256,
1080
- queueTimeoutMs: void 0,
1081
- onLimitChange: void 0,
1082
- percentile: "p50"
1083
- };
1084
- function resolveConfig(config) {
1085
- if (!config) return DEFAULTS;
1086
- validateConfig(config);
1087
- const effectiveConfig = config.preset === void 0 ? config : { ...adaptiveLimiterPresets[config.preset], ...config };
1088
- let minLimit = _nullishCoalesce(effectiveConfig.minLimit, () => ( DEFAULTS.minLimit));
1089
- let maxLimit = _nullishCoalesce(effectiveConfig.maxLimit, () => ( DEFAULTS.maxLimit));
1090
- if (minLimit > maxLimit) {
1091
- maxLimit = minLimit;
1092
- }
1093
- let initialLimit = _nullishCoalesce(effectiveConfig.initialLimit, () => ( DEFAULTS.initialLimit));
1094
- initialLimit = Math.max(minLimit, Math.min(maxLimit, initialLimit));
1095
- const windowSize = Math.floor(_nullishCoalesce(effectiveConfig.windowSize, () => ( DEFAULTS.windowSize)));
1096
- const minSamples = Math.max(1, Math.min(Math.floor(_nullishCoalesce(effectiveConfig.minSamples, () => ( DEFAULTS.minSamples))), windowSize));
1097
- const decreaseCooldownSamples = Math.floor(_nullishCoalesce(effectiveConfig.decreaseCooldownSamples, () => ( DEFAULTS.decreaseCooldownSamples)));
1098
- const historySize = Math.floor(_nullishCoalesce(effectiveConfig.historySize, () => ( DEFAULTS.historySize)));
1099
- const errorSmoothingFactor = _nullishCoalesce(_nullishCoalesce(effectiveConfig.errorSmoothingFactor, () => ( effectiveConfig.smoothingFactor)), () => ( DEFAULTS.smoothingFactor));
1100
- const stateTtlMs = effectiveConfig.stateTtlMs === false ? void 0 : Math.floor(_nullishCoalesce(effectiveConfig.stateTtlMs, () => ( DEFAULTS.stateTtlMs)));
1101
- return {
1102
- preset: effectiveConfig.preset,
1103
- initialLimit,
1104
- minLimit,
1105
- maxLimit,
1106
- smoothingFactor: _nullishCoalesce(effectiveConfig.smoothingFactor, () => ( DEFAULTS.smoothingFactor)),
1107
- probeInterval: Math.floor(_nullishCoalesce(effectiveConfig.probeInterval, () => ( DEFAULTS.probeInterval))),
1108
- probeJitterRatio: _nullishCoalesce(effectiveConfig.probeJitterRatio, () => ( DEFAULTS.probeJitterRatio)),
1109
- windowSize,
1110
- minSamples,
1111
- baselineStrategy: _nullishCoalesce(effectiveConfig.baselineStrategy, () => ( DEFAULTS.baselineStrategy)),
1112
- decreaseCooldownSamples,
1113
- historySize,
1114
- windowDecayFactor: _nullishCoalesce(effectiveConfig.windowDecayFactor, () => ( DEFAULTS.windowDecayFactor)),
1115
- errorWeight: _nullishCoalesce(effectiveConfig.errorWeight, () => ( DEFAULTS.errorWeight)),
1116
- errorSmoothingFactor,
1117
- errorStatusThreshold: Math.floor(_nullishCoalesce(effectiveConfig.errorStatusThreshold, () => ( DEFAULTS.errorStatusThreshold))),
1118
- queueStrategy: _nullishCoalesce(effectiveConfig.queueStrategy, () => ( DEFAULTS.queueStrategy)),
1119
- queueLoadShedding: _nullishCoalesce(effectiveConfig.queueLoadShedding, () => ( DEFAULTS.queueLoadShedding)),
1120
- rejectionBackoffThreshold: Math.floor(_nullishCoalesce(effectiveConfig.rejectionBackoffThreshold, () => ( DEFAULTS.rejectionBackoffThreshold))),
1121
- rejectionBackoffMs: effectiveConfig.rejectionBackoffMs === void 0 ? DEFAULTS.rejectionBackoffMs : Math.floor(effectiveConfig.rejectionBackoffMs),
1122
- stateTtlMs,
1123
- warmupRequests: Math.floor(_nullishCoalesce(effectiveConfig.warmupRequests, () => ( DEFAULTS.warmupRequests))),
1124
- decreaseThreshold: _nullishCoalesce(effectiveConfig.decreaseThreshold, () => ( DEFAULTS.decreaseThreshold)),
1125
- increaseThreshold: _nullishCoalesce(effectiveConfig.increaseThreshold, () => ( DEFAULTS.increaseThreshold)),
1126
- maxDecreaseRatio: _nullishCoalesce(effectiveConfig.maxDecreaseRatio, () => ( DEFAULTS.maxDecreaseRatio)),
1127
- headroomStrategy: _nullishCoalesce(effectiveConfig.headroomStrategy, () => ( DEFAULTS.headroomStrategy)),
1128
- slowStartRecovery: _nullishCoalesce(effectiveConfig.slowStartRecovery, () => ( DEFAULTS.slowStartRecovery)),
1129
- slowStartSaturationThreshold: _nullishCoalesce(effectiveConfig.slowStartSaturationThreshold, () => ( DEFAULTS.slowStartSaturationThreshold)),
1130
- slowStartSaturationSamples: Math.floor(_nullishCoalesce(effectiveConfig.slowStartSaturationSamples, () => ( DEFAULTS.slowStartSaturationSamples))),
1131
- key: _nullishCoalesce(effectiveConfig.key, () => ( DEFAULTS.key)),
1132
- maxQueue: _nullishCoalesce(effectiveConfig.maxQueue, () => ( DEFAULTS.maxQueue)),
1133
- queueTimeoutMs: effectiveConfig.queueTimeoutMs,
1134
- onLimitChange: effectiveConfig.onLimitChange,
1135
- percentile: _nullishCoalesce(effectiveConfig.percentile, () => ( DEFAULTS.percentile))
1136
- };
1137
- }
1138
-
1139
- // src/http/adaptiveLimiter/adaptiveLimiter.ts
1140
- var monotonicNow = () => {
1141
- const perf = globalThis.performance;
1142
- if (perf && typeof perf.now === "function") return perf.now();
1143
- return Date.now();
1144
- };
1145
- var wallNow = () => Date.now();
1146
- var DEFAULT_PRIORITY = 5;
1147
- var clampPriority = (value) => {
1148
- if (value === void 0 || !Number.isFinite(value)) return DEFAULT_PRIORITY;
1149
- return Math.max(0, Math.min(9, Math.floor(value)));
1150
- };
1151
- var poolTimeoutError = (key, timeoutMs) => ({
1152
- _tag: "PoolTimeout",
1153
- key,
1154
- timeoutMs,
1155
- message: `Adaptive limiter '${key}' did not grant a slot within ${timeoutMs}ms`
1156
- });
1157
- var poolRejectedError2 = (key, limit, retryAfterMs2) => ({
1158
- _tag: "PoolRejected",
1159
- key,
1160
- limit,
1161
- message: `Adaptive limiter '${key}' queue is full (max ${limit})`,
1162
- ...retryAfterMs2 === void 0 ? {} : { retryAfterMs: retryAfterMs2 }
1163
- });
1164
- var abortError2 = () => ({ _tag: "Abort" });
1165
- var poolClosedError = (key) => ({
1166
- _tag: "PoolClosed",
1167
- key,
1168
- message: `Adaptive limiter '${key}' has been destroyed`
1169
- });
1170
- var AdaptiveLimiter = (_class5 = class {
1171
-
1172
- __init9() {this.states = /* @__PURE__ */ new Map()}
1173
- __init10() {this.destroyed = false}
1174
- constructor(config) {;_class5.prototype.__init9.call(this);_class5.prototype.__init10.call(this);
1175
- this.config = resolveConfig(config);
1176
- }
1177
- /** Key resolver for external use by the HTTP client. */
1178
- get keyResolver() {
1179
- return this.config.key;
1180
- }
1181
- /**
1182
- * Acquire a concurrency slot for the given key.
1183
- * Resolves immediately if under the limit, otherwise queues the request.
1184
- * Rejects with PoolRejected if the queue is full, or PoolTimeout if the queue timeout expires.
1185
- */
1186
- acquire(key, signal, options) {
1187
- if (this.destroyed) return Promise.reject(poolClosedError(key));
1188
- const state = this.getOrCreateState(key);
1189
- this.touch(state);
1190
- const priority = clampPriority(_optionalChain([options, 'optionalAccess', _18 => _18.priority]));
1191
- if (signal.aborted) {
1192
- this.scheduleIdleEviction(state);
1193
- return Promise.reject(abortError2());
1194
- }
1195
- if (state.inFlight < state.limit) {
1196
- state.inFlight++;
1197
- state.acquired++;
1198
- state.rejectionStreak = 0;
1199
- return Promise.resolve(this.makeLease(state));
1200
- }
1201
- if (state.queue.length >= this.config.maxQueue) {
1202
- const evicted = this.tryEvictLowerPriorityWaiter(state, priority);
1203
- if (!evicted) {
1204
- state.rejected++;
1205
- state.rejectionStreak++;
1206
- this.scheduleIdleEviction(state);
1207
- return Promise.reject(poolRejectedError2(key, this.config.maxQueue, this.suggestedBackoffMs(state)));
1208
- }
1209
- }
1210
- return new Promise((resolve, reject) => {
1211
- const waiter = {
1212
- signal,
1213
- resolve,
1214
- reject,
1215
- priority,
1216
- arrivalOrder: state.queueSequence++
1217
- };
1218
- const removeWaiter = () => this.removeWaiter(state, waiter);
1219
- const cleanup = () => this.cleanupWaiter(waiter);
1220
- waiter.abort = () => {
1221
- cleanup();
1222
- removeWaiter();
1223
- this.touch(state);
1224
- state.abortedWhileQueued++;
1225
- this.scheduleIdleEviction(state);
1226
- reject(abortError2());
1227
- };
1228
- signal.addEventListener("abort", waiter.abort, { once: true });
1229
- if (this.config.queueTimeoutMs !== void 0 && this.config.queueTimeoutMs > 0) {
1230
- waiter.timer = setTimeout(() => {
1231
- cleanup();
1232
- removeWaiter();
1233
- this.touch(state);
1234
- state.queueTimeouts++;
1235
- this.scheduleIdleEviction(state);
1236
- reject(poolTimeoutError(key, this.config.queueTimeoutMs));
1237
- }, this.config.queueTimeoutMs);
1238
- }
1239
- this.enqueueWaiter(state, waiter);
1240
- });
1241
- }
1242
- /**
1243
- * Get stats for a specific key, or aggregate stats if no key is provided.
1244
- */
1245
- stats(key) {
1246
- this.evictIdleStates();
1247
- if (key !== void 0) {
1248
- const state = this.states.get(key);
1249
- if (!state) {
1250
- return {
1251
- limit: this.config.initialLimit,
1252
- inFlight: 0,
1253
- queueDepth: 0,
1254
- gradient: void 0,
1255
- latencyGradient: void 0,
1256
- errorRate: void 0,
1257
- smoothedLatency: void 0,
1258
- minLatency: void 0,
1259
- baselineLatency: void 0,
1260
- p5: void 0,
1261
- p50: void 0,
1262
- p99: void 0,
1263
- probeCount: 0,
1264
- windowSize: 0,
1265
- warmupCompletions: 0,
1266
- slowStart: false,
1267
- cooldownSamplesRemaining: 0,
1268
- utilization: 0,
1269
- requestsPerSecond: 0,
1270
- completionsPerSecond: 0,
1271
- rejectionRate: 0,
1272
- suggestedBackoffMs: void 0
1273
- };
1274
- }
1275
- return this.stateToStats(state);
1276
- }
1277
- if (this.states.size === 0) {
1278
- return {
1279
- limit: this.config.initialLimit,
1280
- inFlight: 0,
1281
- queueDepth: 0,
1282
- gradient: void 0,
1283
- latencyGradient: void 0,
1284
- errorRate: void 0,
1285
- smoothedLatency: void 0,
1286
- minLatency: void 0,
1287
- baselineLatency: void 0,
1288
- p5: void 0,
1289
- p50: void 0,
1290
- p99: void 0,
1291
- probeCount: 0,
1292
- windowSize: 0,
1293
- warmupCompletions: 0,
1294
- slowStart: false,
1295
- cooldownSamplesRemaining: 0,
1296
- utilization: 0,
1297
- requestsPerSecond: 0,
1298
- completionsPerSecond: 0,
1299
- rejectionRate: 0,
1300
- suggestedBackoffMs: void 0,
1301
- stateCount: 0,
1302
- keys: []
1303
- };
1304
- }
1305
- if (this.states.size === 1) {
1306
- const [state] = this.states.values();
1307
- return {
1308
- ...this.stateToStats(state),
1309
- keys: [state.key]
1310
- };
1311
- }
1312
- let totalLimit = 0;
1313
- let totalInFlight = 0;
1314
- let totalQueueDepth = 0;
1315
- let totalProbeCount = 0;
1316
- let totalWindowSize = 0;
1317
- let totalRequestsPerSecond = 0;
1318
- let totalCompletionsPerSecond = 0;
1319
- let totalRejected = 0;
1320
- let totalAttempts = 0;
1321
- const keys = [];
1322
- let firstState;
1323
- const now = monotonicNow();
1324
- for (const state of this.states.values()) {
1325
- keys.push(state.key);
1326
- totalLimit += state.limit;
1327
- totalInFlight += state.inFlight;
1328
- totalQueueDepth += state.queue.length;
1329
- totalProbeCount += state.probeCount;
1330
- totalWindowSize += state.window.length;
1331
- const stats = this.stateToStats(state, now);
1332
- totalRequestsPerSecond += _nullishCoalesce(stats.requestsPerSecond, () => ( 0));
1333
- totalCompletionsPerSecond += _nullishCoalesce(stats.completionsPerSecond, () => ( 0));
1334
- totalRejected += state.rejected;
1335
- totalAttempts += state.acquired + state.rejected + state.queueTimeouts + state.abortedWhileQueued;
1336
- if (!firstState) firstState = state;
1337
- }
1338
- const minLatency = _optionalChain([firstState, 'optionalAccess', _19 => _19.window, 'access', _20 => _20.min, 'call', _21 => _21()]);
1339
- return {
1340
- limit: totalLimit,
1341
- inFlight: totalInFlight,
1342
- queueDepth: totalQueueDepth,
1343
- gradient: _optionalChain([firstState, 'optionalAccess', _22 => _22.lastGradient]),
1344
- latencyGradient: _optionalChain([firstState, 'optionalAccess', _23 => _23.lastLatencyGradient]),
1345
- errorRate: _optionalChain([firstState, 'optionalAccess', _24 => _24.errorEma, 'access', _25 => _25.value]),
1346
- smoothedLatency: _optionalChain([firstState, 'optionalAccess', _26 => _26.ema, 'access', _27 => _27.value]),
1347
- minLatency,
1348
- baselineLatency: minLatency === void 0 || firstState === void 0 ? void 0 : this.baselineLatency(firstState, minLatency),
1349
- p5: firstState === void 0 ? void 0 : this.windowPercentile(firstState, 5),
1350
- p50: firstState === void 0 ? void 0 : this.windowPercentile(firstState, 50),
1351
- p99: firstState === void 0 ? void 0 : this.windowPercentile(firstState, 99),
1352
- probeCount: totalProbeCount,
1353
- windowSize: totalWindowSize,
1354
- warmupCompletions: _nullishCoalesce(_optionalChain([firstState, 'optionalAccess', _28 => _28.warmupCompletions]), () => ( 0)),
1355
- slowStart: _nullishCoalesce(_optionalChain([firstState, 'optionalAccess', _29 => _29.slowStartActive]), () => ( false)),
1356
- cooldownSamplesRemaining: _nullishCoalesce(_optionalChain([firstState, 'optionalAccess', _30 => _30.decreaseCooldownRemaining]), () => ( 0)),
1357
- utilization: totalLimit > 0 ? totalInFlight / totalLimit : 0,
1358
- requestsPerSecond: totalRequestsPerSecond,
1359
- completionsPerSecond: totalCompletionsPerSecond,
1360
- rejectionRate: totalAttempts > 0 ? totalRejected / totalAttempts : 0,
1361
- suggestedBackoffMs: firstState === void 0 ? void 0 : this.suggestedBackoffMs(firstState),
1362
- stateCount: this.states.size,
1363
- keys
1364
- };
1365
- }
1366
- /** Return the currently retained per-key state identifiers. */
1367
- keys() {
1368
- this.evictIdleStates();
1369
- return [...this.states.keys()];
1370
- }
1371
- /** Return a diagnostic snapshot for one retained key, if present. */
1372
- snapshot(key) {
1373
- this.evictIdleStates();
1374
- const state = this.states.get(key);
1375
- return state ? this.stateToKeySnapshot(state) : void 0;
1376
- }
1377
- /** Return a full diagnostic dump across all retained keys. */
1378
- dump() {
1379
- this.evictIdleStates();
1380
- const keys = [...this.states.keys()];
1381
- return {
1382
- stateCount: this.states.size,
1383
- keys,
1384
- aggregate: this.stats(),
1385
- states: [...this.states.values()].map((state) => this.stateToKeySnapshot(state)),
1386
- history: this.history()
1387
- };
1388
- }
1389
- /** Return retained limit-change history for one key, or all keys if omitted. */
1390
- history(key) {
1391
- this.evictIdleStates();
1392
- if (key !== void 0) {
1393
- return [..._nullishCoalesce(_optionalChain([this, 'access', _31 => _31.states, 'access', _32 => _32.get, 'call', _33 => _33(key), 'optionalAccess', _34 => _34.history]), () => ( []))];
1394
- }
1395
- return [...this.states.values()].flatMap((state) => state.history).sort((a, b) => a.timestamp - b.timestamp);
1396
- }
1397
- /**
1398
- * Circuit-breaker feedback hook. When a circuit is already open for `key`,
1399
- * collapse that key's limit to minLimit immediately instead of waiting for
1400
- * latency gradients to discover the saturation indirectly.
1401
- */
1402
- markCircuitOpen(key) {
1403
- if (this.destroyed) return;
1404
- const state = this.getOrCreateState(key);
1405
- this.touch(state);
1406
- state.saturationStreak = this.config.slowStartSaturationSamples;
1407
- state.slowStartActive = this.config.slowStartRecovery;
1408
- state.slowStartRecoveryStarted = false;
1409
- state.slowStartHeadroom = Math.max(1, this.resolveHeadroom(state, 0, "circuit-open"));
1410
- const minLatency = _nullishCoalesce(state.window.min(), () => ( 0));
1411
- this.applyLimit(
1412
- state,
1413
- this.config.minLimit,
1414
- 0,
1415
- 0,
1416
- _nullishCoalesce(state.errorEma.value, () => ( 0)),
1417
- _nullishCoalesce(state.ema.value, () => ( 0)),
1418
- minLatency,
1419
- _nullishCoalesce(state.baselineEma.value, () => ( minLatency)),
1420
- "circuit-open"
1421
- );
1422
- this.scheduleIdleEviction(state);
1423
- }
1424
- /** Destroy the limiter, reject queued waiters, clear timers, and drop state. */
1425
- destroy() {
1426
- if (this.destroyed) return;
1427
- this.destroyed = true;
1428
- for (const state of this.states.values()) {
1429
- this.clearIdleTimer(state);
1430
- for (const waiter of state.queue.splice(0)) {
1431
- this.cleanupWaiter(waiter);
1432
- waiter.reject(poolClosedError(state.key));
1433
- }
1434
- state.inFlight = 0;
1435
- }
1436
- this.states.clear();
1437
- }
1438
- /** Alias for destroy(), useful for graceful shutdown code paths. */
1439
- shutdown() {
1440
- this.destroy();
1441
- }
1442
- getOrCreateState(key) {
1443
- const existing = this.states.get(key);
1444
- if (existing) return existing;
1445
- const now = monotonicNow();
1446
- const timestamp = wallNow();
1447
- const state = {
1448
- key,
1449
- limit: this.config.initialLimit,
1450
- inFlight: 0,
1451
- window: new LatencyWindow(this.config.windowSize),
1452
- ema: new EmaComputer(this.config.smoothingFactor),
1453
- baselineEma: new EmaComputer(this.config.smoothingFactor),
1454
- errorEma: new EmaComputer(this.config.errorSmoothingFactor),
1455
- probeCount: 0,
1456
- queue: [],
1457
- lastGradient: void 0,
1458
- lastLatencyGradient: void 0,
1459
- acquired: 0,
1460
- released: 0,
1461
- rejected: 0,
1462
- queueTimeouts: 0,
1463
- abortedWhileQueued: 0,
1464
- evictedWhileQueued: 0,
1465
- rejectionStreak: 0,
1466
- queueSequence: 0,
1467
- createdAt: now,
1468
- createdTimestamp: timestamp,
1469
- lastActivityAt: now,
1470
- lastActivityTimestamp: timestamp,
1471
- nextProbeAt: this.nextProbeInterval(),
1472
- warmupCompletions: 0,
1473
- warmupDone: this.config.warmupRequests <= 0,
1474
- saturationStreak: 0,
1475
- slowStartActive: false,
1476
- slowStartRecoveryStarted: false,
1477
- slowStartHeadroom: 1,
1478
- decreaseCooldownRemaining: 0,
1479
- history: []
1480
- };
1481
- this.states.set(key, state);
1482
- this.scheduleIdleEviction(state);
1483
- return state;
1484
- }
1485
- makeLease(state) {
1486
- let released = false;
1487
- return {
1488
- key: state.key,
1489
- release: (latencyMs, info) => {
1490
- if (released) return;
1491
- released = true;
1492
- if (this.destroyed) return;
1493
- this.touch(state);
1494
- if (state.inFlight > 0) state.inFlight--;
1495
- state.released++;
1496
- this.recordAndAdjust(state, latencyMs, info);
1497
- this.drain(state);
1498
- this.scheduleIdleEviction(state);
1499
- }
1500
- };
1501
- }
1502
- recordAndAdjust(state, latencyMs, info) {
1503
- state.window.record(latencyMs);
1504
- state.errorEma.update(this.isErrorSignal(info) ? 1 : 0);
1505
- if (Number.isFinite(latencyMs) && latencyMs > 0) {
1506
- state.ema.update(latencyMs);
1507
- state.baselineEma.update(this.lowLatencySample(state, latencyMs));
1508
- }
1509
- const minLat = state.window.min();
1510
- const emaValue = state.ema.value;
1511
- if (minLat === void 0 || emaValue === void 0) return;
1512
- const currentLatency = this.currentLatency(state, emaValue);
1513
- if (currentLatency === void 0) return;
1514
- const baselineLatency = this.baselineLatency(state, minLat);
1515
- const latencyGradient = computeGradient(baselineLatency, currentLatency);
1516
- const gradient = this.combineGradientWithErrors(latencyGradient, _nullishCoalesce(state.errorEma.value, () => ( 0)));
1517
- state.lastGradient = gradient;
1518
- state.lastLatencyGradient = latencyGradient;
1519
- this.recordSaturation(state, gradient);
1520
- if (this.tryWarmup(
1521
- state,
1522
- gradient,
1523
- latencyGradient,
1524
- _nullishCoalesce(state.errorEma.value, () => ( 0)),
1525
- emaValue,
1526
- minLat,
1527
- baselineLatency
1528
- )) return;
1529
- if (state.window.length < this.config.minSamples) return;
1530
- const mode = state.slowStartActive && gradient >= this.config.increaseThreshold ? "slow-start" : "stable";
1531
- let headroom = this.resolveHeadroom(state, gradient, mode);
1532
- if (mode === "slow-start") {
1533
- headroom = Math.max(headroom, state.slowStartHeadroom);
1534
- }
1535
- const cooldownActive = state.decreaseCooldownRemaining > 0;
1536
- if (cooldownActive) state.decreaseCooldownRemaining--;
1537
- const wantsDecrease = gradient < this.config.decreaseThreshold;
1538
- const decreaseBlockedByCooldown = wantsDecrease && cooldownActive;
1539
- let newLimit = decreaseBlockedByCooldown ? state.limit : computeNewLimit(
1540
- state.limit,
1541
- gradient,
1542
- headroom,
1543
- this.config.minLimit,
1544
- this.config.maxLimit,
1545
- {
1546
- decreaseThreshold: this.config.decreaseThreshold,
1547
- increaseThreshold: this.config.increaseThreshold,
1548
- maxDecreaseRatio: this.config.maxDecreaseRatio
1549
- }
1550
- );
1551
- let reason = mode === "slow-start" ? "slow-start" : "gradient";
1552
- if (!decreaseBlockedByCooldown) state.probeCount++;
1553
- if (!decreaseBlockedByCooldown && state.probeCount >= state.nextProbeAt) {
1554
- const probeHeadroom = this.resolveHeadroom(state, gradient, "probe");
1555
- newLimit = Math.min(newLimit + probeHeadroom, this.config.maxLimit);
1556
- state.probeCount = 0;
1557
- state.nextProbeAt = this.nextProbeInterval();
1558
- reason = "probe";
1559
- }
1560
- const previousLimit = state.limit;
1561
- this.applyLimit(state, newLimit, gradient, latencyGradient, _nullishCoalesce(state.errorEma.value, () => ( 0)), emaValue, minLat, baselineLatency, reason);
1562
- if (state.limit < previousLimit) {
1563
- state.decreaseCooldownRemaining = this.config.decreaseCooldownSamples;
1564
- }
1565
- if (gradient < this.config.decreaseThreshold) {
1566
- if (state.slowStartRecoveryStarted) {
1567
- state.slowStartActive = false;
1568
- state.slowStartRecoveryStarted = false;
1569
- state.slowStartHeadroom = 1;
1570
- }
1571
- } else if (state.slowStartActive && gradient >= this.config.increaseThreshold && state.limit > previousLimit) {
1572
- state.slowStartRecoveryStarted = true;
1573
- state.slowStartHeadroom = Math.max(
1574
- 1,
1575
- Math.min(this.config.maxLimit, Math.ceil(headroom * 2))
1576
- );
1577
- }
1578
- }
1579
- tryWarmup(state, gradient, latencyGradient, errorRate, emaValue, minLat, baselineLatency) {
1580
- if (state.warmupDone) return false;
1581
- state.warmupCompletions++;
1582
- if (gradient < this.config.decreaseThreshold) {
1583
- state.warmupDone = true;
1584
- return false;
1585
- }
1586
- const progress = Math.min(state.warmupCompletions, this.config.warmupRequests) / this.config.warmupRequests;
1587
- const target = Math.ceil(
1588
- this.config.initialLimit + (this.config.maxLimit - this.config.initialLimit) * progress
1589
- );
1590
- const warmupHeadroom = this.resolveHeadroom(state, gradient, "warmup");
1591
- const newLimit = Math.max(
1592
- state.limit,
1593
- Math.min(this.config.maxLimit, Math.max(target, state.limit + warmupHeadroom))
1594
- );
1595
- if (state.warmupCompletions >= this.config.warmupRequests) {
1596
- state.warmupDone = true;
1597
- }
1598
- this.applyLimit(state, newLimit, gradient, latencyGradient, errorRate, emaValue, minLat, baselineLatency, "warmup");
1599
- return true;
1600
- }
1601
- baselineLatency(state, minLatency) {
1602
- if (this.config.baselineStrategy === "p5") {
1603
- return _nullishCoalesce(this.windowPercentile(state, 5), () => ( minLatency));
1604
- }
1605
- if (this.config.baselineStrategy === "ema-low") {
1606
- return _nullishCoalesce(_nullishCoalesce(state.baselineEma.value, () => ( this.windowPercentile(state, 5))), () => ( minLatency));
1607
- }
1608
- return minLatency;
1609
- }
1610
- lowLatencySample(state, fallback) {
1611
- return _nullishCoalesce(_nullishCoalesce(this.windowPercentile(state, 5), () => ( state.window.min())), () => ( fallback));
1612
- }
1613
- isErrorSignal(info) {
1614
- if (!info) return false;
1615
- if (info.error) return true;
1616
- return info.status !== void 0 && info.status >= this.config.errorStatusThreshold;
1617
- }
1618
- combineGradientWithErrors(latencyGradient, errorRate) {
1619
- if (this.config.errorWeight <= 0 || errorRate <= 0) return latencyGradient;
1620
- const errorGradient = 1 - Math.min(1, errorRate * this.config.errorWeight);
1621
- return Math.max(0, Math.min(latencyGradient, errorGradient));
1622
- }
1623
- windowPercentile(state, percentile) {
1624
- return this.config.windowDecayFactor < 1 ? state.window.weightedPercentile(percentile, this.config.windowDecayFactor) : state.window.percentile(percentile);
1625
- }
1626
- recordSaturation(state, gradient) {
1627
- if (!this.config.slowStartRecovery) return;
1628
- if (gradient <= this.config.slowStartSaturationThreshold) {
1629
- state.saturationStreak++;
1630
- if (state.saturationStreak >= this.config.slowStartSaturationSamples) {
1631
- state.slowStartActive = true;
1632
- state.slowStartRecoveryStarted = false;
1633
- state.slowStartHeadroom = Math.max(1, this.resolveHeadroom(state, gradient, "slow-start"));
1634
- }
1635
- return;
1636
- }
1637
- if (gradient >= this.config.increaseThreshold) {
1638
- state.saturationStreak = 0;
1639
- }
1640
- }
1641
- applyLimit(state, proposedLimit, gradient, latencyGradient, errorRate, smoothedLatency, minLatency, baselineLatency, reason) {
1642
- const newLimit = Math.max(this.config.minLimit, Math.min(this.config.maxLimit, Math.floor(proposedLimit)));
1643
- if (newLimit === state.limit) {
1644
- state.limit = newLimit;
1645
- return;
1646
- }
1647
- const previousLimit = state.limit;
1648
- state.limit = newLimit;
1649
- const event = {
1650
- key: state.key,
1651
- previousLimit,
1652
- newLimit,
1653
- gradient,
1654
- latencyGradient,
1655
- errorRate,
1656
- smoothedLatency,
1657
- minLatency,
1658
- baselineLatency,
1659
- p5: this.windowPercentile(state, 5),
1660
- timestamp: wallNow(),
1661
- reason
1662
- };
1663
- this.recordLimitChange(state, event);
1664
- if (this.config.onLimitChange) {
1665
- this.config.onLimitChange(event);
1666
- }
1667
- }
1668
- recordLimitChange(state, event) {
1669
- if (this.config.historySize <= 0) return;
1670
- state.history.push(event);
1671
- if (state.history.length > this.config.historySize) {
1672
- state.history.splice(0, state.history.length - this.config.historySize);
1673
- }
1674
- }
1675
- resolveHeadroom(state, gradient, mode) {
1676
- const strategy = this.config.headroomStrategy;
1677
- let value;
1678
- if (typeof strategy === "function") {
1679
- value = strategy({
1680
- key: state.key,
1681
- currentLimit: state.limit,
1682
- minLimit: this.config.minLimit,
1683
- maxLimit: this.config.maxLimit,
1684
- gradient,
1685
- mode
1686
- });
1687
- } else if (typeof strategy === "number") {
1688
- value = strategy;
1689
- } else if (strategy === "proportional") {
1690
- value = Math.ceil(state.limit * 0.05);
1691
- } else if (strategy === "fixed") {
1692
- value = 1;
1693
- } else if (strategy.type === "proportional") {
1694
- const ratio = _nullishCoalesce(strategy.ratio, () => ( 0.05));
1695
- const min = _nullishCoalesce(strategy.min, () => ( 1));
1696
- const max = _nullishCoalesce(strategy.max, () => ( Number.POSITIVE_INFINITY));
1697
- value = Math.max(min, Math.min(max, Math.ceil(state.limit * ratio)));
1698
- } else {
1699
- value = _nullishCoalesce(strategy.value, () => ( 1));
1700
- }
1701
- if (!Number.isFinite(value) || value <= 0) return 1;
1702
- return Math.max(1, Math.ceil(value));
1703
- }
1704
- nextProbeInterval() {
1705
- const base = this.config.probeInterval;
1706
- const jitter = this.config.probeJitterRatio;
1707
- if (jitter <= 0) return base;
1708
- const spread = base * jitter;
1709
- const min = Math.max(1, base - spread);
1710
- const max = base + spread;
1711
- return Math.max(1, Math.round(min + Math.random() * (max - min)));
1712
- }
1713
- enqueueWaiter(state, waiter) {
1714
- state.queue.push(waiter);
1715
- }
1716
- dequeueWaiter(state) {
1717
- if (state.queue.length === 0) return void 0;
1718
- if (this.config.queueStrategy === "fifo") return state.queue.shift();
1719
- let bestIdx = 0;
1720
- for (let i = 1; i < state.queue.length; i++) {
1721
- const candidate = state.queue[i];
1722
- const best = state.queue[bestIdx];
1723
- if (candidate.priority < best.priority || candidate.priority === best.priority && candidate.arrivalOrder < best.arrivalOrder) {
1724
- bestIdx = i;
1725
- }
1726
- }
1727
- return state.queue.splice(bestIdx, 1)[0];
1728
- }
1729
- tryEvictLowerPriorityWaiter(state, newPriority) {
1730
- if (this.config.queueLoadShedding !== "priority-evict" || state.queue.length === 0) {
1731
- return false;
1732
- }
1733
- let evictIdx = -1;
1734
- for (let i = 0; i < state.queue.length; i++) {
1735
- const candidate = state.queue[i];
1736
- if (candidate.priority <= newPriority) continue;
1737
- if (evictIdx < 0) {
1738
- evictIdx = i;
1739
- continue;
1740
- }
1741
- const current = state.queue[evictIdx];
1742
- if (candidate.priority > current.priority || candidate.priority === current.priority && candidate.arrivalOrder > current.arrivalOrder) {
1743
- evictIdx = i;
1744
- }
1745
- }
1746
- if (evictIdx < 0) return false;
1747
- const [evicted] = state.queue.splice(evictIdx, 1);
1748
- if (!evicted) return false;
1749
- this.cleanupWaiter(evicted);
1750
- state.evictedWhileQueued++;
1751
- state.rejected++;
1752
- state.rejectionStreak++;
1753
- evicted.reject(poolRejectedError2(state.key, this.config.maxQueue, this.suggestedBackoffMs(state)));
1754
- return true;
1755
- }
1756
- suggestedBackoffMs(state) {
1757
- if (this.config.rejectionBackoffMs === void 0) return void 0;
1758
- if (state.rejectionStreak < this.config.rejectionBackoffThreshold) return void 0;
1759
- const multiplier = Math.min(8, Math.max(1, state.rejectionStreak - this.config.rejectionBackoffThreshold + 1));
1760
- return this.config.rejectionBackoffMs * multiplier;
1761
- }
1762
- drain(state) {
1763
- while (state.inFlight < state.limit && state.queue.length > 0) {
1764
- const waiter = this.dequeueWaiter(state);
1765
- this.cleanupWaiter(waiter);
1766
- if (waiter.signal.aborted) {
1767
- this.touch(state);
1768
- state.abortedWhileQueued++;
1769
- waiter.reject(abortError2());
1770
- continue;
1771
- }
1772
- this.touch(state);
1773
- state.inFlight++;
1774
- state.acquired++;
1775
- state.rejectionStreak = 0;
1776
- waiter.resolve(this.makeLease(state));
1777
- }
1778
- }
1779
- currentLatency(state, emaValue) {
1780
- const percentileLatency = this.config.percentile === "p99" ? this.windowPercentile(state, 99) : this.windowPercentile(state, 50);
1781
- return _nullishCoalesce(percentileLatency, () => ( emaValue));
1782
- }
1783
- touch(state) {
1784
- state.lastActivityAt = monotonicNow();
1785
- state.lastActivityTimestamp = wallNow();
1786
- this.clearIdleTimer(state);
1787
- }
1788
- scheduleIdleEviction(state) {
1789
- if (this.destroyed || this.config.stateTtlMs === void 0) return;
1790
- this.clearIdleTimer(state);
1791
- if (state.inFlight > 0 || state.queue.length > 0) return;
1792
- const delay = Math.max(1, this.config.stateTtlMs - (monotonicNow() - state.lastActivityAt));
1793
- state.ttlTimer = setTimeout(() => {
1794
- state.ttlTimer = void 0;
1795
- this.evictIdleState(state, monotonicNow());
1796
- }, delay);
1797
- _optionalChain([state, 'access', _35 => _35.ttlTimer, 'optionalAccess', _36 => _36.unref, 'optionalCall', _37 => _37()]);
1798
- }
1799
- clearIdleTimer(state) {
1800
- if (state.ttlTimer !== void 0) {
1801
- clearTimeout(state.ttlTimer);
1802
- state.ttlTimer = void 0;
1803
- }
1804
- }
1805
- evictIdleStates() {
1806
- if (this.config.stateTtlMs === void 0) return;
1807
- const now = monotonicNow();
1808
- for (const state of Array.from(this.states.values())) {
1809
- this.evictIdleState(state, now);
1810
- }
1811
- }
1812
- evictIdleState(state, now) {
1813
- if (this.config.stateTtlMs === void 0) return;
1814
- if (state.inFlight > 0 || state.queue.length > 0) {
1815
- this.scheduleIdleEviction(state);
1816
- return;
1817
- }
1818
- if (now - state.lastActivityAt < this.config.stateTtlMs) {
1819
- this.scheduleIdleEviction(state);
1820
- return;
1821
- }
1822
- this.clearIdleTimer(state);
1823
- this.states.delete(state.key);
1824
- }
1825
- cleanupWaiter(waiter) {
1826
- if (waiter.timer !== void 0) {
1827
- clearTimeout(waiter.timer);
1828
- waiter.timer = void 0;
1829
- }
1830
- if (waiter.abort) {
1831
- waiter.signal.removeEventListener("abort", waiter.abort);
1832
- waiter.abort = void 0;
1833
- }
1834
- }
1835
- removeWaiter(state, waiter) {
1836
- const idx = state.queue.indexOf(waiter);
1837
- if (idx >= 0) state.queue.splice(idx, 1);
1838
- }
1839
- stateToStats(state, now = monotonicNow()) {
1840
- const minLatency = state.window.min();
1841
- const elapsedSeconds = Math.max((now - state.createdAt) / 1e3, 1e-3);
1842
- const attempts = state.acquired + state.rejected + state.queueTimeouts + state.abortedWhileQueued;
1843
- return {
1844
- limit: state.limit,
1845
- inFlight: state.inFlight,
1846
- queueDepth: state.queue.length,
1847
- gradient: state.lastGradient,
1848
- latencyGradient: state.lastLatencyGradient,
1849
- errorRate: state.errorEma.value,
1850
- smoothedLatency: state.ema.value,
1851
- minLatency,
1852
- baselineLatency: minLatency === void 0 ? void 0 : this.baselineLatency(state, minLatency),
1853
- p5: this.windowPercentile(state, 5),
1854
- p50: this.windowPercentile(state, 50),
1855
- p99: this.windowPercentile(state, 99),
1856
- probeCount: state.probeCount,
1857
- windowSize: state.window.length,
1858
- warmupCompletions: state.warmupCompletions,
1859
- slowStart: state.slowStartActive,
1860
- cooldownSamplesRemaining: state.decreaseCooldownRemaining,
1861
- utilization: state.limit > 0 ? state.inFlight / state.limit : 0,
1862
- requestsPerSecond: state.acquired / elapsedSeconds,
1863
- completionsPerSecond: state.released / elapsedSeconds,
1864
- rejectionRate: attempts > 0 ? state.rejected / attempts : 0,
1865
- suggestedBackoffMs: this.suggestedBackoffMs(state),
1866
- stateCount: this.states.size
1867
- };
1868
- }
1869
- stateToKeySnapshot(state) {
1870
- return {
1871
- ...this.stateToStats(state),
1872
- key: state.key,
1873
- createdAt: state.createdAt,
1874
- createdTimestamp: state.createdTimestamp,
1875
- lastActivityAt: state.lastActivityAt,
1876
- lastActivityTimestamp: state.lastActivityTimestamp,
1877
- nextProbeAt: state.nextProbeAt,
1878
- warmupDone: state.warmupDone,
1879
- saturationStreak: state.saturationStreak,
1880
- slowStartRecoveryStarted: state.slowStartRecoveryStarted,
1881
- history: [...state.history],
1882
- acquired: state.acquired,
1883
- released: state.released,
1884
- rejected: state.rejected,
1885
- queueTimeouts: state.queueTimeouts,
1886
- abortedWhileQueued: state.abortedWhileQueued,
1887
- evictedWhileQueued: state.evictedWhileQueued
1888
- };
1889
- }
1890
- }, _class5);
1891
-
1892
- // src/http/optics/lens.ts
1893
- var Lens = {
1894
- make(get, set) {
1895
- return { get, set };
1896
- },
1897
- over(ln, f) {
1898
- return (s) => ln.set(f(ln.get(s)))(s);
1899
- },
1900
- compose(ab, sa) {
1901
- return Lens.make(
1902
- (s) => ab.get(sa.get(s)),
1903
- (b) => (s) => sa.set(ab.set(b)(sa.get(s)))(s)
1904
- );
1905
- }
1906
- };
1907
-
1908
- // src/http/optics/request.ts
1909
- var Request = {
1910
- headers: Lens.make(
1911
- (req) => _nullishCoalesce(req.headers, () => ( {})),
1912
- (headers) => (req) => ({ ...req, headers })
1913
- )
1914
- };
1915
- var mergeHeaders = (extra) => (req) => Lens.over(Request.headers, (h) => ({ ...h, ...extra }))(req);
1916
- var mergeHeadersUnder = (under) => (req) => Lens.over(Request.headers, (h) => ({ ...under, ...h }))(req);
1917
- var setHeaderIfMissing = (k, v) => (req) => Lens.over(Request.headers, (h) => h[k] ? h : { ...h, [k]: v })(req);
1918
-
1919
- // src/http/transport.ts
1920
- var isTaggedHttpError = (error) => {
1921
- return _chunk3LOYJFRRcjs.isHttpError.call(void 0, error);
1922
- };
1923
- var isAbortError = (error) => _chunk3LOYJFRRcjs.isExternalAbortError.call(void 0, error);
1924
- var normalizeHttpError = (error, options) => _chunk3LOYJFRRcjs.toHttpError.call(void 0, error, options);
1925
- var headersOf = (response) => {
1926
- const headers = {};
1927
- response.headers.forEach((value, key) => {
1928
- headers[key] = value;
1929
- });
1930
- return headers;
1931
- };
1932
- function normalizeHttpHeaders(headers) {
1933
- if (!headers) return {};
1934
- if (typeof Headers !== "undefined" && headers instanceof Headers) {
1935
- const out = {};
1936
- headers.forEach((value, key) => {
1937
- out[key] = value;
1938
- });
1939
- return out;
1940
- }
1941
- if (Array.isArray(headers)) {
1942
- return headers.reduce((acc, item) => {
1943
- if (!Array.isArray(item) || item.length < 2) return acc;
1944
- const [key, value] = item;
1945
- if (key !== void 0 && value !== void 0 && value !== null) {
1946
- acc[String(key)] = Array.isArray(value) ? value.map(String).join(", ") : String(value);
1947
- }
1948
- return acc;
1949
- }, {});
1950
- }
1951
- if (typeof headers.toJSON === "function") {
1952
- return normalizeHttpHeaders(headers.toJSON());
1953
- }
1954
- if (typeof headers === "object") {
1955
- return Object.entries(headers).reduce((acc, [key, value]) => {
1956
- if (value !== void 0 && value !== null) {
1957
- acc[key] = Array.isArray(value) ? value.map(String).join(", ") : String(value);
1958
- }
1959
- return acc;
1960
- }, {});
1961
- }
1962
- return {};
1963
- }
1964
- var abortErrorForSignal = (signal) => {
1965
- const reason = signal.reason;
1966
- if (isTaggedHttpError(reason) && reason._tag === "Timeout") return reason;
1967
- return { _tag: "Abort" };
1968
- };
1969
- var linkAbortSignals = (...signals) => {
1970
- const activeSignals = signals.filter((signal) => signal !== void 0);
1971
- if (activeSignals.length === 0) {
1972
- const controller2 = new AbortController();
1973
- return { signal: controller2.signal, cleanup: () => void 0 };
1974
- }
1975
- const controller = new AbortController();
1976
- const listeners = [];
1977
- const abortFrom = (signal) => {
1978
- try {
1979
- controller.abort(signal.reason);
1980
- } catch (e2) {
1981
- controller.abort();
1982
- }
1983
- };
1984
- for (const signal of activeSignals) {
1985
- if (signal.aborted) {
1986
- abortFrom(signal);
1987
- break;
1988
- }
1989
- const abort = () => abortFrom(signal);
1990
- signal.addEventListener("abort", abort, { once: true });
1991
- listeners.push({ signal, abort });
1992
- }
1993
- return {
1994
- signal: controller.signal,
1995
- cleanup: () => {
1996
- for (const listener of listeners) {
1997
- listener.signal.removeEventListener("abort", listener.abort);
1998
- }
1999
- listeners.length = 0;
2000
- }
2001
- };
2002
- };
2003
- var nowMs = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
2004
- var hasMethod = (value, name) => typeof value === "object" && value !== null && typeof value[name] === "function";
2005
- var defaultPromiseBody = (response, mode) => {
2006
- if (mode === "json" && hasMethod(response, "json")) return response.json();
2007
- if (mode === "text" && hasMethod(response, "text")) return response.text();
2008
- if (typeof response === "object" && response !== null) {
2009
- const record = response;
2010
- if ("data" in record) return record.data;
2011
- if ("bodyText" in record) return record.bodyText;
2012
- if ("body" in record) return record.body;
2013
- }
2014
- return response;
2015
- };
2016
- var encodePromiseBody = (body, mode) => {
2017
- if (mode === "text") return body === void 0 || body === null ? "" : String(body);
2018
- const encoded = JSON.stringify(body);
2019
- return encoded === void 0 ? "" : encoded;
2020
- };
2021
- var finiteNumber = (value) => {
2022
- const n = typeof value === "number" ? value : Number(value);
2023
- return Number.isFinite(n) ? n : void 0;
2024
- };
2025
- var isPlainRecord = (value) => Object.prototype.toString.call(value) === "[object Object]";
2026
- var injectSignal = (config, signal) => isPlainRecord(config) ? { ...config, signal } : config;
2027
- var inferPromiseResponseInfo = (response) => {
2028
- if (typeof response !== "object" || response === null) {
2029
- return { status: 200, statusText: "", headers: {} };
2030
- }
2031
- const record = response;
2032
- return {
2033
- status: _nullishCoalesce(_nullishCoalesce(finiteNumber(record.status), () => ( finiteNumber(record.statusCode))), () => ( 200)),
2034
- statusText: typeof record.statusText === "string" ? record.statusText : typeof record.statusMessage === "string" ? record.statusMessage : "",
2035
- headers: record.headers,
2036
- ms: finiteNumber(record.ms)
2037
- };
2038
- };
2039
- var toPromiseTransportResponse = (bodyText, info) => ({
2040
- status: _nullishCoalesce(info.status, () => ( 200)),
2041
- statusText: _nullishCoalesce(info.statusText, () => ( "")),
2042
- headers: normalizeHttpHeaders(info.headers),
2043
- bodyText,
2044
- ...info.ms !== void 0 ? { ms: info.ms } : {},
2045
- ...info.transportMeta !== void 0 ? { transportMeta: info.transportMeta } : {}
2046
- });
2047
- function makePromiseHttpTransport(config) {
2048
- return (context) => _chunkMVGUEJ5Zcjs.asyncEffect.call(void 0, (_env, cb) => {
2049
- let done = false;
2050
- const finish = (exit) => {
2051
- if (done) return;
2052
- done = true;
2053
- context.signal.removeEventListener("abort", abort);
2054
- cb(exit);
2055
- };
2056
- const fail = (error) => finish({ _tag: "Failure", cause: _chunkMVGUEJ5Zcjs.Cause.fail(error) });
2057
- const abort = () => fail(abortErrorForSignal(context.signal));
2058
- if (context.signal.aborted) {
2059
- abort();
2060
- return;
2061
- }
2062
- context.signal.addEventListener("abort", abort, { once: true });
2063
- const run = async () => {
2064
- const startedAt = nowMs();
2065
- try {
2066
- const raw = await config.request(context);
2067
- const durationMs = Math.round(nowMs() - startedAt);
2068
- const mapped = await config.response(raw, context, { startedAt, durationMs });
2069
- finish({
2070
- _tag: "Success",
2071
- value: {
2072
- ...mapped,
2073
- ms: _nullishCoalesce(mapped.ms, () => ( durationMs))
2074
- }
2075
- });
2076
- } catch (error) {
2077
- if (context.signal.aborted) {
2078
- fail(abortErrorForSignal(context.signal));
2079
- return;
2080
- }
2081
- fail(_nullishCoalesce(_optionalChain([config, 'access', _38 => _38.error, 'optionalCall', _39 => _39(error, context)]), () => ( normalizeHttpError(error, { signal: context.signal }))));
2082
- }
2083
- };
2084
- void run();
2085
- return () => {
2086
- if (done) return;
2087
- done = true;
2088
- context.signal.removeEventListener("abort", abort);
2089
- };
2090
- });
2091
- }
2092
- function makePromiseHttpTransportBodyBuilder(config) {
2093
- const makeBodyTransport = (mode, body, responseMapper, currentConfig = config) => makePromiseHttpTransport({
2094
- ...currentConfig,
2095
- response: async (raw, context, timing) => {
2096
- const selected = await (_nullishCoalesce(body, () => ( ((value) => defaultPromiseBody(value, mode)))))(raw, context, timing);
2097
- const inferred = inferPromiseResponseInfo(raw);
2098
- const mapped = responseMapper ? await responseMapper(raw, context, timing) : {};
2099
- return toPromiseTransportResponse(encodePromiseBody(selected, mode), {
2100
- ...inferred,
2101
- ...mapped,
2102
- headers: _nullishCoalesce(mapped.headers, () => ( inferred.headers))
2103
- });
2104
- }
2105
- });
2106
- const makeFluentResponseBuilder = (mode, body, currentConfig = config) => {
2107
- return {
2108
- response: (responseMapper) => makeBodyTransport(mode, body, responseMapper, currentConfig),
2109
- error: (error) => makeFluentResponseBuilder(mode, body, { ...currentConfig, error })
2110
- };
2111
- };
2112
- return {
2113
- response: (response) => makePromiseHttpTransport({ ...config, response }),
2114
- json: (body, response) => makeBodyTransport("json", body, response),
2115
- text: (body, response) => makeBodyTransport("text", body, response),
2116
- fromJson: (body) => makeFluentResponseBuilder("json", body),
2117
- fromText: (body) => makeFluentResponseBuilder("text", body),
2118
- error: (error) => makePromiseHttpTransportBodyBuilder({ ...config, error })
2119
- };
2120
- }
2121
- function makePromiseHttpTransportRequestConfigBuilder(requestConfig) {
2122
- return {
2123
- send: (send) => makePromiseHttpTransportBodyBuilder({
2124
- request: async (context) => {
2125
- const config = await requestConfig({
2126
- request: context.request,
2127
- url: context.url
2128
- });
2129
- return send(injectSignal(config, context.signal));
2130
- }
2131
- })
2132
- };
2133
- }
2134
- function promiseHttpTransport() {
2135
- return {
2136
- request: (request) => makePromiseHttpTransportBodyBuilder({ request }),
2137
- requestConfig: (requestConfig) => makePromiseHttpTransportRequestConfigBuilder(requestConfig)
2138
- };
2139
- }
2140
- var fetchUnavailableError = () => ({
2141
- _tag: "FetchError",
2142
- message: "global `fetch` is not available; provide MakeHttpConfig.transport/streamTransport or run in an environment with fetch support."
2143
- });
2144
- function makeFetchTransport() {
2145
- return ({ request, url, signal }) => _chunkMVGUEJ5Zcjs.asyncEffect.call(void 0, (_env, cb) => {
2146
- if (typeof fetch === "undefined") {
2147
- cb({ _tag: "Failure", cause: _chunkMVGUEJ5Zcjs.Cause.fail(fetchUnavailableError()) });
2148
- return;
2149
- }
2150
- const localController = new AbortController();
2151
- const linkedSignal = linkAbortSignals(signal, _optionalChain([request, 'access', _40 => _40.init, 'optionalAccess', _41 => _41.signal]), localController.signal);
2152
- let done = false;
2153
- const finish = (exit) => {
2154
- if (done) return;
2155
- done = true;
2156
- linkedSignal.cleanup();
2157
- cb(exit);
2158
- };
2159
- const run = async () => {
2160
- try {
2161
- if (linkedSignal.signal.aborted) throw abortErrorForSignal(linkedSignal.signal);
2162
- const started = nowMs();
2163
- const response = await fetch(url, {
2164
- ..._nullishCoalesce(request.init, () => ( {})),
2165
- method: request.method,
2166
- headers: Request.headers.get(request),
2167
- body: request.body,
2168
- signal: linkedSignal.signal
2169
- });
2170
- const bodyText = await response.text();
2171
- const latencyMs = Math.round(nowMs() - started);
2172
- finish({
2173
- _tag: "Success",
2174
- value: {
2175
- status: response.status,
2176
- statusText: response.statusText,
2177
- headers: headersOf(response),
2178
- bodyText,
2179
- ms: latencyMs
2180
- }
2181
- });
2182
- } catch (error) {
2183
- finish({
2184
- _tag: "Failure",
2185
- cause: _chunkMVGUEJ5Zcjs.Cause.fail(normalizeHttpError(error, { signal: linkedSignal.signal }))
2186
- });
2187
- }
2188
- };
2189
- void run();
2190
- return () => {
2191
- if (done) return;
2192
- try {
2193
- localController.abort();
2194
- } catch (e3) {
2195
- }
2196
- };
2197
- });
2198
- }
2199
- function makeFetchStreamTransport() {
2200
- return ({ request, url, signal }) => _chunkMVGUEJ5Zcjs.asyncEffect.call(void 0, (_env, cb) => {
2201
- if (typeof fetch === "undefined") {
2202
- cb({ _tag: "Failure", cause: _chunkMVGUEJ5Zcjs.Cause.fail(fetchUnavailableError()) });
2203
- return;
2204
- }
2205
- const localController = new AbortController();
2206
- const linkedSignal = linkAbortSignals(signal, _optionalChain([request, 'access', _42 => _42.init, 'optionalAccess', _43 => _43.signal]), localController.signal);
2207
- let done = false;
2208
- let cleanupTransferredToBody = false;
2209
- const cleanup = () => {
2210
- if (!cleanupTransferredToBody) linkedSignal.cleanup();
2211
- };
2212
- const finish = (exit) => {
2213
- if (done) return;
2214
- done = true;
2215
- cleanup();
2216
- cb(exit);
2217
- };
2218
- const run = async () => {
2219
- try {
2220
- if (linkedSignal.signal.aborted) throw abortErrorForSignal(linkedSignal.signal);
2221
- const started = nowMs();
2222
- const response = await fetch(url, {
2223
- ..._nullishCoalesce(request.init, () => ( {})),
2224
- method: request.method,
2225
- headers: Request.headers.get(request),
2226
- body: request.body,
2227
- signal: linkedSignal.signal
2228
- });
2229
- const headers = headersOf(response);
2230
- const latencyMs = Math.round(nowMs() - started);
2231
- const body = _chunkKZJQ723Ncjs.streamFromReadableStream.call(void 0, response.body, normalizeHttpError, {
2232
- signal: linkedSignal.signal,
2233
- onRelease: linkedSignal.cleanup
2234
- });
2235
- cleanupTransferredToBody = response.body !== null;
2236
- finish({
2237
- _tag: "Success",
2238
- value: {
2239
- status: response.status,
2240
- statusText: response.statusText,
2241
- headers,
2242
- body,
2243
- ms: latencyMs
2244
- }
2245
- });
2246
- } catch (error) {
2247
- finish({
2248
- _tag: "Failure",
2249
- cause: _chunkMVGUEJ5Zcjs.Cause.fail(normalizeHttpError(error, { signal: linkedSignal.signal }))
2250
- });
2251
- }
2252
- };
2253
- void run();
2254
- return () => {
2255
- if (done) return;
2256
- try {
2257
- localController.abort();
2258
- } catch (e4) {
2259
- }
2260
- };
2261
- });
2262
- }
2263
-
2264
- // src/http/configValidation.ts
2265
- var fn = _chunkCZIVE6NTcjs.Schema.custom((value) => typeof value === "function", "function");
2266
- var object = _chunkCZIVE6NTcjs.Schema.custom(
2267
- (value) => typeof value === "object" && value !== null && !Array.isArray(value),
2268
- "object"
2269
- );
2270
- var keyResolver = _chunkCZIVE6NTcjs.Schema.union([
2271
- _chunkCZIVE6NTcjs.Schema.enum(["global", "origin", "host"]),
2272
- fn
2273
- ]);
2274
- var headroomStrategyConfig = _chunkCZIVE6NTcjs.Schema.union([
2275
- _chunkCZIVE6NTcjs.Schema.number({ min: 1 }),
2276
- _chunkCZIVE6NTcjs.Schema.enum(["fixed", "proportional"]),
2277
- fn,
2278
- _chunkCZIVE6NTcjs.Schema.object({
2279
- type: _chunkCZIVE6NTcjs.Schema.literal("fixed"),
2280
- value: _chunkCZIVE6NTcjs.Schema.number({ min: 1 }).optional()
2281
- }, { unknownKeys: "passthrough" }),
2282
- _chunkCZIVE6NTcjs.Schema.object({
2283
- type: _chunkCZIVE6NTcjs.Schema.literal("proportional"),
2284
- ratio: _chunkCZIVE6NTcjs.Schema.number({ min: 0 }).refine((n) => n > 0, "ratio must be > 0").optional(),
2285
- min: _chunkCZIVE6NTcjs.Schema.number({ min: 1 }).optional(),
2286
- max: _chunkCZIVE6NTcjs.Schema.number({ min: 1 }).optional()
2287
- }, { unknownKeys: "passthrough" })
2288
- ]);
2289
- var poolConfig = _chunkCZIVE6NTcjs.Schema.union([
2290
- _chunkCZIVE6NTcjs.Schema.literal(false),
2291
- _chunkCZIVE6NTcjs.Schema.object({
2292
- concurrency: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2293
- maxQueue: _chunkCZIVE6NTcjs.Schema.number({ min: 0, int: true }).optional(),
2294
- queueTimeoutMs: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2295
- key: keyResolver.optional(),
2296
- engine: _chunkCZIVE6NTcjs.Schema.enum(["ts", "wasm"]).optional(),
2297
- wasm: _chunkCZIVE6NTcjs.Schema.boolean().optional()
2298
- }, { unknownKeys: "passthrough" })
2299
- ]);
2300
- var adaptiveLimiterConfig = _chunkCZIVE6NTcjs.Schema.union([
2301
- _chunkCZIVE6NTcjs.Schema.literal(false),
2302
- _chunkCZIVE6NTcjs.Schema.object({
2303
- preset: _chunkCZIVE6NTcjs.Schema.enum(["conservative", "balanced", "aggressive"]).optional(),
2304
- initialLimit: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2305
- minLimit: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2306
- maxLimit: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2307
- smoothingFactor: _chunkCZIVE6NTcjs.Schema.number({ min: 0, max: 1 }).refine((n) => n > 0, "smoothingFactor must be in (0, 1]").optional(),
2308
- probeInterval: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2309
- probeJitterRatio: _chunkCZIVE6NTcjs.Schema.number({ min: 0, max: 1 }).optional(),
2310
- windowSize: _chunkCZIVE6NTcjs.Schema.number({ min: 2, int: true }).optional(),
2311
- minSamples: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2312
- baselineStrategy: _chunkCZIVE6NTcjs.Schema.enum(["min", "p5", "ema-low"]).optional(),
2313
- decreaseCooldownSamples: _chunkCZIVE6NTcjs.Schema.number({ min: 0, int: true }).optional(),
2314
- historySize: _chunkCZIVE6NTcjs.Schema.number({ min: 0, int: true }).optional(),
2315
- windowDecayFactor: _chunkCZIVE6NTcjs.Schema.number({ min: 0, max: 1 }).refine((n) => n > 0, "windowDecayFactor must be in (0, 1]").optional(),
2316
- errorWeight: _chunkCZIVE6NTcjs.Schema.number({ min: 0, max: 1 }).optional(),
2317
- errorSmoothingFactor: _chunkCZIVE6NTcjs.Schema.number({ min: 0, max: 1 }).refine((n) => n > 0, "errorSmoothingFactor must be in (0, 1]").optional(),
2318
- errorStatusThreshold: _chunkCZIVE6NTcjs.Schema.number({ min: 100, max: 599, int: true }).optional(),
2319
- queueStrategy: _chunkCZIVE6NTcjs.Schema.enum(["fifo", "priority"]).optional(),
2320
- queueLoadShedding: _chunkCZIVE6NTcjs.Schema.enum(["reject-new", "priority-evict"]).optional(),
2321
- rejectionBackoffThreshold: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2322
- rejectionBackoffMs: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2323
- stateTtlMs: _chunkCZIVE6NTcjs.Schema.union([_chunkCZIVE6NTcjs.Schema.literal(false), _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true })]).optional(),
2324
- warmupRequests: _chunkCZIVE6NTcjs.Schema.number({ min: 0, int: true }).optional(),
2325
- decreaseThreshold: _chunkCZIVE6NTcjs.Schema.number({ min: 0, max: 1 }).refine((n) => n > 0, "decreaseThreshold must be in (0, 1]").optional(),
2326
- increaseThreshold: _chunkCZIVE6NTcjs.Schema.number({ min: 1 }).optional(),
2327
- maxDecreaseRatio: _chunkCZIVE6NTcjs.Schema.number({ min: 0, max: 1 }).refine((n) => n > 0, "maxDecreaseRatio must be in (0, 1]").optional(),
2328
- headroomStrategy: headroomStrategyConfig.optional(),
2329
- slowStartRecovery: _chunkCZIVE6NTcjs.Schema.boolean().optional(),
2330
- slowStartSaturationThreshold: _chunkCZIVE6NTcjs.Schema.number({ min: 0, max: 1 }).refine((n) => n > 0, "slowStartSaturationThreshold must be in (0, 1]").optional(),
2331
- slowStartSaturationSamples: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2332
- key: keyResolver.optional(),
2333
- maxQueue: _chunkCZIVE6NTcjs.Schema.number({ min: 0, int: true }).optional(),
2334
- queueTimeoutMs: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2335
- onLimitChange: fn.optional(),
2336
- percentile: _chunkCZIVE6NTcjs.Schema.enum(["p50", "p99"]).optional()
2337
- }, { unknownKeys: "passthrough" })
2338
- ]);
2339
- var cacheConfig = _chunkCZIVE6NTcjs.Schema.union([
2340
- _chunkCZIVE6NTcjs.Schema.literal(false),
2341
- _chunkCZIVE6NTcjs.Schema.object({
2342
- ttlSeconds: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2343
- maxEntries: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2344
- staleWhileRevalidate: _chunkCZIVE6NTcjs.Schema.boolean().optional(),
2345
- cachePolicy: fn.optional(),
2346
- cacheRelevantHeaders: _chunkCZIVE6NTcjs.Schema.array(_chunkCZIVE6NTcjs.Schema.string()).optional(),
2347
- onEvent: fn.optional(),
2348
- onLifecycleEvent: fn.optional()
2349
- }, { unknownKeys: "passthrough" })
2350
- ]);
2351
- var priorityConfig = _chunkCZIVE6NTcjs.Schema.union([
2352
- _chunkCZIVE6NTcjs.Schema.literal(false),
2353
- _chunkCZIVE6NTcjs.Schema.object({
2354
- concurrency: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2355
- queueTimeoutMs: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2356
- onEvent: fn.optional()
2357
- }, { unknownKeys: "passthrough" })
2358
- ]);
2359
- var retryConfig = _chunkCZIVE6NTcjs.Schema.union([
2360
- _chunkCZIVE6NTcjs.Schema.literal(false),
2361
- _chunkCZIVE6NTcjs.Schema.object({
2362
- maxRetries: _chunkCZIVE6NTcjs.Schema.number({ min: 0, int: true }).optional(),
2363
- baseDelayMs: _chunkCZIVE6NTcjs.Schema.number({ min: 0, int: true }).optional(),
2364
- maxDelayMs: _chunkCZIVE6NTcjs.Schema.number({ min: 0, int: true }).optional(),
2365
- maxElapsedMs: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2366
- respectRetryAfter: _chunkCZIVE6NTcjs.Schema.boolean().optional(),
2367
- retryOnMethods: _chunkCZIVE6NTcjs.Schema.array(_chunkCZIVE6NTcjs.Schema.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"])).optional(),
2368
- retryOnStatus: fn.optional(),
2369
- retryOnError: fn.optional(),
2370
- engine: _chunkCZIVE6NTcjs.Schema.enum(["ts", "wasm"]).optional(),
2371
- wasm: _chunkCZIVE6NTcjs.Schema.boolean().optional(),
2372
- onRetry: fn.optional()
2373
- }, { unknownKeys: "passthrough" })
2374
- ]);
2375
- var requestRetryOverrideConfig = _chunkCZIVE6NTcjs.Schema.union([
2376
- _chunkCZIVE6NTcjs.Schema.literal(false),
2377
- _chunkCZIVE6NTcjs.Schema.object({
2378
- maxRetries: _chunkCZIVE6NTcjs.Schema.number({ min: 0, int: true }).optional(),
2379
- baseDelayMs: _chunkCZIVE6NTcjs.Schema.number({ min: 0, int: true }).optional(),
2380
- maxDelayMs: _chunkCZIVE6NTcjs.Schema.number({ min: 0, int: true }).optional(),
2381
- schedule: object.optional(),
2382
- retryOnStatus: fn.optional()
2383
- }, { unknownKeys: "passthrough" })
2384
- ]);
2385
- var requestPolicyConfig = _chunkCZIVE6NTcjs.Schema.object({
2386
- preset: _chunkCZIVE6NTcjs.Schema.string({ minLength: 1 }).optional(),
2387
- lane: _chunkCZIVE6NTcjs.Schema.string({ minLength: 1 }).optional(),
2388
- dedupKey: _chunkCZIVE6NTcjs.Schema.string({ minLength: 1 }).optional(),
2389
- priority: _chunkCZIVE6NTcjs.Schema.number({ min: 0, max: 9, int: true }).optional(),
2390
- retry: requestRetryOverrideConfig.optional(),
2391
- poolKey: _chunkCZIVE6NTcjs.Schema.string({ minLength: 1 }).optional()
2392
- }, { unknownKeys: "passthrough" });
2393
- var policyPresetsConfig = _chunkCZIVE6NTcjs.Schema.record(_chunkCZIVE6NTcjs.Schema.union([requestPolicyConfig, fn]));
2394
- var compressionConfig = _chunkCZIVE6NTcjs.Schema.union([
2395
- _chunkCZIVE6NTcjs.Schema.literal(false),
2396
- _chunkCZIVE6NTcjs.Schema.object({
2397
- encodings: _chunkCZIVE6NTcjs.Schema.array(_chunkCZIVE6NTcjs.Schema.enum(["gzip", "br", "deflate"])).optional()
2398
- }, { unknownKeys: "passthrough" })
2399
- ]);
2400
- var prewarmConfig = _chunkCZIVE6NTcjs.Schema.union([
2401
- _chunkCZIVE6NTcjs.Schema.literal(false),
2402
- _chunkCZIVE6NTcjs.Schema.object({
2403
- origins: _chunkCZIVE6NTcjs.Schema.array(_chunkCZIVE6NTcjs.Schema.string()).optional(),
2404
- afterResponse: fn.optional(),
2405
- keepAliveDurationMs: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2406
- budget: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2407
- probeTimeoutMs: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2408
- autoRefresh: _chunkCZIVE6NTcjs.Schema.boolean().optional(),
2409
- useClientPool: _chunkCZIVE6NTcjs.Schema.boolean().optional(),
2410
- onEvent: fn.optional()
2411
- }, { unknownKeys: "passthrough" })
2412
- ]);
2413
- var batchConfig = _chunkCZIVE6NTcjs.Schema.union([
2414
- _chunkCZIVE6NTcjs.Schema.literal(false),
2415
- _chunkCZIVE6NTcjs.Schema.object({
2416
- batch: object,
2417
- windowMs: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }),
2418
- maxBatchSize: _chunkCZIVE6NTcjs.Schema.number({ min: 2, int: true }),
2419
- batchKey: fn
2420
- }, { unknownKeys: "passthrough" })
2421
- ]);
2422
- var wireConfig = _chunkCZIVE6NTcjs.Schema.object({
2423
- baseUrl: _chunkCZIVE6NTcjs.Schema.string().optional(),
2424
- headers: _chunkCZIVE6NTcjs.Schema.record(_chunkCZIVE6NTcjs.Schema.string()).optional(),
2425
- timeoutMs: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2426
- transport: fn.optional(),
2427
- streamTransport: fn.optional(),
2428
- pool: poolConfig.optional(),
2429
- adaptiveLimiter: adaptiveLimiterConfig.optional()
2430
- }, { unknownKeys: "passthrough" });
2431
- var lifecycleConfig = _chunkCZIVE6NTcjs.Schema.object({
2432
- baseUrl: _chunkCZIVE6NTcjs.Schema.string().optional(),
2433
- headers: _chunkCZIVE6NTcjs.Schema.record(_chunkCZIVE6NTcjs.Schema.string()).optional(),
2434
- timeoutMs: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2435
- transport: fn.optional(),
2436
- streamTransport: fn.optional(),
2437
- pool: poolConfig.optional(),
2438
- adaptiveLimiter: adaptiveLimiterConfig.optional(),
2439
- dedup: _chunkCZIVE6NTcjs.Schema.union([_chunkCZIVE6NTcjs.Schema.literal(false), object]).optional(),
2440
- batch: batchConfig.optional(),
2441
- cache: cacheConfig.optional(),
2442
- priority: priorityConfig.optional(),
2443
- retry: retryConfig.optional(),
2444
- prewarm: prewarmConfig.optional(),
2445
- onEvent: fn.optional(),
2446
- policyPresets: policyPresetsConfig.optional()
2447
- }, { unknownKeys: "passthrough" });
2448
- var defaultClientConfig = _chunkCZIVE6NTcjs.Schema.object({
2449
- baseUrl: _chunkCZIVE6NTcjs.Schema.string().optional(),
2450
- headers: _chunkCZIVE6NTcjs.Schema.record(_chunkCZIVE6NTcjs.Schema.string()).optional(),
2451
- timeoutMs: _chunkCZIVE6NTcjs.Schema.number({ min: 1, int: true }).optional(),
2452
- transport: fn.optional(),
2453
- streamTransport: fn.optional(),
2454
- pool: poolConfig.optional(),
2455
- adaptiveLimiter: adaptiveLimiterConfig.optional(),
2456
- dedup: _chunkCZIVE6NTcjs.Schema.union([_chunkCZIVE6NTcjs.Schema.literal(false), object]).optional(),
2457
- batch: batchConfig.optional(),
2458
- cache: cacheConfig.optional(),
2459
- priority: priorityConfig.optional(),
2460
- retry: retryConfig.optional(),
2461
- prewarm: prewarmConfig.optional(),
2462
- onEvent: fn.optional(),
2463
- preset: _chunkCZIVE6NTcjs.Schema.enum(["minimal", "balanced", "default", "production"]).optional(),
2464
- compression: compressionConfig.optional(),
2465
- middleware: _chunkCZIVE6NTcjs.Schema.array(fn).optional(),
2466
- policyPresets: policyPresetsConfig.optional()
2467
- }, { unknownKeys: "passthrough" });
2468
- function validateMakeHttpConfig(config) {
2469
- _chunkCZIVE6NTcjs.parseConfig.call(void 0, "MakeHttpConfig", wireConfig, config);
2470
- }
2471
- function validateLifecycleClientConfig(config) {
2472
- _chunkCZIVE6NTcjs.parseConfig.call(void 0, "LifecycleClientConfig", lifecycleConfig, config);
2473
- }
2474
- function validateDefaultHttpClientConfig(config) {
2475
- _chunkCZIVE6NTcjs.parseConfig.call(void 0, "DefaultHttpClientConfig", defaultClientConfig, config);
2476
- }
2477
-
2478
- // src/http/client.ts
2479
- var emptyStats = () => ({
2480
- inFlight: 0,
2481
- started: 0,
2482
- succeeded: 0,
2483
- failed: 0,
2484
- aborted: 0,
2485
- timedOut: 0,
2486
- poolRejected: 0,
2487
- poolTimeouts: 0
2488
- });
2489
- var decorate = (run, stats = emptyStats, metadata = {}) => {
2490
- const clientFn = ((req) => run(req));
2491
- Object.assign(clientFn, metadata);
2492
- return Object.assign(clientFn, {
2493
- with: (mw) => decorate(mw(clientFn), stats, metadata),
2494
- stats
2495
- }, metadata);
2496
- };
2497
- var withMiddleware = (mw) => (c) => decorate(mw(c), c.stats, {
2498
- adaptiveLimiter: c.adaptiveLimiter,
2499
- destroy: c.destroy,
2500
- shutdown: c.shutdown
2501
- });
2502
- var decorateStream = (run, stats = emptyStats) => Object.assign(((req) => run(req)), { stats });
2503
- var normalizeHeadersInit = (h) => {
2504
- if (!h) return void 0;
2505
- if (typeof Headers !== "undefined" && h instanceof Headers) {
2506
- const out = {};
2507
- h.forEach((v, k) => out[k] = v);
2508
- return out;
2509
- }
2510
- if (Array.isArray(h)) return Object.fromEntries(h);
2511
- if (typeof h === "object") return { ...h };
2512
- return void 0;
2513
- };
2514
- var normalizeRequest = (defaultHeaders) => (req0) => {
2515
- let req = Object.keys(defaultHeaders).length ? mergeHeadersUnder(defaultHeaders)(req0) : req0;
2516
- const initHeaders = normalizeHeadersInit(_optionalChain([req0, 'access', _44 => _44.init, 'optionalAccess', _45 => _45.headers]));
2517
- if (initHeaders && Object.keys(initHeaders).length) {
2518
- req = mergeHeadersUnder(initHeaders)(req);
2519
- }
2520
- return req;
2521
- };
2522
- var resolvePositiveTimeout = (value) => {
2523
- if (value === void 0 || !Number.isFinite(value)) return void 0;
2524
- const n = Math.floor(value);
2525
- return n > 0 ? n : void 0;
2526
- };
2527
- var makeHttpStats = (pool, adaptiveLimiter) => {
2528
- const stats = {
2529
- inFlight: 0,
2530
- started: 0,
2531
- succeeded: 0,
2532
- failed: 0,
2533
- aborted: 0,
2534
- timedOut: 0,
2535
- poolRejected: 0,
2536
- poolTimeouts: 0
2537
- };
2538
- const onStart = () => {
2539
- stats.inFlight++;
2540
- stats.started++;
2541
- };
2542
- const onFinish = (finish) => {
2543
- if (stats.inFlight > 0) stats.inFlight--;
2544
- stats.lastDurationMs = finish.durationMs;
2545
- if (finish.outcome === "success") {
2546
- stats.succeeded++;
2547
- return;
2548
- }
2549
- if (finish.outcome === "interrupt") {
2550
- stats.aborted++;
2551
- return;
2552
- }
2553
- if (finish.outcome === "timeout") {
2554
- stats.timedOut++;
2555
- return;
2556
- }
2557
- const err = normalizeHttpError(finish.error);
2558
- switch (err._tag) {
2559
- case "Abort":
2560
- stats.aborted++;
2561
- return;
2562
- case "Timeout":
2563
- stats.timedOut++;
2564
- return;
2565
- case "PoolRejected":
2566
- stats.poolRejected++;
2567
- stats.failed++;
2568
- return;
2569
- case "PoolTimeout":
2570
- stats.poolTimeouts++;
2571
- stats.failed++;
2572
- return;
2573
- default:
2574
- stats.failed++;
2575
- return;
2576
- }
2577
- };
2578
- const snapshot = () => ({
2579
- ...stats,
2580
- ...pool ? { pool: pool.stats() } : {},
2581
- ...adaptiveLimiter ? { adaptiveLimiter: adaptiveLimiter.stats() } : {}
2582
- });
2583
- return { onStart, onFinish, snapshot };
2584
- };
2585
- var makePool = (cfg) => cfg.pool === void 0 || cfg.pool === false ? void 0 : new HttpConcurrencyPool(cfg.pool);
2586
- var makeAdaptiveLimiter = (cfg) => cfg.adaptiveLimiter === void 0 || cfg.adaptiveLimiter === false ? void 0 : new AdaptiveLimiter(cfg.adaptiveLimiter);
2587
- var resolveRequestUrl = (req, baseUrl) => {
2588
- try {
2589
- return new URL(req.url, baseUrl);
2590
- } catch (e5) {
2591
- return { _tag: "BadUrl", message: `URL inv\xE1lida: ${req.url}` };
2592
- }
2593
- };
2594
- var fetchLabel = (req, url) => `http:${req.method}:${url.origin}`;
2595
- var timeoutReason = (req, url, timeoutMs) => ({
2596
- _tag: "Timeout",
2597
- timeoutMs,
2598
- phase: "request",
2599
- message: `HTTP ${req.method} ${url.origin} timed out after ${timeoutMs}ms`
2600
- });
2601
- var requestPriority = (req) => {
2602
- const fromPolicy = _chunk3LOYJFRRcjs.getHttpRequestPolicy.call(void 0, req).priority;
2603
- if (fromPolicy !== void 0) return fromPolicy;
2604
- return _optionalChain([req, 'access', _46 => _46.init, 'optionalAccess', _47 => _47.priority]);
2605
- };
2606
- var exitError = (exit) => {
2607
- if (exit._tag === "Success") return void 0;
2608
- const failure = _chunkMVGUEJ5Zcjs.Cause.firstFailure(exit.cause);
2609
- if (failure._tag === "Some") return failure.value;
2610
- const defect = _chunkMVGUEJ5Zcjs.Cause.firstDefect(exit.cause);
2611
- if (defect._tag === "Some") return defect.value;
2612
- if (_chunkMVGUEJ5Zcjs.Cause.containsInterrupt(exit.cause)) return { _tag: "Abort" };
2613
- return _chunkMVGUEJ5Zcjs.Cause.toError(exit.cause);
2614
- };
2615
- var runTransportEffect = (effect, env, signal) => new Promise((resolve, reject) => {
2616
- let done = false;
2617
- let cancel;
2618
- const finish = (exit) => {
2619
- if (done) return;
2620
- done = true;
2621
- signal.removeEventListener("abort", abort);
2622
- cancel = void 0;
2623
- if (exit._tag === "Success") {
2624
- resolve(exit.value);
2625
- return;
2626
- }
2627
- reject(exitError(exit));
2628
- };
2629
- const abort = () => {
2630
- if (done) return;
2631
- done = true;
2632
- signal.removeEventListener("abort", abort);
2633
- const currentCancel = cancel;
2634
- cancel = void 0;
2635
- _optionalChain([currentCancel, 'optionalCall', _48 => _48()]);
2636
- reject(abortErrorForSignal(signal));
2637
- };
2638
- if (signal.aborted) {
2639
- abort();
2640
- return;
2641
- }
2642
- signal.addEventListener("abort", abort, { once: true });
2643
- try {
2644
- cancel = _chunkL6VB5N7Qcjs.registerHttpEffect.call(void 0, effect, env, finish);
2645
- } catch (error) {
2646
- if (done) return;
2647
- done = true;
2648
- signal.removeEventListener("abort", abort);
2649
- reject(error);
2650
- }
2651
- });
2652
- var releaseSuccess = (lease, adaptiveLimiter, response) => {
2653
- if (!lease) return void 0;
2654
- if (adaptiveLimiter) {
2655
- lease.release(response.ms, { status: response.status });
2656
- } else {
2657
- lease.release();
2658
- }
2659
- return void 0;
2660
- };
2661
- var releaseFailure = (lease, adaptiveLimiter) => {
2662
- if (!lease) return void 0;
2663
- if (adaptiveLimiter) {
2664
- lease.release(0, { error: true });
2665
- } else {
2666
- lease.release();
2667
- }
2668
- return void 0;
2669
- };
2670
- function makeHttpStream(cfg = {}) {
2671
- validateMakeHttpConfig(cfg);
2672
- const baseUrl = _nullishCoalesce(cfg.baseUrl, () => ( ""));
2673
- const defaultHeaders = _nullishCoalesce(cfg.headers, () => ( {}));
2674
- const normalize = normalizeRequest(defaultHeaders);
2675
- const adaptiveLimiter = makeAdaptiveLimiter(cfg);
2676
- const pool = adaptiveLimiter ? void 0 : makePool(cfg);
2677
- const metrics = makeHttpStats(pool, adaptiveLimiter);
2678
- const transport = _nullishCoalesce(cfg.streamTransport, () => ( makeFetchStreamTransport()));
2679
- const run = (req0) => {
2680
- const req = normalize(req0);
2681
- const url = resolveRequestUrl(req, baseUrl);
2682
- if (!(url instanceof URL)) return _chunkMVGUEJ5Zcjs.asyncFail.call(void 0, url);
2683
- const timeoutMs = resolvePositiveTimeout(_nullishCoalesce(req.timeoutMs, () => ( cfg.timeoutMs)));
2684
- return _chunkGLE2WY7Zcjs.fromPromiseAbortable.call(void 0,
2685
- async (signal, env) => {
2686
- let lease;
2687
- const linkedSignal = linkAbortSignals(signal, _optionalChain([req, 'access', _49 => _49.init, 'optionalAccess', _50 => _50.signal]));
2688
- try {
2689
- if (linkedSignal.signal.aborted) throw abortErrorForSignal(linkedSignal.signal);
2690
- if (adaptiveLimiter) {
2691
- const key = resolveHttpPoolKey(adaptiveLimiter.keyResolver, req, url);
2692
- lease = await adaptiveLimiter.acquire(key, linkedSignal.signal, { priority: requestPriority(req) });
2693
- } else if (pool) {
2694
- const key = resolveHttpPoolKey(pool.keyResolver, req, url);
2695
- lease = await pool.acquire(key, linkedSignal.signal);
2696
- }
2697
- const response = await runTransportEffect(
2698
- transport({ request: req, url, signal: linkedSignal.signal }),
2699
- env,
2700
- linkedSignal.signal
2701
- );
2702
- lease = releaseSuccess(lease, adaptiveLimiter, response);
2703
- lease = void 0;
2704
- return response;
2705
- } finally {
2706
- linkedSignal.cleanup();
2707
- if (lease) {
2708
- releaseFailure(lease, adaptiveLimiter);
2709
- }
2710
- }
2711
- },
2712
- normalizeHttpError,
2713
- {
2714
- label: fetchLabel(req, url),
2715
- timeoutMs,
2716
- timeoutReason: timeoutMs ? () => timeoutReason(req, url, timeoutMs) : void 0,
2717
- onStart: metrics.onStart,
2718
- onFinish: metrics.onFinish
2719
- }
2720
- );
2721
- };
2722
- return decorateStream(run, metrics.snapshot);
2723
- }
2724
- function makeHttp(cfg = {}) {
2725
- validateMakeHttpConfig(cfg);
2726
- const baseUrl = _nullishCoalesce(cfg.baseUrl, () => ( ""));
2727
- const defaultHeaders = _nullishCoalesce(cfg.headers, () => ( {}));
2728
- const normalize = normalizeRequest(defaultHeaders);
2729
- const adaptiveLimiter = makeAdaptiveLimiter(cfg);
2730
- const pool = adaptiveLimiter ? void 0 : makePool(cfg);
2731
- const metrics = makeHttpStats(pool, adaptiveLimiter);
2732
- const transport = _nullishCoalesce(cfg.transport, () => ( makeFetchTransport()));
2733
- const run = (req0) => {
2734
- const req = normalize(req0);
2735
- const url = resolveRequestUrl(req, baseUrl);
2736
- if (!(url instanceof URL)) return _chunkMVGUEJ5Zcjs.asyncFail.call(void 0, url);
2737
- const timeoutMs = resolvePositiveTimeout(_nullishCoalesce(req.timeoutMs, () => ( cfg.timeoutMs)));
2738
- return _chunkGLE2WY7Zcjs.fromPromiseAbortable.call(void 0,
2739
- async (signal, env) => {
2740
- let lease;
2741
- const linkedSignal = linkAbortSignals(signal, _optionalChain([req, 'access', _51 => _51.init, 'optionalAccess', _52 => _52.signal]));
2742
- try {
2743
- if (linkedSignal.signal.aborted) throw abortErrorForSignal(linkedSignal.signal);
2744
- if (adaptiveLimiter) {
2745
- const key = resolveHttpPoolKey(adaptiveLimiter.keyResolver, req, url);
2746
- lease = await adaptiveLimiter.acquire(key, linkedSignal.signal, { priority: requestPriority(req) });
2747
- } else if (pool) {
2748
- const key = resolveHttpPoolKey(pool.keyResolver, req, url);
2749
- lease = await pool.acquire(key, linkedSignal.signal);
2750
- }
2751
- const response = await runTransportEffect(
2752
- transport({ request: req, url, signal: linkedSignal.signal }),
2753
- env,
2754
- linkedSignal.signal
2755
- );
2756
- lease = releaseSuccess(lease, adaptiveLimiter, response);
2757
- return response;
2758
- } finally {
2759
- linkedSignal.cleanup();
2760
- if (lease) {
2761
- releaseFailure(lease, adaptiveLimiter);
2762
- }
2763
- }
2764
- },
2765
- normalizeHttpError,
2766
- {
2767
- label: fetchLabel(req, url),
2768
- timeoutMs,
2769
- timeoutReason: timeoutMs ? () => timeoutReason(req, url, timeoutMs) : void 0,
2770
- onStart: metrics.onStart,
2771
- onFinish: metrics.onFinish
2772
- }
2773
- );
2774
- };
2775
- return decorate(run, metrics.snapshot, adaptiveLimiter ? {
2776
- adaptiveLimiter,
2777
- destroy: () => adaptiveLimiter.destroy(),
2778
- shutdown: () => adaptiveLimiter.shutdown()
2779
- } : {});
2780
- }
2781
- var withRetryStream = (p) => (next) => {
2782
- const retryOnStatus = _nullishCoalesce(p.retryOnStatus, () => ( defaultRetryOnStatus));
2783
- const retryOnError = _nullishCoalesce(p.retryOnError, () => ( defaultRetryOnError));
2784
- const retryOnMethods = _nullishCoalesce(p.retryOnMethods, () => ( defaultRetryableMethods));
2785
- const maxElapsedMs = normalizeRetryBudget(p.maxElapsedMs);
2786
- const run = (req) => {
2787
- if (!retryOnMethods.includes(req.method)) return next(req);
2788
- const startedAt = performance.now();
2789
- const remainingBudget = () => maxElapsedMs === void 0 ? Number.POSITIVE_INFINITY : maxElapsedMs - (performance.now() - startedAt);
2790
- const delayWithinBudget = (delayMs) => Math.max(0, Math.min(delayMs, remainingBudget()));
2791
- const loop = (attempt) => _chunkMVGUEJ5Zcjs.asyncFold.call(void 0,
2792
- next(req),
2793
- (e) => {
2794
- if (e._tag === "Abort" || e._tag === "BadUrl" || e._tag === "PoolRejected" || e._tag === "PoolClosed") return _chunkMVGUEJ5Zcjs.asyncFail.call(void 0, e);
2795
- const canRetry = attempt < p.maxRetries && retryOnError(e) && remainingBudget() > 0;
2796
- if (!canRetry) return _chunkMVGUEJ5Zcjs.asyncFail.call(void 0, e);
2797
- const d = delayWithinBudget(backoffDelayMs(attempt, p.baseDelayMs, p.maxDelayMs));
2798
- if (d <= 0 && maxElapsedMs !== void 0) return _chunkMVGUEJ5Zcjs.asyncFail.call(void 0, e);
2799
- _optionalChain([p, 'access', _53 => _53.onRetry, 'optionalCall', _54 => _54({
2800
- attempt,
2801
- delayMs: d,
2802
- error: e,
2803
- status: void 0,
2804
- url: req.url,
2805
- method: req.method,
2806
- timestamp: Date.now()
2807
- })]);
2808
- return _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0, _chunkAGR5B2BCcjs.sleep.call(void 0, d), () => loop(attempt + 1));
2809
- },
2810
- (w) => {
2811
- const canRetry = attempt < p.maxRetries && retryOnStatus(w.status) && remainingBudget() > 0;
2812
- if (!canRetry) return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, w);
2813
- const ra = p.respectRetryAfter === false ? void 0 : retryAfterMs(w.headers);
2814
- const rawDelay = ra === void 0 ? backoffDelayMs(attempt, p.baseDelayMs, p.maxDelayMs) : Math.min(ra, p.maxDelayMs);
2815
- const d = delayWithinBudget(rawDelay);
2816
- if (d <= 0 && maxElapsedMs !== void 0) return _chunkMVGUEJ5Zcjs.asyncSucceed.call(void 0, w);
2817
- _optionalChain([p, 'access', _55 => _55.onRetry, 'optionalCall', _56 => _56({
2818
- attempt,
2819
- delayMs: d,
2820
- error: void 0,
2821
- status: w.status,
2822
- url: req.url,
2823
- method: req.method,
2824
- timestamp: Date.now()
2825
- })]);
2826
- return _chunkMVGUEJ5Zcjs.asyncFlatMap.call(void 0, _chunkAGR5B2BCcjs.sleep.call(void 0, d), () => loop(attempt + 1));
2827
- }
2828
- );
2829
- return loop(0);
2830
- };
2831
- return decorateStream(run, next.stats);
2832
- };
2833
-
2834
-
2835
-
2836
-
2837
-
2838
-
2839
-
2840
-
2841
-
2842
-
2843
-
2844
-
2845
-
2846
-
2847
-
2848
-
2849
-
2850
-
2851
-
2852
-
2853
-
2854
-
2855
-
2856
-
2857
-
2858
-
2859
-
2860
-
2861
-
2862
-
2863
-
2864
-
2865
-
2866
-
2867
-
2868
-
2869
-
2870
-
2871
-
2872
-
2873
-
2874
- exports.mergeHeaders = mergeHeaders; exports.setHeaderIfMissing = setHeaderIfMissing; exports.defaultRetryableMethods = defaultRetryableMethods; exports.defaultRetryOnStatus = defaultRetryOnStatus; exports.defaultRetryOnError = defaultRetryOnError; exports.backoffDelayMs = backoffDelayMs; exports.retryAfterMs = retryAfterMs; exports.normalizeRetryBudget = normalizeRetryBudget; exports.withRetry = withRetry; exports.resolveHttpPoolKey = resolveHttpPoolKey; exports.HttpConcurrencyPool = HttpConcurrencyPool; exports.LatencyWindow = LatencyWindow; exports.EmaComputer = EmaComputer; exports.computeGradient = computeGradient; exports.computeNewLimit = computeNewLimit; exports.adaptiveLimiterPresets = adaptiveLimiterPresets; exports.makeAdaptiveLimiterConfig = makeAdaptiveLimiterConfig; exports.validateConfig = validateConfig; exports.resolveConfig = resolveConfig; exports.AdaptiveLimiter = AdaptiveLimiter; exports.validateLifecycleClientConfig = validateLifecycleClientConfig; exports.validateDefaultHttpClientConfig = validateDefaultHttpClientConfig; exports.isTaggedHttpError = isTaggedHttpError; exports.isAbortError = isAbortError; exports.normalizeHttpError = normalizeHttpError; exports.headersOf = headersOf; exports.normalizeHttpHeaders = normalizeHttpHeaders; exports.abortErrorForSignal = abortErrorForSignal; exports.linkAbortSignals = linkAbortSignals; exports.makePromiseHttpTransport = makePromiseHttpTransport; exports.promiseHttpTransport = promiseHttpTransport; exports.makeFetchTransport = makeFetchTransport; exports.makeFetchStreamTransport = makeFetchStreamTransport; exports.decorate = decorate; exports.withMiddleware = withMiddleware; exports.normalizeHeadersInit = normalizeHeadersInit; exports.makeHttpStream = makeHttpStream; exports.makeHttp = makeHttp; exports.withRetryStream = withRetryStream;