@apifuse/provider-sdk 2.2.0-beta.31 → 2.2.0-beta.33

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.
@@ -338,11 +338,6 @@ export function createTwoCaptchaResolverVendorAdapter(
338
338
  if (!resolverVendorSupports(TWOCAPTCHA_VENDOR_ID, challenge.kind)) {
339
339
  throw new TypeError(`2captcha resolver does not support ${challenge.kind}`);
340
340
  }
341
- if (challenge.kind !== "recaptcha_v2" && challenge.kind !== "aws_waf") {
342
- throw new ResolverVendorUnavailableError(TWOCAPTCHA_VENDOR_ID, "not_implemented", {
343
- phase: "create_task",
344
- });
345
- }
346
341
  if (
347
342
  challenge.kind === "aws_waf" &&
348
343
  (!challenge.siteKey?.trim() ||
@@ -354,6 +349,11 @@ export function createTwoCaptchaResolverVendorAdapter(
354
349
  phase: "create_task",
355
350
  });
356
351
  }
352
+ if (challenge.kind === "recaptcha_v3" && challenge.minScore === undefined) {
353
+ throw new ResolverVendorUnavailableError(TWOCAPTCHA_VENDOR_ID, "transport_failure", {
354
+ phase: "create_task",
355
+ });
356
+ }
357
357
 
358
358
  assertResolverHostAllowed(challenge.pageUrl, options.allowedHosts);
359
359
  callerSignal.throwIfAborted();
@@ -388,14 +388,49 @@ export function createTwoCaptchaResolverVendorAdapter(
388
388
  ...(identity ? { userAgent: identity.userAgent } : {}),
389
389
  ...(proxy ?? {}),
390
390
  }
391
- : {
392
- type: proxy ? "RecaptchaV2Task" : "RecaptchaV2TaskProxyless",
391
+ : challenge.kind === "recaptcha_v2"
392
+ ? {
393
+ type: proxy ? "RecaptchaV2Task" : "RecaptchaV2TaskProxyless",
393
394
  websiteURL: challenge.pageUrl,
394
395
  websiteKey: challenge.siteKey,
395
396
  isInvisible: false,
396
397
  ...(identity ? { userAgent: identity.userAgent } : {}),
398
+ ...(proxy ?? {}),
399
+ }
400
+ : challenge.kind === "recaptcha_v3"
401
+ ? {
402
+ type: "RecaptchaV3TaskProxyless",
403
+ websiteURL: challenge.pageUrl,
404
+ websiteKey: challenge.siteKey,
405
+ minScore: challenge.minScore,
406
+ pageAction: challenge.action,
407
+ ...(identity ? { userAgent: identity.userAgent } : {}),
408
+ }
409
+ : challenge.kind === "hcaptcha"
410
+ ? {
411
+ type: proxy ? "HCaptchaTask" : "HCaptchaTaskProxyless",
412
+ websiteURL: challenge.pageUrl,
413
+ websiteKey: challenge.siteKey,
414
+ ...(identity ? { userAgent: identity.userAgent } : {}),
415
+ ...(proxy ?? {}),
416
+ }
417
+ : challenge.kind === "turnstile"
418
+ ? {
419
+ type: proxy ? "TurnstileTask" : "TurnstileTaskProxyless",
420
+ websiteURL: challenge.pageUrl,
421
+ websiteKey: challenge.siteKey,
422
+ ...(challenge.action !== undefined ? { action: challenge.action } : {}),
423
+ ...(challenge.cdata !== undefined ? { data: challenge.cdata } : {}),
424
+ ...(identity ? { userAgent: identity.userAgent } : {}),
397
425
  ...(proxy ?? {}),
398
- };
426
+ }
427
+ : // `resolverVendorSupports` above already rejected every kind this
428
+ // adapter does not build a task for, so this branch is unreachable.
429
+ (() => {
430
+ throw new TypeError(
431
+ `2captcha resolver does not support ${challenge.kind}`,
432
+ );
433
+ })();
399
434
  const createResult = await postJson(
400
435
  fetchImpl,
401
436
  endpoint(baseUrl, "createTask"),
@@ -8,15 +8,18 @@ import type { TraceRecorder } from "../trace.js";
8
8
 
9
9
  export const RESOLVER_VENDOR_CAPABILITIES = {
10
10
  browser: ["aws_waf", "cloudflare_interstitial"],
11
+ // Every kind listed per vendor is implemented by that vendor's adapter; the
12
+ // per-adapter "agrees with every declared capability" tests iterate this
13
+ // table, so adding a kind here without an implementation fails the suite.
14
+ // 2captcha omits `cloudflare_interstitial`, `akamai_sec_cpt`, and
15
+ // `akamai_sensor`: their API offers no task type for them, so declaring them
16
+ // would route challenges to a vendor that can only refuse.
11
17
  "2captcha": [
12
18
  "turnstile",
13
19
  "recaptcha_v2",
14
20
  "recaptcha_v3",
15
21
  "hcaptcha",
16
- "cloudflare_interstitial",
17
22
  "aws_waf",
18
- "akamai_sec_cpt",
19
- "akamai_sensor",
20
23
  ],
21
24
  capsolver: [
22
25
  "turnstile",
@@ -24,6 +24,7 @@ import {
24
24
  resolverChallengeIssuingIdentity,
25
25
  } from "./resolver-vendors/bindings.js";
26
26
  import { createBrowserResolverVendorAdapter } from "./resolver-vendors/browser.js";
27
+ import { createCapsolverResolverVendorAdapter } from "./resolver-vendors/capsolver.js";
27
28
  import { assertResolverHostAllowed } from "./resolver-vendors/hosts.js";
28
29
  import { createTwoCaptchaResolverVendorAdapter } from "./resolver-vendors/twocaptcha.js";
29
30
  import {
@@ -70,7 +71,7 @@ type ResolvedResolverVendor =
70
71
  | {
71
72
  readonly vendor: Exclude<ProviderResolverVendor, "custom">;
72
73
  readonly available: true;
73
- readonly configuration: string;
74
+ readonly configuration: string | undefined;
74
75
  }
75
76
  | {
76
77
  readonly vendor: ProviderResolverVendor;
@@ -183,19 +184,29 @@ export type ResolverInstrumentationMetadata = {
183
184
  };
184
185
 
185
186
  export type ResolverAdapterFactory = (
186
- configuration: string,
187
+ configuration: string | undefined,
187
188
  timeoutMs: number,
188
189
  allowedHosts: readonly string[],
189
190
  ) => ResolverVendorAdapter;
190
191
 
191
192
  const resolverAdapterRegistry: Partial<Record<ProviderResolverVendor, ResolverAdapterFactory>> = {
192
193
  "2captcha"(configuration, timeoutMs, allowedHosts) {
194
+ if (configuration === undefined) {
195
+ throw new Error("2captcha resolver adapter factory requires an API key");
196
+ }
193
197
  return createTwoCaptchaResolverVendorAdapter({
194
198
  allowedHosts,
195
199
  apiKey: configuration,
196
200
  timeoutMs,
197
201
  });
198
202
  },
203
+ capsolver(configuration, timeoutMs, allowedHosts) {
204
+ return createCapsolverResolverVendorAdapter({
205
+ allowedHosts,
206
+ apiKey: configuration,
207
+ timeoutMs,
208
+ });
209
+ },
199
210
  browser(configuration, timeoutMs, allowedHosts) {
200
211
  return createBrowserResolverVendorAdapter({
201
212
  allowedHosts,
@@ -246,7 +257,6 @@ export function swapResolverDefaultUserAgentForTests(
246
257
  // This is the sole allowlist for declared vendors whose registry entry may be absent.
247
258
  // Remove a vendor here when its adapter is registered.
248
259
  const KNOWN_UNIMPLEMENTED_RESOLVER_VENDORS: ReadonlySet<ProviderResolverVendor> = new Set([
249
- "capsolver",
250
260
  "capmonster",
251
261
  "custom",
252
262
  ]);
@@ -959,15 +969,20 @@ function resolveVendorAvailability(
959
969
  reason: "missing_transport",
960
970
  };
961
971
  }
972
+ if (vendor === "browser") {
973
+ return {
974
+ vendor,
975
+ available: true,
976
+ configuration: normalizedEnvValue(env, APIFUSE__CDP_POOL__URL),
977
+ };
978
+ }
962
979
 
963
980
  const envKey =
964
981
  vendor === "2captcha"
965
982
  ? APIFUSE__RESOLVER__2CAPTCHA__API_KEY
966
983
  : vendor === "capsolver"
967
984
  ? APIFUSE__RESOLVER__CAPSOLVER__API_KEY
968
- : vendor === "capmonster"
969
- ? APIFUSE__RESOLVER__CAPMONSTER__API_KEY
970
- : APIFUSE__CDP_POOL__URL;
985
+ : APIFUSE__RESOLVER__CAPMONSTER__API_KEY;
971
986
 
972
987
  const configuration = normalizedEnvValue(env, envKey);
973
988
  return configuration
@@ -39,7 +39,6 @@ import { createProviderCache } from "../runtime/cache.js";
39
39
  import {
40
40
  createProviderChoiceContext,
41
41
  PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV,
42
- PROVIDER_RUNTIME_CHOICE_WORD_ISSUANCE_ENV,
43
42
  } from "../runtime/choice.js";
44
43
  import { createCredentialContext } from "../runtime/credential.js";
45
44
  import { createEnvContext } from "../runtime/env.js";
@@ -627,7 +626,6 @@ function createProviderContext(
627
626
  const env = createEnvContext([
628
627
  ...(provider.secrets?.map((secret) => secret.name) ?? []),
629
628
  PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV,
630
- PROVIDER_RUNTIME_CHOICE_WORD_ISSUANCE_ENV,
631
629
  ]);
632
630
  const credential = createCredentialContext({
633
631
  allowedKeys: provider.credential?.keys,
package/src/types.ts CHANGED
@@ -1757,7 +1757,7 @@ export interface BrowserCookie {
1757
1757
  readonly sameSite?: "Strict" | "Lax" | "None";
1758
1758
  }
1759
1759
 
1760
- export type BrowserResourceMethod = "GET" | "HEAD";
1760
+ export type BrowserResourceMethod = "GET" | "HEAD" | "POST";
1761
1761
 
1762
1762
  export type BrowserResourceRequest = {
1763
1763
  readonly url: string;
@@ -1769,6 +1769,9 @@ export type BrowserResourceRequest = {
1769
1769
  export type BrowserResourceBody = Buffer | Uint8Array | ArrayBuffer | string;
1770
1770
 
1771
1771
  export type BrowserResourceDecision =
1772
+ | {
1773
+ readonly action: "continue";
1774
+ }
1772
1775
  | {
1773
1776
  readonly action: "fulfill";
1774
1777
  readonly status?: number;
@@ -1793,6 +1796,12 @@ export type BrowserResourceRoute = {
1793
1796
  export type BrowserResourcePolicy = {
1794
1797
  readonly defaultAction?: "block";
1795
1798
  readonly allowedMethods?: readonly BrowserResourceMethod[];
1799
+ /**
1800
+ * Appends an enforcing CSP header to every renderable document response
1801
+ * while the policy is active. Existing CSP headers are retained, so this
1802
+ * can only further restrict the document.
1803
+ */
1804
+ readonly documentContentSecurityPolicy?: string;
1796
1805
  readonly routes: readonly BrowserResourceRoute[];
1797
1806
  };
1798
1807