@apifuse/provider-sdk 2.2.0-beta.1 → 2.2.0-beta.10
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/AUTHORING.md +106 -0
- package/CHANGELOG.md +37 -0
- package/README.md +5 -1
- package/SUBMISSION.md +1 -1
- package/bin/apifuse-check.ts +44 -59
- package/bin/apifuse-create.ts +1 -1
- package/bin/apifuse-dev.ts +27 -52
- package/bin/apifuse-pack-check.ts +14 -0
- package/bin/apifuse-pack-smoke.ts +22 -81
- package/bin/apifuse-pack-types.ts +266 -0
- package/bin/apifuse-perf.ts +45 -127
- package/bin/apifuse-record.ts +53 -70
- package/bin/apifuse-submit-check.ts +510 -45
- package/bin/apifuse-sync-assets.ts +117 -0
- package/bin/apifuse.ts +1 -1
- package/bin/submit-check-delimited-text.ts +50 -0
- package/bin/submit-check-xml-semantics.ts +204 -0
- package/bin/submit-check-xml.ts +134 -0
- package/dist/auth-turn/index.d.ts +3 -3
- package/dist/auth.d.ts +2 -2
- package/dist/auth.js +9 -18
- package/dist/ceremonies/index.d.ts +1 -1
- package/dist/ceremonies/index.js +8 -18
- package/dist/cli/commands.d.ts +1 -1
- package/dist/cli/commands.js +8 -0
- package/dist/cli/create.d.ts +3 -0
- package/dist/cli/create.js +34 -35
- package/dist/cli/prompt-assets.d.ts +80 -0
- package/dist/cli/prompt-assets.js +743 -0
- package/dist/cli/templates/provider/AGENTS.md.tpl +17 -8
- package/dist/config/loader.d.ts +149 -8
- package/dist/config/loader.js +378 -89
- package/dist/contract-serialization.d.ts +2 -2
- package/dist/contract-serialization.js +3 -6
- package/dist/contract-types.d.ts +2 -2
- package/dist/contract.d.ts +3 -3
- package/dist/contract.js +4 -6
- package/dist/define.d.ts +8 -1
- package/dist/define.js +119 -122
- package/dist/dev.d.ts +1 -1
- package/dist/dev.js +1 -1
- package/dist/errors.d.ts +4 -1
- package/dist/errors.js +48 -0
- package/dist/i18n/catalog.d.ts +2 -2
- package/dist/i18n/catalog.js +4 -10
- package/dist/i18n/index.d.ts +2 -2
- package/dist/i18n/index.js +2 -2
- package/dist/i18n/keys.d.ts +2 -2
- package/dist/index.d.ts +44 -42
- package/dist/index.js +39 -37
- package/dist/lint.js +8 -15
- package/dist/provider.d.ts +11 -11
- package/dist/provider.js +9 -9
- package/dist/public-schema-field-lint.d.ts +1 -1
- package/dist/recipes/gov-api.js +1 -1
- package/dist/runtime/auth-flow.d.ts +1 -1
- package/dist/runtime/auth-flow.js +3 -3
- package/dist/runtime/browser.d.ts +1 -1
- package/dist/runtime/browser.js +15 -29
- package/dist/runtime/cache.d.ts +1 -1
- package/dist/runtime/cache.js +4 -8
- package/dist/runtime/choice.d.ts +1 -1
- package/dist/runtime/choice.js +31 -35
- package/dist/runtime/credential.d.ts +1 -1
- package/dist/runtime/credential.js +1 -1
- package/dist/runtime/env.d.ts +1 -1
- package/dist/runtime/executor.d.ts +1 -1
- package/dist/runtime/executor.js +15 -3
- package/dist/runtime/http.d.ts +2 -2
- package/dist/runtime/http.js +144 -348
- package/dist/runtime/insights.d.ts +1 -1
- package/dist/runtime/insights.js +6 -13
- package/dist/runtime/instrumentation.d.ts +2 -2
- package/dist/runtime/instrumentation.js +56 -19
- package/dist/runtime/keyring.js +1 -1
- package/dist/runtime/namespace.js +1 -1
- package/dist/runtime/otlp.d.ts +1 -1
- package/dist/runtime/perf.d.ts +1 -1
- package/dist/runtime/provider.d.ts +1 -1
- package/dist/runtime/provider.js +1 -2
- package/dist/runtime/proxy-errors.d.ts +1 -1
- package/dist/runtime/proxy-errors.js +9 -7
- package/dist/runtime/proxy-nodemaven.d.ts +35 -0
- package/dist/runtime/proxy-nodemaven.js +128 -0
- package/dist/runtime/proxy-retry-policy.d.ts +40 -0
- package/dist/runtime/proxy-retry-policy.js +326 -0
- package/dist/runtime/proxy-telemetry.d.ts +2 -1
- package/dist/runtime/proxy-telemetry.js +55 -52
- package/dist/runtime/redis.d.ts +1 -1
- package/dist/runtime/redis.js +2 -4
- package/dist/runtime/request-options.d.ts +1 -1
- package/dist/runtime/secrets.d.ts +27 -0
- package/dist/runtime/secrets.js +51 -0
- package/dist/runtime/state.d.ts +2 -2
- package/dist/runtime/state.js +15 -4
- package/dist/runtime/stealth.d.ts +2 -2
- package/dist/runtime/stealth.js +108 -212
- package/dist/runtime/stt.d.ts +1 -1
- package/dist/runtime/stt.js +11 -15
- package/dist/runtime/trace.d.ts +2 -2
- package/dist/runtime/trace.js +2 -4
- package/dist/runtime/waterfall.d.ts +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +7 -15
- package/dist/serve.d.ts +1 -1
- package/dist/serve.js +1 -1
- package/dist/server/index.d.ts +7 -7
- package/dist/server/index.js +6 -6
- package/dist/server/self-test-redaction.d.ts +1 -1
- package/dist/server/self-test-redaction.js +1 -1
- package/dist/server/self-test.d.ts +104 -3
- package/dist/server/self-test.js +673 -115
- package/dist/server/serve.d.ts +8 -3
- package/dist/server/serve.js +105 -59
- package/dist/server/types.d.ts +10 -9
- package/dist/server/types.js +3 -7
- package/dist/stealth/profiles.d.ts +1 -1
- package/dist/stealth/profiles.js +5 -14
- package/dist/stream.d.ts +1 -1
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +2 -2
- package/dist/testing/run.d.ts +1 -1
- package/dist/testing/run.js +7 -14
- package/dist/types.d.ts +87 -1
- package/dist/user-input.d.ts +30 -0
- package/dist/user-input.js +66 -0
- package/package.json +9 -5
- package/src/auth-turn/index.ts +1 -1
- package/src/auth.ts +28 -86
- package/src/ceremonies/index.ts +24 -78
- package/src/cli/commands.ts +10 -0
- package/src/cli/create.ts +42 -35
- package/src/cli/prompt-assets.ts +865 -0
- package/src/cli/templates/provider/AGENTS.md.tpl +17 -8
- package/src/config/loader.ts +543 -208
- package/src/contract-serialization.ts +5 -11
- package/src/contract-types.ts +2 -2
- package/src/contract.ts +12 -28
- package/src/define.ts +247 -505
- package/src/dev.ts +4 -9
- package/src/errors.ts +58 -5
- package/src/i18n/catalog.ts +10 -32
- package/src/i18n/index.ts +2 -2
- package/src/i18n/keys.ts +5 -11
- package/src/index.ts +49 -42
- package/src/lint.ts +89 -159
- package/src/provider.ts +15 -11
- package/src/public-schema-field-lint.ts +7 -33
- package/src/recipes/gov-api.ts +2 -5
- package/src/runtime/auth-flow.ts +5 -7
- package/src/runtime/browser.ts +64 -187
- package/src/runtime/cache.ts +20 -67
- package/src/runtime/choice.ts +79 -132
- package/src/runtime/credential.ts +2 -2
- package/src/runtime/env.ts +1 -1
- package/src/runtime/executor.ts +23 -20
- package/src/runtime/http.ts +195 -559
- package/src/runtime/insights.ts +15 -53
- package/src/runtime/instrumentation.ts +78 -65
- package/src/runtime/keyring.ts +7 -19
- package/src/runtime/namespace.ts +2 -7
- package/src/runtime/otlp.ts +12 -23
- package/src/runtime/perf.ts +1 -1
- package/src/runtime/provider.ts +4 -9
- package/src/runtime/proxy-errors.ts +29 -42
- package/src/runtime/proxy-nodemaven.ts +178 -0
- package/src/runtime/proxy-retry-policy.ts +469 -0
- package/src/runtime/proxy-telemetry.ts +79 -77
- package/src/runtime/redis.ts +4 -12
- package/src/runtime/request-options.ts +4 -13
- package/src/runtime/secrets.ts +64 -0
- package/src/runtime/state.ts +41 -110
- package/src/runtime/stealth.ts +162 -377
- package/src/runtime/stt.ts +38 -94
- package/src/runtime/trace.ts +14 -44
- package/src/runtime/waterfall.ts +5 -18
- package/src/schema.ts +23 -84
- package/src/serve.ts +1 -1
- package/src/server/index.ts +12 -7
- package/src/server/self-test-redaction.ts +2 -2
- package/src/server/self-test.ts +857 -132
- package/src/server/serve.ts +172 -245
- package/src/server/types.ts +7 -19
- package/src/stealth/profiles.ts +10 -26
- package/src/stream.ts +8 -19
- package/src/testing/index.ts +2 -2
- package/src/testing/run.ts +19 -67
- package/src/types.ts +88 -1
- package/src/user-input.ts +118 -0
- package/dist/cli/templates/provider/CLAUDE.md.tpl +0 -1
- package/src/cli/templates/provider/CLAUDE.md.tpl +0 -1
- /package/dist/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
package/dist/runtime/state.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { providerStateRedisUrlFromEnv } from "../config/loader";
|
|
2
|
-
import { ProviderError } from "../errors";
|
|
3
|
-
import { createProviderRedisClient, ensureRedisReady, withRedisTimeout, } from "./redis";
|
|
1
|
+
import { providerStateRedisUrlFromEnv } from "../config/loader.js";
|
|
2
|
+
import { ProviderError } from "../errors.js";
|
|
3
|
+
import { createProviderRedisClient, ensureRedisReady, withRedisTimeout, } from "./redis.js";
|
|
4
4
|
const DEFAULT_REDIS_TIMEOUT_MS = 250;
|
|
5
5
|
const REDIS_STATE_PREFIX = "apifuse:provider-state:v1";
|
|
6
6
|
const redisBackends = new Map();
|
|
@@ -69,7 +69,18 @@ function resolveExpiresAt(ttl) {
|
|
|
69
69
|
function envelopeFromJson(key, raw) {
|
|
70
70
|
if (!raw)
|
|
71
71
|
return null;
|
|
72
|
-
|
|
72
|
+
// A corrupt/undecodable persisted envelope must be treated as absent rather
|
|
73
|
+
// than throwing a raw JSON.parse SyntaxError: an uncaught SyntaxError escapes
|
|
74
|
+
// the provider error taxonomy, is masked as internal_error 500, and is then
|
|
75
|
+
// retried by the hub (2026-07-22 catchtable reserve RCA, candidate A). Returning
|
|
76
|
+
// null also keeps list() from aborting the whole scan on a single bad entry.
|
|
77
|
+
let parsed;
|
|
78
|
+
try {
|
|
79
|
+
parsed = JSON.parse(raw);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
73
84
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
74
85
|
return null;
|
|
75
86
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ImpitResponse } from "impit";
|
|
2
|
-
import type { ProxyResolutionOptions } from "../config/loader";
|
|
3
|
-
import type { StealthClient, StealthResponse } from "../types";
|
|
2
|
+
import type { ProxyResolutionOptions } from "../config/loader.js";
|
|
3
|
+
import type { StealthClient, StealthResponse } from "../types.js";
|
|
4
4
|
export type StealthClientOptions = ProxyResolutionOptions & {
|
|
5
5
|
warn?: (message: string) => void;
|
|
6
6
|
/**
|
package/dist/runtime/stealth.js
CHANGED
|
@@ -1,44 +1,19 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { Impit } from "impit";
|
|
3
|
-
import { DEFAULT_SMARTPROXY_POOL_SIZE, invalidateProxyResolutionCacheAsync, ProxyResolutionError, resolveProxyConfigAsync,
|
|
4
|
-
import {
|
|
5
|
-
import { getStealthProfile } from "../stealth/profiles";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { appendQueryParams } from "./request-options";
|
|
3
|
+
import { DEFAULT_SMARTPROXY_POOL_SIZE, invalidateProxyResolutionCacheAsync, policyResolvesRegistryVendorChain, ProxyResolutionError, resolvePolicyProxyPoolSpan, resolvePolicyTransportAttemptCap, resolveProxyConfigAsync, vendorFromResolvedSource, } from "../config/loader.js";
|
|
4
|
+
import { SDKError, TransportError } from "../errors.js";
|
|
5
|
+
import { getStealthProfile } from "../stealth/profiles.js";
|
|
6
|
+
import { createProxyAuthIpDeniedError, createProxyEdgeAuthRejectedError, createProxyEdgeTlsRejectedError, createProxyPoolExhaustedError, createProxyPoolStaleError, isProxyAuthIpDeniedMessage, isProxyEdgeAuthRejectedMessage, isProxyEdgeTlsRejectedResponse, isProxyPoolRefreshableError, isProxyPoolStaleMessage, isProxyPoolStaleStatus, PROXY_EDGE_AUTH_REJECTED_CODE, PROXY_POOL_STALE_CODE, } from "./proxy-errors.js";
|
|
7
|
+
import { computeProxyAttemptIndex, computeProxyTransportRetryDelayMs, createDefaultProxyTransportRetryOptions, normalizeProxyTransportRetryOptions, shouldRetryProxyTransportAttempt, validateUnsafeProxyTransportRetryMethods, } from "./proxy-retry-policy.js";
|
|
8
|
+
import { appendQueryParams } from "./request-options.js";
|
|
9
9
|
const DEFAULT_PROFILE = "chrome-146";
|
|
10
10
|
const MISSING_PROXY_WARNING = "[provider-sdk] Provider requested proxy routing, but no proxy URL was configured. Continuing without proxy.";
|
|
11
|
-
const MAX_POLICY_PROXY_RETRY_ATTEMPTS = SMARTPROXY_MAX_POOL_SIZE;
|
|
12
11
|
const MAX_POLICY_PROXY_POOL_REFRESHES = 1;
|
|
13
12
|
const PROXY_CONNECT_FAILURE_CODE = "proxy_connect_failed";
|
|
14
13
|
const PROXY_CONNECT_FAILURE_BODY_PATTERN = /\bproxy\b.*\b(non[\s-]?200|connect|tunnel)|\bconnect\b.*\bproxy\b|\btunnel\b/i;
|
|
15
14
|
const PROXY_AUTH_DIAGNOSTIC_URL = "http://example.com/";
|
|
16
15
|
const PROXY_AUTH_DIAGNOSTIC_TIMEOUT_MS = 5_000;
|
|
17
|
-
const
|
|
18
|
-
const DEFAULT_STEALTH_RETRY_ERROR_CODES = [
|
|
19
|
-
PROXY_CONNECT_FAILURE_CODE,
|
|
20
|
-
"transport_network_error",
|
|
21
|
-
"transport_timeout",
|
|
22
|
-
];
|
|
23
|
-
const RATE_LIMIT_STEALTH_RETRY_ERROR_CODES = ["transport_timeout"];
|
|
24
|
-
const KNOWN_STEALTH_RETRY_METHODS = new Set([
|
|
25
|
-
"GET",
|
|
26
|
-
"HEAD",
|
|
27
|
-
"POST",
|
|
28
|
-
"PUT",
|
|
29
|
-
"DELETE",
|
|
30
|
-
"OPTIONS",
|
|
31
|
-
"TRACE",
|
|
32
|
-
"PATCH",
|
|
33
|
-
]);
|
|
34
|
-
const UNSAFE_STEALTH_RETRY_METHODS = new Set([
|
|
35
|
-
"POST",
|
|
36
|
-
"PUT",
|
|
37
|
-
"PATCH",
|
|
38
|
-
"DELETE",
|
|
39
|
-
"TRACE",
|
|
40
|
-
]);
|
|
41
|
-
const MAX_STEALTH_RETRY_ATTEMPTS = 8;
|
|
16
|
+
const STEALTH_PROXY_TRANSPORT_RETRY_ERROR_CODES = [PROXY_CONNECT_FAILURE_CODE];
|
|
42
17
|
const REMOVED_CHROME_PROFILE_NAMES = new Set([
|
|
43
18
|
"chrome-120",
|
|
44
19
|
"chrome-124",
|
|
@@ -303,130 +278,8 @@ function isPolicyManagedProxy(options) {
|
|
|
303
278
|
const policy = options.proxyPolicy ?? options.upstream?.proxy;
|
|
304
279
|
return Boolean(policy && typeof policy === "object");
|
|
305
280
|
}
|
|
306
|
-
function isRetrySafeStealthMethod(method) {
|
|
307
|
-
return method === "GET" || method === "HEAD" || method === "OPTIONS";
|
|
308
|
-
}
|
|
309
|
-
function createStealthRetryOptions(preset) {
|
|
310
|
-
switch (preset) {
|
|
311
|
-
case HttpRetryPreset.Off:
|
|
312
|
-
return {
|
|
313
|
-
attempts: 1,
|
|
314
|
-
methods: DEFAULT_STEALTH_RETRY_METHODS,
|
|
315
|
-
errorCodes: DEFAULT_STEALTH_RETRY_ERROR_CODES,
|
|
316
|
-
unsafeMethodPolicy: HttpRetryUnsafeMethodPolicy.Reject,
|
|
317
|
-
};
|
|
318
|
-
case HttpRetryPreset.AggressiveRead:
|
|
319
|
-
return {
|
|
320
|
-
attempts: 4,
|
|
321
|
-
methods: DEFAULT_STEALTH_RETRY_METHODS,
|
|
322
|
-
errorCodes: DEFAULT_STEALTH_RETRY_ERROR_CODES,
|
|
323
|
-
unsafeMethodPolicy: HttpRetryUnsafeMethodPolicy.Reject,
|
|
324
|
-
};
|
|
325
|
-
case HttpRetryPreset.RateLimitAware:
|
|
326
|
-
return {
|
|
327
|
-
attempts: 3,
|
|
328
|
-
methods: DEFAULT_STEALTH_RETRY_METHODS,
|
|
329
|
-
errorCodes: RATE_LIMIT_STEALTH_RETRY_ERROR_CODES,
|
|
330
|
-
unsafeMethodPolicy: HttpRetryUnsafeMethodPolicy.Reject,
|
|
331
|
-
};
|
|
332
|
-
case HttpRetryPreset.SafeRead:
|
|
333
|
-
case HttpRetryPreset.TransportTransient:
|
|
334
|
-
return {
|
|
335
|
-
attempts: 3,
|
|
336
|
-
methods: DEFAULT_STEALTH_RETRY_METHODS,
|
|
337
|
-
errorCodes: DEFAULT_STEALTH_RETRY_ERROR_CODES,
|
|
338
|
-
unsafeMethodPolicy: HttpRetryUnsafeMethodPolicy.Reject,
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
throw new ProviderError(`Unknown stealth retry preset: ${preset}`, {
|
|
342
|
-
code: "retry_invalid_policy",
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
function normalizeStealthRetryOptions(retry) {
|
|
346
|
-
if (retry === undefined)
|
|
347
|
-
return undefined;
|
|
348
|
-
if (retry === false)
|
|
349
|
-
return createStealthRetryOptions(HttpRetryPreset.Off);
|
|
350
|
-
if (retry === true)
|
|
351
|
-
return createStealthRetryOptions(HttpRetryPreset.TransportTransient);
|
|
352
|
-
if (typeof retry === "string") {
|
|
353
|
-
if (!Object.values(HttpRetryPreset).includes(retry)) {
|
|
354
|
-
throw new ProviderError(`Unknown stealth retry preset: ${retry}`, {
|
|
355
|
-
code: "retry_invalid_policy",
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
return createStealthRetryOptions(retry);
|
|
359
|
-
}
|
|
360
|
-
if (typeof retry !== "object" || retry === null || Array.isArray(retry)) {
|
|
361
|
-
throw new ProviderError("Stealth retry policy must be a plain object", {
|
|
362
|
-
code: "retry_invalid_policy",
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
if (retry.unsafeMethodPolicy !== undefined &&
|
|
366
|
-
!Object.values(HttpRetryUnsafeMethodPolicy).includes(retry.unsafeMethodPolicy)) {
|
|
367
|
-
throw new ProviderError(`Unknown stealth retry unsafe method policy: ${String(retry.unsafeMethodPolicy)}`, { code: "retry_invalid_policy" });
|
|
368
|
-
}
|
|
369
|
-
if (retry.methods !== undefined) {
|
|
370
|
-
if (!Array.isArray(retry.methods)) {
|
|
371
|
-
throw new ProviderError("Stealth retry methods must be an array", {
|
|
372
|
-
code: "retry_invalid_policy",
|
|
373
|
-
});
|
|
374
|
-
}
|
|
375
|
-
const unknownMethods = retry.methods
|
|
376
|
-
.map((method) => (typeof method === "string" ? method.toUpperCase() : ""))
|
|
377
|
-
.filter((method) => !KNOWN_STEALTH_RETRY_METHODS.has(method));
|
|
378
|
-
if (unknownMethods.length > 0) {
|
|
379
|
-
throw new ProviderError(`Unknown stealth retry method(s): ${unknownMethods.join(", ")}`, { code: "retry_invalid_policy" });
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
if (retry.errorCodes !== undefined) {
|
|
383
|
-
if (!Array.isArray(retry.errorCodes) ||
|
|
384
|
-
retry.errorCodes.some((errorCode) => typeof errorCode !== "string")) {
|
|
385
|
-
throw new ProviderError("Stealth retry errorCodes must contain only strings", { code: "retry_invalid_policy" });
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
const base = createStealthRetryOptions(retry.preset ?? HttpRetryPreset.TransportTransient);
|
|
389
|
-
const attempts = retry.attempts === undefined || !Number.isFinite(retry.attempts)
|
|
390
|
-
? base.attempts
|
|
391
|
-
: Math.max(1, Math.min(MAX_STEALTH_RETRY_ATTEMPTS, Math.floor(retry.attempts)));
|
|
392
|
-
const normalized = {
|
|
393
|
-
attempts,
|
|
394
|
-
methods: retry.methods?.map((method) => method.toUpperCase()) ?? base.methods,
|
|
395
|
-
errorCodes: retry.errorCodes ?? base.errorCodes,
|
|
396
|
-
unsafeMethodPolicy: retry.unsafeMethodPolicy ?? base.unsafeMethodPolicy,
|
|
397
|
-
};
|
|
398
|
-
if (normalized.unsafeMethodPolicy !==
|
|
399
|
-
HttpRetryUnsafeMethodPolicy.AllowExplicitUnsafe) {
|
|
400
|
-
const unsafeMethods = normalized.methods.filter((method) => UNSAFE_STEALTH_RETRY_METHODS.has(method.toUpperCase()));
|
|
401
|
-
if (unsafeMethods.length > 0) {
|
|
402
|
-
throw new ProviderError(`Stealth retry methods include unsafe method(s): ${unsafeMethods.join(", ")}`, { code: "retry_unsafe_method" });
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
return normalized;
|
|
406
|
-
}
|
|
407
|
-
function isExplicitStealthRetryAllowed(method, error, retryOptions) {
|
|
408
|
-
if (!retryOptions || retryOptions.attempts <= 1)
|
|
409
|
-
return false;
|
|
410
|
-
return (retryOptions.methods.includes(method.toUpperCase()) &&
|
|
411
|
-
retryOptions.errorCodes.includes(proxyAttemptErrorCode(error)));
|
|
412
|
-
}
|
|
413
|
-
function isRetryableProxyTransportError(error) {
|
|
414
|
-
if (error instanceof TransportError) {
|
|
415
|
-
if (error.code === PROXY_AUTH_IP_DENIED_CODE) {
|
|
416
|
-
return false;
|
|
417
|
-
}
|
|
418
|
-
return (error.code === PROXY_CONNECT_FAILURE_CODE ||
|
|
419
|
-
error.code === "transport_network_error" ||
|
|
420
|
-
error.code === "transport_timeout");
|
|
421
|
-
}
|
|
422
|
-
if (error instanceof SDKError) {
|
|
423
|
-
return false;
|
|
424
|
-
}
|
|
425
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
426
|
-
return /\bproxy\b|\bnon[\s-]?200\b|\bconnect\b|\btunnel\b/i.test(message);
|
|
427
|
-
}
|
|
428
281
|
function isProxyConnectFailureResponse(response, body) {
|
|
429
|
-
return
|
|
282
|
+
return response.status === 0 && PROXY_CONNECT_FAILURE_BODY_PATTERN.test(body ?? "");
|
|
430
283
|
}
|
|
431
284
|
function createProxyConnectFailureError(body, cause) {
|
|
432
285
|
const bodyExcerpt = (body ?? "").trim().slice(0, 1_000);
|
|
@@ -529,8 +382,7 @@ function normalizeStealthTransportError(error) {
|
|
|
529
382
|
return createProxyEdgeAuthRejectedError(error instanceof Error ? error : undefined);
|
|
530
383
|
}
|
|
531
384
|
const proxyTunnelStatus = getProxyTunnelStatus(error);
|
|
532
|
-
if (proxyTunnelStatus !== undefined &&
|
|
533
|
-
isProxyPoolStaleStatus(proxyTunnelStatus)) {
|
|
385
|
+
if (proxyTunnelStatus !== undefined && isProxyPoolStaleStatus(proxyTunnelStatus)) {
|
|
534
386
|
return createProxyPoolStaleError(proxyTunnelStatus, error instanceof Error ? error : undefined);
|
|
535
387
|
}
|
|
536
388
|
if (PROXY_CONNECT_FAILURE_BODY_PATTERN.test(message)) {
|
|
@@ -542,6 +394,9 @@ function normalizeStealthTransportError(error) {
|
|
|
542
394
|
cause: error instanceof Error ? error : undefined,
|
|
543
395
|
});
|
|
544
396
|
}
|
|
397
|
+
function sleep(ms) {
|
|
398
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
399
|
+
}
|
|
545
400
|
function normalizeMethod(method) {
|
|
546
401
|
switch (method.toUpperCase()) {
|
|
547
402
|
case "HEAD":
|
|
@@ -607,19 +462,21 @@ function createSessionFetcher(baseUrl, defaultProfile, clientOptions) {
|
|
|
607
462
|
}
|
|
608
463
|
return client;
|
|
609
464
|
}
|
|
610
|
-
async function resolveRequestProxy(options, proxyAttempt) {
|
|
611
|
-
const rawProxyAttemptOffset = options?.proxyAttemptOffset ?? 0;
|
|
612
|
-
const proxyAttemptOffset = Number.isFinite(rawProxyAttemptOffset)
|
|
613
|
-
? Math.max(0, Math.floor(rawProxyAttemptOffset))
|
|
614
|
-
: 0;
|
|
465
|
+
async function resolveRequestProxy(options, proxyAttempt, refreshEpoch) {
|
|
615
466
|
const resolvedProxy = await resolveProxyConfigAsync({
|
|
616
467
|
proxy: options?.proxy ?? clientOptions.proxy,
|
|
617
468
|
upstream: clientOptions.upstream,
|
|
618
469
|
apifuseConfig: clientOptions.apifuseConfig,
|
|
619
470
|
affinityKey: clientOptions.affinityKey,
|
|
620
|
-
proxyAttempt:
|
|
621
|
-
|
|
622
|
-
: proxyAttemptOffset
|
|
471
|
+
proxyAttempt: computeProxyAttemptIndex({
|
|
472
|
+
baseProxyAttempt: clientOptions.proxyAttempt,
|
|
473
|
+
proxyAttemptOffset: options?.proxyAttemptOffset,
|
|
474
|
+
retryAttemptOffset: proxyAttempt,
|
|
475
|
+
}),
|
|
476
|
+
// The impit stealth transport tunnels both HTTP CONNECT and SOCKS5,
|
|
477
|
+
// preserving the client TLS fingerprint end-to-end.
|
|
478
|
+
transportProtocols: ["http", "socks5"],
|
|
479
|
+
...(refreshEpoch === undefined ? {} : { proxyRefreshEpoch: refreshEpoch }),
|
|
623
480
|
telemetry: clientOptions.telemetry,
|
|
624
481
|
});
|
|
625
482
|
if (resolvedProxy.shouldWarn && !hasWarnedMissingProxy) {
|
|
@@ -630,22 +487,51 @@ function createSessionFetcher(baseUrl, defaultProfile, clientOptions) {
|
|
|
630
487
|
url: resolvedProxy.url,
|
|
631
488
|
poolIndex: proxyPoolIndexFromDiagnostics(resolvedProxy.diagnostics),
|
|
632
489
|
proxyHash: proxyEndpointHash(resolvedProxy.url),
|
|
490
|
+
vendor: vendorFromResolvedSource(resolvedProxy.source),
|
|
633
491
|
};
|
|
634
492
|
}
|
|
635
493
|
const session = {
|
|
636
494
|
async fetch(url, options = {}) {
|
|
637
495
|
const method = normalizeMethod(options.method ?? "GET");
|
|
638
496
|
const hasExplicitRetryPolicy = options.retry !== undefined;
|
|
639
|
-
const stealthRetryOptions =
|
|
497
|
+
const stealthRetryOptions = normalizeProxyTransportRetryOptions(options.retry, {
|
|
498
|
+
extraErrorCodes: STEALTH_PROXY_TRANSPORT_RETRY_ERROR_CODES,
|
|
499
|
+
label: "Stealth",
|
|
500
|
+
}) ??
|
|
501
|
+
(hasExplicitRetryPolicy
|
|
502
|
+
? undefined
|
|
503
|
+
: createDefaultProxyTransportRetryOptions({
|
|
504
|
+
extraErrorCodes: STEALTH_PROXY_TRANSPORT_RETRY_ERROR_CODES,
|
|
505
|
+
label: "Stealth",
|
|
506
|
+
}));
|
|
507
|
+
if (stealthRetryOptions) {
|
|
508
|
+
validateUnsafeProxyTransportRetryMethods(stealthRetryOptions, "Stealth");
|
|
509
|
+
}
|
|
640
510
|
const hasPolicyProxy = isPolicyManagedProxy(clientOptions);
|
|
641
511
|
const usesPolicyAllocator = hasPolicyProxy && !options.proxy && !clientOptions.proxy;
|
|
642
|
-
const
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
512
|
+
const retryAttemptCap = Math.max(1, stealthRetryOptions?.attempts ?? 1);
|
|
513
|
+
// Span the whole vendor chain: successive attempts rotate one vendor's
|
|
514
|
+
// pool, then fail over to the next vendor via the flat attempt index.
|
|
515
|
+
const policyProxy = clientOptions.proxyPolicy ??
|
|
516
|
+
(typeof clientOptions.upstream?.proxy === "object"
|
|
517
|
+
? clientOptions.upstream.proxy
|
|
518
|
+
: undefined);
|
|
519
|
+
// The pool span is already bounded by each vendor's max pool size
|
|
520
|
+
// (smartproxy ≤20, nodemaven ≤50), so the configured span never exceeds
|
|
521
|
+
// the chain's true maximum — a large NodeMaven pool stays fully
|
|
522
|
+
// reachable rather than being truncated at an arbitrary ceiling.
|
|
523
|
+
const policyProxyAttemptCap = Math.max(1, policyProxy ? resolvePolicyProxyPoolSpan(policyProxy) : DEFAULT_SMARTPROXY_POOL_SIZE);
|
|
524
|
+
// A registry vendor chain (smartproxy/nodemaven) is the only policy whose
|
|
525
|
+
// successive attempts resolve a *different* endpoint, so it is the only one
|
|
526
|
+
// that may widen the attempt cap to the pool span, de-duplicate endpoints,
|
|
527
|
+
// and drive allocator stale-pool refresh. A static custom/decodo policy
|
|
528
|
+
// resolves the same URL every attempt: widening/refreshing it would resend
|
|
529
|
+
// the request dozens of times (up to maxAttempts × refreshes) and bypass
|
|
530
|
+
// retry:false and unsafe-method controls. Static policies therefore follow
|
|
531
|
+
// the ordinary transport-retry budget instead.
|
|
532
|
+
const rotatesRegistryChain = usesPolicyAllocator && policyResolvesRegistryVendorChain(policyProxy);
|
|
533
|
+
const maxAttempts = rotatesRegistryChain ? policyProxyAttemptCap : retryAttemptCap;
|
|
534
|
+
const dedupeAllocatorEndpoints = rotatesRegistryChain;
|
|
649
535
|
let lastError;
|
|
650
536
|
for (let refreshAttempt = 0; refreshAttempt <= MAX_POLICY_PROXY_POOL_REFRESHES; refreshAttempt += 1) {
|
|
651
537
|
let stalePoolError;
|
|
@@ -661,14 +547,12 @@ function createSessionFetcher(baseUrl, defaultProfile, clientOptions) {
|
|
|
661
547
|
return;
|
|
662
548
|
attemptRecorded = true;
|
|
663
549
|
clientOptions.telemetry?.recordProxyAttempt?.({
|
|
664
|
-
provider: "smartproxy",
|
|
550
|
+
provider: attemptProxy?.vendor ?? "smartproxy",
|
|
665
551
|
attempt: attempt + 1,
|
|
666
552
|
...(attemptProxy?.poolIndex === undefined
|
|
667
553
|
? {}
|
|
668
554
|
: { poolIndex: attemptProxy.poolIndex }),
|
|
669
|
-
...(attemptProxy?.proxyHash
|
|
670
|
-
? { proxyHash: attemptProxy.proxyHash }
|
|
671
|
-
: {}),
|
|
555
|
+
...(attemptProxy?.proxyHash ? { proxyHash: attemptProxy.proxyHash } : {}),
|
|
672
556
|
outcome,
|
|
673
557
|
...(errorCode ? { errorCode } : {}),
|
|
674
558
|
...(status === undefined ? {} : { status }),
|
|
@@ -677,18 +561,21 @@ function createSessionFetcher(baseUrl, defaultProfile, clientOptions) {
|
|
|
677
561
|
};
|
|
678
562
|
try {
|
|
679
563
|
assertNoUnsupportedFingerprintOverrides(options);
|
|
680
|
-
attemptProxy = await resolveRequestProxy(options, attempt);
|
|
564
|
+
attemptProxy = await resolveRequestProxy(options, attempt, refreshAttempt);
|
|
681
565
|
proxy = attemptProxy.url;
|
|
682
|
-
if (proxy) {
|
|
566
|
+
if (proxy && dedupeAllocatorEndpoints) {
|
|
567
|
+
// An under-filled allocation repeats endpoints (via the modulo
|
|
568
|
+
// pool mapping) before the flat offset crosses into the next
|
|
569
|
+
// vendor. Skip an already-tried endpoint and advance the offset
|
|
570
|
+
// rather than breaking — breaking here would strand the request on
|
|
571
|
+
// the primary vendor and never reach the fallback leg.
|
|
683
572
|
if (attemptedProxies.has(proxy)) {
|
|
684
|
-
|
|
573
|
+
continue;
|
|
685
574
|
}
|
|
686
575
|
attemptedProxies.add(proxy);
|
|
687
576
|
}
|
|
688
577
|
const ignoreTlsErrors = Boolean(options.stealth?.insecureSkipVerify ??
|
|
689
|
-
(!hasPolicyProxy &&
|
|
690
|
-
proxy &&
|
|
691
|
-
clientOptions.proxyStealth?.insecureSkipVerify));
|
|
578
|
+
(!hasPolicyProxy && proxy && clientOptions.proxyStealth?.insecureSkipVerify));
|
|
692
579
|
const profileName = options.profile ?? defaultProfile;
|
|
693
580
|
const requestUrl = appendQueryParams(resolveUrl(baseUrl, url), options.params);
|
|
694
581
|
const headers = { ...(options.headers ?? {}) };
|
|
@@ -709,17 +596,13 @@ function createSessionFetcher(baseUrl, defaultProfile, clientOptions) {
|
|
|
709
596
|
const response = await getClient(profileName, proxy, ignoreTlsErrors).fetch(requestUrl, requestInit);
|
|
710
597
|
const normalized = await normalizeResponse(response, requestUrl);
|
|
711
598
|
cookieJar.setFromCookieStrings(setCookieHeadersFromResponse(response.headers));
|
|
712
|
-
if (proxy &&
|
|
713
|
-
isProxyConnectFailureResponse(response, normalized.body)) {
|
|
599
|
+
if (proxy && isProxyConnectFailureResponse(response, normalized.body)) {
|
|
714
600
|
throw createProxyConnectFailureError(normalized.body);
|
|
715
601
|
}
|
|
716
602
|
if (response.status >= 400) {
|
|
717
603
|
if (proxy &&
|
|
718
604
|
usesPolicyAllocator &&
|
|
719
|
-
isProxyEdgeTlsRejectedResponse(response.status, [
|
|
720
|
-
JSON.stringify(responseHeadersToRecord(response.headers)),
|
|
721
|
-
normalized.body,
|
|
722
|
-
].join("\n"))) {
|
|
605
|
+
isProxyEdgeTlsRejectedResponse(response.status, [JSON.stringify(responseHeadersToRecord(response.headers)), normalized.body].join("\n"))) {
|
|
723
606
|
throw createProxyEdgeTlsRejectedError(response.status);
|
|
724
607
|
}
|
|
725
608
|
if (proxy && isProxyAuthIpDeniedMessage(normalized.body)) {
|
|
@@ -747,9 +630,7 @@ function createSessionFetcher(baseUrl, defaultProfile, clientOptions) {
|
|
|
747
630
|
const normalizedError = normalizeStealthTransportError(error);
|
|
748
631
|
recordProxyAttempt("error", proxyAttemptErrorCode(normalizedError), proxyAttemptStatus(normalizedError));
|
|
749
632
|
lastError = normalizedError;
|
|
750
|
-
if (proxy &&
|
|
751
|
-
usesPolicyAllocator &&
|
|
752
|
-
isProxyPoolRefreshableError(normalizedError)) {
|
|
633
|
+
if (proxy && rotatesRegistryChain && isProxyPoolRefreshableError(normalizedError)) {
|
|
753
634
|
stalePoolError = normalizedError;
|
|
754
635
|
if (shouldRunProxyAuthDiagnostic(normalizedError)) {
|
|
755
636
|
stalePoolDiagnosticProxy = proxy;
|
|
@@ -759,21 +640,43 @@ function createSessionFetcher(baseUrl, defaultProfile, clientOptions) {
|
|
|
759
640
|
}
|
|
760
641
|
break;
|
|
761
642
|
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
643
|
+
// Cap the number of transport retries. For a policy-allocator chain,
|
|
644
|
+
// every attempt resolves a *different* endpoint/vendor (poolIndex
|
|
645
|
+
// rotates across the concatenated vendor pool spans), so a transport
|
|
646
|
+
// failure is a signal to advance to the next endpoint — potentially
|
|
647
|
+
// crossing into the fallback vendor — not to retry the same endpoint.
|
|
648
|
+
// Truncating that rotation at the per-endpoint retry budget would
|
|
649
|
+
// strand the request on the primary vendor and never reach the
|
|
650
|
+
// fallback, since the crossover only happens once the flat attempt
|
|
651
|
+
// index exceeds the primary vendor's pool size (~10-20).
|
|
652
|
+
// resolvePolicyTransportAttemptCap widens to the full chain span only
|
|
653
|
+
// for implicit, safe-method allocator requests; explicit retry
|
|
654
|
+
// policies (their documented `attempts` ceiling), unsafe methods, and
|
|
655
|
+
// static/non-registry vendors keep the per-endpoint retry budget.
|
|
656
|
+
const transportRetryCap = resolvePolicyTransportAttemptCap({
|
|
657
|
+
policy: policyProxy,
|
|
658
|
+
usesPolicyAllocator,
|
|
659
|
+
retryAttempts: stealthRetryOptions?.attempts ?? 1,
|
|
660
|
+
explicitRetry: hasExplicitRetryPolicy,
|
|
661
|
+
method,
|
|
662
|
+
});
|
|
663
|
+
if (attempt + 1 < transportRetryCap &&
|
|
664
|
+
shouldRetryProxyTransportAttempt({
|
|
665
|
+
error: normalizedError,
|
|
666
|
+
explicitRetry: hasExplicitRetryPolicy,
|
|
667
|
+
method,
|
|
668
|
+
options: stealthRetryOptions,
|
|
669
|
+
proxyUsed: Boolean(proxy),
|
|
670
|
+
})) {
|
|
671
|
+
if (stealthRetryOptions) {
|
|
672
|
+
await sleep(computeProxyTransportRetryDelayMs(stealthRetryOptions, attempt + 1));
|
|
673
|
+
}
|
|
771
674
|
continue;
|
|
772
675
|
}
|
|
773
676
|
throw normalizedError;
|
|
774
677
|
}
|
|
775
678
|
}
|
|
776
|
-
if (
|
|
679
|
+
if (rotatesRegistryChain &&
|
|
777
680
|
stalePoolError &&
|
|
778
681
|
refreshAttempt < MAX_POLICY_PROXY_POOL_REFRESHES) {
|
|
779
682
|
await invalidateProxyResolutionCacheAsync({
|
|
@@ -920,10 +823,7 @@ function createSessionFetcher(baseUrl, defaultProfile, clientOptions) {
|
|
|
920
823
|
}
|
|
921
824
|
catch (error) {
|
|
922
825
|
const message = error instanceof Error
|
|
923
|
-
? [
|
|
924
|
-
error.message,
|
|
925
|
-
error.cause instanceof Error ? error.cause.message : "",
|
|
926
|
-
]
|
|
826
|
+
? [error.message, error.cause instanceof Error ? error.cause.message : ""]
|
|
927
827
|
.filter(Boolean)
|
|
928
828
|
.join(" ")
|
|
929
829
|
: String(error);
|
|
@@ -951,12 +851,8 @@ function hasHeader(headers, name) {
|
|
|
951
851
|
return Object.keys(headers).some((key) => key.toLowerCase() === needle);
|
|
952
852
|
}
|
|
953
853
|
export function createStealthClient(baseUrl, defaultProfileOrOptions = DEFAULT_PROFILE, clientOptions = {}) {
|
|
954
|
-
const defaultProfile = typeof defaultProfileOrOptions === "string"
|
|
955
|
-
|
|
956
|
-
: DEFAULT_PROFILE;
|
|
957
|
-
const resolvedClientOptions = typeof defaultProfileOrOptions === "string"
|
|
958
|
-
? clientOptions
|
|
959
|
-
: defaultProfileOrOptions;
|
|
854
|
+
const defaultProfile = typeof defaultProfileOrOptions === "string" ? defaultProfileOrOptions : DEFAULT_PROFILE;
|
|
855
|
+
const resolvedClientOptions = typeof defaultProfileOrOptions === "string" ? clientOptions : defaultProfileOrOptions;
|
|
960
856
|
let sharedSession = null;
|
|
961
857
|
function getSharedSession() {
|
|
962
858
|
if (!sharedSession) {
|
package/dist/runtime/stt.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ProviderSttConfig, SttContext, SttTranscribeRequest, SttVerificationCodeOptions, VerificationCodeExtractionResult } from "../types";
|
|
1
|
+
import type { ProviderSttConfig, SttContext, SttTranscribeRequest, SttVerificationCodeOptions, VerificationCodeExtractionResult } from "../types.js";
|
|
2
2
|
export declare const APIFUSE__STT__BACKEND_ENV = "APIFUSE__STT__BACKEND";
|
|
3
3
|
export declare const APIFUSE__STT__MODEL_ENV = "APIFUSE__STT__MODEL";
|
|
4
4
|
export declare const CLOUDFLARE_ACCOUNT_ID_ENV = "APIFUSE__CLOUDFLARE__ACCOUNT_ID";
|
package/dist/runtime/stt.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ProviderError, TransportError, ValidationError } from "../errors";
|
|
1
|
+
import { ProviderError, TransportError, ValidationError } from "../errors.js";
|
|
2
2
|
export const APIFUSE__STT__BACKEND_ENV = "APIFUSE__STT__BACKEND";
|
|
3
3
|
export const APIFUSE__STT__MODEL_ENV = "APIFUSE__STT__MODEL";
|
|
4
4
|
export const CLOUDFLARE_ACCOUNT_ID_ENV = "APIFUSE__CLOUDFLARE__ACCOUNT_ID";
|
|
@@ -59,17 +59,12 @@ export function createSttClientFromEnv(config, env = process.env) {
|
|
|
59
59
|
return createCloudflareWorkersAiSttClient({
|
|
60
60
|
accountId,
|
|
61
61
|
apiToken,
|
|
62
|
-
model: normalizedEnvValue(env, APIFUSE__STT__MODEL_ENV) ??
|
|
63
|
-
DEFAULT_CLOUDFLARE_WORKERS_AI_STT_MODEL,
|
|
62
|
+
model: normalizedEnvValue(env, APIFUSE__STT__MODEL_ENV) ?? DEFAULT_CLOUDFLARE_WORKERS_AI_STT_MODEL,
|
|
64
63
|
});
|
|
65
64
|
}
|
|
66
65
|
function base64ByteLength(data) {
|
|
67
66
|
const normalized = data.trim();
|
|
68
|
-
const padding = normalized.endsWith("==")
|
|
69
|
-
? 2
|
|
70
|
-
: normalized.endsWith("=")
|
|
71
|
-
? 1
|
|
72
|
-
: 0;
|
|
67
|
+
const padding = normalized.endsWith("==") ? 2 : normalized.endsWith("=") ? 1 : 0;
|
|
73
68
|
return Math.floor((normalized.length * 3) / 4) - padding;
|
|
74
69
|
}
|
|
75
70
|
function assertBase64Audio(audio, maxAudioBytes) {
|
|
@@ -80,9 +75,7 @@ function assertBase64Audio(audio, maxAudioBytes) {
|
|
|
80
75
|
});
|
|
81
76
|
}
|
|
82
77
|
const data = audio.data.trim();
|
|
83
|
-
if (data.length === 0 ||
|
|
84
|
-
data.length % 4 !== 0 ||
|
|
85
|
-
!BASE64_AUDIO_PATTERN.test(data)) {
|
|
78
|
+
if (data.length === 0 || data.length % 4 !== 0 || !BASE64_AUDIO_PATTERN.test(data)) {
|
|
86
79
|
throw new ValidationError("STT audio.data must be a base64-encoded string", {
|
|
87
80
|
code: "INVALID_STT_AUDIO",
|
|
88
81
|
});
|
|
@@ -90,7 +83,9 @@ function assertBase64Audio(audio, maxAudioBytes) {
|
|
|
90
83
|
const bytes = base64ByteLength(data);
|
|
91
84
|
const maxBytes = maxAudioBytes ?? DEFAULT_STT_MAX_AUDIO_BYTES;
|
|
92
85
|
if (bytes > maxBytes) {
|
|
93
|
-
throw new ValidationError(`STT audio exceeds maxAudioBytes (${bytes} > ${maxBytes})`, {
|
|
86
|
+
throw new ValidationError(`STT audio exceeds maxAudioBytes (${bytes} > ${maxBytes})`, {
|
|
87
|
+
code: "STT_AUDIO_TOO_LARGE",
|
|
88
|
+
});
|
|
94
89
|
}
|
|
95
90
|
return bytes;
|
|
96
91
|
}
|
|
@@ -227,8 +222,7 @@ export function createCloudflareWorkersAiSttClient(options) {
|
|
|
227
222
|
return {
|
|
228
223
|
async transcribe(request) {
|
|
229
224
|
const warnings = [];
|
|
230
|
-
if (request.initialPrompt &&
|
|
231
|
-
effectivePromptPolicy(request) !== "custom-hint") {
|
|
225
|
+
if (request.initialPrompt && effectivePromptPolicy(request) !== "custom-hint") {
|
|
232
226
|
const warning = warnOrThrowUnsupportedOption(request, "initialPrompt is honored only when promptPolicy is custom-hint");
|
|
233
227
|
if (warning)
|
|
234
228
|
warnings.push(warning);
|
|
@@ -350,7 +344,9 @@ function lengthSet(codeLengths) {
|
|
|
350
344
|
}
|
|
351
345
|
function validCodeLength(value) {
|
|
352
346
|
if (!Number.isInteger(value) || value < 1 || value > 32) {
|
|
353
|
-
throw new ValidationError("STT verification code length must be an integer between 1 and 32", {
|
|
347
|
+
throw new ValidationError("STT verification code length must be an integer between 1 and 32", {
|
|
348
|
+
code: "INVALID_STT_VERIFICATION_CODE_OPTIONS",
|
|
349
|
+
});
|
|
354
350
|
}
|
|
355
351
|
return value;
|
|
356
352
|
}
|
package/dist/runtime/trace.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { TraceContext as BaseTraceContext, TraceAttributeValue, TraceConfig, TraceSpan } from "../types";
|
|
2
|
-
import { type OTLPExportOptions } from "./otlp";
|
|
1
|
+
import type { TraceContext as BaseTraceContext, TraceAttributeValue, TraceConfig, TraceSpan } from "../types.js";
|
|
2
|
+
import { type OTLPExportOptions } from "./otlp.js";
|
|
3
3
|
export type SpanAttributeValue = TraceAttributeValue;
|
|
4
4
|
export type Span = TraceSpan;
|
|
5
5
|
export interface TraceContext extends BaseTraceContext {
|
package/dist/runtime/trace.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
-
import { exportSpansOTLP } from "./otlp";
|
|
2
|
+
import { exportSpansOTLP } from "./otlp.js";
|
|
3
3
|
export const TRACE_RECORDER = Symbol.for("@apifuse/provider-sdk/runtime/trace-recorder");
|
|
4
4
|
function buildOTLPExportOptions(config) {
|
|
5
5
|
if (config?.exporter !== "otlp") {
|
|
@@ -23,9 +23,7 @@ export function resolveTraceContextOptions(config) {
|
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
function normalizeAttributeValue(value) {
|
|
26
|
-
if (typeof value === "string" ||
|
|
27
|
-
typeof value === "number" ||
|
|
28
|
-
typeof value === "boolean") {
|
|
26
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
29
27
|
return value;
|
|
30
28
|
}
|
|
31
29
|
if (value === null || value === undefined) {
|
package/dist/schema.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ZodString, type ZodType, z } from "zod";
|
|
2
|
-
import type { InferSchemaOutput, ProviderLocaleKey, SchemaLike } from "./types";
|
|
2
|
+
import type { InferSchemaOutput, ProviderLocaleKey, SchemaLike } from "./types.js";
|
|
3
3
|
export { z };
|
|
4
4
|
export type SchemaValidationResult<TSchema extends SchemaLike> = {
|
|
5
5
|
success: true;
|