@apifuse/provider-sdk 2.2.0-beta.27 → 2.2.0-beta.29
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/CHANGELOG.md +8 -0
- package/bin/apifuse-dev.ts +34 -5
- package/bin/apifuse-pack-smoke.ts +1 -1
- package/bin/apifuse-pack-types.ts +26 -2
- package/bin/apifuse-perf.ts +2 -4
- package/bin/apifuse-record.ts +39 -6
- package/dist/auth-turn/index.d.ts +1 -1
- package/dist/auth-turn/index.js +1 -1
- package/dist/auth.d.ts +14 -0
- package/dist/auth.js +38 -0
- package/dist/ceremonies/index.js +52 -11
- package/dist/config/loader.d.ts +3 -1
- package/dist/config/loader.js +4 -2
- package/dist/index.d.ts +8 -7
- package/dist/index.js +5 -7
- package/dist/provider.d.ts +2 -1
- package/dist/provider.js +1 -1
- package/dist/runtime/auth-flow.js +1 -1
- package/dist/runtime/browser.js +45 -2
- package/dist/runtime/http.d.ts +1 -0
- package/dist/runtime/http.js +135 -12
- package/dist/runtime/instrumentation.js +1 -1
- package/dist/runtime/native-network-errors.d.ts +33 -0
- package/dist/runtime/native-network-errors.js +69 -0
- package/dist/runtime/native-network.d.ts +2 -33
- package/dist/runtime/native-network.js +2 -68
- package/dist/runtime/proxy-telemetry.js +3 -0
- package/dist/runtime/redis.d.ts +1 -1
- package/dist/runtime/redis.js +4 -2
- package/dist/runtime/resolver-config.d.ts +6 -0
- package/dist/runtime/resolver-config.js +6 -0
- package/dist/runtime/resolver-public.d.ts +1 -0
- package/dist/runtime/resolver-public.js +1 -0
- package/dist/runtime/resolver-shared.d.ts +3 -0
- package/dist/runtime/resolver-shared.js +12 -0
- package/dist/runtime/resolver-vendors/browser.js +14 -4
- package/dist/runtime/resolver-vendors/twocaptcha.d.ts +2 -1
- package/dist/runtime/resolver-vendors/twocaptcha.js +157 -53
- package/dist/runtime/resolver-vendors/types.d.ts +2 -2
- package/dist/runtime/resolver-vendors/types.js +3 -1
- package/dist/runtime/resolver.d.ts +15 -10
- package/dist/runtime/resolver.js +92 -23
- package/dist/runtime/state.js +5 -115
- package/dist/runtime/stealth-cookies.d.ts +20 -0
- package/dist/runtime/stealth-cookies.js +111 -0
- package/dist/runtime/stealth.d.ts +1 -0
- package/dist/runtime/stealth.js +8 -131
- package/dist/serve.d.ts +1 -1
- package/dist/serve.js +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/self-test.d.ts +13 -0
- package/dist/server/self-test.js +124 -46
- package/dist/server/serve-implementation.d.ts +199 -0
- package/dist/server/serve-implementation.js +2072 -0
- package/dist/server/serve.d.ts +1 -187
- package/dist/server/serve.js +1 -1827
- package/dist/stateful/errors.d.ts +5 -0
- package/dist/stateful/errors.js +10 -0
- package/dist/stateful/stateful-provider-session-routing.d.ts +1 -5
- package/dist/stateful/stateful-provider-session-routing.js +2 -10
- package/dist/stream.js +7 -1
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.js +1 -0
- package/package.json +27 -2
- package/src/auth-turn/index.ts +1 -1
- package/src/auth.ts +78 -0
- package/src/ceremonies/index.ts +68 -18
- package/src/config/loader.ts +8 -2
- package/src/index.ts +18 -24
- package/src/provider.ts +12 -14
- package/src/runtime/auth-flow.ts +1 -1
- package/src/runtime/browser.ts +50 -2
- package/src/runtime/http.ts +155 -11
- package/src/runtime/instrumentation.ts +1 -1
- package/src/runtime/native-network-errors.ts +99 -0
- package/src/runtime/native-network.ts +16 -97
- package/src/runtime/proxy-telemetry.ts +5 -0
- package/src/runtime/redis.ts +7 -2
- package/src/runtime/resolver-config.ts +6 -0
- package/src/runtime/resolver-public.ts +18 -0
- package/src/runtime/resolver-shared.ts +17 -0
- package/src/runtime/resolver-vendors/browser.ts +14 -4
- package/src/runtime/resolver-vendors/twocaptcha.ts +190 -56
- package/src/runtime/resolver-vendors/types.ts +8 -2
- package/src/runtime/resolver.ts +140 -28
- package/src/runtime/state.ts +5 -144
- package/src/runtime/stealth-cookies.ts +132 -0
- package/src/runtime/stealth.ts +15 -158
- package/src/serve.ts +6 -1
- package/src/server/index.ts +1 -0
- package/src/server/self-test.ts +184 -59
- package/src/server/serve-implementation.ts +3042 -0
- package/src/server/serve.ts +1 -2661
- package/src/stateful/errors.ts +12 -0
- package/src/stateful/stateful-provider-session-routing.ts +2 -11
- package/src/stream.ts +8 -1
- package/src/testing/index.ts +1 -0
package/dist/runtime/browser.js
CHANGED
|
@@ -141,7 +141,13 @@ function formatExpression(fn) {
|
|
|
141
141
|
}
|
|
142
142
|
function toLaunchOptions(options) {
|
|
143
143
|
return {
|
|
144
|
-
|
|
144
|
+
// `extraArgs` is optional, but playwright-extra's stealth evasions mutate
|
|
145
|
+
// `options.args` unguarded (navigator.webdriver does
|
|
146
|
+
// `options.args.findIndex(...)` in beforeLaunch). Forwarding `undefined`
|
|
147
|
+
// therefore crashes every stealth launch that omits extraArgs with
|
|
148
|
+
// "TypeError: undefined is not an object (evaluating 'options.args.findIndex')".
|
|
149
|
+
// Always hand the launcher a concrete array.
|
|
150
|
+
args: options.extraArgs ?? [],
|
|
145
151
|
executablePath: options.executablePath,
|
|
146
152
|
headless: options.headless ?? true,
|
|
147
153
|
proxy: options.proxy ? { server: options.proxy } : undefined,
|
|
@@ -684,6 +690,17 @@ function getCdpExecutionContext(params) {
|
|
|
684
690
|
id: typeof contextId === "number" ? contextId : undefined,
|
|
685
691
|
};
|
|
686
692
|
}
|
|
693
|
+
function getCdpDestroyedExecutionContextId(params) {
|
|
694
|
+
if (!isRecord(params)) {
|
|
695
|
+
return undefined;
|
|
696
|
+
}
|
|
697
|
+
return typeof params.executionContextId === "number"
|
|
698
|
+
? params.executionContextId
|
|
699
|
+
: undefined;
|
|
700
|
+
}
|
|
701
|
+
function isMissingExecutionContextError(error) {
|
|
702
|
+
return error instanceof Error && /\b(?:cannot|failed to) find context\b/i.test(error.message);
|
|
703
|
+
}
|
|
687
704
|
class CdpBrowserLocator {
|
|
688
705
|
frame;
|
|
689
706
|
selector;
|
|
@@ -809,7 +826,19 @@ class CdpPoolBrowserPage {
|
|
|
809
826
|
async evaluateInFrame(frameId, fn) {
|
|
810
827
|
await this.initialize();
|
|
811
828
|
const contextId = await this.getFrameExecutionContextId(frameId);
|
|
812
|
-
|
|
829
|
+
try {
|
|
830
|
+
return await this.evaluateWithContext(fn, contextId);
|
|
831
|
+
}
|
|
832
|
+
catch (error) {
|
|
833
|
+
if (!isMissingExecutionContextError(error)) {
|
|
834
|
+
throw error;
|
|
835
|
+
}
|
|
836
|
+
if (this.frameExecutionContexts.get(frameId) === contextId) {
|
|
837
|
+
this.frameExecutionContexts.delete(frameId);
|
|
838
|
+
}
|
|
839
|
+
const refreshedContextId = await this.getFrameExecutionContextId(frameId);
|
|
840
|
+
return await this.evaluateWithContext(fn, refreshedContextId);
|
|
841
|
+
}
|
|
813
842
|
}
|
|
814
843
|
async waitForSelectorInFrame(frameId, selector, options) {
|
|
815
844
|
const timeout = options?.timeout ?? DEFAULT_WAIT_TIMEOUT_MS;
|
|
@@ -1010,6 +1039,20 @@ class CdpPoolBrowserPage {
|
|
|
1010
1039
|
this.frameExecutionContexts.set(context.frameId, context.id);
|
|
1011
1040
|
}
|
|
1012
1041
|
});
|
|
1042
|
+
this.pageClient.on("Runtime.executionContextDestroyed", (params) => {
|
|
1043
|
+
const destroyedContextId = getCdpDestroyedExecutionContextId(params);
|
|
1044
|
+
if (destroyedContextId === undefined) {
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
for (const [frameId, contextId] of this.frameExecutionContexts) {
|
|
1048
|
+
if (contextId === destroyedContextId) {
|
|
1049
|
+
this.frameExecutionContexts.delete(frameId);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
});
|
|
1053
|
+
this.pageClient.on("Runtime.executionContextsCleared", () => {
|
|
1054
|
+
this.frameExecutionContexts.clear();
|
|
1055
|
+
});
|
|
1013
1056
|
await this.pageClient.send("Page.enable");
|
|
1014
1057
|
await this.pageClient.send("Runtime.enable");
|
|
1015
1058
|
this.initialized = true;
|
package/dist/runtime/http.d.ts
CHANGED
|
@@ -4,5 +4,6 @@ export type HttpClientOptions = ProxyResolutionOptions & {
|
|
|
4
4
|
warn?: (message: string) => void;
|
|
5
5
|
userAgent?: string;
|
|
6
6
|
onRetrySummary?: (summary: HttpRetrySummary) => void;
|
|
7
|
+
signal?: AbortSignal;
|
|
7
8
|
};
|
|
8
9
|
export declare function createHttpClient(baseUrl?: string, clientOptions?: HttpClientOptions): HttpClient;
|
package/dist/runtime/http.js
CHANGED
|
@@ -11,10 +11,42 @@ function isHttpStatusOutcome(outcome) {
|
|
|
11
11
|
function isDedupeSkipOutcome(outcome) {
|
|
12
12
|
return "kind" in outcome && outcome.kind === "dedupe-skip";
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
function toAmbientCancellationError(signal, error = signal.reason) {
|
|
15
|
+
if (error instanceof TransportError && error.code === "transport_cancelled") {
|
|
16
|
+
return error;
|
|
17
|
+
}
|
|
18
|
+
return new TransportError("Request cancelled", {
|
|
19
|
+
code: "transport_cancelled",
|
|
20
|
+
status: 0,
|
|
21
|
+
retryable: false,
|
|
22
|
+
...(error !== undefined
|
|
23
|
+
? { cause: error instanceof Error ? error : new Error(String(error)) }
|
|
24
|
+
: {}),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function throwIfAmbientAborted(signal) {
|
|
28
|
+
if (signal?.aborted)
|
|
29
|
+
throw toAmbientCancellationError(signal);
|
|
30
|
+
}
|
|
31
|
+
async function sleep(ms, signal) {
|
|
32
|
+
throwIfAmbientAborted(signal);
|
|
15
33
|
if (ms <= 0)
|
|
16
34
|
return;
|
|
17
|
-
|
|
35
|
+
if (!signal) {
|
|
36
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
await new Promise((resolve, reject) => {
|
|
40
|
+
const onAbort = () => {
|
|
41
|
+
clearTimeout(timer);
|
|
42
|
+
reject(toAmbientCancellationError(signal));
|
|
43
|
+
};
|
|
44
|
+
const timer = setTimeout(() => {
|
|
45
|
+
signal.removeEventListener("abort", onAbort);
|
|
46
|
+
resolve();
|
|
47
|
+
}, ms);
|
|
48
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
49
|
+
});
|
|
18
50
|
}
|
|
19
51
|
function toUpstreamHttpError(status) {
|
|
20
52
|
return new TransportError(`Upstream request failed with status ${status}`, {
|
|
@@ -53,7 +85,17 @@ function parseJson(body) {
|
|
|
53
85
|
function isTimeoutMessage(message) {
|
|
54
86
|
return /\b(timed out|timeout|deadline exceeded)\b/i.test(message);
|
|
55
87
|
}
|
|
56
|
-
function toHttpTransportError(error) {
|
|
88
|
+
function toHttpTransportError(error, ambientSignal, timeoutSignal) {
|
|
89
|
+
if (ambientSignal?.aborted) {
|
|
90
|
+
return toAmbientCancellationError(ambientSignal, error);
|
|
91
|
+
}
|
|
92
|
+
if (timeoutSignal?.aborted) {
|
|
93
|
+
return new TransportError("Request timed out", {
|
|
94
|
+
code: "transport_timeout",
|
|
95
|
+
status: 0,
|
|
96
|
+
...(error instanceof Error ? { cause: error } : {}),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
57
99
|
if (error instanceof TransportError) {
|
|
58
100
|
if (error.code) {
|
|
59
101
|
return error;
|
|
@@ -125,6 +167,76 @@ function requireNativeResponseBody(response) {
|
|
|
125
167
|
}
|
|
126
168
|
return response.body;
|
|
127
169
|
}
|
|
170
|
+
function mergeAbortSignals(...signals) {
|
|
171
|
+
const activeSignals = signals.filter((signal) => signal != null);
|
|
172
|
+
if (activeSignals.length === 0)
|
|
173
|
+
return undefined;
|
|
174
|
+
if (activeSignals.length === 1)
|
|
175
|
+
return activeSignals[0];
|
|
176
|
+
return AbortSignal.any(activeSignals);
|
|
177
|
+
}
|
|
178
|
+
function cancelStreamOnAbort(body, signal) {
|
|
179
|
+
if (!signal)
|
|
180
|
+
return body;
|
|
181
|
+
let reader;
|
|
182
|
+
let finished = false;
|
|
183
|
+
let streamController;
|
|
184
|
+
const cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
185
|
+
const onAbort = () => {
|
|
186
|
+
if (finished)
|
|
187
|
+
return;
|
|
188
|
+
finished = true;
|
|
189
|
+
cleanup();
|
|
190
|
+
const reason = toAmbientCancellationError(signal);
|
|
191
|
+
streamController?.error(reason);
|
|
192
|
+
const cancellation = reader ? reader.cancel(reason) : body.cancel(reason);
|
|
193
|
+
void cancellation.catch(() => undefined).finally(() => reader?.releaseLock());
|
|
194
|
+
};
|
|
195
|
+
return new ReadableStream({
|
|
196
|
+
start(controller) {
|
|
197
|
+
streamController = controller;
|
|
198
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
199
|
+
if (signal.aborted)
|
|
200
|
+
onAbort();
|
|
201
|
+
},
|
|
202
|
+
async pull(controller) {
|
|
203
|
+
try {
|
|
204
|
+
reader ??= body.getReader();
|
|
205
|
+
const chunk = await reader.read();
|
|
206
|
+
if (finished)
|
|
207
|
+
return;
|
|
208
|
+
if (chunk.done) {
|
|
209
|
+
finished = true;
|
|
210
|
+
cleanup();
|
|
211
|
+
controller.close();
|
|
212
|
+
reader.releaseLock();
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
controller.enqueue(chunk.value);
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
if (finished)
|
|
219
|
+
return;
|
|
220
|
+
finished = true;
|
|
221
|
+
cleanup();
|
|
222
|
+
controller.error(error);
|
|
223
|
+
reader?.releaseLock();
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
async cancel(reason) {
|
|
227
|
+
if (finished)
|
|
228
|
+
return;
|
|
229
|
+
finished = true;
|
|
230
|
+
cleanup();
|
|
231
|
+
try {
|
|
232
|
+
await (reader ? reader.cancel(reason) : body.cancel(reason));
|
|
233
|
+
}
|
|
234
|
+
finally {
|
|
235
|
+
reader?.releaseLock();
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
}, { highWaterMark: 0 });
|
|
239
|
+
}
|
|
128
240
|
function sanitizeStreamErrors(body, serializedUrl) {
|
|
129
241
|
if (serializedUrl.sensitiveValues.length === 0)
|
|
130
242
|
return body;
|
|
@@ -154,9 +266,9 @@ function sanitizeStreamErrors(body, serializedUrl) {
|
|
|
154
266
|
},
|
|
155
267
|
}, { highWaterMark: 0 });
|
|
156
268
|
}
|
|
157
|
-
function toNativeHttpStreamResponse(response, serializedUrl) {
|
|
269
|
+
function toNativeHttpStreamResponse(response, serializedUrl, signal) {
|
|
158
270
|
const headers = Object.fromEntries(response.headers.entries());
|
|
159
|
-
const body = sanitizeStreamErrors(requireNativeResponseBody(response), serializedUrl);
|
|
271
|
+
const body = sanitizeStreamErrors(cancelStreamOnAbort(requireNativeResponseBody(response), signal), serializedUrl);
|
|
160
272
|
return {
|
|
161
273
|
body,
|
|
162
274
|
headers,
|
|
@@ -418,15 +530,18 @@ async function fetchNativeHttp(baseUrl, url, method, options, clientOptions, war
|
|
|
418
530
|
const serializedUrl = serializeHttpRequestUrl(baseUrl, url, options);
|
|
419
531
|
const { requestUrl } = serializedUrl;
|
|
420
532
|
const controller = options.timeout ? new AbortController() : undefined;
|
|
533
|
+
const signal = mergeAbortSignals(clientOptions.signal, controller?.signal);
|
|
421
534
|
const timeoutHandle = options.timeout
|
|
422
535
|
? setTimeout(() => controller?.abort(), options.timeout)
|
|
423
536
|
: undefined;
|
|
424
537
|
let proxy;
|
|
425
538
|
try {
|
|
539
|
+
throwIfAmbientAborted(clientOptions.signal);
|
|
426
540
|
// Resolve inside the try (and after the timeout is armed) so allocator
|
|
427
541
|
// failures are branded as TransportErrors and count against the request
|
|
428
542
|
// deadline, exactly as an inline resolve would.
|
|
429
543
|
proxy = await resolveNativeProxy(options, clientOptions, warn, proxyAttemptOffset);
|
|
544
|
+
throwIfAmbientAborted(clientOptions.signal);
|
|
430
545
|
// For a registry allocator chain, skip an endpoint a prior attempt already
|
|
431
546
|
// tried rather than re-issuing the same request. Returning the sentinel
|
|
432
547
|
// (instead of breaking) lets the loop keep advancing the flat offset until
|
|
@@ -441,7 +556,7 @@ async function fetchNativeHttp(baseUrl, url, method, options, clientOptions, war
|
|
|
441
556
|
headers: options.headers,
|
|
442
557
|
method,
|
|
443
558
|
...(proxy ? { proxy } : {}),
|
|
444
|
-
signal:
|
|
559
|
+
...(signal ? { signal } : {}),
|
|
445
560
|
};
|
|
446
561
|
if (options.body !== undefined) {
|
|
447
562
|
requestInit.body = normalizeNativeFetchBody(options.body);
|
|
@@ -471,7 +586,7 @@ async function fetchNativeHttp(baseUrl, url, method, options, clientOptions, war
|
|
|
471
586
|
if (error instanceof SyntaxError) {
|
|
472
587
|
throw redactSensitiveError(error, serializedUrl.sensitiveValues, serializedUrl.requestUrl, serializedUrl.redactedUrl);
|
|
473
588
|
}
|
|
474
|
-
const transportError = redactSensitiveError(toHttpTransportError(error), serializedUrl.sensitiveValues, serializedUrl.requestUrl, serializedUrl.redactedUrl);
|
|
589
|
+
const transportError = redactSensitiveError(toHttpTransportError(error, clientOptions.signal, controller?.signal), serializedUrl.sensitiveValues, serializedUrl.requestUrl, serializedUrl.redactedUrl);
|
|
475
590
|
transportError.proxyUsed = Boolean(proxy);
|
|
476
591
|
throw transportError;
|
|
477
592
|
}
|
|
@@ -484,16 +599,19 @@ async function fetchNativeHttpStream(baseUrl, url, method, options, clientOption
|
|
|
484
599
|
const serializedUrl = serializeHttpRequestUrl(baseUrl, url, options);
|
|
485
600
|
const { requestUrl } = serializedUrl;
|
|
486
601
|
const controller = options.timeout ? new AbortController() : undefined;
|
|
602
|
+
const signal = mergeAbortSignals(clientOptions.signal, controller?.signal);
|
|
487
603
|
const timeoutHandle = options.timeout
|
|
488
604
|
? setTimeout(() => controller?.abort(), options.timeout)
|
|
489
605
|
: undefined;
|
|
490
606
|
try {
|
|
607
|
+
throwIfAmbientAborted(clientOptions.signal);
|
|
491
608
|
const proxy = await resolveNativeProxy(options, clientOptions, warn);
|
|
609
|
+
throwIfAmbientAborted(clientOptions.signal);
|
|
492
610
|
const requestInit = {
|
|
493
611
|
headers: options.headers,
|
|
494
612
|
method,
|
|
495
613
|
...(proxy ? { proxy } : {}),
|
|
496
|
-
signal:
|
|
614
|
+
...(signal ? { signal } : {}),
|
|
497
615
|
};
|
|
498
616
|
if (options.body !== undefined) {
|
|
499
617
|
requestInit.body = normalizeNativeFetchBody(options.body);
|
|
@@ -506,13 +624,15 @@ async function fetchNativeHttpStream(baseUrl, url, method, options, clientOption
|
|
|
506
624
|
status: response.status,
|
|
507
625
|
});
|
|
508
626
|
}
|
|
509
|
-
|
|
627
|
+
// Per-call timeout remains header-scoped, while the ambient request signal
|
|
628
|
+
// stays attached to the response body for its full consumption lifetime.
|
|
629
|
+
return toNativeHttpStreamResponse(response, serializedUrl, clientOptions.signal);
|
|
510
630
|
}
|
|
511
631
|
catch (error) {
|
|
512
632
|
if (error instanceof SyntaxError) {
|
|
513
633
|
throw redactSensitiveError(error, serializedUrl.sensitiveValues, serializedUrl.requestUrl, serializedUrl.redactedUrl);
|
|
514
634
|
}
|
|
515
|
-
throw redactSensitiveError(toHttpTransportError(error), serializedUrl.sensitiveValues, serializedUrl.requestUrl, serializedUrl.redactedUrl);
|
|
635
|
+
throw redactSensitiveError(toHttpTransportError(error, clientOptions.signal, controller?.signal), serializedUrl.sensitiveValues, serializedUrl.requestUrl, serializedUrl.redactedUrl);
|
|
516
636
|
}
|
|
517
637
|
finally {
|
|
518
638
|
if (timeoutHandle)
|
|
@@ -616,6 +736,7 @@ export function createHttpClient(baseUrl, clientOptions = {}) {
|
|
|
616
736
|
const dedupeContext = dedupeAllocatorEndpoints ? { attempted: new Set() } : undefined;
|
|
617
737
|
const executeOnce = (proxyAttemptOffset = 0) => fetchNativeHttp(baseUrl, url, methodName, attemptOptions, clientOptions, warnOnce, statusRetryEnabled ? retryOptions?.statusCodes : undefined, proxyAttemptOffset, dedupeContext);
|
|
618
738
|
if (!retryEnabled || !retryOptions) {
|
|
739
|
+
throwIfAmbientAborted(clientOptions.signal);
|
|
619
740
|
const outcome = await executeOnce();
|
|
620
741
|
if (isDedupeSkipOutcome(outcome)) {
|
|
621
742
|
// Single-shot path never de-duplicates (dedupeContext is undefined),
|
|
@@ -639,6 +760,7 @@ export function createHttpClient(baseUrl, clientOptions = {}) {
|
|
|
639
760
|
// allocations skip offsets.
|
|
640
761
|
let issued = 0;
|
|
641
762
|
for (let attempt = 1; attempt <= transportAttemptCap; attempt += 1) {
|
|
763
|
+
throwIfAmbientAborted(clientOptions.signal);
|
|
642
764
|
// Whether this offset actually issued a request (vs. a skipped duplicate),
|
|
643
765
|
// so the catch counts a thrown *transport* failure once without
|
|
644
766
|
// double-counting a status outcome that already incremented before it
|
|
@@ -657,7 +779,7 @@ export function createHttpClient(baseUrl, clientOptions = {}) {
|
|
|
657
779
|
if (isHttpStatusOutcome(outcome)) {
|
|
658
780
|
lastStatus = outcome.status;
|
|
659
781
|
if (outcome.retryable && issued < retryOptions.attempts) {
|
|
660
|
-
await sleep(computeProxyTransportRetryDelayMs(retryOptions, attempt, outcome.headers));
|
|
782
|
+
await sleep(computeProxyTransportRetryDelayMs(retryOptions, attempt, outcome.headers), clientOptions.signal);
|
|
661
783
|
continue;
|
|
662
784
|
}
|
|
663
785
|
throw toUpstreamHttpError(outcome.status);
|
|
@@ -680,6 +802,7 @@ export function createHttpClient(baseUrl, clientOptions = {}) {
|
|
|
680
802
|
return response;
|
|
681
803
|
}
|
|
682
804
|
catch (error) {
|
|
805
|
+
throwIfAmbientAborted(clientOptions.signal);
|
|
683
806
|
if (!issuedThisAttempt)
|
|
684
807
|
issued += 1;
|
|
685
808
|
lastError = error;
|
|
@@ -694,7 +817,7 @@ export function createHttpClient(baseUrl, clientOptions = {}) {
|
|
|
694
817
|
options: retryOptions,
|
|
695
818
|
proxyUsed,
|
|
696
819
|
})) {
|
|
697
|
-
await sleep(computeProxyTransportRetryDelayMs(retryOptions, attempt));
|
|
820
|
+
await sleep(computeProxyTransportRetryDelayMs(retryOptions, attempt), clientOptions.signal);
|
|
698
821
|
continue;
|
|
699
822
|
}
|
|
700
823
|
throw error;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readableBytes, readableLines, readableTextChunks } from "../stream.js";
|
|
2
2
|
import { parseHttpRequestInvocation, isSensitiveKey, redactSensitiveError, redactSensitiveText, redactUrlQueryParams, requestOptionsFromHttpInvocation, serializeRequestUrl, } from "./request-options.js";
|
|
3
3
|
import { createTraceContext, getTraceRecorder, } from "./trace.js";
|
|
4
|
-
import { RESOLVER_INSTRUMENTATION_METADATA } from "./resolver.js";
|
|
4
|
+
import { RESOLVER_INSTRUMENTATION_METADATA } from "./resolver-shared.js";
|
|
5
5
|
const BROWSER_PAGE_METHODS = new Set(["goto", "fill", "click", "type", "waitForSelector"]);
|
|
6
6
|
const DIAGNOSTIC_BASE_URL = "http://apifuse-instrumentation.invalid";
|
|
7
7
|
function isThenable(value) {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { TransportError } from "../errors.js";
|
|
2
|
+
export type NativeNetworkErrorCode = "native_connection_aborted" | "native_connection_closed" | "native_connection_failed" | "native_connection_idle_timeout" | "native_connection_timeout" | "native_egress_authorization_failed" | "native_egress_grant_expired" | "native_egress_grant_invalid" | "native_egress_grant_limit_exceeded" | "native_egress_input_invalid" | "native_egress_not_declared" | "native_egress_policy_invalid" | "native_dynamic_egress_unsupported" | "native_proxy_expired" | "native_proxy_invalid";
|
|
3
|
+
export declare class NativeNetworkError extends TransportError {
|
|
4
|
+
constructor(message: string, code: NativeNetworkErrorCode, cause?: Error);
|
|
5
|
+
get code(): NativeNetworkErrorCode;
|
|
6
|
+
}
|
|
7
|
+
export declare function safeDiagnosticEgressHost(value: unknown): string;
|
|
8
|
+
export declare class NativeProxyExpiredError extends NativeNetworkError {
|
|
9
|
+
readonly expiresAt: string;
|
|
10
|
+
constructor(expiresAt: string);
|
|
11
|
+
}
|
|
12
|
+
/** Raised before transport setup when a native destination is not authorized. */
|
|
13
|
+
export declare class NativeEgressNotDeclaredError extends NativeNetworkError {
|
|
14
|
+
readonly port: number;
|
|
15
|
+
readonly tls: "required" | "disabled";
|
|
16
|
+
readonly host: string;
|
|
17
|
+
constructor(host: string, port: number, tls: "required" | "disabled");
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Raised when the destination was authorized by a grant whose TTL elapsed and
|
|
21
|
+
* its expiry remains in the client's bounded recent-expiry evidence window.
|
|
22
|
+
*/
|
|
23
|
+
export declare class NativeEgressGrantExpiredError extends NativeNetworkError {
|
|
24
|
+
readonly port: number;
|
|
25
|
+
readonly tls: "required" | "disabled";
|
|
26
|
+
readonly expiresAt: string;
|
|
27
|
+
readonly host: string;
|
|
28
|
+
constructor(host: string, port: number, tls: "required" | "disabled", expiresAt: string);
|
|
29
|
+
}
|
|
30
|
+
/** Raised when an established connection exceeds its opt-in read-idle window. */
|
|
31
|
+
export declare class NativeIdleTimeoutError extends NativeNetworkError {
|
|
32
|
+
constructor();
|
|
33
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { TransportError } from "../errors.js";
|
|
2
|
+
import { canonicalizeEgressHost } from "../native-address.js";
|
|
3
|
+
export class NativeNetworkError extends TransportError {
|
|
4
|
+
constructor(message, code, cause) {
|
|
5
|
+
const isEgressPolicyFailure = code.startsWith("native_egress_") || code === "native_dynamic_egress_unsupported";
|
|
6
|
+
super(message, {
|
|
7
|
+
code,
|
|
8
|
+
status: 0,
|
|
9
|
+
...(cause ? { cause } : {}),
|
|
10
|
+
...(isEgressPolicyFailure ? { category: "provider_error", retryable: false } : {}),
|
|
11
|
+
});
|
|
12
|
+
this.name = "NativeNetworkError";
|
|
13
|
+
}
|
|
14
|
+
get code() {
|
|
15
|
+
return super.code;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function safeDiagnosticEgressHost(value) {
|
|
19
|
+
const canonical = canonicalizeEgressHost(value);
|
|
20
|
+
return canonical.ok ? canonical.host : `<invalid-host:${canonical.reason}>`;
|
|
21
|
+
}
|
|
22
|
+
export class NativeProxyExpiredError extends NativeNetworkError {
|
|
23
|
+
expiresAt;
|
|
24
|
+
constructor(expiresAt) {
|
|
25
|
+
super("Native connection closed at sticky proxy expiry", "native_proxy_expired");
|
|
26
|
+
this.expiresAt = expiresAt;
|
|
27
|
+
this.name = "NativeProxyExpiredError";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Raised before transport setup when a native destination is not authorized. */
|
|
31
|
+
export class NativeEgressNotDeclaredError extends NativeNetworkError {
|
|
32
|
+
port;
|
|
33
|
+
tls;
|
|
34
|
+
host;
|
|
35
|
+
constructor(host, port, tls) {
|
|
36
|
+
const diagnosticHost = safeDiagnosticEgressHost(host);
|
|
37
|
+
super(`Native ${tls === "required" ? "TLS" : "TCP"} egress is not declared for ${diagnosticHost}:${port}`, "native_egress_not_declared");
|
|
38
|
+
this.port = port;
|
|
39
|
+
this.tls = tls;
|
|
40
|
+
this.host = diagnosticHost;
|
|
41
|
+
this.name = "NativeEgressNotDeclaredError";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Raised when the destination was authorized by a grant whose TTL elapsed and
|
|
46
|
+
* its expiry remains in the client's bounded recent-expiry evidence window.
|
|
47
|
+
*/
|
|
48
|
+
export class NativeEgressGrantExpiredError extends NativeNetworkError {
|
|
49
|
+
port;
|
|
50
|
+
tls;
|
|
51
|
+
expiresAt;
|
|
52
|
+
host;
|
|
53
|
+
constructor(host, port, tls, expiresAt) {
|
|
54
|
+
const diagnosticHost = safeDiagnosticEgressHost(host);
|
|
55
|
+
super(`Native ${tls === "required" ? "TLS" : "TCP"} egress grant expired for ${diagnosticHost}:${port}`, "native_egress_grant_expired");
|
|
56
|
+
this.port = port;
|
|
57
|
+
this.tls = tls;
|
|
58
|
+
this.expiresAt = expiresAt;
|
|
59
|
+
this.host = diagnosticHost;
|
|
60
|
+
this.name = "NativeEgressGrantExpiredError";
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** Raised when an established connection exceeds its opt-in read-idle window. */
|
|
64
|
+
export class NativeIdleTimeoutError extends NativeNetworkError {
|
|
65
|
+
constructor() {
|
|
66
|
+
super("Native network socket timed out while reading.", "native_connection_idle_timeout");
|
|
67
|
+
this.name = "NativeIdleTimeoutError";
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -1,40 +1,10 @@
|
|
|
1
1
|
import { Socket } from "node:net";
|
|
2
2
|
import { type TLSSocket } from "node:tls";
|
|
3
3
|
import { type ProxyProtocol } from "../config/loader.js";
|
|
4
|
-
import { TransportError } from "../errors.js";
|
|
5
4
|
import { type DynamicEgressRuleSnapshot } from "../native-egress-policy.js";
|
|
6
5
|
import type { NativeNetworkClient, NativeNetworkConnectInput, NativeNetworkConnection, NativeNetworkDynamicGrantOptions, NativeNetworkEgressGrant, NativeProviderConfig, NativeProxyEgressInfo, ProviderProxyPolicy, ProviderProxyProvider, EnvContext } from "../types.js";
|
|
7
|
-
export
|
|
8
|
-
export
|
|
9
|
-
constructor(message: string, code: NativeNetworkErrorCode, cause?: Error);
|
|
10
|
-
get code(): NativeNetworkErrorCode;
|
|
11
|
-
}
|
|
12
|
-
export declare class NativeProxyExpiredError extends NativeNetworkError {
|
|
13
|
-
readonly expiresAt: string;
|
|
14
|
-
constructor(expiresAt: string);
|
|
15
|
-
}
|
|
16
|
-
/** Raised before transport setup when a native destination is not authorized. */
|
|
17
|
-
export declare class NativeEgressNotDeclaredError extends NativeNetworkError {
|
|
18
|
-
readonly port: number;
|
|
19
|
-
readonly tls: "required" | "disabled";
|
|
20
|
-
readonly host: string;
|
|
21
|
-
constructor(host: string, port: number, tls: "required" | "disabled");
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Raised when the destination was authorized by a grant whose TTL elapsed and
|
|
25
|
-
* its expiry remains in the client's bounded recent-expiry evidence window.
|
|
26
|
-
*/
|
|
27
|
-
export declare class NativeEgressGrantExpiredError extends NativeNetworkError {
|
|
28
|
-
readonly port: number;
|
|
29
|
-
readonly tls: "required" | "disabled";
|
|
30
|
-
readonly expiresAt: string;
|
|
31
|
-
readonly host: string;
|
|
32
|
-
constructor(host: string, port: number, tls: "required" | "disabled", expiresAt: string);
|
|
33
|
-
}
|
|
34
|
-
/** Raised when an established connection exceeds its opt-in read-idle window. */
|
|
35
|
-
export declare class NativeIdleTimeoutError extends NativeNetworkError {
|
|
36
|
-
constructor();
|
|
37
|
-
}
|
|
6
|
+
export { NativeEgressGrantExpiredError, NativeEgressNotDeclaredError, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, } from "./native-network-errors.js";
|
|
7
|
+
export type { NativeNetworkErrorCode } from "./native-network-errors.js";
|
|
38
8
|
export type NativeGatewayProxy = NativeProxyEgressInfo & {
|
|
39
9
|
readonly url: string;
|
|
40
10
|
};
|
|
@@ -124,4 +94,3 @@ export declare function createNativeEgressAuthorization(options: NativeNetworkCl
|
|
|
124
94
|
};
|
|
125
95
|
/** Create the SDK byte-stream runtime with provider-declared egress enforcement. */
|
|
126
96
|
export declare function createNativeNetworkClient(options?: NativeNetworkClientOptions): NativeNetworkClient;
|
|
127
|
-
export {};
|
|
@@ -3,79 +3,13 @@ import { Socket } from "node:net";
|
|
|
3
3
|
import { connect as connectTlsSocket } from "node:tls";
|
|
4
4
|
import { SocksClient } from "socks";
|
|
5
5
|
import { assertTunnelingScheme, ProxyResolutionError, SMARTPROXY_APP_KEY_ENV, VENDOR_DEFAULT_PROTOCOL, resolveWithVendor, } from "../config/loader.js";
|
|
6
|
-
import { TransportError } from "../errors.js";
|
|
7
6
|
import { NativeEgressPolicyValidationError, parseNativeEgressPolicy, } from "../native-egress-policy.js";
|
|
8
7
|
import { canonicalizeEgressHost, classifyEgressHost, embeddedIpv4FromIpv6, ipv4InCidr, ipv6InCidr, parseIpv6, parseStrictIpv4, } from "../native-address.js";
|
|
9
8
|
import { createEnvContext } from "./env.js";
|
|
9
|
+
import { NativeEgressGrantExpiredError, NativeEgressNotDeclaredError, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, safeDiagnosticEgressHost, } from "./native-network-errors.js";
|
|
10
10
|
import { NODEMAVEN_FILTER_ENV, NODEMAVEN_PASSWORD_ENV, NODEMAVEN_USERNAME_ENV, nodemavenSessionWindow, synthesizeNodemavenProxy, } from "./proxy-nodemaven.js";
|
|
11
11
|
import { redactSensitiveError } from "./request-options.js";
|
|
12
|
-
export
|
|
13
|
-
constructor(message, code, cause) {
|
|
14
|
-
const isEgressPolicyFailure = code.startsWith("native_egress_") || code === "native_dynamic_egress_unsupported";
|
|
15
|
-
super(message, {
|
|
16
|
-
code,
|
|
17
|
-
status: 0,
|
|
18
|
-
...(cause ? { cause } : {}),
|
|
19
|
-
...(isEgressPolicyFailure ? { category: "provider_error", retryable: false } : {}),
|
|
20
|
-
});
|
|
21
|
-
this.name = "NativeNetworkError";
|
|
22
|
-
}
|
|
23
|
-
get code() {
|
|
24
|
-
return super.code;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
function safeDiagnosticEgressHost(value) {
|
|
28
|
-
const canonical = canonicalizeEgressHost(value);
|
|
29
|
-
return canonical.ok ? canonical.host : `<invalid-host:${canonical.reason}>`;
|
|
30
|
-
}
|
|
31
|
-
export class NativeProxyExpiredError extends NativeNetworkError {
|
|
32
|
-
expiresAt;
|
|
33
|
-
constructor(expiresAt) {
|
|
34
|
-
super("Native connection closed at sticky proxy expiry", "native_proxy_expired");
|
|
35
|
-
this.expiresAt = expiresAt;
|
|
36
|
-
this.name = "NativeProxyExpiredError";
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
/** Raised before transport setup when a native destination is not authorized. */
|
|
40
|
-
export class NativeEgressNotDeclaredError extends NativeNetworkError {
|
|
41
|
-
port;
|
|
42
|
-
tls;
|
|
43
|
-
host;
|
|
44
|
-
constructor(host, port, tls) {
|
|
45
|
-
const diagnosticHost = safeDiagnosticEgressHost(host);
|
|
46
|
-
super(`Native ${tls === "required" ? "TLS" : "TCP"} egress is not declared for ${diagnosticHost}:${port}`, "native_egress_not_declared");
|
|
47
|
-
this.port = port;
|
|
48
|
-
this.tls = tls;
|
|
49
|
-
this.host = diagnosticHost;
|
|
50
|
-
this.name = "NativeEgressNotDeclaredError";
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Raised when the destination was authorized by a grant whose TTL elapsed and
|
|
55
|
-
* its expiry remains in the client's bounded recent-expiry evidence window.
|
|
56
|
-
*/
|
|
57
|
-
export class NativeEgressGrantExpiredError extends NativeNetworkError {
|
|
58
|
-
port;
|
|
59
|
-
tls;
|
|
60
|
-
expiresAt;
|
|
61
|
-
host;
|
|
62
|
-
constructor(host, port, tls, expiresAt) {
|
|
63
|
-
const diagnosticHost = safeDiagnosticEgressHost(host);
|
|
64
|
-
super(`Native ${tls === "required" ? "TLS" : "TCP"} egress grant expired for ${diagnosticHost}:${port}`, "native_egress_grant_expired");
|
|
65
|
-
this.port = port;
|
|
66
|
-
this.tls = tls;
|
|
67
|
-
this.expiresAt = expiresAt;
|
|
68
|
-
this.host = diagnosticHost;
|
|
69
|
-
this.name = "NativeEgressGrantExpiredError";
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
/** Raised when an established connection exceeds its opt-in read-idle window. */
|
|
73
|
-
export class NativeIdleTimeoutError extends NativeNetworkError {
|
|
74
|
-
constructor() {
|
|
75
|
-
super("Native network socket timed out while reading.", "native_connection_idle_timeout");
|
|
76
|
-
this.name = "NativeIdleTimeoutError";
|
|
77
|
-
}
|
|
78
|
-
}
|
|
12
|
+
export { NativeEgressGrantExpiredError, NativeEgressNotDeclaredError, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, } from "./native-network-errors.js";
|
|
79
13
|
const VENDOR_CREDENTIAL_NAMES = {
|
|
80
14
|
smartproxy: [SMARTPROXY_APP_KEY_ENV],
|
|
81
15
|
nodemaven: [NODEMAVEN_USERNAME_ENV, NODEMAVEN_PASSWORD_ENV],
|
|
@@ -33,6 +33,7 @@ export class ProxyTelemetryCollector {
|
|
|
33
33
|
recordProxyResolution(event) {
|
|
34
34
|
this.#events.push({
|
|
35
35
|
provider: event.provider,
|
|
36
|
+
...(event.userAgentSource ? { userAgentSource: event.userAgentSource } : {}),
|
|
36
37
|
...(event.protocol ? { protocol: event.protocol } : {}),
|
|
37
38
|
cacheStatus: event.cacheStatus,
|
|
38
39
|
cacheHit: event.cacheHit,
|
|
@@ -99,6 +100,7 @@ export class ProxyTelemetryCollector {
|
|
|
99
100
|
}
|
|
100
101
|
const aggregate = rest.reduce((acc, event) => ({
|
|
101
102
|
provider: event.provider,
|
|
103
|
+
userAgentSource: event.userAgentSource ?? acc.userAgentSource,
|
|
102
104
|
cacheStatus: worseStatus(acc.cacheStatus, event.cacheStatus),
|
|
103
105
|
cacheHit: acc.cacheHit && event.cacheHit,
|
|
104
106
|
resolutionMs: acc.resolutionMs + event.resolutionMs,
|
|
@@ -118,6 +120,7 @@ export class ProxyTelemetryCollector {
|
|
|
118
120
|
v: 1,
|
|
119
121
|
proxy: {
|
|
120
122
|
provider: serving.provider,
|
|
123
|
+
...(aggregate.userAgentSource ? { userAgentSource: aggregate.userAgentSource } : {}),
|
|
121
124
|
...(serving.protocol ? { protocol: serving.protocol } : {}),
|
|
122
125
|
cacheStatus: aggregate.cacheStatus,
|
|
123
126
|
cacheHit: aggregate.cacheHit,
|
package/dist/runtime/redis.d.ts
CHANGED
package/dist/runtime/redis.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
const require = createRequire(import.meta.url);
|
|
2
3
|
export function createProviderRedisClient(options) {
|
|
3
|
-
const
|
|
4
|
+
const { Redis: RedisClient } = require("ioredis");
|
|
5
|
+
const redis = new RedisClient(options.redisUrl, {
|
|
4
6
|
connectTimeout: options.timeoutMs,
|
|
5
7
|
enableOfflineQueue: false,
|
|
6
8
|
lazyConnect: true,
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const APIFUSE__RESOLVER__2CAPTCHA__API_KEY = "APIFUSE__RESOLVER__2CAPTCHA__API_KEY";
|
|
2
|
+
export declare const APIFUSE__RESOLVER__CAPSOLVER__API_KEY = "APIFUSE__RESOLVER__CAPSOLVER__API_KEY";
|
|
3
|
+
export declare const APIFUSE__RESOLVER__CAPMONSTER__API_KEY = "APIFUSE__RESOLVER__CAPMONSTER__API_KEY";
|
|
4
|
+
export declare const APIFUSE__RESOLVER__TIMEOUT_MS = "APIFUSE__RESOLVER__TIMEOUT_MS";
|
|
5
|
+
export declare const APIFUSE__CDP_POOL__URL = "APIFUSE__CDP_POOL__URL";
|
|
6
|
+
export declare const DEFAULT_RESOLVER_TIMEOUT_MS = 180000;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const APIFUSE__RESOLVER__2CAPTCHA__API_KEY = "APIFUSE__RESOLVER__2CAPTCHA__API_KEY";
|
|
2
|
+
export const APIFUSE__RESOLVER__CAPSOLVER__API_KEY = "APIFUSE__RESOLVER__CAPSOLVER__API_KEY";
|
|
3
|
+
export const APIFUSE__RESOLVER__CAPMONSTER__API_KEY = "APIFUSE__RESOLVER__CAPMONSTER__API_KEY";
|
|
4
|
+
export const APIFUSE__RESOLVER__TIMEOUT_MS = "APIFUSE__RESOLVER__TIMEOUT_MS";
|
|
5
|
+
export const APIFUSE__CDP_POOL__URL = "APIFUSE__CDP_POOL__URL";
|
|
6
|
+
export const DEFAULT_RESOLVER_TIMEOUT_MS = 180_000;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { APIFUSE__CDP_POOL__URL, APIFUSE__RESOLVER__2CAPTCHA__API_KEY, APIFUSE__RESOLVER__CAPMONSTER__API_KEY, APIFUSE__RESOLVER__CAPSOLVER__API_KEY, APIFUSE__RESOLVER__TIMEOUT_MS, bindResolverSignal, createResolverClient, createResolverClientFromEnv, createUnsupportedResolverClient, DEFAULT_RESOLVER_TIMEOUT_MS, invalidateResolverSolution, RESOLVER_ADAPTER_REGISTRY, RESOLVER_INSTRUMENTATION_METADATA, type ResolverAdapterFactory, type ResolverInstrumentationMetadata, type ResolverRuntimeOptions, } from "./resolver.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { APIFUSE__CDP_POOL__URL, APIFUSE__RESOLVER__2CAPTCHA__API_KEY, APIFUSE__RESOLVER__CAPMONSTER__API_KEY, APIFUSE__RESOLVER__CAPSOLVER__API_KEY, APIFUSE__RESOLVER__TIMEOUT_MS, bindResolverSignal, createResolverClient, createResolverClientFromEnv, createUnsupportedResolverClient, DEFAULT_RESOLVER_TIMEOUT_MS, invalidateResolverSolution, RESOLVER_ADAPTER_REGISTRY, RESOLVER_INSTRUMENTATION_METADATA, } from "./resolver.js";
|