@providerkit/core 0.22.0 → 0.24.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.
- package/README.md +29 -7
- package/dist/auth/flows.d.ts.map +1 -1
- package/dist/auth/flows.js +5 -5
- package/dist/auth/flows.js.map +1 -1
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +1 -0
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/oauth.d.ts +12 -0
- package/dist/auth/oauth.d.ts.map +1 -1
- package/dist/auth/oauth.js +19 -1
- package/dist/auth/oauth.js.map +1 -1
- package/dist/auth/token-source.d.ts +9 -3
- package/dist/auth/token-source.d.ts.map +1 -1
- package/dist/auth/token-source.js +24 -9
- package/dist/auth/token-source.js.map +1 -1
- package/dist/auth/with-token.d.ts +32 -0
- package/dist/auth/with-token.d.ts.map +1 -0
- package/dist/auth/with-token.js +88 -0
- package/dist/auth/with-token.js.map +1 -0
- package/dist/context.d.ts +39 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +119 -0
- package/dist/context.js.map +1 -1
- package/dist/errors.d.ts +12 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +44 -5
- package/dist/errors.js.map +1 -1
- package/dist/fallback.d.ts +45 -1
- package/dist/fallback.d.ts.map +1 -1
- package/dist/fallback.js +138 -75
- package/dist/fallback.js.map +1 -1
- package/dist/gate.d.ts +29 -0
- package/dist/gate.d.ts.map +1 -0
- package/dist/gate.js +96 -0
- package/dist/gate.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/key-pool.d.ts +21 -4
- package/dist/key-pool.d.ts.map +1 -1
- package/dist/key-pool.js +43 -12
- package/dist/key-pool.js.map +1 -1
- package/dist/presets.d.ts +7 -2
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +12 -2
- package/dist/presets.js.map +1 -1
- package/dist/providers/anthropic.d.ts +7 -0
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +83 -26
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/factory.d.ts +26 -0
- package/dist/providers/factory.d.ts.map +1 -1
- package/dist/providers/factory.js +41 -9
- package/dist/providers/factory.js.map +1 -1
- package/dist/providers/gemini.d.ts +6 -0
- package/dist/providers/gemini.d.ts.map +1 -1
- package/dist/providers/gemini.js +102 -27
- package/dist/providers/gemini.js.map +1 -1
- package/dist/providers/openai.d.ts +7 -0
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +66 -15
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/responses.d.ts +11 -0
- package/dist/providers/responses.d.ts.map +1 -1
- package/dist/providers/responses.js +101 -53
- package/dist/providers/responses.js.map +1 -1
- package/dist/rate-limit.d.ts +10 -0
- package/dist/rate-limit.d.ts.map +1 -1
- package/dist/rate-limit.js +7 -1
- package/dist/rate-limit.js.map +1 -1
- package/dist/registry.d.ts +105 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +291 -0
- package/dist/registry.js.map +1 -0
- package/dist/retry.d.ts +11 -0
- package/dist/retry.d.ts.map +1 -1
- package/dist/retry.js +25 -12
- package/dist/retry.js.map +1 -1
- package/dist/tool-args.d.ts +22 -0
- package/dist/tool-args.d.ts.map +1 -1
- package/dist/tool-args.js +28 -0
- package/dist/tool-args.js.map +1 -1
- package/dist/tools.d.ts +8 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +2 -2
- package/dist/tools.js.map +1 -1
- package/dist/transport.d.ts +34 -4
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +77 -16
- package/dist/transport.js.map +1 -1
- package/dist/turn.d.ts +55 -0
- package/dist/turn.d.ts.map +1 -0
- package/dist/turn.js +125 -0
- package/dist/turn.js.map +1 -0
- package/dist/types.d.ts +21 -22
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -53
- package/dist/types.js.map +1 -1
- package/dist/watchdog.d.ts +2 -0
- package/dist/watchdog.d.ts.map +1 -1
- package/dist/watchdog.js +25 -6
- package/dist/watchdog.js.map +1 -1
- package/package.json +1 -1
- package/src/auth/flows.ts +5 -4
- package/src/auth/index.ts +1 -0
- package/src/auth/oauth.ts +23 -1
- package/src/auth/token-source.ts +30 -11
- package/src/auth/with-token.ts +100 -0
- package/src/context.ts +137 -2
- package/src/errors.ts +46 -6
- package/src/fallback.ts +173 -75
- package/src/gate.ts +152 -0
- package/src/index.ts +3 -0
- package/src/key-pool.ts +45 -13
- package/src/presets.ts +12 -2
- package/src/providers/anthropic.ts +93 -25
- package/src/providers/factory.ts +66 -21
- package/src/providers/gemini.ts +102 -28
- package/src/providers/openai.ts +71 -14
- package/src/providers/responses.ts +116 -51
- package/src/rate-limit.ts +31 -3
- package/src/registry.ts +420 -0
- package/src/retry.ts +41 -10
- package/src/tool-args.ts +44 -0
- package/src/tools.ts +10 -2
- package/src/transport.ts +97 -17
- package/src/turn.ts +166 -0
- package/src/types.ts +21 -62
- package/src/watchdog.ts +25 -6
package/dist/fallback.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { classify, parseRetryAfterMs, ProviderError } from "./errors.js";
|
|
2
|
-
import {
|
|
2
|
+
import { sleep } from "./retry.js";
|
|
3
|
+
import { STREAM_PROGRESS_MS, withWatchdog } from "./watchdog.js";
|
|
3
4
|
import { createPresetProvider } from "./providers/factory.js";
|
|
4
5
|
/** Retry intervals when the server supplies no deadline, not estimates of when
|
|
5
6
|
* it will recover. A server deadline always wins over these defaults. */
|
|
@@ -37,6 +38,30 @@ export function withConfiguredFallbacks(primary, config) {
|
|
|
37
38
|
...config.fallbacks.map((candidate) => resolveFallback(candidate, config.watchdog)),
|
|
38
39
|
], config.fallbackOptions);
|
|
39
40
|
}
|
|
41
|
+
function openProbe(since) {
|
|
42
|
+
let settle = () => { };
|
|
43
|
+
const settled = new Promise((resolve) => {
|
|
44
|
+
settle = resolve;
|
|
45
|
+
});
|
|
46
|
+
return { since, settled, settle };
|
|
47
|
+
}
|
|
48
|
+
/** How many times a call that found nothing free waits on a probe before it
|
|
49
|
+
* fails. The first wait covers a probe that answers or fails. The second
|
|
50
|
+
* covers one that ended with neither (its own caller stopped it) and was
|
|
51
|
+
* taken over by another waiter. Past that the caller's own retry decides. */
|
|
52
|
+
const PROBE_WAITS = 2;
|
|
53
|
+
/** Resolve when any probe settles or `ms` passes. Rejects with the caller's
|
|
54
|
+
* reason on abort, and leaves no timer running once a probe wins. */
|
|
55
|
+
async function waitForProbe(settled, ms, signal) {
|
|
56
|
+
const done = new AbortController();
|
|
57
|
+
const wake = signal ? AbortSignal.any([signal, done.signal]) : done.signal;
|
|
58
|
+
try {
|
|
59
|
+
await Promise.race([...settled, sleep(Math.max(0, ms), wake)]);
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
done.abort();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
40
65
|
/** The whole chain is unavailable. Fail promptly instead of holding a request
|
|
41
66
|
* open for hours. `retryAtMs` names its next opportunity, not a sleep to cap. */
|
|
42
67
|
export class NoAvailableProviderError extends ProviderError {
|
|
@@ -57,7 +82,8 @@ export class NoAvailableProviderError extends ProviderError {
|
|
|
57
82
|
export class FallbackPool {
|
|
58
83
|
options;
|
|
59
84
|
candidates;
|
|
60
|
-
cooldowns
|
|
85
|
+
cooldowns;
|
|
86
|
+
probeStaleMs;
|
|
61
87
|
now;
|
|
62
88
|
constructor(candidates, options = {}) {
|
|
63
89
|
this.options = options;
|
|
@@ -72,23 +98,29 @@ export class FallbackPool {
|
|
|
72
98
|
}
|
|
73
99
|
}
|
|
74
100
|
this.candidates = [...candidates];
|
|
101
|
+
this.cooldowns = options.cooldowns ?? new Map();
|
|
102
|
+
this.probeStaleMs = options.probeStaleMs ?? STREAM_PROGRESS_MS;
|
|
103
|
+
if (!Number.isFinite(this.probeStaleMs) || this.probeStaleMs < 0) {
|
|
104
|
+
throw new Error("providerkit: probeStaleMs must be finite, non-negative milliseconds");
|
|
105
|
+
}
|
|
75
106
|
this.now = options.now ?? Date.now;
|
|
76
107
|
}
|
|
77
108
|
/** Clear a cooldown after replacing a key or fixing configuration. Omit the
|
|
78
|
-
* candidate to clear all
|
|
109
|
+
* candidate to clear all of this pool's own; a shared store keeps the benches
|
|
110
|
+
* of candidates only other pools hold. Does not interrupt calls in flight. */
|
|
79
111
|
reset(...selection) {
|
|
80
|
-
|
|
81
|
-
this.cooldowns.
|
|
82
|
-
|
|
83
|
-
this.cooldowns.delete(selection[0]);
|
|
112
|
+
for (const candidate of selection.length === 0 ? this.candidates : selection) {
|
|
113
|
+
this.cooldowns.delete(candidate);
|
|
114
|
+
}
|
|
84
115
|
}
|
|
85
116
|
status() {
|
|
86
|
-
return this.candidates.map((candidate) =>
|
|
87
|
-
candidate
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
...
|
|
91
|
-
|
|
117
|
+
return this.candidates.map((candidate) => {
|
|
118
|
+
const cooldown = this.cooldowns.get(candidate);
|
|
119
|
+
if (!cooldown)
|
|
120
|
+
return { candidate, retryAtMs: 0, probing: false };
|
|
121
|
+
const { probe, ...bench } = cooldown;
|
|
122
|
+
return { candidate, ...bench, probing: probe !== undefined };
|
|
123
|
+
});
|
|
92
124
|
}
|
|
93
125
|
/** Buffered calls only: do not wrap an agent turn that has run side effects. */
|
|
94
126
|
async with(attempt, signal) {
|
|
@@ -104,74 +136,105 @@ export class FallbackPool {
|
|
|
104
136
|
signal?.throwIfAborted();
|
|
105
137
|
let hasFailed = false;
|
|
106
138
|
let lastError;
|
|
107
|
-
for (
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
139
|
+
for (let round = 0;; round++) {
|
|
140
|
+
const probing = [];
|
|
141
|
+
for (const candidate of this.candidates) {
|
|
142
|
+
signal?.throwIfAborted();
|
|
143
|
+
const previous = this.cooldowns.get(candidate);
|
|
144
|
+
if (previous && previous.retryAtMs > this.now())
|
|
145
|
+
continue;
|
|
146
|
+
if (previous?.probe && this.now() - previous.probe.since < this.probeStaleMs) {
|
|
147
|
+
probing.push(previous.probe);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
// One recovery probe after expiry. Healthy endpoints still allow normal
|
|
151
|
+
// concurrency; only a known failed endpoint gets a single probe. A stale
|
|
152
|
+
// one is replaced: it hung, and holding the candidate for it is an outage.
|
|
153
|
+
const probe = previous ? openProbe(this.now()) : undefined;
|
|
154
|
+
if (previous)
|
|
155
|
+
previous.probe = probe;
|
|
156
|
+
const controller = new AbortController();
|
|
157
|
+
const inner = signal ? AbortSignal.any([signal, controller.signal]) : controller.signal;
|
|
158
|
+
let emitted = false;
|
|
159
|
+
try {
|
|
160
|
+
for await (const chunk of attempt(candidate, inner)) {
|
|
161
|
+
inner.throwIfAborted();
|
|
162
|
+
if (!emitted) {
|
|
163
|
+
this.recovered(candidate, previous);
|
|
164
|
+
probe?.settle();
|
|
165
|
+
}
|
|
166
|
+
emitted = true;
|
|
167
|
+
yield chunk;
|
|
129
168
|
}
|
|
130
|
-
|
|
169
|
+
inner.throwIfAborted();
|
|
170
|
+
if (!emitted)
|
|
171
|
+
this.recovered(candidate, previous);
|
|
172
|
+
return;
|
|
131
173
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
174
|
+
catch (error) {
|
|
175
|
+
signal?.throwIfAborted();
|
|
176
|
+
const kind = classify(error);
|
|
177
|
+
if (kind === "aborted")
|
|
178
|
+
throw error;
|
|
179
|
+
const configured = this.options.cooldownMs?.[kind];
|
|
180
|
+
const interval = configured === undefined ? DEFAULT_FALLBACK_COOLDOWNS[kind] : configured;
|
|
181
|
+
if (interval === undefined || interval === null)
|
|
182
|
+
throw error;
|
|
183
|
+
const now = this.now();
|
|
184
|
+
const after = parseRetryAfterMs(error);
|
|
185
|
+
const reset = error instanceof ProviderError ? error.resetAtMs : undefined;
|
|
186
|
+
const hints = [reset, after === undefined ? undefined : now + after].filter((value) => value !== undefined && Number.isFinite(value));
|
|
187
|
+
const retryAtMs = Math.max(now, ...(hints.length ? hints : [now + interval]), this.cooldowns.get(candidate)?.retryAtMs ?? 0);
|
|
188
|
+
const window = error instanceof ProviderError ? error.window : undefined;
|
|
189
|
+
this.cooldowns.set(candidate, { retryAtMs, kind, window });
|
|
190
|
+
this.options.onCooldown?.({ candidate, error, kind, retryAtMs, window });
|
|
191
|
+
hasFailed = true;
|
|
192
|
+
lastError = error;
|
|
193
|
+
if (emitted)
|
|
194
|
+
throw error;
|
|
135
195
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
throw error;
|
|
147
|
-
const now = this.now();
|
|
148
|
-
const after = parseRetryAfterMs(error);
|
|
149
|
-
const reset = error instanceof ProviderError ? error.resetAtMs : undefined;
|
|
150
|
-
const hints = [reset, after === undefined ? undefined : now + after].filter((value) => value !== undefined && Number.isFinite(value));
|
|
151
|
-
const retryAtMs = Math.max(now, ...(hints.length ? hints : [now + interval]), this.cooldowns.get(candidate)?.retryAtMs ?? 0);
|
|
152
|
-
const window = error instanceof ProviderError ? error.window : undefined;
|
|
153
|
-
this.cooldowns.set(candidate, { retryAtMs, kind, window, probing: false });
|
|
154
|
-
this.options.onCooldown?.({ candidate, error, kind, retryAtMs, window });
|
|
155
|
-
attemptFailed = true;
|
|
156
|
-
hasFailed = true;
|
|
157
|
-
lastError = error;
|
|
158
|
-
if (emitted)
|
|
159
|
-
throw error;
|
|
160
|
-
}
|
|
161
|
-
finally {
|
|
162
|
-
controller.abort();
|
|
163
|
-
const current = this.cooldowns.get(candidate);
|
|
164
|
-
if (current && current.probing && !attemptFailed) {
|
|
165
|
-
current.probing = false;
|
|
196
|
+
finally {
|
|
197
|
+
controller.abort();
|
|
198
|
+
// Only the owner releases its probe. Clearing whatever probe was set
|
|
199
|
+
// let a stale probe that ended late free the one that replaced it, and
|
|
200
|
+
// any call that did not fail let a second probe in.
|
|
201
|
+
if (probe) {
|
|
202
|
+
if (previous?.probe === probe)
|
|
203
|
+
previous.probe = undefined;
|
|
204
|
+
probe.settle();
|
|
205
|
+
}
|
|
166
206
|
}
|
|
167
207
|
}
|
|
208
|
+
if (hasFailed)
|
|
209
|
+
throw lastError;
|
|
210
|
+
// Nothing was free, and a probe is deciding whether something will be.
|
|
211
|
+
// Failing here answered a 0 ms retry, which `withRetry` spent at once: at
|
|
212
|
+
// 70 concurrent calls every one but the probe failed. Wait for a probe to
|
|
213
|
+
// answer or end, or until the oldest goes stale, then look again.
|
|
214
|
+
if (probing.length > 0 && round < PROBE_WAITS) {
|
|
215
|
+
const staleAt = Math.min(...probing.map((probe) => probe.since + this.probeStaleMs));
|
|
216
|
+
await waitForProbe(probing.map((probe) => probe.settled), staleAt - this.now(), signal);
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
// Every candidate is cooling, or its probe outlasted the waits; a probe
|
|
220
|
+
// still in flight makes the next opportunity now.
|
|
221
|
+
const retryAtMs = Math.min(...this.status().map((entry) => Math.max(this.now(), entry.retryAtMs)));
|
|
222
|
+
throw new NoAvailableProviderError(retryAtMs, this.now());
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/** An answer proves the candidate serves again. It lifts the bench this call
|
|
226
|
+
* was admitted under as the probe, and any bench a sibling set while it ran:
|
|
227
|
+
* a call that started before one stray 401 and then answered used to leave
|
|
228
|
+
* a busy primary benched for an hour. Rate and quota stay. A call that
|
|
229
|
+
* started before the throttle proves nothing about the window, and lifting
|
|
230
|
+
* it walks every caller back into the 429. */
|
|
231
|
+
recovered(candidate, admittedUnder) {
|
|
232
|
+
const current = this.cooldowns.get(candidate);
|
|
233
|
+
if (!current)
|
|
234
|
+
return;
|
|
235
|
+
if (current === admittedUnder || (current.kind !== "rate" && current.kind !== "quota")) {
|
|
236
|
+
this.cooldowns.delete(candidate);
|
|
168
237
|
}
|
|
169
|
-
if (hasFailed)
|
|
170
|
-
throw lastError;
|
|
171
|
-
// If all expired candidates are already being probed, the next opportunity
|
|
172
|
-
// is now. Other callers need not wait for those probes or start duplicates.
|
|
173
|
-
const retryAtMs = Math.min(...this.status().map((entry) => Math.max(this.now(), entry.retryAtMs)));
|
|
174
|
-
throw new NoAvailableProviderError(retryAtMs, this.now());
|
|
175
238
|
}
|
|
176
239
|
}
|
|
177
240
|
/** Compose bound provider/model pairs. Identity names the configured primary;
|
package/dist/fallback.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fallback.js","sourceRoot":"","sources":["../src/fallback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,aAAa,EAAkB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"fallback.js","sourceRoot":"","sources":["../src/fallback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,aAAa,EAAkB,MAAM,aAAa,CAAC;AAGzF,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAwB,MAAM,eAAe,CAAC;AACvF,OAAO,EAAE,oBAAoB,EAA6B,MAAM,wBAAwB,CAAC;AAEzF;0EAC0E;AAC1E,MAAM,CAAC,MAAM,0BAA0B,GACrC,MAAM,CAAC,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,SAAS;IAChB,OAAO,EAAE,MAAM;IACf,OAAO,EAAE,MAAM;IACf,QAAQ,EAAE,MAAM;IAChB,IAAI,EAAE,SAAS;IACf,WAAW,EAAE,SAAS;IACtB,KAAK,EAAE,SAAS;CACjB,CAAC,CAAC;AA2CL,SAAS,eAAe,CACtB,SAA4B,EAC5B,iBAAmC;IAEnC,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,IAAI,IAAI,cAAc,IAAI,SAAS,EAAE,CAAC;QACvF,OAAO,iBAAiB,CAAC,CAAC,CAAC,YAAY,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACpF,CAAC;IACD,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,iBAAiB,EAAE,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;IACtE,OAAO,oBAAoB,CAAC,MAAM,EAAE;QAClC,GAAG,MAAM;QACT,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAClC,CAAC,CAAC;AACL,CAAC;AAeD;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,OAAiB,EACjB,MAA+B;IAE/B,MAAM,cAAc,GAAG,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC3F,IAAI,CAAC,MAAM,EAAE,SAAS,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,cAAc,CAAC;IAC/E,OAAO,qBAAqB,CAC1B;QACE,cAAc;QACd,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,eAAe,CAAC,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;KACpF,EACD,MAAM,CAAC,eAAe,CACvB,CAAC;AACJ,CAAC;AAqBD,SAAS,SAAS,CAAC,KAAa;IAC9B,IAAI,MAAM,GAAG,GAAS,EAAE,GAAE,CAAC,CAAC;IAC5B,MAAM,OAAO,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAC5C,MAAM,GAAG,OAAO,CAAC;IACnB,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AACpC,CAAC;AAED;;;8EAG8E;AAC9E,MAAM,WAAW,GAAG,CAAC,CAAC;AAEtB;sEACsE;AACtE,KAAK,UAAU,YAAY,CACzB,OAAiC,EACjC,EAAU,EACV,MAAoB;IAEpB,MAAM,IAAI,GAAG,IAAI,eAAe,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IAC3E,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACjE,CAAC;YAAS,CAAC;QACT,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;AACH,CAAC;AAED;kFACkF;AAClF,MAAM,OAAO,wBAAyB,SAAQ,aAAa;IAChD,SAAS,CAAS;IAE3B,YAAY,SAAiB,EAAE,GAAW;QACxC,KAAK,CACH,UAAU,EACV,MAAM,EACN,qEAAqE,EACrE;YACE,SAAS,EAAE,SAAS;YACpB,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC;SAC3C,CACF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;QACvC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF;AAED;;;oEAGoE;AACpE,MAAM,OAAO,YAAY;IAQJ;IAPF,UAAU,CAAe;IACzB,SAAS,CAAmB;IAC5B,YAAY,CAAS;IACrB,GAAG,CAAe;IAEnC,YACE,UAAwB,EACP,UAA8B,EAAE;QAAhC,YAAO,GAAP,OAAO,CAAyB;QAEjD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACtE,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,MAAM,EAAE,CAAC;YACnD,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;QAChF,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,CAAC;YAC5D,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC;gBACpF,MAAM,IAAI,KAAK,CACb,2EAA2E,CAC5E,CAAC;YACJ,CAAC;QACH,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;QAClC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,GAAG,EAAE,CAAC;QAChD,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,kBAAkB,CAAC;QAC/D,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,YAAY,GAAG,CAAC,EAAE,CAAC;YACjE,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;QACzF,CAAC;QACD,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACrC,CAAC;IAED;;mFAE+E;IAC/E,KAAK,CAAC,GAAG,SAAmB;QAC1B,KAAK,MAAM,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;YAC7E,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED,MAAM;QAOJ,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE;YACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAC/C,IAAI,CAAC,QAAQ;gBAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YAClE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,GAAG,QAAQ,CAAC;YACrC,OAAO,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/D,CAAC,CAAC,CAAC;IACL,CAAC;IAED,gFAAgF;IAChF,KAAK,CAAC,IAAI,CACR,OAA0D,EAC1D,MAAoB;QAEpB,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,SAAS,CAAC,EAAE,SAAS,EAAE,KAAK;YACtE,MAAM,MAAM,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACxC,CAAC,EAAE,MAAM,CAAC;YACR,OAAO,MAAM,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IAED;qFACiF;IACjF,KAAK,CAAC,CAAC,MAAM,CACX,OAAgE,EAChE,MAAoB;QAEpB,MAAM,EAAE,cAAc,EAAE,CAAC;QACzB,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,IAAI,SAAkB,CAAC;QACvB,KAAK,IAAI,KAAK,GAAG,CAAC,GAAI,KAAK,EAAE,EAAE,CAAC;YAC9B,MAAM,OAAO,GAA0C,EAAE,CAAC;YAC1D,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACxC,MAAM,EAAE,cAAc,EAAE,CAAC;gBACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBAC/C,IAAI,QAAQ,IAAI,QAAQ,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE;oBAAE,SAAS;gBAC1D,IAAI,QAAQ,EAAE,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;oBAC7E,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;oBAC7B,SAAS;gBACX,CAAC;gBACD,wEAAwE;gBACxE,yEAAyE;gBACzE,2EAA2E;gBAC3E,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC3D,IAAI,QAAQ;oBAAE,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAC;gBACrC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;gBACzC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC;gBACxF,IAAI,OAAO,GAAG,KAAK,CAAC;gBACpB,IAAI,CAAC;oBACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC;wBACpD,KAAK,CAAC,cAAc,EAAE,CAAC;wBACvB,IAAI,CAAC,OAAO,EAAE,CAAC;4BACb,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;4BACpC,KAAK,EAAE,MAAM,EAAE,CAAC;wBAClB,CAAC;wBACD,OAAO,GAAG,IAAI,CAAC;wBACf,MAAM,KAAK,CAAC;oBACd,CAAC;oBACD,KAAK,CAAC,cAAc,EAAE,CAAC;oBACvB,IAAI,CAAC,OAAO;wBAAE,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;oBAClD,OAAO;gBACT,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,EAAE,cAAc,EAAE,CAAC;oBACzB,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;oBAC7B,IAAI,IAAI,KAAK,SAAS;wBAAE,MAAM,KAAK,CAAC;oBACpC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC;oBACnD,MAAM,QAAQ,GAAG,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;oBAC1F,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,IAAI;wBAAE,MAAM,KAAK,CAAC;oBAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;oBACvB,MAAM,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;oBACvC,MAAM,KAAK,GAAG,KAAK,YAAY,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;oBAC3E,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC,MAAM,CACzE,CAAC,KAAK,EAAmB,EAAE,CAAC,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAC1E,CAAC;oBACF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CACxB,GAAG,EACH,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,QAAQ,CAAC,CAAC,EAC5C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,SAAS,IAAI,CAAC,CAC9C,CAAC;oBACF,MAAM,MAAM,GAAG,KAAK,YAAY,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;oBACzE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;oBAC3D,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;oBACzE,SAAS,GAAG,IAAI,CAAC;oBACjB,SAAS,GAAG,KAAK,CAAC;oBAClB,IAAI,OAAO;wBAAE,MAAM,KAAK,CAAC;gBAC3B,CAAC;wBAAS,CAAC;oBACT,UAAU,CAAC,KAAK,EAAE,CAAC;oBACnB,qEAAqE;oBACrE,uEAAuE;oBACvE,oDAAoD;oBACpD,IAAI,KAAK,EAAE,CAAC;wBACV,IAAI,QAAQ,EAAE,KAAK,KAAK,KAAK;4BAAE,QAAQ,CAAC,KAAK,GAAG,SAAS,CAAC;wBAC1D,KAAK,CAAC,MAAM,EAAE,CAAC;oBACjB,CAAC;gBACH,CAAC;YACH,CAAC;YACD,IAAI,SAAS;gBAAE,MAAM,SAAS,CAAC;YAC/B,uEAAuE;YACvE,0EAA0E;YAC1E,0EAA0E;YAC1E,kEAAkE;YAClE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,GAAG,WAAW,EAAE,CAAC;gBAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;gBACrF,MAAM,YAAY,CAChB,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,EACrC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,EACpB,MAAM,CACP,CAAC;gBACF,SAAS;YACX,CAAC;YACD,wEAAwE;YACxE,kDAAkD;YAClD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CACxB,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CACvE,CAAC;YACF,MAAM,IAAI,wBAAwB,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAED;;;;;mDAK+C;IACvC,SAAS,CAAC,SAAY,EAAE,aAAmC;QACjE,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,IAAI,OAAO,KAAK,aAAa,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,EAAE,CAAC;YACvF,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;CACF;AAMD;;;sEAGsE;AACtE,MAAM,UAAU,qBAAqB,CACnC,SAA8B,EAC9B,UAAqC,EAAE;IAEvC,MAAM,SAAS,GAAG,IAAI,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAE,CAAC;IAC9B,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,SAAS;QACT,YAAY,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE;YACrC,OAAO,SAAS,CAAC,MAAM,CAAC,KAAK,SAAS,CAAC,EAAE,QAAQ,EAAE,MAAM;gBACvD,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;gBAC1C,MAAM,KAAK,GAAG,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;gBACnF,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,QAAQ,CAAC,YAAY,CAAC,QAAQ,EAAE,KAAK,EAAE;oBAC/D,GAAG,IAAI;oBACP,KAAK;oBACL,MAAM;iBACP,CAAC,EAAE,CAAC;oBACH,MAAM,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC;gBAC/E,CAAC;YACH,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/gate.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Provider } from "./types.ts";
|
|
2
|
+
export interface Gate {
|
|
3
|
+
/** How many calls may hold a slot at once. */
|
|
4
|
+
readonly max: number;
|
|
5
|
+
/** How many slots are held right now. */
|
|
6
|
+
readonly held: number;
|
|
7
|
+
/** How many calls are queued for a slot. */
|
|
8
|
+
readonly waiting: number;
|
|
9
|
+
/**
|
|
10
|
+
* Wait for a slot, first in, first out. Resolves to its release, which is
|
|
11
|
+
* safe to call more than once. The signal covers the whole life of the slot:
|
|
12
|
+
* an abort while waiting leaves the queue and rejects with `signal.reason`,
|
|
13
|
+
* and an abort while held releases it.
|
|
14
|
+
*/
|
|
15
|
+
acquire(signal?: AbortSignal): Promise<() => void>;
|
|
16
|
+
}
|
|
17
|
+
/** A gate with `max` slots. Keep one alive per connection, so every call on
|
|
18
|
+
* it shares the count. */
|
|
19
|
+
export declare function createGate(max: number): Gate;
|
|
20
|
+
/**
|
|
21
|
+
* Let a provider run at most `gate.max` calls at once.
|
|
22
|
+
*
|
|
23
|
+
* Put it outside the watchdog. The watchdog arms on its first read, and this
|
|
24
|
+
* reads it only once a slot is held, so a call queued here never spends its
|
|
25
|
+
* deadlines waiting. Inside it, a call that stood in line for five minutes
|
|
26
|
+
* would time out as a silent provider before it ever sent a byte.
|
|
27
|
+
*/
|
|
28
|
+
export declare function withGate(provider: Provider, gate: Gate): Provider;
|
|
29
|
+
//# sourceMappingURL=gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAEV,QAAQ,EAIT,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,IAAI;IACnB,8CAA8C;IAC9C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;CACpD;AAED;2BAC2B;AAC3B,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CA8D5C;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,GAAG,QAAQ,CA0BjE"}
|
package/dist/gate.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/** A gate with `max` slots. Keep one alive per connection, so every call on
|
|
2
|
+
* it shares the count. */
|
|
3
|
+
export function createGate(max) {
|
|
4
|
+
if (!Number.isInteger(max) || max < 1) {
|
|
5
|
+
throw new Error(`[providerkit] A gate needs a whole number of slots, 1 or more. Got ${max}.`);
|
|
6
|
+
}
|
|
7
|
+
let held = 0;
|
|
8
|
+
const queue = [];
|
|
9
|
+
function acquire(signal) {
|
|
10
|
+
// Rejected before it queues: a caller already gone must not take a place
|
|
11
|
+
// in line, or a slot, even for a moment.
|
|
12
|
+
if (signal?.aborted)
|
|
13
|
+
return Promise.reject(signal.reason);
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
let state = "waiting";
|
|
16
|
+
const release = () => {
|
|
17
|
+
if (state !== "held")
|
|
18
|
+
return;
|
|
19
|
+
state = "released";
|
|
20
|
+
signal?.removeEventListener("abort", onAbort);
|
|
21
|
+
// Handed straight to the next waiter, so `held` never dips and a
|
|
22
|
+
// newcomer arriving now finds the gate full and queues behind them.
|
|
23
|
+
const next = queue.shift();
|
|
24
|
+
if (next)
|
|
25
|
+
next();
|
|
26
|
+
else
|
|
27
|
+
held--;
|
|
28
|
+
};
|
|
29
|
+
const grant = () => {
|
|
30
|
+
state = "held";
|
|
31
|
+
resolve(release);
|
|
32
|
+
};
|
|
33
|
+
function onAbort() {
|
|
34
|
+
if (state === "held") {
|
|
35
|
+
release();
|
|
36
|
+
}
|
|
37
|
+
else if (state === "waiting") {
|
|
38
|
+
state = "released";
|
|
39
|
+
queue.splice(queue.indexOf(grant), 1);
|
|
40
|
+
reject(signal?.reason);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (held < max) {
|
|
44
|
+
held++;
|
|
45
|
+
grant();
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
queue.push(grant);
|
|
49
|
+
}
|
|
50
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
max,
|
|
55
|
+
get held() {
|
|
56
|
+
return held;
|
|
57
|
+
},
|
|
58
|
+
get waiting() {
|
|
59
|
+
return queue.length;
|
|
60
|
+
},
|
|
61
|
+
acquire,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Let a provider run at most `gate.max` calls at once.
|
|
66
|
+
*
|
|
67
|
+
* Put it outside the watchdog. The watchdog arms on its first read, and this
|
|
68
|
+
* reads it only once a slot is held, so a call queued here never spends its
|
|
69
|
+
* deadlines waiting. Inside it, a call that stood in line for five minutes
|
|
70
|
+
* would time out as a silent provider before it ever sent a byte.
|
|
71
|
+
*/
|
|
72
|
+
export function withGate(provider, gate) {
|
|
73
|
+
return {
|
|
74
|
+
...provider,
|
|
75
|
+
createStream(messages, tools, opts = {}) {
|
|
76
|
+
// A generator, so nothing runs (the wait included) until the first read.
|
|
77
|
+
async function* gated() {
|
|
78
|
+
const release = await gate.acquire(opts.signal);
|
|
79
|
+
try {
|
|
80
|
+
// The slot can be granted and released by the same abort before this
|
|
81
|
+
// line runs (two calls sharing one signal). Such a call is over, and
|
|
82
|
+
// must not reach the wire without a slot.
|
|
83
|
+
opts.signal?.throwIfAborted();
|
|
84
|
+
yield* provider.createStream(messages, tools, opts);
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
// Covers the end, a throw and a consumer's `break`. An abort may
|
|
88
|
+
// have released it already, and a second call is a no-op.
|
|
89
|
+
release();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return gated();
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=gate.js.map
|
package/dist/gate.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
export * from "./types.ts";
|
|
2
|
+
export * from "./turn.ts";
|
|
2
3
|
export * from "./errors.ts";
|
|
3
4
|
export * from "./retry.ts";
|
|
4
5
|
export * from "./fallback.ts";
|
|
5
6
|
export * from "./key-pool.ts";
|
|
6
7
|
export * from "./watchdog.ts";
|
|
8
|
+
export * from "./gate.ts";
|
|
7
9
|
export * from "./usage.ts";
|
|
8
10
|
export * from "./transport.ts";
|
|
9
11
|
export * from "./rate-limit.ts";
|
|
@@ -21,4 +23,5 @@ export * from "./providers/responses.ts";
|
|
|
21
23
|
export * from "./providers/gemini.ts";
|
|
22
24
|
export * from "./providers/zai.ts";
|
|
23
25
|
export * from "./providers/factory.ts";
|
|
26
|
+
export * from "./registry.ts";
|
|
24
27
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
export * from "./types.js";
|
|
2
|
+
export * from "./turn.js";
|
|
2
3
|
export * from "./errors.js";
|
|
3
4
|
export * from "./retry.js";
|
|
4
5
|
export * from "./fallback.js";
|
|
5
6
|
export * from "./key-pool.js";
|
|
6
7
|
export * from "./watchdog.js";
|
|
8
|
+
export * from "./gate.js";
|
|
7
9
|
export * from "./usage.js";
|
|
8
10
|
export * from "./transport.js";
|
|
9
11
|
export * from "./rate-limit.js";
|
|
@@ -21,4 +23,5 @@ export * from "./providers/responses.js";
|
|
|
21
23
|
export * from "./providers/gemini.js";
|
|
22
24
|
export * from "./providers/zai.js";
|
|
23
25
|
export * from "./providers/factory.js";
|
|
26
|
+
export * from "./registry.js";
|
|
24
27
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,eAAe,CAAC"}
|
package/dist/key-pool.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ProviderError } from "./errors.ts";
|
|
1
2
|
import type { ErrorKind } from "./errors.ts";
|
|
2
3
|
import type { Provider } from "./types.ts";
|
|
3
4
|
export type KeyTier = "free" | "paid";
|
|
@@ -16,10 +17,15 @@ export interface KeyPoolOptions {
|
|
|
16
17
|
* 12-hour cooldown. */
|
|
17
18
|
now?: () => number;
|
|
18
19
|
}
|
|
19
|
-
/** No key can serve right now. `retryAtMs` = when the soonest one is back.
|
|
20
|
-
|
|
20
|
+
/** No key can serve right now. `retryAtMs` = when the soonest one is back.
|
|
21
|
+
*
|
|
22
|
+
* A `ProviderError` of kind `rate` that carries that moment as `resetAtMs` and
|
|
23
|
+
* `retryAfterMs`. As a plain `Error` it classified as `rate` only by its
|
|
24
|
+
* wording and carried no deadline anyone read, so a FallbackPool around the
|
|
25
|
+
* key pool benched it for its default minute, whatever the keys had said. */
|
|
26
|
+
export declare class NoAvailableKeyError extends ProviderError {
|
|
21
27
|
readonly retryAtMs: number;
|
|
22
|
-
constructor(label: string, retryAtMs: number);
|
|
28
|
+
constructor(label: string, retryAtMs: number, now: number);
|
|
23
29
|
}
|
|
24
30
|
export declare class KeyPool {
|
|
25
31
|
private readonly label;
|
|
@@ -30,6 +36,13 @@ export declare class KeyPool {
|
|
|
30
36
|
private cursor;
|
|
31
37
|
constructor(label: string, opts: KeyPoolOptions);
|
|
32
38
|
get size(): number;
|
|
39
|
+
/** Each key's tier and when it is back (0 = serving now): free keys in
|
|
40
|
+
* config order, then the paid one. Never the key itself, so a status page
|
|
41
|
+
* can show it as is. */
|
|
42
|
+
status(): Array<{
|
|
43
|
+
tier: KeyTier;
|
|
44
|
+
evictedUntil: number;
|
|
45
|
+
}>;
|
|
33
46
|
/**
|
|
34
47
|
* Run `fn` with the next available key, rotating on key-specific and
|
|
35
48
|
* transient failures. Everything else (a bad request, a content block) throws
|
|
@@ -39,7 +52,7 @@ export declare class KeyPool {
|
|
|
39
52
|
with<T>(fn: (apiKey: string, tier: KeyTier) => Promise<T>): Promise<T>;
|
|
40
53
|
/** Free keys round-robin from a moving cursor, then the paid key. */
|
|
41
54
|
private candidates;
|
|
42
|
-
private
|
|
55
|
+
private noneAvailable;
|
|
43
56
|
}
|
|
44
57
|
/**
|
|
45
58
|
* Give any provider a rotating pool of keys.
|
|
@@ -55,6 +68,10 @@ export declare class KeyPool {
|
|
|
55
68
|
* committed to one key, exactly as a retry is committed past its first chunk
|
|
56
69
|
* (retry.ts, rule 2): a mid-stream 429 evicts nothing and rotates nothing,
|
|
57
70
|
* because there is no way to resume a half-rendered answer on another key.
|
|
71
|
+
*
|
|
72
|
+
* The factory runs once per attempt. An adapter with a session header mints
|
|
73
|
+
* its id when it is built, so give the factory an `instanceSessionId`, or each
|
|
74
|
+
* attempt opens a new session on a gateway that pins sessions to one host.
|
|
58
75
|
*/
|
|
59
76
|
export declare function withKeyPool(pool: KeyPool, factory: (apiKey: string) => Provider): Provider;
|
|
60
77
|
//# sourceMappingURL=key-pool.d.ts.map
|
package/dist/key-pool.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"key-pool.d.ts","sourceRoot":"","sources":["../src/key-pool.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"key-pool.d.ts","sourceRoot":"","sources":["../src/key-pool.ts"],"names":[],"mappings":"AAeA,OAAO,EAAe,aAAa,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAEV,QAAQ,EAIT,MAAM,YAAY,CAAC;AAapB,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAStC,MAAM,WAAW,cAAc;IAC7B,8DAA8D;IAC9D,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;mEAC+D;IAC/D,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC5E;4BACwB;IACxB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;;;8EAK8E;AAC9E,qBAAa,mBAAoB,SAAQ,aAAa;IACpD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;CAQ1D;AAED,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAY;IACjC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAiB;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,MAAM,CAAK;gBAEP,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc;IAe/C,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;6BAEyB;IACzB,MAAM,IAAI,KAAK,CAAC;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IAQxD;;;;;OAKG;IACG,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAyB5E,qEAAqE;IACrE,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,aAAa;CAKtB;AA0CD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,QAAQ,GAAG,QAAQ,CAqE1F"}
|