@apifuse/provider-sdk 2.2.0-beta.26 → 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 +8 -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/contract-serialization.d.ts +1 -20
- package/dist/contract-serialization.js +8 -587
- package/dist/contract.d.ts +0 -2
- package/dist/contract.js +5 -9
- package/dist/index.d.ts +9 -8
- package/dist/index.js +6 -8
- package/dist/provider.d.ts +3 -2
- package/dist/provider.js +2 -2
- 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/schema.d.ts +0 -63
- package/dist/schema.js +8 -808
- 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/contract-serialization.ts +8 -859
- package/src/contract.ts +5 -16
- package/src/index.ts +18 -34
- package/src/provider.ts +12 -24
- 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/schema.ts +9 -1060
- 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
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @apifuse/provider-sdk Changelog
|
|
2
2
|
|
|
3
|
+
## 2.2.0-beta.28
|
|
4
|
+
|
|
5
|
+
- Release candidate for main commit 2936f1891d4e2326502f0585081f8a58060d6dd7.
|
|
6
|
+
|
|
7
|
+
## 2.2.0-beta.27
|
|
8
|
+
|
|
9
|
+
- Release candidate for main commit 579d9e7fd22d8414b151be2b71a43a0990456911.
|
|
10
|
+
|
|
3
11
|
## 2.2.0-beta.26
|
|
4
12
|
|
|
5
13
|
- Release candidate for main commit 924fe13d1101e7840d799a562a7a70174355185d.
|
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,
|
|
@@ -1,23 +1,4 @@
|
|
|
1
1
|
import { type JsonValue } from "./contract-json.js";
|
|
2
2
|
import type { SchemaLike } from "./types.js";
|
|
3
|
-
|
|
4
|
-
readonly eventName?: string;
|
|
5
|
-
readonly operationId?: string;
|
|
6
|
-
readonly outputTextTrust?: boolean;
|
|
7
|
-
}
|
|
8
|
-
export declare class OutputTextTrustProjectionError extends Error {
|
|
9
|
-
readonly schemaPath: string;
|
|
10
|
-
readonly operationId?: string | undefined;
|
|
11
|
-
readonly eventName?: string | undefined;
|
|
12
|
-
readonly classification: "untrusted";
|
|
13
|
-
readonly code = "output_text_trust_projection_failed";
|
|
14
|
-
constructor(schemaPath: string, cause: unknown, operationId?: string | undefined, eventName?: string | undefined);
|
|
15
|
-
}
|
|
16
|
-
export declare class OutputTextTrustProjectionMarkerError extends TypeError {
|
|
17
|
-
readonly schemaPath: string;
|
|
18
|
-
readonly code = "invalid_output_text_trust_projection_marker";
|
|
19
|
-
constructor(schemaPath: string);
|
|
20
|
-
}
|
|
21
|
-
export declare function describeSchema(schema: SchemaLike, options?: DescribeSchemaOptions): JsonValue;
|
|
3
|
+
export declare function describeSchema(schema: SchemaLike): JsonValue;
|
|
22
4
|
export declare function serializeSmsMatcher(value: Record<string, unknown>): Record<string, unknown>;
|
|
23
|
-
export {};
|