@apifuse/provider-sdk 2.2.0-beta.23 → 2.2.0-beta.24

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 (49) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/bin/apifuse-dev.ts +2 -0
  3. package/bin/apifuse-pack-types.ts +234 -38
  4. package/bin/apifuse-perf.ts +15 -12
  5. package/bin/apifuse-record.ts +2 -0
  6. package/dist/config/loader.d.ts +8 -19
  7. package/dist/config/loader.js +28 -86
  8. package/dist/define.d.ts +4 -1
  9. package/dist/define.js +64 -6
  10. package/dist/index.d.ts +3 -2
  11. package/dist/index.js +1 -0
  12. package/dist/provider.d.ts +1 -1
  13. package/dist/runtime/auth-flow.js +2 -0
  14. package/dist/runtime/browser.js +50 -0
  15. package/dist/runtime/http.js +0 -1
  16. package/dist/runtime/instrumentation.js +26 -1
  17. package/dist/runtime/resolver-vendors/bindings.d.ts +8 -0
  18. package/dist/runtime/resolver-vendors/bindings.js +15 -0
  19. package/dist/runtime/resolver-vendors/browser.d.ts +24 -0
  20. package/dist/runtime/resolver-vendors/browser.js +287 -0
  21. package/dist/runtime/resolver-vendors/types.d.ts +42 -0
  22. package/dist/runtime/resolver-vendors/types.js +57 -0
  23. package/dist/runtime/resolver.d.ts +39 -0
  24. package/dist/runtime/resolver.js +414 -0
  25. package/dist/runtime/state.d.ts +3 -0
  26. package/dist/runtime/state.js +245 -141
  27. package/dist/runtime/stealth.js +3 -6
  28. package/dist/server/serve.d.ts +4 -1
  29. package/dist/server/serve.js +35 -8
  30. package/dist/testing/run.js +7 -0
  31. package/dist/types.d.ts +112 -4
  32. package/package.json +1 -1
  33. package/src/config/loader.ts +35 -111
  34. package/src/define.ts +105 -8
  35. package/src/index.ts +20 -1
  36. package/src/provider.ts +1 -0
  37. package/src/runtime/auth-flow.ts +2 -0
  38. package/src/runtime/browser.ts +69 -0
  39. package/src/runtime/http.ts +0 -1
  40. package/src/runtime/instrumentation.ts +36 -2
  41. package/src/runtime/resolver-vendors/bindings.ts +31 -0
  42. package/src/runtime/resolver-vendors/browser.ts +420 -0
  43. package/src/runtime/resolver-vendors/types.ts +113 -0
  44. package/src/runtime/resolver.ts +668 -0
  45. package/src/runtime/state.ts +323 -166
  46. package/src/runtime/stealth.ts +3 -6
  47. package/src/server/serve.ts +73 -5
  48. package/src/testing/run.ts +8 -0
  49. package/src/types.ts +130 -4
@@ -221,64 +221,7 @@ function serializeSmartproxyPool(pool) {
221
221
  }
222
222
  function normalizeProxyUrl(url) {
223
223
  const normalized = url?.trim();
224
- return normalized ? applyStickyProxySession(normalized) : undefined;
225
- }
226
- function readPositiveIntegerEnv(name) {
227
- const raw = process.env[name]?.trim();
228
- if (!raw)
229
- return undefined;
230
- if (!/^[1-9]\d*$/.test(raw)) {
231
- throw new Error(`${name} must be a positive integer`);
232
- }
233
- return raw;
234
- }
235
- function applyStickyProxySession(proxyUrl) {
236
- let parsed;
237
- try {
238
- parsed = new URL(proxyUrl);
239
- }
240
- catch {
241
- return proxyUrl;
242
- }
243
- if (!parsed.hostname || !parsed.username || !parsed.password) {
244
- return proxyUrl;
245
- }
246
- // This rewrites sticky-session usernames for a bring-your-own *gateway* URL
247
- // (APIFUSE__PROXY__URL). The `smartproxy` host here means a smartproxy.com /
248
- // Decodo-family gateway that authenticates by username — NOT the
249
- // api.smartproxy.org allocation vendor, whose endpoints are raw ip:port with
250
- // no credentials and therefore return early above.
251
- const host = parsed.hostname.toLowerCase();
252
- if (!host.includes("smartproxy") && !host.includes("decodo")) {
253
- return proxyUrl;
254
- }
255
- const username = decodeURIComponent(parsed.username);
256
- const sessionId = process.env.APIFUSE__PROXY__SESSION_ID?.trim() || "apifuse-shared";
257
- const sessionDuration = readPositiveIntegerEnv("APIFUSE__PROXY__SESSION_DURATION");
258
- const stickyUsername = host.includes("smartproxy")
259
- ? buildSmartproxyUsername(username, sessionId, sessionDuration)
260
- : buildDecodoUsername(username, sessionId, sessionDuration ?? "60");
261
- parsed.username = stickyUsername;
262
- return parsed.toString();
263
- }
264
- function buildSmartproxyUsername(username, sessionId, sessionDuration) {
265
- const parts = username.split("_");
266
- const configuredLife = parts.find((part) => part.startsWith("life-"))?.slice("life-".length);
267
- const baseUsername = parts
268
- .filter((part) => !part.startsWith("session-") && !part.startsWith("life-"))
269
- .join("_");
270
- return `${baseUsername}_session-${sessionId}_life-${sessionDuration ?? configuredLife ?? "60"}`;
271
- }
272
- function buildDecodoUsername(username, sessionId, sessionDuration) {
273
- const withoutSticky = username.replace(/-session-.+-sessionduration-\d+$/, "");
274
- const baseUsername = withoutSticky.startsWith("user-") ? withoutSticky : `user-${withoutSticky}`;
275
- return `${baseUsername}-session-${sessionId}-sessionduration-${sessionDuration}`;
276
- }
277
- function syncProxyEnv(config) {
278
- const configProxyUrl = normalizeProxyUrl(config.proxy?.url);
279
- if (!process.env.APIFUSE__PROXY__URL && configProxyUrl) {
280
- process.env.APIFUSE__PROXY__URL = configProxyUrl;
281
- }
224
+ return normalized || undefined;
282
225
  }
283
226
  export function resolveProxyConfig(options = {}) {
284
227
  const explicitProxyUrl = normalizeProxyUrl(options.proxy);
@@ -293,14 +236,6 @@ export function resolveProxyConfig(options = {}) {
293
236
  if (!legacyProxyRequested) {
294
237
  return { shouldWarn: false };
295
238
  }
296
- const envProxyUrl = normalizeProxyUrl(process.env.APIFUSE__PROXY__URL);
297
- if (envProxyUrl) {
298
- return { shouldWarn: false, url: envProxyUrl };
299
- }
300
- const configuredProxyUrl = normalizeProxyUrl(options.apifuseConfig?.proxy?.url);
301
- if (configuredProxyUrl) {
302
- return { shouldWarn: false, url: configuredProxyUrl };
303
- }
304
239
  return { shouldWarn: true };
305
240
  }
306
241
  export async function resolveProxyConfigAsync(options = {}) {
@@ -317,7 +252,17 @@ export async function resolveProxyConfigAsync(options = {}) {
317
252
  }
318
253
  const chain = resolveVendorChain(policy);
319
254
  if (chain.length === 0) {
320
- // decodo/custom/env-static providers keep the legacy static-URL path.
255
+ const declared = declaredVendorChain(policy);
256
+ const deprecated = declared.filter((vendor) => vendor === "decodo" || vendor === "custom");
257
+ if (policy.mode === "required") {
258
+ const providerIds = declared.length > 0 ? declared.map((vendor) => `"${vendor}"`).join(", ") : "none";
259
+ const deprecatedDetail = deprecated.length > 0
260
+ ? ` Deprecated vendor(s): ${deprecated.map((vendor) => `"${vendor}"`).join(", ")}.`
261
+ : "";
262
+ throw new ProxyResolutionError("PROXY_REQUIRED", `Required proxy policy has no SDK-managed adapter for provider id(s): ${providerIds}.${deprecatedDetail} Use "smartproxy" or "nodemaven".`);
263
+ }
264
+ // Deprecated decodo/custom providers have no SDK-managed adapter. Optional
265
+ // policies preserve the warning-only behavior and may continue directly.
321
266
  return resolveProxyConfig({
322
267
  ...options,
323
268
  upstream: { proxy: true },
@@ -524,18 +469,21 @@ function resolvePolicy(options) {
524
469
  function isRegistryVendor(name) {
525
470
  return name === "smartproxy" || name === "nodemaven";
526
471
  }
472
+ function declaredVendorChain(policy) {
473
+ const declared = policy.providers?.length
474
+ ? policy.providers
475
+ : [policy.provider ?? envDefaultProvider()];
476
+ return declared.filter((vendor) => vendor !== undefined);
477
+ }
527
478
  /**
528
479
  * Ordered list of SDK-native proxy vendors declared by the policy. `providers`
529
480
  * takes precedence over the legacy singular `provider`; the platform default
530
481
  * env is the final fallback. Non-registry names (decodo/custom) are dropped so
531
- * an all-static chain falls through to the legacy env-URL path unchanged.
482
+ * an all-deprecated chain has no managed adapter.
532
483
  */
533
484
  export function resolveVendorChain(policy) {
534
- const declared = policy.providers?.length
535
- ? policy.providers
536
- : [policy.provider ?? envDefaultProvider()];
537
485
  const chain = [];
538
- for (const name of declared) {
486
+ for (const name of declaredVendorChain(policy)) {
539
487
  if (isRegistryVendor(name) && !chain.includes(name)) {
540
488
  chain.push(name);
541
489
  }
@@ -600,9 +548,8 @@ const UNSAFE_TRANSPORT_RETRY_METHODS = new Set(["POST", "PUT", "PATCH", "DELETE"
600
548
  * - the method is safe/idempotent — an unsafe request must never be duplicated
601
549
  * across the pool even if some framework default would allow it;
602
550
  * - the policy resolves a non-empty *registry* vendor chain (smartproxy /
603
- * nodemaven). Static vendors (custom / decodo) and credential-less policies
604
- * resolve no allocator pool, so every attempt would hit the same endpoint
605
- * with no possible crossover — they keep the retry budget.
551
+ * nodemaven). Deprecated vendors (custom / decodo) resolve no managed pool,
552
+ * so there is no possible endpoint crossover they keep the retry budget.
606
553
  *
607
554
  * The widened cap is bounded by the chain's true maximum span (sum of each
608
555
  * vendor's max pool size), so a large NodeMaven pool (≤50) stays reachable and
@@ -621,8 +568,8 @@ const UNSAFE_TRANSPORT_RETRY_METHODS = new Set(["POST", "PUT", "PATCH", "DELETE"
621
568
  * endpoint each attempt resolves (even a repeated one), so no de-duplication;
622
569
  * - the method is safe/idempotent — an unsafe request is never duplicated;
623
570
  * - the policy resolves a non-empty registry vendor chain (smartproxy /
624
- * nodemaven). Static vendors (custom / decodo) resolve the same URL every
625
- * attempt, so there is nothing to rotate or de-duplicate.
571
+ * nodemaven). Deprecated vendors (custom / decodo) resolve no managed
572
+ * endpoint, so there is nothing to rotate or de-duplicate.
626
573
  */
627
574
  export function policyRotatesTransportVendorChain(input) {
628
575
  if (!input.usesPolicyAllocator || !input.policy || input.explicitRetry) {
@@ -650,9 +597,8 @@ export function resolvePolicyTransportAttemptCap(input) {
650
597
  * A registry vendor chain (smartproxy/nodemaven) resolves a potentially
651
598
  * *different* endpoint per flat attempt index, so a transport retry should
652
599
  * advance across endpoints and de-duplicate once the chain stops yielding new
653
- * ones. Static/custom/decodo policies (empty registry chain) resolve the *same*
654
- * URL every attempt by design retrying that same endpoint is intended, so the
655
- * transport loop must not de-duplicate them.
600
+ * ones. Deprecated custom/decodo policies have an empty registry chain and no
601
+ * managed endpoint, so the transport loop has nothing to rotate or de-duplicate.
656
602
  */
657
603
  export function policyResolvesRegistryVendorChain(policy) {
658
604
  return Boolean(policy) && resolveVendorChain(policy).length > 0;
@@ -1249,16 +1195,12 @@ export async function loadApiFuseConfig(dir = process.cwd()) {
1249
1195
  const tsPath = path.resolve(dir, "apifuse.config.ts");
1250
1196
  if (existsSync(tsPath)) {
1251
1197
  const config = await importConfig(tsPath);
1252
- const resolvedConfig = config ?? {};
1253
- syncProxyEnv(resolvedConfig);
1254
- return resolvedConfig;
1198
+ return config ?? {};
1255
1199
  }
1256
1200
  const jsPath = path.resolve(dir, "apifuse.config.js");
1257
1201
  if (existsSync(jsPath)) {
1258
1202
  const config = await importConfig(jsPath);
1259
- const resolvedConfig = config ?? {};
1260
- syncProxyEnv(resolvedConfig);
1261
- return resolvedConfig;
1203
+ return config ?? {};
1262
1204
  }
1263
1205
  return {};
1264
1206
  }
package/dist/define.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { AuthConfig, BrowserEngine, ContextDeclaration, CredentialDeclaration, HealthJourneyDefinition, HealthJourneySchedule, HealthScheduleRandomization, InferSchemaOutput, OperationDefinition, OperationHandlerResult, OperationHttpStreamTransport, OperationSseTransport, OperationWebSocketTransport, NativeProviderConfig, ProviderOcrConfig, ProviderAccessConfig, ProviderDefinition, ProviderDeploymentOverrides, ProviderHealthMonitorConfig, ProviderProxyConfig, ProviderPublicProfile, ProviderReviewed, ProviderSecretDeclaration, ProviderStreamEvent, ProviderSttConfig, SchemaLike, SmsOtpMatcherDefinition, StealthPlatform } from "./types.js";
1
+ import type { AuthConfig, BrowserEngine, ContextDeclaration, CredentialDeclaration, HealthJourneyDefinition, HealthJourneySchedule, HealthScheduleRandomization, InferSchemaOutput, NativeProviderConfig, OperationDefinition, OperationHandlerResult, OperationHttpStreamTransport, OperationSseTransport, OperationWebSocketTransport, ProviderAccessConfig, ProviderDefinition, ProviderOcrConfig, ProviderDeploymentOverrides, ProviderHealthMonitorConfig, ProviderProxyConfig, ProviderPublicProfile, ProviderResolverConfig, ProviderReviewed, ProviderSecretDeclaration, ProviderStreamEvent, ProviderSttConfig, SchemaLike, SmsOtpMatcherDefinition, StealthPlatform } from "./types.js";
2
2
  type ProviderImplementationSourceAccess = "official_api" | "private_api" | "browser_flow" | "hybrid";
3
3
  type ProviderImplementationCredentialStrategy = "apifuse_managed" | "workspace_secret" | "user_oauth" | "user_session" | "none";
4
4
  interface ProviderImplementationProfile {
@@ -8,6 +8,8 @@ interface ProviderImplementationProfile {
8
8
  operatorNotes?: string;
9
9
  visibility: "internal" | "operator";
10
10
  }
11
+ export declare const VALID_PROVIDER_RESOLVER_VENDORS: readonly ["browser", "capsolver", "capmonster", "2captcha", "custom"];
12
+ export declare const VALID_PROVIDER_CHALLENGE_KINDS: readonly ["turnstile", "recaptcha_v2", "recaptcha_v3", "hcaptcha", "cloudflare_interstitial", "aws_waf"];
11
13
  type ProviderOperation = OperationDefinition<SchemaLike, SchemaLike>;
12
14
  type OperationConfig<TInput extends SchemaLike, TOutput extends SchemaLike> = Omit<OperationDefinition<TInput, TOutput>, "handler"> & {
13
15
  handler(ctx: Parameters<OperationDefinition<TInput, TOutput>["handler"]>[0], input: InferSchemaOutput<TInput>): OperationHandlerResult<InferSchemaOutput<TOutput>> | Promise<OperationHandlerResult<InferSchemaOutput<TOutput>>>;
@@ -57,6 +59,7 @@ export interface ProviderConfig<TOperations extends Record<string, ProviderOpera
57
59
  proxy?: ProviderProxyConfig;
58
60
  ocr?: ProviderOcrConfig;
59
61
  stt?: ProviderSttConfig;
62
+ resolver?: ProviderResolverConfig;
60
63
  browser?: {
61
64
  engine: BrowserEngine;
62
65
  };
package/dist/define.js CHANGED
@@ -49,6 +49,24 @@ const VALID_PROVIDER_PROXY_AFFINITIES = [
49
49
  ];
50
50
  const VALID_PROVIDER_OCR_MODES = ["optional", "required"];
51
51
  const VALID_PROVIDER_STT_MODES = ["optional", "required"];
52
+ function exhaustiveLiteralArray() {
53
+ return (values, ..._missing) => values;
54
+ }
55
+ export const VALID_PROVIDER_RESOLVER_VENDORS = exhaustiveLiteralArray()([
56
+ "browser",
57
+ "capsolver",
58
+ "capmonster",
59
+ "2captcha",
60
+ "custom",
61
+ ]);
62
+ export const VALID_PROVIDER_CHALLENGE_KINDS = exhaustiveLiteralArray()([
63
+ "turnstile",
64
+ "recaptcha_v2",
65
+ "recaptcha_v3",
66
+ "hcaptcha",
67
+ "cloudflare_interstitial",
68
+ "aws_waf",
69
+ ]);
52
70
  const SMARTPROXY_APP_KEY_SECRET = "APIFUSE__PROXY__SMARTPROXY_APP_KEY";
53
71
  const NODEMAVEN_USERNAME_SECRET = "APIFUSE__PROXY__NODEMAVEN_USERNAME";
54
72
  const NODEMAVEN_PASSWORD_SECRET = "APIFUSE__PROXY__NODEMAVEN_PASSWORD";
@@ -57,9 +75,8 @@ const NODEMAVEN_PASSWORD_SECRET = "APIFUSE__PROXY__NODEMAVEN_PASSWORD";
57
75
  // credential fails at build/validation time rather than during a live outage: a
58
76
  // declared-but-uncredentialed fallback leg is a silently dead SPOF, which is
59
77
  // exactly the failure class the multi-vendor chain exists to remove. Vendors
60
- // absent from this map (e.g. `custom`/`decodo`, whose credentials come from the
61
- // `APIFUSE__PROXY__URL` bring-your-own escape hatch, not provider secrets) impose
62
- // no declaration requirement.
78
+ // absent from this map (the deprecated `custom`/`decodo` values have no managed
79
+ // adapter) impose no declaration requirement.
63
80
  const VENDOR_REQUIRED_SECRETS = {
64
81
  smartproxy: [SMARTPROXY_APP_KEY_SECRET],
65
82
  nodemaven: [NODEMAVEN_USERNAME_SECRET, NODEMAVEN_PASSWORD_SECRET],
@@ -362,8 +379,15 @@ function validateProviderProxy(config) {
362
379
  // `decodo`/`custom` are deprecated vendor values (string-union members, so the
363
380
  // @deprecated symbol gate can't catch them — warn at validation time instead).
364
381
  const deprecatedVendors = vendorChain.filter((vendor) => vendor === "decodo" || vendor === "custom");
382
+ if (proxy.mode === "required" &&
383
+ vendorChain.length > 0 &&
384
+ deprecatedVendors.length === vendorChain.length) {
385
+ throw new ValidationError(`Provider "${config.id}" requires proxy egress but declares only deprecated proxy vendor(s): ${deprecatedVendors.join(", ")}.`, {
386
+ fix: `Use proxy.provider or proxy.providers with "smartproxy" and/or "nodemaven".`,
387
+ });
388
+ }
365
389
  if (deprecatedVendors.length > 0) {
366
- console.warn(`[provider-sdk] Provider "${config.id}" uses deprecated proxy vendor(s): ${deprecatedVendors.join(", ")}. Use "smartproxy"/"nodemaven", or the APIFUSE__PROXY__URL bring-your-own escape hatch.`);
390
+ console.warn(`[provider-sdk] Provider "${config.id}" uses deprecated proxy vendor(s): ${deprecatedVendors.join(", ")}. Use "smartproxy"/"nodemaven".`);
367
391
  }
368
392
  }
369
393
  function validateProviderStt(config) {
@@ -390,6 +414,34 @@ function validateProviderOcr(config) {
390
414
  rejectUnknownFields(ocr, new Set(["mode"]), "ocr");
391
415
  assertLiteralField(ocr.mode, "ocr.mode", VALID_PROVIDER_OCR_MODES, config.id);
392
416
  }
417
+ function validateProviderResolver(config) {
418
+ const resolver = config.resolver;
419
+ if (resolver === undefined)
420
+ return;
421
+ if (!resolver || typeof resolver !== "object" || Array.isArray(resolver)) {
422
+ throw new ValidationError(`Provider "${config.id}" has invalid resolver: must be an object.`, {
423
+ fix: `Set resolver for provider "${config.id}" to { vendors: ["2captcha"], kinds: ["turnstile"] }.`,
424
+ });
425
+ }
426
+ rejectUnknownFields(resolver, new Set(["vendors", "kinds"]), "resolver", config.id);
427
+ validateResolverLiteralArray(resolver.vendors, "resolver.vendors", VALID_PROVIDER_RESOLVER_VENDORS, config.id);
428
+ validateResolverLiteralArray(resolver.kinds, "resolver.kinds", VALID_PROVIDER_CHALLENGE_KINDS, config.id);
429
+ }
430
+ function validateResolverLiteralArray(value, field, validValues, providerId) {
431
+ if (!Array.isArray(value)) {
432
+ throw new ValidationError(`Provider "${providerId}" has invalid ${field}: must be an array.`, {
433
+ fix: `Set ${field} for provider "${providerId}" to an array containing only: ${validValues.join(", ")}.`,
434
+ });
435
+ }
436
+ for (const [index, item] of value.entries()) {
437
+ if (typeof item === "string" && validValues.some((validValue) => validValue === item)) {
438
+ continue;
439
+ }
440
+ throw new ValidationError(`Provider "${providerId}" has invalid ${field}[${index}]: ${JSON.stringify(item)}. Expected one of: ${validValues.join(", ")}`, {
441
+ fix: `Set ${field}[${index}] for provider "${providerId}" to one of ${validValues.map((validValue) => `"${validValue}"`).join(", ")}.`,
442
+ });
443
+ }
444
+ }
393
445
  function validateOperationIds(providerId, operations) {
394
446
  for (const operationName of Object.keys(operations)) {
395
447
  if (!OPERATION_ID_REGEX.test(operationName))
@@ -764,14 +816,18 @@ function suggestField(unknown, candidates) {
764
816
  }
765
817
  return best;
766
818
  }
767
- function rejectUnknownFields(value, allowed, fieldPath) {
819
+ function rejectUnknownFields(value, allowed, fieldPath, providerId) {
768
820
  for (const key of Object.keys(value)) {
769
821
  if (allowed.has(key))
770
822
  continue;
771
823
  const hint = suggestField(key, allowed);
772
824
  throw new ValidationError(hint
773
825
  ? `Unknown field "${key}" on ${fieldPath}. Did you mean "${hint}"?`
774
- : `Unknown field "${key}" on ${fieldPath}.`, { fix: `Remove ${fieldPath}.${key} or rename it.` });
826
+ : `Unknown field "${key}" on ${fieldPath}.`, {
827
+ fix: providerId
828
+ ? `Remove ${fieldPath}.${key} from provider "${providerId}" or rename it.`
829
+ : `Remove ${fieldPath}.${key} or rename it.`,
830
+ });
775
831
  }
776
832
  }
777
833
  function assertBoundedIntegerMs(value, fieldPath, options) {
@@ -1553,6 +1609,7 @@ export function defineProvider(config) {
1553
1609
  validateProviderProxy(config);
1554
1610
  validateProviderOcr(config);
1555
1611
  validateProviderStt(config);
1612
+ validateProviderResolver(config);
1556
1613
  if (config.runtime === "browser" && !config.browser)
1557
1614
  throw new ProviderError(`Provider "${config.id}" must define browser.engine when runtime is "browser"`, {
1558
1615
  fix: 'Add browser: { engine: "playwright-stealth" } for TypeScript providers, or another supported engine for your runtime',
@@ -1572,6 +1629,7 @@ export function defineProvider(config) {
1572
1629
  proxy: config.proxy,
1573
1630
  ocr: config.ocr,
1574
1631
  stt: config.stt,
1632
+ resolver: config.resolver,
1575
1633
  browser: config.browser,
1576
1634
  auth: config.auth,
1577
1635
  reviewed: config.reviewed,
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export * from "./auth.js";
2
2
  export * from "./ceremonies/index.js";
3
3
  export * from "./choice-token.js";
4
- export type { ApiFuseConfig, BrowserConfig, ProxyConfig, ProxyProtocol, ProxyResolutionOptions, ProxyResolutionSource, ProxyVendorName, ResolvedProxyConfig, SessionConfig, } from "./config/loader.js";
4
+ export type { ApiFuseConfig, BrowserConfig, ProxyProtocol, ProxyResolutionOptions, ProxyResolutionSource, ProxyVendorName, ResolvedProxyConfig, SessionConfig, } from "./config/loader.js";
5
5
  export { defineConfig, loadApiFuseConfig, resolveProxy } from "./config/loader.js";
6
6
  export { canonicalJson, digestProviderContract, extractProviderContract, type JsonPrimitive, type JsonValue, PROVIDER_CONTRACT_SCHEMA_VERSION, type ProviderContractOperation, type ProviderContractSnapshot, } from "./contract.js";
7
7
  export { centered, delayed, defineHealthJourney, defineOperation, defineProvider, defineSmsOtpMatcher, defineStreamOperation, every, type ProviderConfig, } from "./define.js";
@@ -29,6 +29,7 @@ export { generateInsights } from "./runtime/insights.js";
29
29
  export { type InstrumentationOptions, type InstrumentedProviderContext, wrapWithInstrumentation, } from "./runtime/instrumentation.js";
30
30
  export { type PrevalidateResult, prevalidate } 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, createResolverClientFromEnv, createUnsupportedResolverClient, DEFAULT_RESOLVER_TIMEOUT_MS, invalidateResolverSolution, type ResolverRuntimeOptions, } from "./runtime/resolver.js";
32
33
  export { assertRequiredSecretsPresent, listMissingRequiredSecrets, MISSING_SECRET_CODE, } from "./runtime/secrets.js";
33
34
  export { createUnsupportedProviderRuntimeState, UnsupportedProviderStateError, } from "./runtime/state.js";
34
35
  export { createStealthClient } from "./runtime/stealth.js";
@@ -39,7 +40,7 @@ export { APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SEN
39
40
  export { createServerApp, ERROR_OBSERVABILITY_HEADER, type ServeOptions, serve, } from "./server/index.js";
40
41
  export { getStealthProfile, listStealthProfiles } from "./stealth/profiles.js";
41
42
  export * from "./stream.js";
42
- export type { ApiFuseResponse, AuthConfig, AuthContext, AuthFlowDefinition, AuthFlowInputHandler, AuthFlowStartHandler, AuthMode, AuthTurn, Bcp47Locale, BrowserEngine, BrowserOptions, BrowserResourceBody, BrowserResourceDecision, BrowserResourceMethod, BrowserResourcePolicy, BrowserResourceRequest, BrowserResourceRoute, 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, ProviderContext, ProviderDefinition, ProviderDeploymentOverrides, ProviderFileRef, ProviderFilesContext, ProviderHealthMonitorConfig, ProviderHealthProbeConfig, ProviderLocale, ProviderLocaleKey, ProviderLocaleKeyInput, ProviderLogoProfile, ProviderLogoSource, ProviderMeta, ProviderOcrConfig, ProviderProxyConfig, ProviderProxyMode, ProviderProxyPolicy, ProxiedOAuthConfig, ProviderProxyProvider, ProviderProxySessionAffinity, ProviderPublicConnectionMode, ProviderPublicProfile, ProviderReviewed, ProviderResolvedFile, ProviderRuntimeState, ProviderSecretDeclaration, ProviderStateDurationString, ProviderStateNamespace, ProviderStreamEvent, ProviderSttConfig, ProviderSttMode, ProviderSupportLevel, RequestOptions, RedirectRunReason, Rfc3339Instant, SchemaLike, SmsOrigin, SmsOtpExtractionPattern, SmsOtpMatcherDefinition, SseMessage, StandardSchemaV1, StateCasResult, StateNamespaceOptions, 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";
43
+ 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";
43
44
  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";
44
45
  export * from "./utils/date.js";
45
46
  export * from "./utils/parse.js";
package/dist/index.js CHANGED
@@ -26,6 +26,7 @@ export { generateInsights } from "./runtime/insights.js";
26
26
  export { wrapWithInstrumentation, } from "./runtime/instrumentation.js";
27
27
  export { prevalidate } from "./runtime/prevalidate.js";
28
28
  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, createResolverClientFromEnv, createUnsupportedResolverClient, DEFAULT_RESOLVER_TIMEOUT_MS, invalidateResolverSolution, } from "./runtime/resolver.js";
29
30
  export { assertRequiredSecretsPresent, listMissingRequiredSecrets, MISSING_SECRET_CODE, } from "./runtime/secrets.js";
30
31
  export { createUnsupportedProviderRuntimeState, UnsupportedProviderStateError, } from "./runtime/state.js";
31
32
  export { createStealthClient } from "./runtime/stealth.js";
@@ -7,6 +7,6 @@ export { AuthError, HttpRedirectError, isProviderError, isSessionExpiredError, i
7
7
  export { getProviderLocalePath, providerLocaleKey, qualifyProviderLocaleKey, } from "./i18n/index.js";
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
- 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, StateValue, StateWriteOptions, } from "./types.js";
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
11
  export { createNativeNetworkClient, createEnvVendorCredentialResolver, deriveNativeCredentialAffinityKey, NativeEgressGrantExpiredError, NativeEgressNotDeclaredError, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, resolveNativeGatewayProxy, type NativeGatewayProxy, type NativeGatewayProxyResolutionInput, type NativeGatewayProxySkipReason, type NativeGatewayProxySynthesizer, type NativeGatewayProxySynthesisResult, type NativeGatewayProxySynthesisInput, type NativeNetworkClientOptions, type NativeNetworkErrorCode, type VendorCredentialLookup, type VendorCredentialResolver, } from "./runtime/native-network.js";
12
12
  export { HttpRetryAfterPolicy, HttpRetryDelayStrategy, HttpRetryJitter, HttpRetryPreset, HttpRetryUnsafeMethodPolicy, } from "./types.js";
@@ -1,6 +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
5
  import { createUnsupportedSttClient } from "./stt.js";
5
6
  function normalizeAllowedKeys(allowedKeys) {
6
7
  return new Set(allowedKeys.filter((key) => key.trim().length > 0));
@@ -44,6 +45,7 @@ export function createFlowContext(options) {
44
45
  context: createScratchpad(options.allowedKeys, options.initialContext),
45
46
  ocr: options.ocr ?? createUnsupportedOcrClient(),
46
47
  stt: options.stt ?? createUnsupportedSttClient(),
48
+ resolver: createUnsupportedResolverClient("Resolver is not available in auth flow context"),
47
49
  auth: createAuthFlowHelpers(),
48
50
  };
49
51
  }
@@ -357,6 +357,9 @@ class PlaywrightBrowserPage {
357
357
  async close() {
358
358
  await this.page.close();
359
359
  }
360
+ async cookies() {
361
+ return (await this.page.context().cookies()).map(toBrowserCookie);
362
+ }
360
363
  async withResourcePolicy(policy, run) {
361
364
  const allowedMethods = new Set(policy.allowedMethods ?? DEFAULT_RESOURCE_METHODS);
362
365
  const handler = async (route) => {
@@ -586,6 +589,48 @@ function flattenCdpFrameTree(node, out = []) {
586
589
  function isRecord(value) {
587
590
  return value !== null && typeof value === "object" && !Array.isArray(value);
588
591
  }
592
+ function isBrowserCookieSameSite(value) {
593
+ return value === "Strict" || value === "Lax" || value === "None";
594
+ }
595
+ function toBrowserCookie(cookie) {
596
+ return {
597
+ name: cookie.name,
598
+ value: cookie.value,
599
+ domain: cookie.domain,
600
+ path: cookie.path,
601
+ ...(cookie.expires !== undefined && cookie.expires > 0 ? { expires: cookie.expires } : {}),
602
+ httpOnly: cookie.httpOnly,
603
+ secure: cookie.secure,
604
+ ...(isBrowserCookieSameSite(cookie.sameSite) ? { sameSite: cookie.sameSite } : {}),
605
+ };
606
+ }
607
+ function parseCdpCookies(value) {
608
+ if (!Array.isArray(value)) {
609
+ throw new Error("CDP Network.getCookies returned an invalid cookie list");
610
+ }
611
+ return value.map((cookie) => {
612
+ if (!isRecord(cookie) ||
613
+ typeof cookie.name !== "string" ||
614
+ typeof cookie.value !== "string" ||
615
+ typeof cookie.domain !== "string" ||
616
+ typeof cookie.path !== "string" ||
617
+ typeof cookie.expires !== "number" ||
618
+ typeof cookie.httpOnly !== "boolean" ||
619
+ typeof cookie.secure !== "boolean") {
620
+ throw new Error("CDP Network.getCookies returned an invalid cookie");
621
+ }
622
+ return toBrowserCookie({
623
+ name: cookie.name,
624
+ value: cookie.value,
625
+ domain: cookie.domain,
626
+ path: cookie.path,
627
+ expires: cookie.expires,
628
+ httpOnly: cookie.httpOnly,
629
+ secure: cookie.secure,
630
+ sameSite: cookie.sameSite,
631
+ });
632
+ });
633
+ }
589
634
  function parsePoolAcquireResponse(value) {
590
635
  if (!isRecord(value) ||
591
636
  typeof value.pageId !== "string" ||
@@ -864,6 +909,11 @@ class CdpPoolBrowserPage {
864
909
  });
865
910
  return Buffer.from(String(result.data ?? ""), "base64");
866
911
  }
912
+ async cookies() {
913
+ await this.initialize();
914
+ const result = await this.pageClient.send("Network.getCookies");
915
+ return parseCdpCookies(result.cookies);
916
+ }
867
917
  async close() {
868
918
  if (this.closed) {
869
919
  return;
@@ -376,7 +376,6 @@ async function resolveNativeProxy(options, clientOptions, warn, proxyAttemptOffs
376
376
  const resolvedProxy = await resolveProxyConfigAsync({
377
377
  proxy: options.proxy ?? clientOptions.proxy,
378
378
  upstream: clientOptions.upstream,
379
- apifuseConfig: clientOptions.apifuseConfig,
380
379
  proxyPolicy: clientOptions.proxyPolicy,
381
380
  affinityKey: clientOptions.affinityKey,
382
381
  proxyAttempt: computeProxyAttemptIndex({
@@ -1,6 +1,7 @@
1
1
  import { readableBytes, readableLines, readableTextChunks } from "../stream.js";
2
2
  import { parseHttpRequestInvocation, isSensitiveKey, redactSensitiveError, redactSensitiveText, redactUrlQueryParams, requestOptionsFromHttpInvocation, serializeRequestUrl, } from "./request-options.js";
3
3
  import { createTraceContext, getTraceRecorder, } from "./trace.js";
4
+ import { RESOLVER_INSTRUMENTATION_METADATA } from "./resolver.js";
4
5
  const BROWSER_PAGE_METHODS = new Set(["goto", "fill", "click", "type", "waitForSelector"]);
5
6
  const DIAGNOSTIC_BASE_URL = "http://apifuse-instrumentation.invalid";
6
7
  function isThenable(value) {
@@ -420,12 +421,35 @@ function wrapNamespace(namespace, target, trace, shouldInstrument) {
420
421
  return target;
421
422
  }
422
423
  const wrappedMethods = new Map();
424
+ const resolverMetadata = namespace === "resolver" ? { target, traceRecorder: recorder } : undefined;
423
425
  return new Proxy(target, {
424
426
  get(namespaceTarget, property, receiver) {
427
+ if (property === RESOLVER_INSTRUMENTATION_METADATA && resolverMetadata) {
428
+ return resolverMetadata;
429
+ }
425
430
  const value = Reflect.get(namespaceTarget, property, receiver);
426
431
  if (typeof value !== "function" || property === "constructor") {
427
432
  return value;
428
433
  }
434
+ if (namespace === "resolver" && property === "solve") {
435
+ if (wrappedMethods.has(property)) {
436
+ return wrappedMethods.get(property);
437
+ }
438
+ const wrapped = (...args) => {
439
+ const challenge = args[0];
440
+ const challengeKind = typeof challenge === "object" &&
441
+ challenge !== null &&
442
+ "kind" in challenge &&
443
+ typeof challenge.kind === "string"
444
+ ? challenge.kind
445
+ : undefined;
446
+ return recorder.runSpan("resolver.solve", () => Reflect.apply(value, namespaceTarget, [args[0], args[1], recorder]), {
447
+ attributes: challengeKind ? { challenge_kind: challengeKind } : undefined,
448
+ });
449
+ };
450
+ wrappedMethods.set(property, wrapped);
451
+ return wrapped;
452
+ }
429
453
  if (namespace === "browser" && property === "newPage") {
430
454
  if (wrappedMethods.has(property)) {
431
455
  return wrappedMethods.get(property);
@@ -573,7 +597,8 @@ export function wrapWithInstrumentation(ctx, options = {}) {
573
597
  property === "stealth" ||
574
598
  property === "browser" ||
575
599
  property === "session" ||
576
- property === "state") {
600
+ property === "state" ||
601
+ property === "resolver") {
577
602
  const namespace = property;
578
603
  if (wrappedTargets.has(namespace)) {
579
604
  return wrappedTargets.get(namespace);
@@ -0,0 +1,8 @@
1
+ import type { ProviderChallenge } from "../../types.js";
2
+ import type { ResolverIssuingIdentity } from "./types.js";
3
+ export declare const RESOLVER_CHALLENGE_BINDINGS: {
4
+ readonly aws_waf: "portable";
5
+ readonly cloudflare_interstitial: "identity_scoped";
6
+ };
7
+ export declare function resolverChallengeIsIdentityScoped(challenge: ProviderChallenge): boolean;
8
+ export declare function resolverChallengeIssuingIdentity(challenge: ProviderChallenge, identity: ResolverIssuingIdentity): ResolverIssuingIdentity;
@@ -0,0 +1,15 @@
1
+ export const RESOLVER_CHALLENGE_BINDINGS = {
2
+ aws_waf: "portable",
3
+ cloudflare_interstitial: "identity_scoped",
4
+ };
5
+ export function resolverChallengeIsIdentityScoped(challenge) {
6
+ return (RESOLVER_CHALLENGE_BINDINGS[challenge.kind] ===
7
+ "identity_scoped");
8
+ }
9
+ export function resolverChallengeIssuingIdentity(challenge, identity) {
10
+ const binding = RESOLVER_CHALLENGE_BINDINGS[challenge.kind];
11
+ if (binding === "portable") {
12
+ return { userAgent: identity.userAgent };
13
+ }
14
+ return identity;
15
+ }
@@ -0,0 +1,24 @@
1
+ import type { BrowserClient, ChallengeSolution, ProviderChallenge } from "../../types.js";
2
+ import { type BrowserClientOptions } from "../browser.js";
3
+ import type { TraceRecorder } from "../trace.js";
4
+ import { type ResolverIdentity, type ResolverVendorAdapter } from "./types.js";
5
+ type BrowserClientFactory = (options: BrowserClientOptions) => BrowserClient;
6
+ export interface BrowserResolverVendorOptions {
7
+ readonly cdpUrl?: string;
8
+ readonly timeoutMs: number;
9
+ readonly pollIntervalMs?: number;
10
+ readonly allowedHosts: readonly string[];
11
+ readonly createClient?: BrowserClientFactory;
12
+ }
13
+ export type BrowserResolverSolution = Extract<ChallengeSolution, {
14
+ readonly form: "cookies";
15
+ }> & {
16
+ /** Unix seconds from the cookie that proved the challenge cleared. */
17
+ readonly expires?: number;
18
+ };
19
+ export interface BrowserResolverVendorAdapter extends ResolverVendorAdapter {
20
+ readonly id: "browser";
21
+ solve(challenge: ProviderChallenge, identity: ResolverIdentity | undefined, signal: AbortSignal, traceRecorder?: TraceRecorder): Promise<BrowserResolverSolution>;
22
+ }
23
+ export declare function createBrowserResolverVendorAdapter(options: BrowserResolverVendorOptions): BrowserResolverVendorAdapter;
24
+ export {};