@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.
Files changed (90) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/bin/apifuse-dev.ts +2 -2
  3. package/bin/apifuse-pack-smoke.ts +1 -1
  4. package/bin/apifuse-pack-types.ts +2 -1
  5. package/bin/apifuse-perf.ts +2 -4
  6. package/bin/apifuse-record.ts +1 -1
  7. package/dist/auth-turn/index.d.ts +1 -1
  8. package/dist/auth-turn/index.js +1 -1
  9. package/dist/ceremonies/index.js +52 -11
  10. package/dist/config/loader.d.ts +1 -1
  11. package/dist/config/loader.js +4 -2
  12. package/dist/contract-serialization.d.ts +1 -20
  13. package/dist/contract-serialization.js +8 -587
  14. package/dist/contract.d.ts +0 -2
  15. package/dist/contract.js +5 -9
  16. package/dist/index.d.ts +9 -8
  17. package/dist/index.js +6 -8
  18. package/dist/provider.d.ts +3 -2
  19. package/dist/provider.js +2 -2
  20. package/dist/runtime/auth-flow.js +1 -1
  21. package/dist/runtime/http.d.ts +1 -0
  22. package/dist/runtime/http.js +135 -12
  23. package/dist/runtime/instrumentation.js +1 -1
  24. package/dist/runtime/native-network-errors.d.ts +33 -0
  25. package/dist/runtime/native-network-errors.js +69 -0
  26. package/dist/runtime/native-network.d.ts +2 -33
  27. package/dist/runtime/native-network.js +2 -68
  28. package/dist/runtime/redis.d.ts +1 -1
  29. package/dist/runtime/redis.js +4 -2
  30. package/dist/runtime/resolver-config.d.ts +6 -0
  31. package/dist/runtime/resolver-config.js +6 -0
  32. package/dist/runtime/resolver-shared.d.ts +3 -0
  33. package/dist/runtime/resolver-shared.js +12 -0
  34. package/dist/runtime/resolver-vendors/twocaptcha.d.ts +2 -1
  35. package/dist/runtime/resolver-vendors/twocaptcha.js +80 -43
  36. package/dist/runtime/resolver-vendors/types.d.ts +1 -1
  37. package/dist/runtime/resolver.d.ts +6 -10
  38. package/dist/runtime/resolver.js +19 -18
  39. package/dist/runtime/state.js +5 -115
  40. package/dist/runtime/stealth-cookies.d.ts +20 -0
  41. package/dist/runtime/stealth-cookies.js +111 -0
  42. package/dist/runtime/stealth.js +7 -130
  43. package/dist/schema.d.ts +0 -63
  44. package/dist/schema.js +8 -808
  45. package/dist/serve.d.ts +1 -1
  46. package/dist/serve.js +1 -1
  47. package/dist/server/index.d.ts +1 -1
  48. package/dist/server/index.js +1 -1
  49. package/dist/server/self-test.d.ts +13 -0
  50. package/dist/server/self-test.js +124 -46
  51. package/dist/server/serve-implementation.d.ts +199 -0
  52. package/dist/server/serve-implementation.js +2054 -0
  53. package/dist/server/serve.d.ts +1 -187
  54. package/dist/server/serve.js +1 -1827
  55. package/dist/stateful/errors.d.ts +5 -0
  56. package/dist/stateful/errors.js +10 -0
  57. package/dist/stateful/stateful-provider-session-routing.d.ts +1 -5
  58. package/dist/stateful/stateful-provider-session-routing.js +2 -10
  59. package/dist/stream.js +7 -1
  60. package/package.json +27 -2
  61. package/src/auth-turn/index.ts +1 -1
  62. package/src/ceremonies/index.ts +68 -18
  63. package/src/config/loader.ts +5 -2
  64. package/src/contract-serialization.ts +8 -859
  65. package/src/contract.ts +5 -16
  66. package/src/index.ts +18 -34
  67. package/src/provider.ts +12 -24
  68. package/src/runtime/auth-flow.ts +1 -1
  69. package/src/runtime/http.ts +155 -11
  70. package/src/runtime/instrumentation.ts +1 -1
  71. package/src/runtime/native-network-errors.ts +99 -0
  72. package/src/runtime/native-network.ts +16 -97
  73. package/src/runtime/redis.ts +7 -2
  74. package/src/runtime/resolver-config.ts +6 -0
  75. package/src/runtime/resolver-shared.ts +17 -0
  76. package/src/runtime/resolver-vendors/twocaptcha.ts +100 -49
  77. package/src/runtime/resolver-vendors/types.ts +1 -0
  78. package/src/runtime/resolver.ts +47 -22
  79. package/src/runtime/state.ts +5 -144
  80. package/src/runtime/stealth-cookies.ts +132 -0
  81. package/src/runtime/stealth.ts +14 -157
  82. package/src/schema.ts +9 -1060
  83. package/src/serve.ts +6 -1
  84. package/src/server/index.ts +1 -0
  85. package/src/server/self-test.ts +184 -59
  86. package/src/server/serve-implementation.ts +3024 -0
  87. package/src/server/serve.ts +1 -2661
  88. package/src/stateful/errors.ts +12 -0
  89. package/src/stateful/stateful-provider-session-routing.ts +2 -11
  90. 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.
@@ -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, invalidateResolverSolution, ProviderError, resolveProxy, SessionExpiredError, z } from "@apifuse/provider-sdk";',
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";',
@@ -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 });
@@ -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
- * compiles this same document. `kind` is an OPEN string on the wire: the known
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
@@ -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
- * compiles this same document. `kind` is an OPEN string on the wire: the known
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
@@ -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
- if (!validateAuthTurn(turn)) {
118
- const detail = validateAuthTurn.errors
119
- ?.map((error) => `${error.instancePath || "$"} ${error.message ?? "invalid"}`)
120
- .join("; ");
121
- throw new TurnValidationError(detail || "Invalid AuthTurn output");
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
  }
@@ -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";
@@ -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 redis = new Redis(redisUrl, {
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
- interface DescribeSchemaOptions {
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 {};