@apifuse/provider-sdk 2.2.0-beta.27 → 2.2.0-beta.28
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 +4 -0
- package/bin/apifuse-dev.ts +2 -2
- package/bin/apifuse-pack-smoke.ts +1 -1
- package/bin/apifuse-pack-types.ts +2 -1
- package/bin/apifuse-perf.ts +2 -4
- package/bin/apifuse-record.ts +1 -1
- package/dist/auth-turn/index.d.ts +1 -1
- package/dist/auth-turn/index.js +1 -1
- package/dist/ceremonies/index.js +52 -11
- package/dist/config/loader.d.ts +1 -1
- package/dist/config/loader.js +4 -2
- package/dist/index.d.ts +7 -6
- package/dist/index.js +4 -6
- package/dist/provider.d.ts +2 -1
- package/dist/provider.js +1 -1
- package/dist/runtime/auth-flow.js +1 -1
- 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/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-shared.d.ts +3 -0
- package/dist/runtime/resolver-shared.js +12 -0
- package/dist/runtime/resolver-vendors/twocaptcha.d.ts +2 -1
- package/dist/runtime/resolver-vendors/twocaptcha.js +80 -43
- package/dist/runtime/resolver-vendors/types.d.ts +1 -1
- package/dist/runtime/resolver.d.ts +6 -10
- package/dist/runtime/resolver.js +19 -18
- 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.js +7 -130
- 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 +2054 -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/package.json +27 -2
- package/src/auth-turn/index.ts +1 -1
- package/src/ceremonies/index.ts +68 -18
- package/src/config/loader.ts +5 -2
- package/src/index.ts +18 -23
- package/src/provider.ts +12 -14
- package/src/runtime/auth-flow.ts +1 -1
- 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/redis.ts +7 -2
- package/src/runtime/resolver-config.ts +6 -0
- package/src/runtime/resolver-shared.ts +17 -0
- package/src/runtime/resolver-vendors/twocaptcha.ts +100 -49
- package/src/runtime/resolver-vendors/types.ts +1 -0
- package/src/runtime/resolver.ts +47 -22
- package/src/runtime/state.ts +5 -144
- package/src/runtime/stealth-cookies.ts +132 -0
- package/src/runtime/stealth.ts +14 -157
- 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 +3024 -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/CHANGELOG.md
CHANGED
package/bin/apifuse-dev.ts
CHANGED
|
@@ -4,7 +4,6 @@ import { existsSync } from "node:fs";
|
|
|
4
4
|
import { dirname, relative, resolve } from "node:path";
|
|
5
5
|
import type { ProviderDefinition } from "../src/index.js";
|
|
6
6
|
import {
|
|
7
|
-
createBrowserClient,
|
|
8
7
|
createCredentialContext,
|
|
9
8
|
createEnvContext,
|
|
10
9
|
createHttpClient,
|
|
@@ -12,12 +11,13 @@ import {
|
|
|
12
11
|
createProviderCache,
|
|
13
12
|
createProviderChoiceContext,
|
|
14
13
|
createUnsupportedResolverClient,
|
|
15
|
-
createStealthClient,
|
|
16
14
|
createSttClientFromEnv,
|
|
17
15
|
PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV,
|
|
18
16
|
ProviderError,
|
|
19
17
|
} from "../src/index.js";
|
|
18
|
+
import { createBrowserClient } from "../src/runtime/browser.js";
|
|
20
19
|
import { createMemoryProviderRuntimeState } from "../src/runtime/state.js";
|
|
20
|
+
import { createStealthClient } from "../src/runtime/stealth.js";
|
|
21
21
|
import { createTraceContext } from "../src/runtime/trace.js";
|
|
22
22
|
import type { BrowserClient, ProviderContext } from "../src/types.js";
|
|
23
23
|
|
|
@@ -224,7 +224,7 @@ function smokePackedStealthNative(consumerDir: string): void {
|
|
|
224
224
|
"--eval",
|
|
225
225
|
[
|
|
226
226
|
'import { createServer } from "node:http";',
|
|
227
|
-
'import { createStealthClient } from "@apifuse/provider-sdk";',
|
|
227
|
+
'import { createStealthClient } from "@apifuse/provider-sdk/runtime/stealth";',
|
|
228
228
|
"const server = createServer((_request, response) => {",
|
|
229
229
|
' response.setHeader("set-cookie", "pack_native_cookie=landed; Path=/");',
|
|
230
230
|
' response.end("packed native stealth ok");',
|
|
@@ -357,7 +357,8 @@ function setUpFixtureConsumer(consumerDir: string, tarballPath: string): void {
|
|
|
357
357
|
writeFileSync(
|
|
358
358
|
join(consumerDir, "consumer.ts"),
|
|
359
359
|
[
|
|
360
|
-
'import { defineProvider,
|
|
360
|
+
'import { defineProvider, ProviderError, resolveProxy, SessionExpiredError, z } from "@apifuse/provider-sdk";',
|
|
361
|
+
'import { invalidateResolverSolution } from "@apifuse/provider-sdk/runtime/resolver";',
|
|
361
362
|
'import type { BrowserCookie, ChallengeSolution, NativeNetworkClient, NativeNetworkConnection, NativeProviderConfig, NativeProviderContext, NativeTcpEgressGrant, ProviderChallenge, ProviderContext, ProviderFileRef, ProviderFilesContext, ProviderResolvedFile, ProviderResolverConfig, ResolverContext, ResolverRuntimeOptions } from "@apifuse/provider-sdk";',
|
|
362
363
|
'import type { ProxyProtocol, ProxyResolutionOptions, ProxyResolutionSource, ProxyVendorName, RequestOptions, ResolvedProxyConfig } from "@apifuse/provider-sdk";',
|
|
363
364
|
'import { defineCredentialsAuth } from "@apifuse/provider-sdk/provider";',
|
package/bin/apifuse-perf.ts
CHANGED
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
createBypassProviderCache,
|
|
12
12
|
createHttpClient,
|
|
13
13
|
createProviderChoiceContext,
|
|
14
|
-
createStealthClient,
|
|
15
14
|
createSttClientFromEnv,
|
|
16
15
|
executeOperation,
|
|
17
16
|
getProviderBaseUrl,
|
|
@@ -28,6 +27,7 @@ import {
|
|
|
28
27
|
} from "../src/index.js";
|
|
29
28
|
import { computeStats, groupSpansByName, type PerfStats } from "../src/runtime/perf.js";
|
|
30
29
|
import { createMemoryProviderRuntimeState } from "../src/runtime/state.js";
|
|
30
|
+
import { createStealthClient } from "../src/runtime/stealth.js";
|
|
31
31
|
import { createTraceContext, resolveTraceContextOptions } from "../src/runtime/trace.js";
|
|
32
32
|
import { renderWaterfall } from "../src/runtime/waterfall.js";
|
|
33
33
|
import type { BrowserClient } from "../src/types.js";
|
|
@@ -458,9 +458,7 @@ async function loadFixtureReplay(providerDirectory: string): Promise<FixtureRepl
|
|
|
458
458
|
async function assertProxyConfigured(provider: ProviderDefinition): Promise<void> {
|
|
459
459
|
const policy = provider.proxy;
|
|
460
460
|
if (!policy || typeof policy !== "object" || policy.mode === "disabled") {
|
|
461
|
-
throw new Error(
|
|
462
|
-
"--compare-proxy requires an enabled ProviderProxyPolicy on the provider.",
|
|
463
|
-
);
|
|
461
|
+
throw new Error("--compare-proxy requires an enabled ProviderProxyPolicy on the provider.");
|
|
464
462
|
}
|
|
465
463
|
|
|
466
464
|
const resolved = await resolveProxy({ proxyPolicy: policy });
|
package/bin/apifuse-record.ts
CHANGED
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
createHttpClient,
|
|
11
11
|
createOcrClientFromEnv,
|
|
12
12
|
createProviderChoiceContext,
|
|
13
|
-
createStealthClient,
|
|
14
13
|
createSttClientFromEnv,
|
|
15
14
|
createUnsupportedResolverClient,
|
|
16
15
|
executeOperation,
|
|
@@ -33,6 +32,7 @@ import {
|
|
|
33
32
|
sanitizeFixtureString,
|
|
34
33
|
} from "../src/fixture-sanitization.js";
|
|
35
34
|
import { createMemoryProviderRuntimeState } from "../src/runtime/state.js";
|
|
35
|
+
import { createStealthClient } from "../src/runtime/stealth.js";
|
|
36
36
|
import {
|
|
37
37
|
REDACTED_QUERY_VALUE,
|
|
38
38
|
isSensitiveKey,
|
|
@@ -20,7 +20,7 @@ export declare const AUTH_TURN_SCHEMA_ARTIFACT_PATH = "dist/auth-turn/auth-turn.
|
|
|
20
20
|
*
|
|
21
21
|
* This is the exact codification of the runtime validation the SDK applies to
|
|
22
22
|
* ceremony outputs (see `validateCeremonyOutput` in `src/ceremonies`), which
|
|
23
|
-
*
|
|
23
|
+
* evaluates this same document. `kind` is an OPEN string on the wire: the known
|
|
24
24
|
* kinds in {@link TURN_KINDS} are tooling metadata, never a wire constraint.
|
|
25
25
|
*
|
|
26
26
|
* The committed artifact at `src/auth-turn/auth-turn.v1.schema.json` (shipped
|
package/dist/auth-turn/index.js
CHANGED
|
@@ -18,7 +18,7 @@ export const AUTH_TURN_SCHEMA_ARTIFACT_PATH = "dist/auth-turn/auth-turn.v1.schem
|
|
|
18
18
|
*
|
|
19
19
|
* This is the exact codification of the runtime validation the SDK applies to
|
|
20
20
|
* ceremony outputs (see `validateCeremonyOutput` in `src/ceremonies`), which
|
|
21
|
-
*
|
|
21
|
+
* evaluates this same document. `kind` is an OPEN string on the wire: the known
|
|
22
22
|
* kinds in {@link TURN_KINDS} are tooling metadata, never a wire constraint.
|
|
23
23
|
*
|
|
24
24
|
* The committed artifact at `src/auth-turn/auth-turn.v1.schema.json` (shipped
|
package/dist/ceremonies/index.js
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
2
|
-
import Ajv2020 from "ajv/dist/2020.js";
|
|
3
2
|
import { AUTH_TURN_SCHEMA } from "../auth-turn/index.js";
|
|
4
3
|
import { FlowExpiredError, ProviderSecretError, TurnValidationError, ValidationError, } from "../errors.js";
|
|
5
|
-
const ajv = new Ajv2020({ allErrors: true, strict: true, strictSchema: true });
|
|
6
|
-
// Runtime ceremony-output validation derives from the exported versioned
|
|
7
|
-
// contract: it compiles the exact AUTH_TURN_SCHEMA document shipped at
|
|
8
|
-
// dist/auth-turn/auth-turn.v1.schema.json, so the two cannot drift.
|
|
9
|
-
const validateAuthTurn = ajv.compile(AUTH_TURN_SCHEMA);
|
|
10
4
|
const OAUTH2_STATE_KEY = "__oauth2_state";
|
|
11
5
|
const OAUTH2_PKCE_VERIFIER_KEY = "__oauth2_pkce_verifier";
|
|
12
6
|
export const OAUTH2_PROXIED_AUTH_PROXY_ORIGIN_ENV_KEY = "APIFUSE__AUTH_PROXY__URL";
|
|
@@ -26,6 +20,50 @@ const FORM_FIELD_ORDER_EXTENSION = "x-apifuse-field-order";
|
|
|
26
20
|
function isRecord(value) {
|
|
27
21
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
28
22
|
}
|
|
23
|
+
function validateSchemaNode(value, schema, path, errors) {
|
|
24
|
+
if (schema.type === "object") {
|
|
25
|
+
if (!isRecord(value)) {
|
|
26
|
+
errors.push(`${path} must be object`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const properties = schema.properties ?? {};
|
|
30
|
+
for (const required of schema.required ?? []) {
|
|
31
|
+
if (!Object.hasOwn(value, required) || value[required] === undefined) {
|
|
32
|
+
errors.push(`${path} must have required property '${required}'`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (schema.additionalProperties === false) {
|
|
36
|
+
for (const key of Object.keys(value)) {
|
|
37
|
+
if (!Object.hasOwn(properties, key)) {
|
|
38
|
+
errors.push(`${path} must NOT have additional property '${key}'`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
for (const [key, childSchema] of Object.entries(properties)) {
|
|
43
|
+
if (Object.hasOwn(value, key) && value[key] !== undefined) {
|
|
44
|
+
validateSchemaNode(value[key], childSchema, `${path}/${key}`, errors);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (schema.type === "string") {
|
|
50
|
+
if (typeof value !== "string") {
|
|
51
|
+
errors.push(`${path} must be string`);
|
|
52
|
+
}
|
|
53
|
+
else if (schema.minLength !== undefined && value.length < schema.minLength) {
|
|
54
|
+
errors.push(`${path} must NOT have fewer than ${schema.minLength} characters`);
|
|
55
|
+
}
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (schema.type === "number") {
|
|
59
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
60
|
+
errors.push(`${path} must be number`);
|
|
61
|
+
}
|
|
62
|
+
else if (schema.minimum !== undefined && value < schema.minimum) {
|
|
63
|
+
errors.push(`${path} must be >= ${schema.minimum}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
29
67
|
function ensureRecord(value) {
|
|
30
68
|
return isRecord(value) ? value : {};
|
|
31
69
|
}
|
|
@@ -114,11 +152,14 @@ function withDeclaredFormFieldOrder(expectedInput) {
|
|
|
114
152
|
};
|
|
115
153
|
}
|
|
116
154
|
export function validateCeremonyOutput(turn) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
155
|
+
// Evaluate the exact exported versioned schema without eagerly initializing
|
|
156
|
+
// a general-purpose JSON Schema compiler in every provider process. Contract
|
|
157
|
+
// parity tests compare this focused evaluator with AJV over all fixtures and
|
|
158
|
+
// edge probes, so the runtime and shipped document remain locked together.
|
|
159
|
+
const errors = [];
|
|
160
|
+
validateSchemaNode(turn, AUTH_TURN_SCHEMA, "", errors);
|
|
161
|
+
if (errors.length > 0) {
|
|
162
|
+
throw new TurnValidationError(errors.join("; "));
|
|
122
163
|
}
|
|
123
164
|
return turn;
|
|
124
165
|
}
|
package/dist/config/loader.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Redis } from "ioredis";
|
|
1
|
+
import type { Redis } from "ioredis";
|
|
2
2
|
import type { ProviderProxyPolicy, TraceConfig } from "../types.js";
|
|
3
3
|
import { type ProxyProtocol } from "../runtime/proxy-nodemaven.js";
|
|
4
4
|
export type { ProxyProtocol } from "../runtime/proxy-nodemaven.js";
|
package/dist/config/loader.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
3
4
|
import path from "node:path";
|
|
4
|
-
import { Redis } from "ioredis";
|
|
5
5
|
import { NODEMAVEN_DEFAULT_PROTOCOL, NODEMAVEN_FILTER_ENV, NODEMAVEN_MAX_POOL_SIZE, NODEMAVEN_PASSWORD_ENV, NODEMAVEN_USERNAME_ENV, hasNodemavenCredentials, nodemavenPoolSize, synthesizeNodemavenProxy, } from "../runtime/proxy-nodemaven.js";
|
|
6
6
|
// "smartproxy" here is api.smartproxy.org — a residential proxy with an IP
|
|
7
7
|
// extraction API (app_key → raw ip:port pool). It is NOT the company formerly
|
|
@@ -34,6 +34,7 @@ export class ProxyResolutionError extends Error {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
const proxyCache = new Map();
|
|
37
|
+
const require = createRequire(import.meta.url);
|
|
37
38
|
const proxyInflight = new Map();
|
|
38
39
|
const invalidatedProxyKeys = new Map();
|
|
39
40
|
const redisClients = new Map();
|
|
@@ -84,7 +85,8 @@ function getProxyRedis() {
|
|
|
84
85
|
const existing = redisClients.get(redisUrl);
|
|
85
86
|
if (existing)
|
|
86
87
|
return existing;
|
|
87
|
-
const
|
|
88
|
+
const { Redis: RedisClient } = require("ioredis");
|
|
89
|
+
const redis = new RedisClient(redisUrl, {
|
|
88
90
|
connectTimeout: REDIS_TIMEOUT_MS,
|
|
89
91
|
enableOfflineQueue: false,
|
|
90
92
|
lazyConnect: true,
|
package/dist/index.d.ts
CHANGED
|
@@ -16,29 +16,30 @@ export * from "./recipes/gov-api.js";
|
|
|
16
16
|
export * from "./recipes/rest-api.js";
|
|
17
17
|
export { createFlowContext, createScratchpad } from "./runtime/auth-flow.js";
|
|
18
18
|
export type { BrowserClientOptions } from "./runtime/browser.js";
|
|
19
|
-
export { BrowserClient, createBrowserClient } from "./runtime/browser.js";
|
|
20
19
|
export { APIFUSE__CACHE__KEY_PEPPER_ENV, createBypassProviderCache, createProviderCache, type ProviderCacheOptions, resetProviderCacheForTests, } from "./runtime/cache.js";
|
|
21
20
|
export { type CreateProviderChoiceContextOptions, createProviderChoiceContext, createTestProviderChoiceContext, PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV, } from "./runtime/choice.js";
|
|
22
21
|
export { type CreateCredentialContextOptions, createCredentialContext, } from "./runtime/credential.js";
|
|
23
22
|
export { createEnvContext } from "./runtime/env.js";
|
|
24
23
|
export { executeOperation } from "./runtime/executor.js";
|
|
25
24
|
export { createHttpClient } from "./runtime/http.js";
|
|
26
|
-
export {
|
|
25
|
+
export { NativeEgressGrantExpiredError, NativeEgressNotDeclaredError, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, } from "./runtime/native-network-errors.js";
|
|
26
|
+
export type { NativeGatewayProxy, NativeGatewayProxyResolutionInput, NativeGatewayProxySkipReason, NativeGatewayProxySynthesizer, NativeGatewayProxySynthesisResult, NativeGatewayProxySynthesisInput, NativeNetworkClientOptions, NativeNetworkErrorCode, VendorCredentialLookup, VendorCredentialResolver, } from "./runtime/native-network.js";
|
|
27
27
|
export type { Insight, InsightSeverity } from "./runtime/insights.js";
|
|
28
28
|
export { generateInsights } from "./runtime/insights.js";
|
|
29
29
|
export { type InstrumentationOptions, type InstrumentedProviderContext, wrapWithInstrumentation, } from "./runtime/instrumentation.js";
|
|
30
|
-
export {
|
|
30
|
+
export type { PrevalidateResult } from "./runtime/prevalidate.js";
|
|
31
31
|
export { getProviderBaseUrl } from "./runtime/provider.js";
|
|
32
|
-
export { APIFUSE__CDP_POOL__URL, APIFUSE__RESOLVER__2CAPTCHA__API_KEY, APIFUSE__RESOLVER__CAPMONSTER__API_KEY, APIFUSE__RESOLVER__CAPSOLVER__API_KEY, APIFUSE__RESOLVER__TIMEOUT_MS,
|
|
32
|
+
export { APIFUSE__CDP_POOL__URL, APIFUSE__RESOLVER__2CAPTCHA__API_KEY, APIFUSE__RESOLVER__CAPMONSTER__API_KEY, APIFUSE__RESOLVER__CAPSOLVER__API_KEY, APIFUSE__RESOLVER__TIMEOUT_MS, DEFAULT_RESOLVER_TIMEOUT_MS, } from "./runtime/resolver-config.js";
|
|
33
|
+
export { createUnsupportedResolverClient } from "./runtime/resolver-shared.js";
|
|
34
|
+
export type { ResolverRuntimeOptions } from "./runtime/resolver.js";
|
|
33
35
|
export type { ResolverVendorTransport } from "./runtime/resolver-vendors/types.js";
|
|
34
36
|
export { assertRequiredSecretsPresent, listMissingRequiredSecrets, MISSING_SECRET_CODE, } from "./runtime/secrets.js";
|
|
35
37
|
export { createUnsupportedProviderRuntimeState, UnsupportedProviderStateError, } from "./runtime/state.js";
|
|
36
|
-
export { createStealthClient } from "./runtime/stealth.js";
|
|
37
38
|
export { APIFUSE__OCR__API_KEY_ENV, APIFUSE__OCR__BACKEND_ENV, APIFUSE__OCR__BASE_URL_ENV, APIFUSE__OCR__CLOUDFLARE_API_TOKEN_ENV, APIFUSE__OCR__MODEL_ENV, CLOUDFLARE_ACCOUNT_ID_ENV, CLOUDFLARE_WORKERS_AI_OCR_BACKEND, createCloudflareWorkersAiOcrClient, createOcrClientFromEnv, createOpenAiCompatibleOcrClient, createUnsupportedOcrClient, DEFAULT_CLOUDFLARE_WORKERS_AI_OCR_MODEL, extractCaptchaCandidates, OPENAI_COMPATIBLE_OCR_BACKEND, } from "./runtime/ocr.js";
|
|
38
39
|
export { APIFUSE__STT__BACKEND_ENV, APIFUSE__STT__CLOUDFLARE_API_TOKEN_ENV, APIFUSE__STT__MODEL_ENV, createSttClientFromEnv, createUnsupportedSttClient, extractVerificationCode, resolveSttPrompt, } from "./runtime/stt.js";
|
|
39
40
|
export { type CreateTraceContextOptions, createTraceContext, type Span, type TraceContext, } from "./runtime/trace.js";
|
|
40
41
|
export { APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, redactPayload, type SensitiveFieldKind, type SensitiveFieldOptions, type SensitivePath, sensitive, z, } from "./schema.js";
|
|
41
|
-
export { createServerApp, ERROR_OBSERVABILITY_HEADER, type ServeOptions, serve, } from "./server/
|
|
42
|
+
export { createServerApp, createServerAppAsync, ERROR_OBSERVABILITY_HEADER, type ServeOptions, serve, } from "./server/serve.js";
|
|
42
43
|
export { getStealthProfile, listStealthProfiles } from "./stealth/profiles.js";
|
|
43
44
|
export * from "./stream.js";
|
|
44
45
|
export type { ApiFuseResponse, AuthConfig, AuthContext, AuthFlowDefinition, AuthFlowInputHandler, AuthFlowStartHandler, AuthMode, AuthTurn, Bcp47Locale, BrowserCookie, BrowserEngine, BrowserOptions, BrowserResourceBody, BrowserResourceDecision, BrowserResourceMethod, BrowserResourcePolicy, BrowserResourceRequest, BrowserResourceRoute, ChallengeSolution, ConnectionMode, ContextDeclaration, CookieJar, ContextScratchpad, CredentialContext, CredentialDeclaration, E164PhoneNumber, EnvContext, FlowContext, FlowContextStore, HealthCheckAssertionContext, HealthCheckCase, HealthCheckCaseResult, HealthCheckSuite, HealthCheckUnsupported, HealthJourneyDefinition, HealthJourneyEventContext, HealthJourneyGatewayContext, HealthJourneyJournalContext, HealthJourneyManualTriggerPolicy, HealthJourneyRunContext, HealthJourneyRunResult, HealthJourneySchedule, HealthScheduleRandomization, HealthJourneySmsContext, HealthJourneyStep, HttpClient, HttpMethod, HttpRedirectFailureReason, HttpRedirectPolicy, HttpRedirectPolicyMode, HttpResponse, HttpRetryOptions, HttpRetrySummary, HttpStreamResponse, IanaTimeZone, InferSchemaOutput, Iso3166Alpha2CountryCode, Iso4217CurrencyCode, Iso8601Duration, NativeContext, NativeNetworkClient, NativeNetworkCloseReason, NativeNetworkConnection, NativeNetworkConnectInput, NativeNetworkConnectOptions, NativeNetworkDynamicGrantOptions, NativeNetworkEgressGrant, NativeProviderConfig, NativeProviderContext, NativeProxyDrainHandler, NativeProxyEgressInfo, NativeProxyExpiringEvent, NativeProxyExpiringReason, NativeTcpDynamicEgressRule, NativeTcpEgressGrant, NativeTcpEgressRule, NativeTcpPortRange, NativeTcpTlsMode, NativeTlsConnectOptions, OcrCaptchaCandidate, OcrCaptchaOptions, OcrCaptchaResult, OcrContext, OcrImageInput, OcrRecognizeRequest, OcrResult, OcrWarning, OperationAnnotations, OperationApprovalPolicy, OperationContractMetadata, OperationDefinition, OperationDeprecationMetadata, OperationDocMeta, OperationErrorCode, ProviderErrorStatus, OperationHandlerResult, OperationInputExample, OperationLifecycle, OperationObservabilityConfig, OperationObservabilitySensitiveConfig, OperationRelationships, OperationRiskClass, OperationSensitivePath, OperationToolRouterMetadata, OperationTransport, OperationTransportKind, ProbeInterval, ProviderAccessConfig, ProviderAccessVisibility, ProviderCache, ProviderCacheGetOrSetOptions, ProviderCacheKeyOptions, ProviderCacheLookupMeta, ProviderCacheResponseMeta, ProviderCacheResult, ProviderChoiceBindingOptions, ProviderChoiceContext, ProviderChoiceIssueOptions, ProviderChoiceParseOptions, ProviderChallenge, ProviderChallengeKind, ProviderContext, ProviderDefinition, ProviderDeploymentOverrides, ProviderFileRef, ProviderFilesContext, ProviderHealthMonitorConfig, ProviderHealthProbeConfig, ProviderLocale, ProviderLocaleKey, ProviderLocaleKeyInput, ProviderLogoProfile, ProviderLogoSource, ProviderMeta, ProviderOcrConfig, ProviderProxyConfig, ProviderProxyMode, ProviderProxyPolicy, ProxiedOAuthConfig, ProviderProxyProvider, ProviderProxySessionAffinity, ProviderPublicConnectionMode, ProviderPublicProfile, ProviderReviewed, ProviderResolvedFile, ProviderResolverConfig, ProviderResolverVendor, ProviderRuntimeState, ProviderSecretDeclaration, ProviderStateDurationString, ProviderStateNamespace, ProviderStreamEvent, ProviderSttConfig, ProviderSttMode, ProviderSupportLevel, RequestOptions, RedirectRunReason, ResolverContext, Rfc3339Instant, SchemaLike, SmsOrigin, SmsOtpExtractionPattern, SmsOtpMatcherDefinition, SseMessage, StandardSchemaV1, StateCasResult, StateNamespaceOptions, StateNamespaceScope, StateValue, StateWriteOptions, StealthClient, StealthCookieStore, StealthCookieStoreV1, StealthFetchOptions, StealthPlatform, StealthProfile, StealthRedirectHop, StealthRedirectRunOptions, StealthRedirectRunResult, StealthResponse, StealthSession, StealthSessionCookies, SttAudioInput, SttContext, SttPromptPolicy, SttSegment, SttTranscribeMode, SttTranscribeRequest, SttTranscript, SttUnsupportedOptionPolicy, SttUsage, SttVerificationCodeOptions, SttWarning, TraceConfig, TraceSpan, VerificationCodeCandidate, VerificationCodeCandidateSource, VerificationCodeExtractionResult, } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -14,27 +14,25 @@ export { lintOperation, lintProvider, } from "./lint.js";
|
|
|
14
14
|
export * from "./recipes/gov-api.js";
|
|
15
15
|
export * from "./recipes/rest-api.js";
|
|
16
16
|
export { createFlowContext, createScratchpad } from "./runtime/auth-flow.js";
|
|
17
|
-
export { BrowserClient, createBrowserClient } from "./runtime/browser.js";
|
|
18
17
|
export { APIFUSE__CACHE__KEY_PEPPER_ENV, createBypassProviderCache, createProviderCache, resetProviderCacheForTests, } from "./runtime/cache.js";
|
|
19
18
|
export { createProviderChoiceContext, createTestProviderChoiceContext, PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV, } from "./runtime/choice.js";
|
|
20
19
|
export { createCredentialContext, } from "./runtime/credential.js";
|
|
21
20
|
export { createEnvContext } from "./runtime/env.js";
|
|
22
21
|
export { executeOperation } from "./runtime/executor.js";
|
|
23
22
|
export { createHttpClient } from "./runtime/http.js";
|
|
24
|
-
export {
|
|
23
|
+
export { NativeEgressGrantExpiredError, NativeEgressNotDeclaredError, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, } from "./runtime/native-network-errors.js";
|
|
25
24
|
export { generateInsights } from "./runtime/insights.js";
|
|
26
25
|
export { wrapWithInstrumentation, } from "./runtime/instrumentation.js";
|
|
27
|
-
export { prevalidate } from "./runtime/prevalidate.js";
|
|
28
26
|
export { getProviderBaseUrl } from "./runtime/provider.js";
|
|
29
|
-
export { APIFUSE__CDP_POOL__URL, APIFUSE__RESOLVER__2CAPTCHA__API_KEY, APIFUSE__RESOLVER__CAPMONSTER__API_KEY, APIFUSE__RESOLVER__CAPSOLVER__API_KEY, APIFUSE__RESOLVER__TIMEOUT_MS,
|
|
27
|
+
export { APIFUSE__CDP_POOL__URL, APIFUSE__RESOLVER__2CAPTCHA__API_KEY, APIFUSE__RESOLVER__CAPMONSTER__API_KEY, APIFUSE__RESOLVER__CAPSOLVER__API_KEY, APIFUSE__RESOLVER__TIMEOUT_MS, DEFAULT_RESOLVER_TIMEOUT_MS, } from "./runtime/resolver-config.js";
|
|
28
|
+
export { createUnsupportedResolverClient } from "./runtime/resolver-shared.js";
|
|
30
29
|
export { assertRequiredSecretsPresent, listMissingRequiredSecrets, MISSING_SECRET_CODE, } from "./runtime/secrets.js";
|
|
31
30
|
export { createUnsupportedProviderRuntimeState, UnsupportedProviderStateError, } from "./runtime/state.js";
|
|
32
|
-
export { createStealthClient } from "./runtime/stealth.js";
|
|
33
31
|
export { APIFUSE__OCR__API_KEY_ENV, APIFUSE__OCR__BACKEND_ENV, APIFUSE__OCR__BASE_URL_ENV, APIFUSE__OCR__CLOUDFLARE_API_TOKEN_ENV, APIFUSE__OCR__MODEL_ENV, CLOUDFLARE_ACCOUNT_ID_ENV, CLOUDFLARE_WORKERS_AI_OCR_BACKEND, createCloudflareWorkersAiOcrClient, createOcrClientFromEnv, createOpenAiCompatibleOcrClient, createUnsupportedOcrClient, DEFAULT_CLOUDFLARE_WORKERS_AI_OCR_MODEL, extractCaptchaCandidates, OPENAI_COMPATIBLE_OCR_BACKEND, } from "./runtime/ocr.js";
|
|
34
32
|
export { APIFUSE__STT__BACKEND_ENV, APIFUSE__STT__CLOUDFLARE_API_TOKEN_ENV, APIFUSE__STT__MODEL_ENV, createSttClientFromEnv, createUnsupportedSttClient, extractVerificationCode, resolveSttPrompt, } from "./runtime/stt.js";
|
|
35
33
|
export { createTraceContext, } from "./runtime/trace.js";
|
|
36
34
|
export { APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, redactPayload, sensitive, z, } from "./schema.js";
|
|
37
|
-
export { createServerApp, ERROR_OBSERVABILITY_HEADER, serve, } from "./server/
|
|
35
|
+
export { createServerApp, createServerAppAsync, ERROR_OBSERVABILITY_HEADER, serve, } from "./server/serve.js";
|
|
38
36
|
export { getStealthProfile, listStealthProfiles } from "./stealth/profiles.js";
|
|
39
37
|
export * from "./stream.js";
|
|
40
38
|
export { DEFAULT_OPERATION_TRANSPORT, HttpRetryAfterPolicy, HttpRetryDelayStrategy, HttpRetryJitter, HttpRetryPreset, HttpRetryUnsafeMethodPolicy, PROBE_INTERVALS, STREAM_CHUNK_BYTES_MAX, STREAM_CHUNK_BYTES_MIN, STREAM_HEARTBEAT_MS_MAX, STREAM_HEARTBEAT_MS_MIN, STREAM_IDLE_TIMEOUT_MS_MAX, STREAM_IDLE_TIMEOUT_MS_MIN, STREAM_MAX_DURATION_MS_MAX, STREAM_MAX_DURATION_MS_MIN, } from "./types.js";
|
package/dist/provider.d.ts
CHANGED
|
@@ -8,5 +8,6 @@ export { getProviderLocalePath, providerLocaleKey, qualifyProviderLocaleKey, } f
|
|
|
8
8
|
export { type CreateProviderChoiceContextOptions, createProviderChoiceContext, createTestProviderChoiceContext, PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV, } from "./runtime/choice.js";
|
|
9
9
|
export { APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, redactPayload, type SensitiveFieldKind, type SensitiveFieldOptions, type SensitivePath, sensitive, z, } from "./schema.js";
|
|
10
10
|
export type { AuthAbortData, AuthAbortRetry, AuthFlowTerminalContext, AuthMode, AuthSafeData, AuthSafeJson, FlowContext, HealthCheckAssertionContext, HealthCheckCase, HealthCheckSuite, HealthCheckUnsupported, HealthJourneyDefinition, HealthJourneyEventContext, HealthJourneyManualTriggerPolicy, HealthJourneyRunContext, HealthJourneyRunResult, HealthScheduleRandomization, HttpRedirectFailureReason, HttpRedirectPolicy, HttpRedirectPolicyMode, HttpRetryOptions, HttpRetrySummary, InferSchemaOutput, NativeContext, NativeNetworkClient, NativeNetworkCloseReason, NativeNetworkConnection, NativeNetworkConnectInput, NativeNetworkConnectOptions, NativeNetworkDynamicGrantOptions, NativeNetworkEgressGrant, NativeProviderConfig, NativeProviderContext, NativeProxyDrainHandler, NativeProxyEgressInfo, NativeProxyExpiringEvent, NativeProxyExpiringReason, NativeTcpDynamicEgressRule, NativeTcpEgressGrant, NativeTcpEgressRule, NativeTcpPortRange, NativeTcpTlsMode, NativeTlsConnectOptions, OperationApprovalPolicy, OperationContractMetadata, OperationDefinition, OperationDocMeta, OperationErrorCode, ProviderErrorStatus, OperationInputExample, OperationLifecycle, OperationObservabilityConfig, OperationObservabilitySensitiveConfig, OperationRelationships, OperationRiskClass, OperationSensitivePath, OperationToolRouterMetadata, OperationTransport, ProviderAccessVisibility, ProviderChoiceBindingOptions, ProviderChoiceContext, ProviderChoiceIssueOptions, ProviderChoiceParseOptions, ProviderContext, ProviderDefinition, ProviderDeploymentOverrides, ProviderFileRef, ProviderFilesContext, ProviderLocale, ProviderLocaleKey, ProviderLocaleKeyInput, ProviderLogoProfile, ProviderProxyPolicy, ProxiedOAuthConfig, ProviderPublicConnectionMode, ProviderPublicProfile, ProviderResolvedFile, ProviderRuntimeState, ProviderStateDurationString, ProviderStateNamespace, ProviderSupportLevel, RedirectRunReason, SchemaLike, SmsOtpMatcherDefinition, StandardSchemaV1, StateCasResult, StateNamespaceOptions, StateNamespaceScope, StateValue, StateWriteOptions, } from "./types.js";
|
|
11
|
-
export {
|
|
11
|
+
export { NativeEgressGrantExpiredError, NativeEgressNotDeclaredError, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, } from "./runtime/native-network-errors.js";
|
|
12
|
+
export type { NativeGatewayProxy, NativeGatewayProxyResolutionInput, NativeGatewayProxySkipReason, NativeGatewayProxySynthesizer, NativeGatewayProxySynthesisResult, NativeGatewayProxySynthesisInput, NativeNetworkClientOptions, NativeNetworkErrorCode, VendorCredentialLookup, VendorCredentialResolver, } from "./runtime/native-network.js";
|
|
12
13
|
export { HttpRetryAfterPolicy, HttpRetryDelayStrategy, HttpRetryJitter, HttpRetryPreset, HttpRetryUnsafeMethodPolicy, } from "./types.js";
|
package/dist/provider.js
CHANGED
|
@@ -6,5 +6,5 @@ export { AuthError, HttpRedirectError, isProviderError, isSessionExpiredError, i
|
|
|
6
6
|
export { getProviderLocalePath, providerLocaleKey, qualifyProviderLocaleKey, } from "./i18n/index.js";
|
|
7
7
|
export { createProviderChoiceContext, createTestProviderChoiceContext, PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV, } from "./runtime/choice.js";
|
|
8
8
|
export { APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, redactPayload, sensitive, z, } from "./schema.js";
|
|
9
|
-
export {
|
|
9
|
+
export { NativeEgressGrantExpiredError, NativeEgressNotDeclaredError, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, } from "./runtime/native-network-errors.js";
|
|
10
10
|
export { HttpRetryAfterPolicy, HttpRetryDelayStrategy, HttpRetryJitter, HttpRetryPreset, HttpRetryUnsafeMethodPolicy, } from "./types.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ContextAccessError } from "../errors.js";
|
|
2
2
|
import { createAuthFlowHelpers } from "../auth.js";
|
|
3
3
|
import { createUnsupportedOcrClient } from "./ocr.js";
|
|
4
|
-
import { createUnsupportedResolverClient } from "./resolver.js";
|
|
4
|
+
import { createUnsupportedResolverClient } from "./resolver-shared.js";
|
|
5
5
|
import { createUnsupportedSttClient } from "./stt.js";
|
|
6
6
|
function normalizeAllowedKeys(allowedKeys) {
|
|
7
7
|
return new Set(allowedKeys.filter((key) => key.trim().length > 0));
|
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;
|