brass-runtime 1.15.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +409 -137
  2. package/dist/agent/cli/main.cjs +40 -35
  3. package/dist/agent/cli/main.js +9 -4
  4. package/dist/agent/cli/main.mjs +9 -4
  5. package/dist/agent/index.cjs +8 -4
  6. package/dist/agent/index.d.ts +1 -1
  7. package/dist/agent/index.js +7 -3
  8. package/dist/agent/index.mjs +7 -3
  9. package/dist/{chunk-PPUXIH5R.js → chunk-2WC63LJK.mjs} +11 -7
  10. package/dist/chunk-3RG5ZIWI.js +10 -0
  11. package/dist/chunk-45F7OKGT.cjs +104 -0
  12. package/dist/chunk-5YOQOXEQ.cjs +2491 -0
  13. package/dist/{chunk-STVLQ3XD.cjs → chunk-7HUOJA4W.cjs} +78 -74
  14. package/dist/{chunk-BMH5AV44.js → chunk-7LVI2GIN.js} +251 -370
  15. package/dist/chunk-7TL2LHQJ.js +2491 -0
  16. package/dist/chunk-7V4KY4RL.mjs +104 -0
  17. package/dist/chunk-7XOPAB5Q.js +2143 -0
  18. package/dist/chunk-CCKHV5BT.mjs +193 -0
  19. package/dist/{chunk-AR22SXML.js → chunk-CY33PGEX.mjs} +488 -421
  20. package/dist/chunk-DJQ7OMMB.cjs +144 -0
  21. package/dist/chunk-F5EUMJL7.mjs +2143 -0
  22. package/dist/chunk-FM4W4QPL.js +193 -0
  23. package/dist/{chunk-TO7IKXYT.js → chunk-G3XGCZDQ.js} +1 -1
  24. package/dist/{chunk-BDF4AMWX.mjs → chunk-G6IQOE4P.mjs} +251 -370
  25. package/dist/chunk-GOV47PPB.mjs +552 -0
  26. package/dist/chunk-H55LI6WY.js +93 -0
  27. package/dist/chunk-IJT6RRQ5.cjs +93 -0
  28. package/dist/{chunk-ELOOF35R.mjs → chunk-J3H54ZRV.mjs} +1 -1
  29. package/dist/chunk-JF4XXPZ5.cjs +552 -0
  30. package/dist/chunk-JNFRRJYH.cjs +2143 -0
  31. package/dist/chunk-JX3LZQJH.cjs +354 -0
  32. package/dist/chunk-K2T3DV26.mjs +93 -0
  33. package/dist/chunk-KCPT2D6G.js +552 -0
  34. package/dist/chunk-MWXMNYJS.cjs +1110 -0
  35. package/dist/{chunk-VEZNF5GZ.cjs → chunk-N6VHMOWB.cjs} +130 -126
  36. package/dist/{chunk-3QMOKAS5.js → chunk-NC5SDRYE.js} +9 -5
  37. package/dist/chunk-NOYZIMUJ.mjs +144 -0
  38. package/dist/{chunk-R3R2FVLG.cjs → chunk-NYL4D7SK.cjs} +5 -5
  39. package/dist/chunk-OBGZSXTJ.cjs +10 -0
  40. package/dist/{chunk-4NHES7VK.mjs → chunk-OOGJ73B6.js} +11 -7
  41. package/dist/chunk-PNVFW245.js +144 -0
  42. package/dist/chunk-PRWCB3QL.mjs +2491 -0
  43. package/dist/{chunk-JFPU5GQI.mjs → chunk-QY5FKYEQ.js} +488 -421
  44. package/dist/chunk-ROJC3NBJ.js +104 -0
  45. package/dist/chunk-SPUEME2B.cjs +343 -0
  46. package/dist/chunk-TDVMADDN.js +343 -0
  47. package/dist/chunk-TVN5I4U6.cjs +193 -0
  48. package/dist/chunk-U5KWK3PX.mjs +343 -0
  49. package/dist/chunk-VFIUZG7J.mjs +354 -0
  50. package/dist/{chunk-TGIFUAK4.cjs → chunk-WQ5QNU5R.cjs} +459 -578
  51. package/dist/chunk-XDZOO4L5.js +354 -0
  52. package/dist/chunk-Y6FXYEAI.mjs +10 -0
  53. package/dist/{chunk-K6M7MDZ4.mjs → chunk-ZGLD4TVZ.mjs} +9 -5
  54. package/dist/client-CtFmoDvM.d.ts +645 -0
  55. package/dist/core/index.cjs +72 -4
  56. package/dist/core/index.d.ts +92 -198
  57. package/dist/core/index.js +106 -38
  58. package/dist/core/index.mjs +106 -38
  59. package/dist/{effect-CMOQKX8y.d.ts → effect-CGNl5Rqp.d.ts} +107 -1
  60. package/dist/effectRunner-3ZHAD3LE.cjs +8 -0
  61. package/dist/effectRunner-A4CHJXJI.js +8 -0
  62. package/dist/effectRunner-OPUF6QRN.mjs +8 -0
  63. package/dist/http/index.cjs +2189 -1271
  64. package/dist/http/index.d.ts +830 -270
  65. package/dist/http/index.js +2008 -1090
  66. package/dist/http/index.mjs +2008 -1090
  67. package/dist/http/testing.cjs +159 -0
  68. package/dist/http/testing.d.ts +42 -0
  69. package/dist/http/testing.js +159 -0
  70. package/dist/http/testing.mjs +159 -0
  71. package/dist/index.cjs +246 -178
  72. package/dist/index.d.ts +9 -35
  73. package/dist/index.js +120 -52
  74. package/dist/index.mjs +120 -52
  75. package/dist/observability/index.cjs +677 -0
  76. package/dist/observability/index.d.ts +79 -0
  77. package/dist/observability/index.js +677 -0
  78. package/dist/observability/index.mjs +677 -0
  79. package/dist/schedule-Fque9Abz.d.ts +70 -0
  80. package/dist/schema/index.cjs +25 -0
  81. package/dist/schema/index.d.ts +177 -0
  82. package/dist/schema/index.js +25 -0
  83. package/dist/schema/index.mjs +25 -0
  84. package/dist/server-C8hDXA74.d.ts +674 -0
  85. package/dist/{stream-FQm9h4Mg.d.ts → stream-dvSs0QS5.d.ts} +1 -1
  86. package/dist/tracer-B5tRH9H7.d.ts +230 -0
  87. package/dist/tracing-Dt9S_6V8.d.ts +148 -0
  88. package/package.json +27 -1
  89. package/dist/chunk-BDYEENHT.js +0 -224
  90. package/dist/chunk-MS34J5LY.cjs +0 -224
  91. package/dist/chunk-UMAZLXAB.mjs +0 -224
  92. package/dist/chunk-XPZNXSVN.cjs +0 -1043
  93. package/dist/tracing-DNT9jEbr.d.ts +0 -106
@@ -0,0 +1,645 @@
1
+ import { A as Async } from './effect-CGNl5Rqp.js';
2
+ import { Z as ZStream } from './stream-dvSs0QS5.js';
3
+ import { S as Schedule } from './schedule-Fque9Abz.js';
4
+
5
+ /**
6
+ * Observable event emitted on each retry attempt via the `onRetry` callback.
7
+ */
8
+ type RetryEvent = {
9
+ /** Zero-based attempt number (0 = first retry, not the initial request). */
10
+ attempt: number;
11
+ /** Computed delay in milliseconds before the next attempt. */
12
+ delayMs: number;
13
+ /** The error that triggered this retry, if the request failed with an HttpError. */
14
+ error?: HttpError;
15
+ /** The HTTP status code that triggered this retry, if the request returned a retryable status. */
16
+ status?: number;
17
+ /** The request URL. */
18
+ url: string;
19
+ /** The request HTTP method. */
20
+ method: HttpMethod;
21
+ /** Timestamp (ms since epoch) when the retry decision was made. */
22
+ timestamp: number;
23
+ };
24
+ type RetryScheduleInput = {
25
+ readonly attempt: number;
26
+ readonly elapsedMs: number;
27
+ readonly request: HttpRequest;
28
+ readonly error?: HttpError;
29
+ readonly status?: number;
30
+ readonly retryAfterMs?: number;
31
+ };
32
+ /**
33
+ * Per-request retry override. Attached as `(req as any).retry`.
34
+ * - `false` disables retry entirely for this request.
35
+ * - A partial policy object merges with the middleware-level policy (per-request wins).
36
+ */
37
+ type PerRequestRetryOverride = false | {
38
+ maxRetries?: number;
39
+ baseDelayMs?: number;
40
+ maxDelayMs?: number;
41
+ schedule?: Schedule<RetryScheduleInput, unknown>;
42
+ retryOnStatus?: (status: number) => boolean;
43
+ };
44
+ type RetryPolicy = {
45
+ maxRetries: number;
46
+ baseDelayMs: number;
47
+ maxDelayMs: number;
48
+ /** Optional declarative schedule. When present, it provides retry delays. */
49
+ schedule?: Schedule<RetryScheduleInput, unknown>;
50
+ /** Optional total retry budget, including request attempts and sleeps. */
51
+ maxElapsedMs?: number;
52
+ /** Defaults to true. When true, Retry-After is honored but capped by maxDelayMs/budget. */
53
+ respectRetryAfter?: boolean;
54
+ retryOnMethods?: HttpMethod[];
55
+ retryOnStatus?: (status: number) => boolean;
56
+ retryOnError?: (e: HttpError) => boolean;
57
+ /** Strict engine selector for retry planning. Defaults to ts. */
58
+ engine?: "ts" | "wasm";
59
+ /** Back-compat knob: wasm=true maps to engine="wasm", wasm=false maps to engine="ts". */
60
+ wasm?: boolean;
61
+ /** Called synchronously before each retry delay begins. Zero overhead when omitted. */
62
+ onRetry?: (event: RetryEvent) => void;
63
+ };
64
+ declare const defaultRetryableMethods: HttpMethod[];
65
+ declare const defaultRetryOnStatus: (s: number) => s is 408 | 429 | 500 | 502 | 503 | 504;
66
+ declare const defaultRetryOnError: (e: HttpError) => e is {
67
+ _tag: "FetchError";
68
+ message: string;
69
+ } | {
70
+ _tag: "Timeout";
71
+ timeoutMs: number;
72
+ message: string;
73
+ phase?: "request" | "queue" | "retry";
74
+ } | {
75
+ _tag: "PoolTimeout";
76
+ key: string;
77
+ timeoutMs: number;
78
+ message: string;
79
+ };
80
+ declare const backoffDelayMs: (attempt: number, base: number, cap: number) => number;
81
+ declare const retryAfterMs: (headers: Record<string, string>) => number | undefined;
82
+ declare const normalizeRetryBudget: (ms: number | undefined) => number | undefined;
83
+ declare const withRetry: (p: RetryPolicy) => HttpMiddleware;
84
+
85
+ type HttpPoolKeyResolver = "global" | "origin" | "host" | ((req: HttpRequest, url: URL) => string);
86
+ type HttpPoolConfig = {
87
+ /** Max concurrent downstream calls per resolved key. */
88
+ readonly concurrency?: number;
89
+ /** Max queued waiters per key. `0` means fail fast when the pool is full. */
90
+ readonly maxQueue?: number;
91
+ /** Max time a request may wait for a pool slot before failing fast. */
92
+ readonly queueTimeoutMs?: number;
93
+ /** How to isolate pools. Default: `origin`; useful values: `global`, `host`, `origin`. */
94
+ readonly key?: HttpPoolKeyResolver;
95
+ /**
96
+ * Strict engine selector for permit governance. Defaults to ts.
97
+ * - ts: TypeScript permit pool.
98
+ * - wasm: require BrassWasmHttpPermitPool from wasm/pkg; never falls back.
99
+ */
100
+ readonly engine?: "ts" | "wasm";
101
+ /** Back-compat knob: wasm=true maps to engine="wasm", wasm=false maps to engine="ts". */
102
+ readonly wasm?: boolean;
103
+ };
104
+ type HttpPoolKeyStats = {
105
+ readonly key: string;
106
+ readonly running: number;
107
+ readonly queued: number;
108
+ readonly concurrency: number;
109
+ readonly maxQueue: number;
110
+ readonly acquired: number;
111
+ readonly released: number;
112
+ readonly rejected: number;
113
+ readonly queueTimeouts: number;
114
+ readonly abortedWhileQueued: number;
115
+ };
116
+ type HttpPoolStats = {
117
+ readonly running: number;
118
+ readonly queued: number;
119
+ readonly acquired: number;
120
+ readonly released: number;
121
+ readonly rejected: number;
122
+ readonly queueTimeouts: number;
123
+ readonly abortedWhileQueued: number;
124
+ readonly wasm?: unknown;
125
+ readonly keys: HttpPoolKeyStats[];
126
+ };
127
+ type HttpPoolLease = {
128
+ readonly key: string;
129
+ release: () => void;
130
+ };
131
+ declare function resolveHttpPoolKey(resolver: HttpPoolKeyResolver | undefined, req: HttpRequest, url: URL): string;
132
+ declare class HttpConcurrencyPool {
133
+ private readonly states;
134
+ private readonly concurrency;
135
+ private readonly maxQueue;
136
+ private readonly queueTimeoutMs;
137
+ readonly keyResolver: HttpPoolKeyResolver | undefined;
138
+ private readonly wasm;
139
+ private readonly wasmWaiters;
140
+ private wasmTimer;
141
+ private nextSubjectId;
142
+ constructor(config?: HttpPoolConfig);
143
+ acquire(key: string, signal: AbortSignal): Promise<HttpPoolLease>;
144
+ stats(): HttpPoolStats;
145
+ private acquireJs;
146
+ private acquireWasm;
147
+ private getState;
148
+ private makeLease;
149
+ private drain;
150
+ private handleWasmGrants;
151
+ private handleWasmTimeouts;
152
+ private scheduleWasmTimeoutPump;
153
+ private cleanupWaiter;
154
+ private removeWaiter;
155
+ private allocateSubjectId;
156
+ }
157
+
158
+ type AdaptiveHeadroomMode = "stable" | "probe" | "warmup" | "slow-start" | "circuit-open";
159
+ type AdaptiveHeadroomContext = {
160
+ readonly key: string;
161
+ readonly currentLimit: number;
162
+ readonly minLimit: number;
163
+ readonly maxLimit: number;
164
+ readonly gradient: number;
165
+ readonly mode: AdaptiveHeadroomMode;
166
+ };
167
+ type AdaptiveHeadroomStrategy = number | "fixed" | "proportional" | {
168
+ readonly type: "fixed";
169
+ readonly value?: number;
170
+ } | {
171
+ readonly type: "proportional";
172
+ readonly ratio?: number;
173
+ readonly min?: number;
174
+ readonly max?: number;
175
+ } | ((context: AdaptiveHeadroomContext) => number);
176
+ type AdaptiveBaselineStrategy = "min" | "p5" | "ema-low";
177
+ type AdaptiveQueueStrategy = "fifo" | "priority";
178
+ type AdaptiveQueueLoadShedding = "reject-new" | "priority-evict";
179
+ type AdaptiveLimiterPreset = "conservative" | "balanced" | "aggressive";
180
+ type AdaptiveAcquireOptions = {
181
+ /** Request priority from 0 (highest) to 9 (lowest). Default: 5. */
182
+ readonly priority?: number;
183
+ };
184
+ type AdaptiveReleaseInfo = {
185
+ /** HTTP response status, used by the error signal when >= 500 by default. */
186
+ readonly status?: number;
187
+ /** Marks a failed request without an HTTP response, e.g. fetch error or timeout. */
188
+ readonly error?: boolean;
189
+ };
190
+ /**
191
+ * Configuration for the adaptive concurrency limiter.
192
+ * All fields are optional with sensible defaults.
193
+ */
194
+ type AdaptiveLimiterConfig = {
195
+ /** Named production preset used before caller overrides are applied. */
196
+ readonly preset?: AdaptiveLimiterPreset;
197
+ /** Initial concurrency limit. Default: 10. */
198
+ readonly initialLimit?: number;
199
+ /** Minimum concurrency limit. Default: 1. */
200
+ readonly minLimit?: number;
201
+ /** Maximum concurrency limit. Default: 200. */
202
+ readonly maxLimit?: number;
203
+ /** EMA smoothing factor in (0, 1]. Default: 0.5. */
204
+ readonly smoothingFactor?: number;
205
+ /** Number of completions between probes. Default: 10. */
206
+ readonly probeInterval?: number;
207
+ /** Random probe interval spread. 0 disables jitter, 0.2 means ±20%. Default: 0.2. */
208
+ readonly probeJitterRatio?: number;
209
+ /** Sliding window size for latency samples. Default: 100. */
210
+ readonly windowSize?: number;
211
+ /** Minimum samples before the limiter may change its limit. Default: 10. */
212
+ readonly minSamples?: number;
213
+ /** Baseline used for gradient computation. Default: "min". */
214
+ readonly baselineStrategy?: AdaptiveBaselineStrategy;
215
+ /** Samples to wait after a decrease before allowing another decrease. Default: 0. */
216
+ readonly decreaseCooldownSamples?: number;
217
+ /** Number of limit-change events retained per key for diagnostics. Default: 32. */
218
+ readonly historySize?: number;
219
+ /** Exponential decay applied to percentile windows. 1 disables weighting. Default: 1. */
220
+ readonly windowDecayFactor?: number;
221
+ /** Error signal weight blended with latency gradient. 0 disables. Default: 0. */
222
+ readonly errorWeight?: number;
223
+ /** EMA smoothing factor for the error rate signal. Defaults to smoothingFactor. */
224
+ readonly errorSmoothingFactor?: number;
225
+ /** HTTP status at/above which responses count as downstream errors. Default: 500. */
226
+ readonly errorStatusThreshold?: number;
227
+ /** Internal queue ordering. Default: "fifo". */
228
+ readonly queueStrategy?: AdaptiveQueueStrategy;
229
+ /** Queue-full behavior. Default: "reject-new". */
230
+ readonly queueLoadShedding?: AdaptiveQueueLoadShedding;
231
+ /** Rejection streak before PoolRejected carries retryAfterMs. Default: 3. */
232
+ readonly rejectionBackoffThreshold?: number;
233
+ /** Backoff hint for sustained PoolRejected errors. Default: undefined. */
234
+ readonly rejectionBackoffMs?: number;
235
+ /** Remove inactive per-key state after this idle period. Use false to disable. Default: 300000. */
236
+ readonly stateTtlMs?: number | false;
237
+ /** Number of valid completions used for explicit linear warmup. 0 disables. Default: 0. */
238
+ readonly warmupRequests?: number;
239
+ /** Gradient below which the limiter decreases concurrency. Default: 0.75. */
240
+ readonly decreaseThreshold?: number;
241
+ /** Gradient at or above which the limiter may increase concurrency. Default: 1.0. */
242
+ readonly increaseThreshold?: number;
243
+ /** Maximum fraction of the current limit that can be removed in one adjustment. Default: 0.2. */
244
+ readonly maxDecreaseRatio?: number;
245
+ /** Fixed, proportional, or custom headroom added on stable growth/probes. Default: 1. */
246
+ readonly headroomStrategy?: AdaptiveHeadroomStrategy;
247
+ /** Enable fast recovery after sustained saturation. Default: true. */
248
+ readonly slowStartRecovery?: boolean;
249
+ /** Gradient at/below which samples count as strong saturation. Default: 0.5. */
250
+ readonly slowStartSaturationThreshold?: number;
251
+ /** Consecutive strong-saturation samples before slow-start recovery arms. Default: 3. */
252
+ readonly slowStartSaturationSamples?: number;
253
+ /** Key resolver for isolation scope. Default: "origin". */
254
+ readonly key?: HttpPoolKeyResolver;
255
+ /** Maximum queue depth per key. Default: 256. */
256
+ readonly maxQueue?: number;
257
+ /** Queue timeout in ms. Default: undefined (no timeout). */
258
+ readonly queueTimeoutMs?: number;
259
+ /** Callback invoked when the limit changes. */
260
+ readonly onLimitChange?: (event: LimitChangeEvent) => void;
261
+ /** Which percentile to use for gradient computation. Default: "p50". */
262
+ readonly percentile?: "p50" | "p99";
263
+ };
264
+ /**
265
+ * Event emitted when the concurrency limit changes.
266
+ */
267
+ type LimitChangeEvent = {
268
+ readonly key: string;
269
+ readonly previousLimit: number;
270
+ readonly newLimit: number;
271
+ readonly gradient: number;
272
+ readonly latencyGradient: number;
273
+ readonly errorRate: number;
274
+ readonly smoothedLatency: number;
275
+ readonly minLatency: number;
276
+ readonly baselineLatency: number;
277
+ readonly p5: number | undefined;
278
+ readonly timestamp: number;
279
+ readonly reason?: "gradient" | "probe" | "warmup" | "slow-start" | "circuit-open";
280
+ };
281
+ /**
282
+ * Snapshot of the adaptive limiter's current state for a given key.
283
+ */
284
+ type AdaptiveLimiterStats = {
285
+ readonly limit: number;
286
+ readonly inFlight: number;
287
+ readonly queueDepth: number;
288
+ readonly gradient: number | undefined;
289
+ readonly latencyGradient: number | undefined;
290
+ readonly errorRate: number | undefined;
291
+ readonly smoothedLatency: number | undefined;
292
+ readonly minLatency: number | undefined;
293
+ readonly baselineLatency: number | undefined;
294
+ readonly p5: number | undefined;
295
+ readonly p50: number | undefined;
296
+ readonly p99: number | undefined;
297
+ readonly probeCount: number;
298
+ readonly windowSize: number;
299
+ readonly warmupCompletions?: number;
300
+ readonly slowStart?: boolean;
301
+ readonly cooldownSamplesRemaining?: number;
302
+ readonly utilization?: number;
303
+ readonly requestsPerSecond?: number;
304
+ readonly completionsPerSecond?: number;
305
+ readonly rejectionRate?: number;
306
+ readonly suggestedBackoffMs?: number;
307
+ readonly stateCount?: number;
308
+ readonly keys?: readonly string[];
309
+ };
310
+ type AdaptiveLimiterKeySnapshot = AdaptiveLimiterStats & {
311
+ readonly key: string;
312
+ readonly createdAt: number;
313
+ readonly createdTimestamp: number;
314
+ readonly lastActivityAt: number;
315
+ readonly lastActivityTimestamp: number;
316
+ readonly nextProbeAt: number;
317
+ readonly warmupDone: boolean;
318
+ readonly saturationStreak: number;
319
+ readonly slowStartRecoveryStarted: boolean;
320
+ readonly history: readonly LimitChangeEvent[];
321
+ readonly acquired: number;
322
+ readonly released: number;
323
+ readonly rejected: number;
324
+ readonly queueTimeouts: number;
325
+ readonly abortedWhileQueued: number;
326
+ readonly evictedWhileQueued: number;
327
+ };
328
+ type AdaptiveLimiterDiagnostics = {
329
+ readonly stateCount: number;
330
+ readonly keys: readonly string[];
331
+ readonly aggregate: AdaptiveLimiterStats;
332
+ readonly states: readonly AdaptiveLimiterKeySnapshot[];
333
+ readonly history: readonly LimitChangeEvent[];
334
+ };
335
+ /**
336
+ * A lease representing an acquired concurrency slot.
337
+ * Call `release(latencyMs)` when the request completes to record latency and free the slot.
338
+ */
339
+ type AdaptiveLease = {
340
+ readonly key: string;
341
+ release(latencyMs: number, info?: AdaptiveReleaseInfo): void;
342
+ };
343
+ /** Resolved (non-optional) configuration with defaults applied. */
344
+ type ResolvedConfig = {
345
+ readonly preset: AdaptiveLimiterPreset | undefined;
346
+ readonly initialLimit: number;
347
+ readonly minLimit: number;
348
+ readonly maxLimit: number;
349
+ readonly smoothingFactor: number;
350
+ readonly probeInterval: number;
351
+ readonly probeJitterRatio: number;
352
+ readonly windowSize: number;
353
+ readonly minSamples: number;
354
+ readonly baselineStrategy: AdaptiveBaselineStrategy;
355
+ readonly decreaseCooldownSamples: number;
356
+ readonly historySize: number;
357
+ readonly windowDecayFactor: number;
358
+ readonly errorWeight: number;
359
+ readonly errorSmoothingFactor: number;
360
+ readonly errorStatusThreshold: number;
361
+ readonly queueStrategy: AdaptiveQueueStrategy;
362
+ readonly queueLoadShedding: AdaptiveQueueLoadShedding;
363
+ readonly rejectionBackoffThreshold: number;
364
+ readonly rejectionBackoffMs: number | undefined;
365
+ readonly stateTtlMs: number | undefined;
366
+ readonly warmupRequests: number;
367
+ readonly decreaseThreshold: number;
368
+ readonly increaseThreshold: number;
369
+ readonly maxDecreaseRatio: number;
370
+ readonly headroomStrategy: AdaptiveHeadroomStrategy;
371
+ readonly slowStartRecovery: boolean;
372
+ readonly slowStartSaturationThreshold: number;
373
+ readonly slowStartSaturationSamples: number;
374
+ readonly key: HttpPoolKeyResolver;
375
+ readonly maxQueue: number;
376
+ readonly queueTimeoutMs: number | undefined;
377
+ readonly onLimitChange: ((event: LimitChangeEvent) => void) | undefined;
378
+ readonly percentile: "p50" | "p99";
379
+ };
380
+ declare const adaptiveLimiterPresets: Readonly<{
381
+ conservative: Readonly<{
382
+ initialLimit: 8;
383
+ minLimit: 2;
384
+ maxLimit: 64;
385
+ maxQueue: 256;
386
+ queueTimeoutMs: 30000;
387
+ smoothingFactor: 0.3;
388
+ probeInterval: 40;
389
+ probeJitterRatio: 0.2;
390
+ windowSize: 100;
391
+ minSamples: 80;
392
+ baselineStrategy: "p5";
393
+ windowDecayFactor: 0.99;
394
+ errorWeight: 0.2;
395
+ decreaseThreshold: 0.65;
396
+ maxDecreaseRatio: 0.08;
397
+ headroomStrategy: "fixed";
398
+ queueStrategy: "priority";
399
+ queueLoadShedding: "priority-evict";
400
+ rejectionBackoffThreshold: 2;
401
+ rejectionBackoffMs: 150;
402
+ percentile: "p50";
403
+ }>;
404
+ balanced: Readonly<{
405
+ initialLimit: 16;
406
+ minLimit: 4;
407
+ maxLimit: 128;
408
+ maxQueue: 512;
409
+ queueTimeoutMs: 30000;
410
+ smoothingFactor: 0.35;
411
+ probeInterval: 25;
412
+ probeJitterRatio: 0.2;
413
+ windowSize: 100;
414
+ minSamples: 50;
415
+ baselineStrategy: "p5";
416
+ windowDecayFactor: 0.98;
417
+ errorWeight: 0.25;
418
+ decreaseThreshold: 0.5;
419
+ maxDecreaseRatio: 0.1;
420
+ headroomStrategy: {
421
+ type: "proportional";
422
+ ratio: number;
423
+ };
424
+ queueStrategy: "priority";
425
+ queueLoadShedding: "priority-evict";
426
+ rejectionBackoffThreshold: 3;
427
+ rejectionBackoffMs: 100;
428
+ percentile: "p50";
429
+ }>;
430
+ aggressive: Readonly<{
431
+ initialLimit: 32;
432
+ minLimit: 8;
433
+ maxLimit: 256;
434
+ maxQueue: 1024;
435
+ queueTimeoutMs: 30000;
436
+ smoothingFactor: 0.35;
437
+ probeInterval: 20;
438
+ probeJitterRatio: 0.2;
439
+ windowSize: 160;
440
+ minSamples: 100;
441
+ baselineStrategy: "p5";
442
+ windowDecayFactor: 0.98;
443
+ errorWeight: 0.25;
444
+ decreaseThreshold: 0.5;
445
+ maxDecreaseRatio: 0.1;
446
+ headroomStrategy: {
447
+ type: "proportional";
448
+ ratio: number;
449
+ };
450
+ queueStrategy: "priority";
451
+ queueLoadShedding: "priority-evict";
452
+ rejectionBackoffThreshold: 3;
453
+ rejectionBackoffMs: 100;
454
+ percentile: "p50";
455
+ }>;
456
+ }>;
457
+ declare function makeAdaptiveLimiterConfig(preset: AdaptiveLimiterPreset, overrides?: AdaptiveLimiterConfig): AdaptiveLimiterConfig;
458
+ /**
459
+ * Validates the adaptive limiter configuration.
460
+ * Throws a descriptive error for invalid combinations.
461
+ */
462
+ declare function validateConfig(config: AdaptiveLimiterConfig): void;
463
+ /**
464
+ * Resolves a partial configuration into a fully-resolved configuration with defaults applied.
465
+ * Handles minLimit > maxLimit by treating minLimit as the effective maxLimit.
466
+ */
467
+ declare function resolveConfig(config?: AdaptiveLimiterConfig): ResolvedConfig;
468
+
469
+ /**
470
+ * Adaptive concurrency limiter that dynamically adjusts the number of concurrent
471
+ * requests based on observed latency patterns using a gradient-based algorithm.
472
+ */
473
+ declare class AdaptiveLimiter {
474
+ private readonly config;
475
+ private readonly states;
476
+ private destroyed;
477
+ constructor(config?: AdaptiveLimiterConfig);
478
+ /** Key resolver for external use by the HTTP client. */
479
+ get keyResolver(): HttpPoolKeyResolver | undefined;
480
+ /**
481
+ * Acquire a concurrency slot for the given key.
482
+ * Resolves immediately if under the limit, otherwise queues the request.
483
+ * Rejects with PoolRejected if the queue is full, or PoolTimeout if the queue timeout expires.
484
+ */
485
+ acquire(key: string, signal: AbortSignal, options?: AdaptiveAcquireOptions): Promise<AdaptiveLease>;
486
+ /**
487
+ * Get stats for a specific key, or aggregate stats if no key is provided.
488
+ */
489
+ stats(key?: string): AdaptiveLimiterStats;
490
+ /** Return the currently retained per-key state identifiers. */
491
+ keys(): readonly string[];
492
+ /** Return a diagnostic snapshot for one retained key, if present. */
493
+ snapshot(key: string): AdaptiveLimiterKeySnapshot | undefined;
494
+ /** Return a full diagnostic dump across all retained keys. */
495
+ dump(): AdaptiveLimiterDiagnostics;
496
+ /** Return retained limit-change history for one key, or all keys if omitted. */
497
+ history(key?: string): readonly LimitChangeEvent[];
498
+ /**
499
+ * Circuit-breaker feedback hook. When a circuit is already open for `key`,
500
+ * collapse that key's limit to minLimit immediately instead of waiting for
501
+ * latency gradients to discover the saturation indirectly.
502
+ */
503
+ markCircuitOpen(key: string): void;
504
+ /** Destroy the limiter, reject queued waiters, clear timers, and drop state. */
505
+ destroy(): void;
506
+ /** Alias for destroy(), useful for graceful shutdown code paths. */
507
+ shutdown(): void;
508
+ private getOrCreateState;
509
+ private makeLease;
510
+ private recordAndAdjust;
511
+ private tryWarmup;
512
+ private baselineLatency;
513
+ private lowLatencySample;
514
+ private isErrorSignal;
515
+ private combineGradientWithErrors;
516
+ private windowPercentile;
517
+ private recordSaturation;
518
+ private applyLimit;
519
+ private recordLimitChange;
520
+ private resolveHeadroom;
521
+ private nextProbeInterval;
522
+ private enqueueWaiter;
523
+ private dequeueWaiter;
524
+ private tryEvictLowerPriorityWaiter;
525
+ private suggestedBackoffMs;
526
+ private drain;
527
+ private currentLatency;
528
+ private touch;
529
+ private scheduleIdleEviction;
530
+ private clearIdleTimer;
531
+ private evictIdleStates;
532
+ private evictIdleState;
533
+ private cleanupWaiter;
534
+ private removeWaiter;
535
+ private stateToStats;
536
+ private stateToKeySnapshot;
537
+ }
538
+
539
+ type HttpError = {
540
+ _tag: "Abort";
541
+ } | {
542
+ _tag: "BadUrl";
543
+ message: string;
544
+ } | {
545
+ _tag: "FetchError";
546
+ message: string;
547
+ } | {
548
+ _tag: "Timeout";
549
+ timeoutMs: number;
550
+ message: string;
551
+ phase?: "request" | "queue" | "retry";
552
+ } | {
553
+ _tag: "PoolRejected";
554
+ key: string;
555
+ limit: number;
556
+ message: string;
557
+ retryAfterMs?: number;
558
+ } | {
559
+ _tag: "PoolTimeout";
560
+ key: string;
561
+ timeoutMs: number;
562
+ message: string;
563
+ } | {
564
+ _tag: "PoolClosed";
565
+ key: string;
566
+ message: string;
567
+ } | {
568
+ _tag: "BatchSplitError";
569
+ expected: number;
570
+ actual: number;
571
+ message: string;
572
+ };
573
+ type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
574
+ type HttpInit = Omit<RequestInit, "method" | "body" | "headers">;
575
+ type HttpBody = string | Uint8Array | ArrayBuffer;
576
+ type HttpRequest = {
577
+ method: HttpMethod;
578
+ url: string;
579
+ headers?: Record<string, string>;
580
+ body?: HttpBody;
581
+ init?: HttpInit;
582
+ /** Per-request override for `MakeHttpConfig.timeoutMs`. */
583
+ timeoutMs?: number;
584
+ /** Optional stable key for downstream isolation. When omitted, the pool uses origin/host/global config. */
585
+ poolKey?: string;
586
+ };
587
+ type HttpWireResponse = {
588
+ status: number;
589
+ statusText: string;
590
+ headers: Record<string, string>;
591
+ bodyText: string;
592
+ ms: number;
593
+ };
594
+ type HttpClientStats = {
595
+ readonly inFlight: number;
596
+ readonly started: number;
597
+ readonly succeeded: number;
598
+ readonly failed: number;
599
+ readonly aborted: number;
600
+ readonly timedOut: number;
601
+ readonly poolRejected: number;
602
+ readonly poolTimeouts: number;
603
+ readonly lastDurationMs?: number;
604
+ readonly pool?: HttpPoolStats;
605
+ readonly adaptiveLimiter?: AdaptiveLimiterStats;
606
+ };
607
+ type MakeHttpConfig = {
608
+ baseUrl?: string;
609
+ headers?: Record<string, string>;
610
+ /** Request budget covering pool wait + fetch + body read. Disabled when omitted. */
611
+ timeoutMs?: number;
612
+ /** Downstream pool/concurrency limiter. Disabled by default to preserve existing behavior. */
613
+ pool?: false | HttpPoolConfig;
614
+ /** Adaptive concurrency limiter. Replaces fixed pool when enabled. */
615
+ adaptiveLimiter?: false | AdaptiveLimiterConfig;
616
+ };
617
+ type HttpWireResponseStream = {
618
+ status: number;
619
+ statusText: string;
620
+ headers: Record<string, string>;
621
+ body: ZStream<unknown, HttpError, Uint8Array>;
622
+ ms: number;
623
+ };
624
+ type HttpClientStreamFn = (req: HttpRequest) => Async<unknown, HttpError, HttpWireResponseStream>;
625
+ type HttpClientStream = HttpClientStreamFn & {
626
+ stats: () => HttpClientStats;
627
+ };
628
+ type HttpClientFn = (req: HttpRequest) => Async<unknown, HttpError, HttpWireResponse>;
629
+ type HttpMiddleware = (next: HttpClientFn) => HttpClientFn;
630
+ type HttpClient = HttpClientFn & {
631
+ with: (mw: HttpMiddleware) => HttpClient;
632
+ stats: () => HttpClientStats;
633
+ adaptiveLimiter?: AdaptiveLimiter;
634
+ destroy?: () => void;
635
+ shutdown?: () => void;
636
+ };
637
+ type HttpClientMetadata = Pick<HttpClient, "adaptiveLimiter" | "destroy" | "shutdown">;
638
+ declare const decorate: (run: HttpClientFn, stats?: () => HttpClientStats, metadata?: HttpClientMetadata) => HttpClient;
639
+ declare const withMiddleware: (mw: HttpMiddleware) => (c: HttpClient) => HttpClient;
640
+ declare const normalizeHeadersInit: (h: any) => Record<string, string> | undefined;
641
+ declare function makeHttpStream(cfg?: MakeHttpConfig): HttpClientStream;
642
+ declare function makeHttp(cfg?: MakeHttpConfig): HttpClient;
643
+ declare const withRetryStream: (p: RetryPolicy) => (next: HttpClientStream) => HttpClientStream;
644
+
645
+ export { resolveHttpPoolKey as $, type AdaptiveLimiterStats as A, HttpConcurrencyPool as B, type HttpInit as C, type HttpPoolKeyResolver as D, type HttpPoolKeyStats as E, type HttpPoolLease as F, type HttpPoolStats as G, type HttpClient as H, type ResolvedConfig as I, type RetryEvent as J, type RetryScheduleInput as K, type LimitChangeEvent as L, type MakeHttpConfig as M, adaptiveLimiterPresets as N, backoffDelayMs as O, type PerRequestRetryOverride as P, decorate as Q, type RetryPolicy as R, defaultRetryOnError as S, defaultRetryOnStatus as T, defaultRetryableMethods as U, makeAdaptiveLimiterConfig as V, makeHttp as W, makeHttpStream as X, normalizeHeadersInit as Y, normalizeRetryBudget as Z, resolveConfig as _, type HttpRequest as a, retryAfterMs as a0, validateConfig as a1, withMiddleware as a2, withRetry as a3, withRetryStream as a4, type HttpWireResponse as b, type HttpError as c, type HttpMiddleware as d, type HttpClientFn as e, type HttpWireResponseStream as f, type HttpClientStream as g, type HttpClientStats as h, AdaptiveLimiter as i, type AdaptiveLimiterConfig as j, type HttpMethod as k, type AdaptiveLimiterPreset as l, type HttpPoolConfig as m, type AdaptiveAcquireOptions as n, type AdaptiveBaselineStrategy as o, type AdaptiveHeadroomContext as p, type AdaptiveHeadroomMode as q, type AdaptiveHeadroomStrategy as r, type AdaptiveLease as s, type AdaptiveLimiterDiagnostics as t, type AdaptiveLimiterKeySnapshot as u, type AdaptiveQueueLoadShedding as v, type AdaptiveQueueStrategy as w, type AdaptiveReleaseInfo as x, type HttpBody as y, type HttpClientStreamFn as z };