@apifuse/provider-sdk 2.2.0-beta.22 → 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 (64) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/bin/apifuse-dev.ts +4 -0
  3. package/bin/apifuse-pack-types.ts +234 -38
  4. package/bin/apifuse-perf.ts +15 -12
  5. package/bin/apifuse-record.ts +4 -0
  6. package/dist/config/loader.d.ts +8 -19
  7. package/dist/config/loader.js +28 -86
  8. package/dist/contract-types.d.ts +1 -0
  9. package/dist/contract.js +2 -0
  10. package/dist/define.d.ts +5 -1
  11. package/dist/define.js +79 -6
  12. package/dist/error-resolution.js +5 -0
  13. package/dist/index.d.ts +4 -2
  14. package/dist/index.js +2 -0
  15. package/dist/provider.d.ts +1 -1
  16. package/dist/runtime/auth-flow.d.ts +2 -1
  17. package/dist/runtime/auth-flow.js +4 -0
  18. package/dist/runtime/browser.js +78 -9
  19. package/dist/runtime/http.js +0 -1
  20. package/dist/runtime/instrumentation.js +26 -1
  21. package/dist/runtime/ocr.d.ts +29 -0
  22. package/dist/runtime/ocr.js +440 -0
  23. package/dist/runtime/resolver-vendors/bindings.d.ts +8 -0
  24. package/dist/runtime/resolver-vendors/bindings.js +15 -0
  25. package/dist/runtime/resolver-vendors/browser.d.ts +24 -0
  26. package/dist/runtime/resolver-vendors/browser.js +287 -0
  27. package/dist/runtime/resolver-vendors/types.d.ts +42 -0
  28. package/dist/runtime/resolver-vendors/types.js +57 -0
  29. package/dist/runtime/resolver.d.ts +39 -0
  30. package/dist/runtime/resolver.js +414 -0
  31. package/dist/runtime/state.d.ts +3 -0
  32. package/dist/runtime/state.js +245 -141
  33. package/dist/runtime/stealth.js +3 -6
  34. package/dist/runtime/stt.js +1 -12
  35. package/dist/runtime/timeout.d.ts +5 -0
  36. package/dist/runtime/timeout.js +12 -0
  37. package/dist/server/serve.d.ts +6 -1
  38. package/dist/server/serve.js +39 -8
  39. package/dist/testing/run.js +10 -0
  40. package/dist/types.d.ts +163 -4
  41. package/package.json +1 -1
  42. package/src/config/loader.ts +35 -111
  43. package/src/contract-types.ts +1 -0
  44. package/src/contract.ts +2 -0
  45. package/src/define.ts +121 -7
  46. package/src/error-resolution.ts +5 -0
  47. package/src/index.ts +45 -1
  48. package/src/provider.ts +1 -0
  49. package/src/runtime/auth-flow.ts +6 -0
  50. package/src/runtime/browser.ts +139 -19
  51. package/src/runtime/http.ts +0 -1
  52. package/src/runtime/instrumentation.ts +36 -2
  53. package/src/runtime/ocr.ts +523 -0
  54. package/src/runtime/resolver-vendors/bindings.ts +31 -0
  55. package/src/runtime/resolver-vendors/browser.ts +420 -0
  56. package/src/runtime/resolver-vendors/types.ts +113 -0
  57. package/src/runtime/resolver.ts +668 -0
  58. package/src/runtime/state.ts +323 -166
  59. package/src/runtime/stealth.ts +3 -6
  60. package/src/runtime/stt.ts +1 -19
  61. package/src/runtime/timeout.ts +18 -0
  62. package/src/server/serve.ts +80 -5
  63. package/src/testing/run.ts +15 -0
  64. package/src/types.ts +188 -4
@@ -1,7 +1,7 @@
1
1
  import { Hono } from "hono";
2
2
  import { z } from "zod";
3
3
  import { type ProviderErrorCategory } from "../observability.js";
4
- import type { ProviderContext, ProviderDefinition, ProviderRuntimeState, SttContext } from "../types.js";
4
+ import type { OcrContext, ProviderContext, ProviderDefinition, ProviderRuntimeState, ResolverContext, SttContext } from "../types.js";
5
5
  import { type OperationRequest } from "./types.js";
6
6
  /** Compact SDK-owned error classification emitted separately from the public response body. */
7
7
  export declare const ERROR_OBSERVABILITY_HEADER = "X-ApiFuse-Error-Observability";
@@ -61,6 +61,7 @@ export type ProviderServerOperationExecutorInput = {
61
61
  };
62
62
  export type ProviderServerOperationExecutor = (input: ProviderServerOperationExecutorInput) => Promise<unknown>;
63
63
  export declare function resolveProviderProxyAffinityKey(provider: ProviderDefinition, request: OperationRequest, operationId: string): string;
64
+ export declare function resolveProviderResolverIdentityScope(provider: ProviderDefinition, affinityKey: string, contextId: string): string;
64
65
  type ProviderRequestCost = {
65
66
  durationMs: number;
66
67
  cpuUserMicros: number;
@@ -133,6 +134,10 @@ export type ProviderServerOptions = {
133
134
  };
134
135
  /** Optional STT override for tests or custom hosts; local/prod normally resolves from env. */
135
136
  stt?: SttContext;
137
+ /** Optional OCR override for tests or custom hosts; local/prod normally resolves from env. */
138
+ ocr?: OcrContext;
139
+ /** Optional resolver override for tests or custom hosts; local/prod normally resolves from env. */
140
+ resolver?: ResolverContext;
136
141
  /** Optional runtime state override for tests or custom hosts. Production resolves Redis from env and fails closed when unavailable. */
137
142
  state?: ProviderRuntimeState;
138
143
  /** Allow process-local runtime state only for local development and tests. */
@@ -18,8 +18,10 @@ import { createHttpClient } from "../runtime/http.js";
18
18
  import { wrapWithInstrumentation } from "../runtime/instrumentation.js";
19
19
  import { createEnvVendorCredentialResolver, createNativeNetworkClient, } from "../runtime/native-network.js";
20
20
  import { getProviderBaseUrl } from "../runtime/provider.js";
21
+ import { createOcrClientFromEnv } from "../runtime/ocr.js";
21
22
  import { PROXY_AUTH_IP_DENIED_CODE, PROXY_EDGE_AUTH_REJECTED_CODE, PROXY_POOL_EXHAUSTED_CODE, } from "../runtime/proxy-errors.js";
22
23
  import { PROVIDER_TELEMETRY_HEADER, ProxyTelemetryCollector } from "../runtime/proxy-telemetry.js";
24
+ import { bindResolverSignal, createResolverClientFromEnv } from "../runtime/resolver.js";
23
25
  import { assertRequiredSecretsPresent, listMissingRequiredSecrets, MISSING_SECRET_CODE, } from "../runtime/secrets.js";
24
26
  import { createProviderRuntimeStateFromEnv, createUnsupportedProviderRuntimeState, } from "../runtime/state.js";
25
27
  import { createStealthClient } from "../runtime/stealth.js";
@@ -148,6 +150,13 @@ export function resolveProviderProxyAffinityKey(provider, request, operationId)
148
150
  }
149
151
  return connectionKey ?? provider.id;
150
152
  }
153
+ export function resolveProviderResolverIdentityScope(provider, affinityKey, contextId) {
154
+ return JSON.stringify({
155
+ proxy: provider.proxy ?? null,
156
+ affinityKey,
157
+ contextId,
158
+ });
159
+ }
151
160
  function resolveOperationConnectionId(request) {
152
161
  return request.connection?.id ?? request.connectionId;
153
162
  }
@@ -160,7 +169,7 @@ function resolveNativeProxyPolicy(provider) {
160
169
  return { mode: "disabled" };
161
170
  return undefined;
162
171
  }
163
- function createProviderContext(provider, request, operationId, options = {}, state = createUnsupportedProviderRuntimeState(), proxyTelemetry) {
172
+ function createProviderContext(provider, request, operationId, options = {}, state = createUnsupportedProviderRuntimeState(), proxyTelemetry, signal) {
164
173
  const baseUrl = getProviderBaseUrl(provider);
165
174
  const stealthBaseUrl = getProviderStealthBaseUrl(provider);
166
175
  const stealthProfile = getProviderStealthProfile(provider);
@@ -169,6 +178,7 @@ function createProviderContext(provider, request, operationId, options = {}, sta
169
178
  affinityKey: resolveProviderProxyAffinityKey(provider, request, operationId),
170
179
  telemetry: proxyTelemetry,
171
180
  };
181
+ const resolverIdentityScope = resolveProviderResolverIdentityScope(provider, proxyClientOptions.affinityKey, request.requestId);
172
182
  let wrappedContext;
173
183
  const stealthClientOptions = {
174
184
  upstream: proxyClientOptions.upstream,
@@ -189,6 +199,8 @@ function createProviderContext(provider, request, operationId, options = {}, sta
189
199
  connectionId: resolveOperationConnectionId(request),
190
200
  headers: request.headers ?? {},
191
201
  };
202
+ const requestState = state.forConnection(requestContext.connectionId);
203
+ const cache = createProviderCache({ providerId: provider.id });
192
204
  const context = wrapWithInstrumentation({
193
205
  env,
194
206
  credential,
@@ -201,8 +213,8 @@ function createProviderContext(provider, request, operationId, options = {}, sta
201
213
  retryResponseMeta.set(wrappedContext, summary);
202
214
  },
203
215
  }),
204
- cache: createProviderCache({ providerId: provider.id }),
205
- state,
216
+ cache,
217
+ state: requestState,
206
218
  stealth: stealthBaseUrl
207
219
  ? stealthProfile
208
220
  ? createStealthClient(stealthBaseUrl, stealthProfile.name, stealthClientOptions)
@@ -232,13 +244,20 @@ function createProviderContext(provider, request, operationId, options = {}, sta
232
244
  : {}),
233
245
  trace: createTraceContext(),
234
246
  auth: createAuthStub(),
247
+ ocr: options.ocr ?? createOcrClientFromEnv(provider.ocr),
235
248
  stt: options.stt ?? createSttClientFromEnv(provider.stt),
249
+ resolver: bindResolverSignal(options.resolver ??
250
+ createResolverClientFromEnv(provider.resolver, undefined, {
251
+ allowedHosts: provider.allowedHosts,
252
+ cache,
253
+ identityScope: resolverIdentityScope,
254
+ }), signal),
236
255
  choice: createProviderChoiceContext({
237
256
  providerId: provider.id,
238
257
  env,
239
258
  request: requestContext,
240
259
  credential,
241
- state,
260
+ state: requestState,
242
261
  }),
243
262
  });
244
263
  wrappedContext = context;
@@ -282,6 +301,7 @@ function createAuthFlowContext(provider, request, options = {}, signal) {
282
301
  request.providerId ??
283
302
  provider.id,
284
303
  };
304
+ const resolverIdentityScope = resolveProviderResolverIdentityScope(provider, proxyClientOptions.affinityKey, request.requestId);
285
305
  const stealthClientOptions = {
286
306
  upstream: proxyClientOptions.upstream,
287
307
  affinityKey: proxyClientOptions.affinityKey,
@@ -294,6 +314,7 @@ function createAuthFlowContext(provider, request, options = {}, signal) {
294
314
  values: request.connection.secrets,
295
315
  })
296
316
  : undefined;
317
+ const cache = createProviderCache({ providerId: provider.id });
297
318
  return {
298
319
  context: {
299
320
  flowId: request.flowId,
@@ -327,7 +348,14 @@ function createAuthFlowContext(provider, request, options = {}, signal) {
327
348
  ]),
328
349
  credential,
329
350
  context: flowContextStore.context,
351
+ ocr: options.ocr ?? createOcrClientFromEnv(provider.ocr),
330
352
  stt: options.stt ?? createSttClientFromEnv(provider.stt),
353
+ resolver: bindResolverSignal(options.resolver ??
354
+ createResolverClientFromEnv(provider.resolver, undefined, {
355
+ allowedHosts: provider.allowedHosts,
356
+ cache,
357
+ identityScope: resolverIdentityScope,
358
+ }), signal),
331
359
  auth: createAuthFlowHelpers({ signal }),
332
360
  },
333
361
  getPatch: flowContextStore.getPatch,
@@ -1045,8 +1073,8 @@ function withAuthRequestHeaders(request, headers) {
1045
1073
  },
1046
1074
  };
1047
1075
  }
1048
- async function handleOperation(provider, request, operationId, options = {}, state = createUnsupportedProviderRuntimeState(), proxyTelemetry) {
1049
- const ctx = createProviderContext(provider, request, operationId, options, state, proxyTelemetry);
1076
+ async function handleOperation(provider, request, operationId, options = {}, state = createUnsupportedProviderRuntimeState(), proxyTelemetry, signal) {
1077
+ const ctx = createProviderContext(provider, request, operationId, options, state, proxyTelemetry, signal);
1050
1078
  const operation = provider.operations[operationId];
1051
1079
  const streaming = operation?.transport?.kind && operation.transport.kind !== "json";
1052
1080
  let cleanupCalled = false;
@@ -1074,6 +1102,7 @@ async function handleOperation(provider, request, operationId, options = {}, sta
1074
1102
  operationId,
1075
1103
  ctx,
1076
1104
  request,
1105
+ signal,
1077
1106
  })
1078
1107
  : await executeOperation(provider, operationId, ctx, request.input);
1079
1108
  if (streaming && operation) {
@@ -1393,7 +1422,7 @@ export function createServerApp(provider, options = {}) {
1393
1422
  }
1394
1423
  const request = operationRequestFromForwardingEnvelope(envelope);
1395
1424
  operationId = envelope.operationId;
1396
- const ctx = createProviderContext(provider, request, operationId, options, state);
1425
+ const ctx = createProviderContext(provider, request, operationId, options, state, undefined, signal);
1397
1426
  if (deadlineAtMs !== undefined && deadlineAtMs <= Date.now()) {
1398
1427
  throw new StatefulRoutingDeadlineError(envelope.requestId, envelope.deadlineAt);
1399
1428
  }
@@ -1432,7 +1461,7 @@ export function createServerApp(provider, options = {}) {
1432
1461
  const body = OperationRequestSchema.parse(rawBody);
1433
1462
  const requestHeaders = Object.fromEntries(c.req.raw.headers.entries());
1434
1463
  body.headers = { ...requestHeaders, ...body.headers };
1435
- const response = await handleOperation(provider, body, operation, options, state, proxyTelemetry);
1464
+ const response = await handleOperation(provider, body, operation, options, state, proxyTelemetry, c.req.raw.signal);
1436
1465
  if (response instanceof Response) {
1437
1466
  logProviderSuccess(logger, provider, "operation", operation, body.requestId, response.status, finishRequestCost(requestCost));
1438
1467
  return responseWithProviderTelemetry(response, proxyTelemetry);
@@ -1608,7 +1637,9 @@ export async function serve(provider, options = {}) {
1608
1637
  const configuredSignals = resolveShutdownSignals(options.shutdown?.signals ?? true);
1609
1638
  const app = createServerApp(provider, {
1610
1639
  logger: options.logger,
1640
+ ocr: options.ocr,
1611
1641
  stt: options.stt,
1642
+ resolver: options.resolver,
1612
1643
  state: options.state,
1613
1644
  allowMemoryStateFallback: options.allowMemoryStateFallback,
1614
1645
  operationExecutor: options.operationExecutor,
@@ -2,6 +2,7 @@ import { describe, expect, it } from "bun:test";
2
2
  import { createProviderCache } from "../runtime/cache.js";
3
3
  import { createTestProviderChoiceContext } from "../runtime/choice.js";
4
4
  import { createMemoryProviderRuntimeState } from "../runtime/state.js";
5
+ import { createUnsupportedOcrClient } from "../runtime/ocr.js";
5
6
  import { createUnsupportedSttClient } from "../runtime/stt.js";
6
7
  import { createNativeEgressAuthorization, NativeNetworkError, snapshotNativeConnectInput, snapshotNativeGrantInput, } from "../runtime/native-network.js";
7
8
  import { safeParseSchemaSync } from "../schema.js";
@@ -247,6 +248,7 @@ function createUpstreamContext(provider, operationName, upstreamStub) {
247
248
  },
248
249
  }),
249
250
  close: async () => { },
251
+ cookies: async () => (await browserAction("cookies")).data,
250
252
  fill: async (selector, textValue) => {
251
253
  await browserAction("fill", { selector, text: textValue });
252
254
  },
@@ -397,7 +399,11 @@ function createUpstreamContext(provider, operationName, upstreamStub) {
397
399
  : {}),
398
400
  trace: { span: async (_name, fn) => fn() },
399
401
  auth: { requestField: async (name) => unsupported(`ctx.auth.requestField(${name})`) },
402
+ ocr: createUnsupportedOcrClient("Standard test upstream context does not support ctx.ocr.recognize"),
400
403
  stt: createUnsupportedSttClient("Standard test upstream context does not support ctx.stt.transcribe"),
404
+ resolver: {
405
+ solve: async () => unsupported("ctx.resolver.solve"),
406
+ },
401
407
  choice: createTestProviderChoiceContext({
402
408
  providerId: `standard-test-${operationName}`,
403
409
  request,
@@ -503,7 +509,11 @@ export function createSnapshotContext(rawFixture) {
503
509
  auth: {
504
510
  requestField: async (name) => unsupported(`ctx.auth.requestField(${name})`),
505
511
  },
512
+ ocr: createUnsupportedOcrClient("Standard test snapshot context does not support ctx.ocr.recognize"),
506
513
  stt: createUnsupportedSttClient("Standard test snapshot context does not support ctx.stt.transcribe"),
514
+ resolver: {
515
+ solve: async () => unsupported("ctx.resolver.solve"),
516
+ },
507
517
  choice: createTestProviderChoiceContext({
508
518
  providerId: "standard-test",
509
519
  request,
package/dist/types.d.ts CHANGED
@@ -196,6 +196,54 @@ export interface SmsOtpMatcherDefinition {
196
196
  /** Runtime/fixture helper. Not serialized into generated registry artifacts. */
197
197
  extractOtp(body: string): string | null;
198
198
  }
199
+ export interface ProviderOcrConfig {
200
+ readonly mode: "required" | "optional";
201
+ }
202
+ export type OcrImageInput = {
203
+ readonly kind: "base64";
204
+ readonly data: string;
205
+ readonly mediaType?: string;
206
+ } | {
207
+ readonly kind: "url";
208
+ readonly url: string;
209
+ };
210
+ export interface OcrRecognizeRequest {
211
+ readonly image: OcrImageInput;
212
+ readonly hint?: "captcha" | "document" | "generic";
213
+ readonly prompt?: string;
214
+ readonly maxTokens?: number;
215
+ readonly timeoutMs?: number;
216
+ }
217
+ export interface OcrWarning {
218
+ readonly code: string;
219
+ readonly message: string;
220
+ }
221
+ export interface OcrResult {
222
+ readonly text: string;
223
+ readonly model: string;
224
+ readonly warnings?: readonly OcrWarning[];
225
+ }
226
+ export interface OcrCaptchaOptions {
227
+ readonly length?: number;
228
+ /** Allowed characters. A RegExp is applied to each character, not to the whole text. */
229
+ readonly charset?: string | RegExp;
230
+ readonly caseSensitive?: boolean;
231
+ readonly maxCandidates?: number;
232
+ }
233
+ export interface OcrCaptchaCandidate {
234
+ readonly text: string;
235
+ readonly satisfiesConstraints: boolean;
236
+ }
237
+ export interface OcrCaptchaResult {
238
+ readonly text: string;
239
+ readonly candidates: readonly OcrCaptchaCandidate[];
240
+ readonly satisfiesConstraints: boolean;
241
+ readonly model: string;
242
+ }
243
+ export interface OcrContext {
244
+ recognize(request: OcrRecognizeRequest): Promise<OcrResult>;
245
+ extractCaptchaText(image: OcrImageInput, options?: OcrCaptchaOptions): Promise<OcrCaptchaResult>;
246
+ }
199
247
  export type SttTranscribeMode = "general" | "otp";
200
248
  export type SttPromptPolicy = "none" | "default-hint" | "custom-hint";
201
249
  export type SttUnsupportedOptionPolicy = "warn" | "error";
@@ -203,6 +251,79 @@ export type ProviderSttMode = "optional" | "required";
203
251
  export interface ProviderSttConfig {
204
252
  mode: ProviderSttMode;
205
253
  }
254
+ /**
255
+ * `browser` is the in-house CDP pool (`apps/cdp-pool`, reached through
256
+ * `createBrowserClient`) and is a first-class vendor rather than an escape hatch:
257
+ * for fingerprint-family kinds, it was measured faster than a paid vendor
258
+ * (4.5 s vs 17.5 s) at zero marginal cost.
259
+ *
260
+ * `2captcha` is the vendor already carrying production traffic in
261
+ * `apifuse-provider-tabelog`.
262
+ *
263
+ * Union order is documentation only; the effective fallback order is whatever
264
+ * `ProviderResolverConfig.vendors` declares.
265
+ */
266
+ export type ProviderResolverVendor = "browser" | "capsolver" | "capmonster" | "2captcha" | "custom";
267
+ /**
268
+ * Token-family kinds resolve to `{ form: "token" }`. Cookie-family kinds resolve
269
+ * to `{ form: "cookies" }`; network-identity binding is defined per kind. `aws_waf`
270
+ * was measured portable across residential leases on buyee, while `cf_clearance`
271
+ * remains unmeasured here and is treated as identity-scoped because it is widely
272
+ * described as IP-bound.
273
+ */
274
+ export type ProviderChallenge = {
275
+ readonly kind: "turnstile";
276
+ readonly siteKey: string;
277
+ readonly pageUrl: string;
278
+ readonly action?: string;
279
+ readonly cdata?: string;
280
+ } | {
281
+ readonly kind: "recaptcha_v2";
282
+ readonly siteKey: string;
283
+ readonly pageUrl: string;
284
+ } | {
285
+ readonly kind: "recaptcha_v3";
286
+ readonly siteKey: string;
287
+ readonly pageUrl: string;
288
+ readonly action: string;
289
+ readonly minScore?: number;
290
+ } | {
291
+ readonly kind: "hcaptcha";
292
+ readonly siteKey: string;
293
+ readonly pageUrl: string;
294
+ } | {
295
+ readonly kind: "cloudflare_interstitial";
296
+ readonly pageUrl: string;
297
+ readonly blockedHtml?: string;
298
+ } | {
299
+ readonly kind: "aws_waf";
300
+ readonly pageUrl: string;
301
+ readonly captchaScript?: string;
302
+ readonly context?: string;
303
+ readonly iv?: string;
304
+ };
305
+ export type ProviderChallengeKind = ProviderChallenge["kind"];
306
+ /**
307
+ * Token solutions carry no network-identity binding. Cookie-solution binding is
308
+ * per challenge kind: `aws_waf` was measured portable across residential leases
309
+ * on buyee, while `cf_clearance` is unmeasured here and treated as scoped to the
310
+ * identity that produced it. The provider attaches the returned cookies to its
311
+ * own requests.
312
+ */
313
+ export type ChallengeSolution = {
314
+ readonly form: "token";
315
+ readonly token: string;
316
+ } | {
317
+ readonly form: "cookies";
318
+ readonly cookies: Readonly<Record<string, string>>;
319
+ readonly userAgent: string;
320
+ };
321
+ export interface ProviderResolverConfig {
322
+ /** Ordered vendor fallback chain, tried first to last. */
323
+ readonly vendors: readonly ProviderResolverVendor[];
324
+ /** Challenge kinds this provider is permitted to request. */
325
+ readonly kinds: readonly ProviderChallengeKind[];
326
+ }
206
327
  export type SttAudioInput = {
207
328
  kind: "base64";
208
329
  data: string;
@@ -267,6 +388,9 @@ export interface SttContext {
267
388
  transcribe(request: SttTranscribeRequest): Promise<SttTranscript>;
268
389
  extractVerificationCode(text: string, options?: SttVerificationCodeOptions): VerificationCodeExtractionResult;
269
390
  }
391
+ export interface ResolverContext {
392
+ solve(challenge: ProviderChallenge, signal?: AbortSignal): Promise<ChallengeSolution>;
393
+ }
270
394
  export interface HealthJourneySchedule {
271
395
  kind: "interval";
272
396
  /** ISO 8601 duration, for example PT8H. */
@@ -668,10 +792,12 @@ export type ProviderProxyMode = "disabled" | "optional" | "required";
668
792
  * - `decodo` — **decodo.com**, the *gateway* proxy that was named "Smartproxy"
669
793
  * (smartproxy.com) before its 2025 rebrand to Decodo. Sticky sessions via
670
794
  * username params. A different company from `smartproxy` above.
671
- * **@deprecated** — unused; no managed adapter. Use `smartproxy`/`nodemaven`,
672
- * or the `APIFUSE__PROXY__URL` bring-your-own escape hatch.
673
- * - `custom` **@deprecated** bring-your-own static proxy URL marker. The
674
- * `APIFUSE__PROXY__URL` env still works without declaring this value.
795
+ * **@deprecated** — unused; no managed adapter. Declare a
796
+ * `ProviderProxyPolicy` using `smartproxy` or `nodemaven` instead; the
797
+ * `smartproxy` allocator requires `APIFUSE__PROXY__SMARTPROXY_APP_KEY`.
798
+ * - `custom` **@deprecated** static proxy marker with no managed adapter.
799
+ * Use `ProviderProxyPolicy` with `smartproxy`/`nodemaven`; the `smartproxy`
800
+ * allocator requires `APIFUSE__PROXY__SMARTPROXY_APP_KEY`.
675
801
  */
676
802
  export type ProviderProxyProvider = "smartproxy" | "nodemaven" | "decodo" | "custom";
677
803
  export type ProviderProxySessionAffinity = "request" | "operation" | "auth-flow" | "connection";
@@ -1281,6 +1407,17 @@ export interface BrowserFrame {
1281
1407
  evaluate<T>(fn: string | (() => T)): Promise<T>;
1282
1408
  locator(selector: string): BrowserLocator;
1283
1409
  }
1410
+ export interface BrowserCookie {
1411
+ readonly name: string;
1412
+ readonly value: string;
1413
+ readonly domain: string;
1414
+ readonly path: string;
1415
+ /** Unix seconds. Absent for a session cookie. */
1416
+ readonly expires?: number;
1417
+ readonly httpOnly: boolean;
1418
+ readonly secure: boolean;
1419
+ readonly sameSite?: "Strict" | "Lax" | "None";
1420
+ }
1284
1421
  export type BrowserResourceMethod = "GET" | "HEAD";
1285
1422
  export type BrowserResourceRequest = {
1286
1423
  readonly url: string;
@@ -1309,6 +1446,11 @@ export type BrowserResourcePolicy = {
1309
1446
  };
1310
1447
  export interface BrowserPage extends BrowserFrame {
1311
1448
  close(): Promise<void>;
1449
+ /**
1450
+ * Reads the browser context's cookie jar, including httpOnly cookies.
1451
+ * Cookie expiry values are Unix seconds and are absent for session cookies.
1452
+ */
1453
+ cookies(): Promise<readonly BrowserCookie[]>;
1312
1454
  fill(selector: string, text: string): Promise<void>;
1313
1455
  goto(url: string): Promise<void>;
1314
1456
  pageId?: string;
@@ -1543,7 +1685,9 @@ export interface FlowContext {
1543
1685
  env: EnvContext;
1544
1686
  credential?: CredentialContext;
1545
1687
  context: ContextScratchpad;
1688
+ ocr: OcrContext;
1546
1689
  stt: SttContext;
1690
+ resolver: ResolverContext;
1547
1691
  auth: AuthFlowTerminalContext;
1548
1692
  }
1549
1693
  export interface AuthTurn {
@@ -1575,7 +1719,13 @@ export interface AuthFlowDefinition {
1575
1719
  refresh?: AuthFlowInputHandler;
1576
1720
  }
1577
1721
  export type ProviderStateDurationString = `${number}${"ms" | "s" | "m" | "h" | "d"}` | `PT${string}`;
1722
+ export type StateNamespaceScope = "connection" | "provider";
1578
1723
  export interface StateNamespaceOptions {
1724
+ /**
1725
+ * State isolation boundary. Connection scope is the default; provider scope
1726
+ * must be selected explicitly for provider-wide coordination state.
1727
+ */
1728
+ scope?: StateNamespaceScope;
1579
1729
  /** Default TTL used when a write omits ttl. Required to avoid unbounded state. */
1580
1730
  defaultTtl: ProviderStateDurationString;
1581
1731
  /** Maximum allowed TTL; writes are rejected when they exceed this policy. */
@@ -1617,6 +1767,11 @@ export interface ProviderStateNamespace {
1617
1767
  increment(key: string, field: string, delta?: number, options?: StateWriteOptions): Promise<StateValue<Record<string, unknown>>>;
1618
1768
  }
1619
1769
  export interface ProviderRuntimeState {
1770
+ /**
1771
+ * Returns an immutable view bound to one request connection. An unresolved
1772
+ * connection uses an isolated reserved sentinel, never the provider-global scope.
1773
+ */
1774
+ forConnection(connectionId: string | undefined): ProviderRuntimeState;
1620
1775
  namespace(name: string, options: StateNamespaceOptions): ProviderStateNamespace;
1621
1776
  }
1622
1777
  export interface ProviderContext {
@@ -1634,7 +1789,9 @@ export interface ProviderContext {
1634
1789
  browser: BrowserClient;
1635
1790
  trace: TraceContext;
1636
1791
  auth: AuthContext;
1792
+ ocr: OcrContext;
1637
1793
  stt: SttContext;
1794
+ resolver: ResolverContext;
1638
1795
  choice: ProviderChoiceContext;
1639
1796
  }
1640
1797
  export interface ProxiedOAuthConfig {
@@ -1785,7 +1942,9 @@ export interface ProviderDefinition {
1785
1942
  platform: StealthPlatform;
1786
1943
  };
1787
1944
  proxy?: ProviderProxyConfig;
1945
+ ocr?: ProviderOcrConfig;
1788
1946
  stt?: ProviderSttConfig;
1947
+ resolver?: ProviderResolverConfig;
1789
1948
  browser?: {
1790
1949
  engine: BrowserEngine;
1791
1950
  };
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.2.0-beta.22",
2
+ "version": "2.2.0-beta.24",
3
3
  "name": "@apifuse/provider-sdk",
4
4
  "private": false,
5
5
  "type": "module",