@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.
- package/CHANGELOG.md +8 -0
- package/bin/apifuse-dev.ts +4 -0
- package/bin/apifuse-pack-types.ts +234 -38
- package/bin/apifuse-perf.ts +15 -12
- package/bin/apifuse-record.ts +4 -0
- package/dist/config/loader.d.ts +8 -19
- package/dist/config/loader.js +28 -86
- package/dist/contract-types.d.ts +1 -0
- package/dist/contract.js +2 -0
- package/dist/define.d.ts +5 -1
- package/dist/define.js +79 -6
- package/dist/error-resolution.js +5 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -0
- package/dist/provider.d.ts +1 -1
- package/dist/runtime/auth-flow.d.ts +2 -1
- package/dist/runtime/auth-flow.js +4 -0
- package/dist/runtime/browser.js +78 -9
- package/dist/runtime/http.js +0 -1
- package/dist/runtime/instrumentation.js +26 -1
- package/dist/runtime/ocr.d.ts +29 -0
- package/dist/runtime/ocr.js +440 -0
- package/dist/runtime/resolver-vendors/bindings.d.ts +8 -0
- package/dist/runtime/resolver-vendors/bindings.js +15 -0
- package/dist/runtime/resolver-vendors/browser.d.ts +24 -0
- package/dist/runtime/resolver-vendors/browser.js +287 -0
- package/dist/runtime/resolver-vendors/types.d.ts +42 -0
- package/dist/runtime/resolver-vendors/types.js +57 -0
- package/dist/runtime/resolver.d.ts +39 -0
- package/dist/runtime/resolver.js +414 -0
- package/dist/runtime/state.d.ts +3 -0
- package/dist/runtime/state.js +245 -141
- package/dist/runtime/stealth.js +3 -6
- package/dist/runtime/stt.js +1 -12
- package/dist/runtime/timeout.d.ts +5 -0
- package/dist/runtime/timeout.js +12 -0
- package/dist/server/serve.d.ts +6 -1
- package/dist/server/serve.js +39 -8
- package/dist/testing/run.js +10 -0
- package/dist/types.d.ts +163 -4
- package/package.json +1 -1
- package/src/config/loader.ts +35 -111
- package/src/contract-types.ts +1 -0
- package/src/contract.ts +2 -0
- package/src/define.ts +121 -7
- package/src/error-resolution.ts +5 -0
- package/src/index.ts +45 -1
- package/src/provider.ts +1 -0
- package/src/runtime/auth-flow.ts +6 -0
- package/src/runtime/browser.ts +139 -19
- package/src/runtime/http.ts +0 -1
- package/src/runtime/instrumentation.ts +36 -2
- package/src/runtime/ocr.ts +523 -0
- package/src/runtime/resolver-vendors/bindings.ts +31 -0
- package/src/runtime/resolver-vendors/browser.ts +420 -0
- package/src/runtime/resolver-vendors/types.ts +113 -0
- package/src/runtime/resolver.ts +668 -0
- package/src/runtime/state.ts +323 -166
- package/src/runtime/stealth.ts +3 -6
- package/src/runtime/stt.ts +1 -19
- package/src/runtime/timeout.ts +18 -0
- package/src/server/serve.ts +80 -5
- package/src/testing/run.ts +15 -0
- package/src/types.ts +188 -4
package/src/runtime/stealth.ts
CHANGED
|
@@ -787,7 +787,6 @@ function createSessionFetcher(
|
|
|
787
787
|
const resolvedProxy = await resolveProxyConfigAsync({
|
|
788
788
|
proxy: options?.proxy ?? clientOptions.proxy,
|
|
789
789
|
upstream: clientOptions.upstream,
|
|
790
|
-
apifuseConfig: clientOptions.apifuseConfig,
|
|
791
790
|
affinityKey: clientOptions.affinityKey,
|
|
792
791
|
proxyAttempt: computeProxyAttemptIndex({
|
|
793
792
|
baseProxyAttempt: clientOptions.proxyAttempt,
|
|
@@ -860,11 +859,9 @@ function createSessionFetcher(
|
|
|
860
859
|
// A registry vendor chain (smartproxy/nodemaven) is the only policy whose
|
|
861
860
|
// successive attempts resolve a *different* endpoint, so it is the only one
|
|
862
861
|
// that may widen the attempt cap to the pool span, de-duplicate endpoints,
|
|
863
|
-
// and drive allocator stale-pool refresh.
|
|
864
|
-
//
|
|
865
|
-
//
|
|
866
|
-
// retry:false and unsafe-method controls. Static policies therefore follow
|
|
867
|
-
// the ordinary transport-retry budget instead.
|
|
862
|
+
// and drive allocator stale-pool refresh. Deprecated custom/decodo policies
|
|
863
|
+
// have no managed endpoint to rotate or refresh, so they follow the ordinary
|
|
864
|
+
// transport-retry budget instead.
|
|
868
865
|
const rotatesRegistryChain =
|
|
869
866
|
usesPolicyAllocator && policyResolvesRegistryVendorChain(policyProxy);
|
|
870
867
|
const maxAttempts = rotatesRegistryChain ? policyProxyAttemptCap : retryAttemptCap;
|
package/src/runtime/stt.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
VerificationCodeCandidateSource,
|
|
15
15
|
VerificationCodeExtractionResult,
|
|
16
16
|
} from "../types.js";
|
|
17
|
+
import { createTimeoutController, isTimeoutLikeError } from "./timeout.js";
|
|
17
18
|
|
|
18
19
|
export const APIFUSE__STT__BACKEND_ENV = "APIFUSE__STT__BACKEND";
|
|
19
20
|
export const APIFUSE__STT__MODEL_ENV = "APIFUSE__STT__MODEL";
|
|
@@ -169,15 +170,6 @@ function normalizeCloudflareLanguage(language: Bcp47Locale | undefined): string
|
|
|
169
170
|
return language?.split("-")[0]?.toLowerCase();
|
|
170
171
|
}
|
|
171
172
|
|
|
172
|
-
function isTimeoutLikeError(error: unknown): error is Error {
|
|
173
|
-
return (
|
|
174
|
-
error instanceof Error &&
|
|
175
|
-
(error.name === "AbortError" ||
|
|
176
|
-
error.name === "TimeoutError" ||
|
|
177
|
-
/\b(timed out|timeout|deadline exceeded)\b/i.test(error.message))
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
173
|
function toSttTransportError(error: unknown): TransportError {
|
|
182
174
|
if (error instanceof TransportError) return error;
|
|
183
175
|
if (isTimeoutLikeError(error)) {
|
|
@@ -194,16 +186,6 @@ function toSttTransportError(error: unknown): TransportError {
|
|
|
194
186
|
});
|
|
195
187
|
}
|
|
196
188
|
|
|
197
|
-
function createTimeoutController(signalTimeoutMs: number): {
|
|
198
|
-
controller: AbortController;
|
|
199
|
-
clear: () => void;
|
|
200
|
-
} {
|
|
201
|
-
const controller = new AbortController();
|
|
202
|
-
const timeout = setTimeout(() => controller.abort(), signalTimeoutMs);
|
|
203
|
-
timeout.unref?.();
|
|
204
|
-
return { controller, clear: () => clearTimeout(timeout) };
|
|
205
|
-
}
|
|
206
|
-
|
|
207
189
|
function toCloudflareInput(request: SttTranscribeRequest): Record<string, unknown> {
|
|
208
190
|
const prompt = resolveSttPrompt(request);
|
|
209
191
|
const input: Record<string, unknown> = {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function isTimeoutLikeError(error: unknown): error is Error {
|
|
2
|
+
return (
|
|
3
|
+
error instanceof Error &&
|
|
4
|
+
(error.name === "AbortError" ||
|
|
5
|
+
error.name === "TimeoutError" ||
|
|
6
|
+
/\b(timed out|timeout|deadline exceeded)\b/i.test(error.message))
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function createTimeoutController(signalTimeoutMs: number): {
|
|
11
|
+
controller: AbortController;
|
|
12
|
+
clear: () => void;
|
|
13
|
+
} {
|
|
14
|
+
const controller = new AbortController();
|
|
15
|
+
const timeout = setTimeout(() => controller.abort(), signalTimeoutMs);
|
|
16
|
+
timeout.unref?.();
|
|
17
|
+
return { controller, clear: () => clearTimeout(timeout) };
|
|
18
|
+
}
|
package/src/server/serve.ts
CHANGED
|
@@ -48,12 +48,14 @@ import {
|
|
|
48
48
|
createNativeNetworkClient,
|
|
49
49
|
} from "../runtime/native-network.js";
|
|
50
50
|
import { getProviderBaseUrl } from "../runtime/provider.js";
|
|
51
|
+
import { createOcrClientFromEnv } from "../runtime/ocr.js";
|
|
51
52
|
import {
|
|
52
53
|
PROXY_AUTH_IP_DENIED_CODE,
|
|
53
54
|
PROXY_EDGE_AUTH_REJECTED_CODE,
|
|
54
55
|
PROXY_POOL_EXHAUSTED_CODE,
|
|
55
56
|
} from "../runtime/proxy-errors.js";
|
|
56
57
|
import { PROVIDER_TELEMETRY_HEADER, ProxyTelemetryCollector } from "../runtime/proxy-telemetry.js";
|
|
58
|
+
import { bindResolverSignal, createResolverClientFromEnv } from "../runtime/resolver.js";
|
|
57
59
|
import {
|
|
58
60
|
assertRequiredSecretsPresent,
|
|
59
61
|
listMissingRequiredSecrets,
|
|
@@ -92,12 +94,14 @@ import type {
|
|
|
92
94
|
OperationErrorCode,
|
|
93
95
|
OperationHttpStreamTransport,
|
|
94
96
|
OperationSseTransport,
|
|
97
|
+
OcrContext,
|
|
95
98
|
ProviderErrorStatus,
|
|
96
99
|
ProviderContext,
|
|
97
100
|
ProviderDefinition,
|
|
98
101
|
ProviderProxyPolicy,
|
|
99
102
|
ProviderRuntimeState,
|
|
100
103
|
ProviderStreamEvent,
|
|
104
|
+
ResolverContext,
|
|
101
105
|
StealthClient,
|
|
102
106
|
SttContext,
|
|
103
107
|
} from "../types.js";
|
|
@@ -298,6 +302,18 @@ export function resolveProviderProxyAffinityKey(
|
|
|
298
302
|
return connectionKey ?? provider.id;
|
|
299
303
|
}
|
|
300
304
|
|
|
305
|
+
export function resolveProviderResolverIdentityScope(
|
|
306
|
+
provider: ProviderDefinition,
|
|
307
|
+
affinityKey: string,
|
|
308
|
+
contextId: string,
|
|
309
|
+
): string {
|
|
310
|
+
return JSON.stringify({
|
|
311
|
+
proxy: provider.proxy ?? null,
|
|
312
|
+
affinityKey,
|
|
313
|
+
contextId,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
301
317
|
function resolveOperationConnectionId(request: OperationRequest): string | undefined {
|
|
302
318
|
return request.connection?.id ?? request.connectionId;
|
|
303
319
|
}
|
|
@@ -316,6 +332,7 @@ function createProviderContext(
|
|
|
316
332
|
options: ProviderServerOptions = {},
|
|
317
333
|
state: ProviderRuntimeState = createUnsupportedProviderRuntimeState(),
|
|
318
334
|
proxyTelemetry?: ProxyTelemetryCollector,
|
|
335
|
+
signal?: AbortSignal,
|
|
319
336
|
): ProviderContext {
|
|
320
337
|
const baseUrl = getProviderBaseUrl(provider);
|
|
321
338
|
const stealthBaseUrl = getProviderStealthBaseUrl(provider);
|
|
@@ -325,6 +342,11 @@ function createProviderContext(
|
|
|
325
342
|
affinityKey: resolveProviderProxyAffinityKey(provider, request, operationId),
|
|
326
343
|
telemetry: proxyTelemetry,
|
|
327
344
|
};
|
|
345
|
+
const resolverIdentityScope = resolveProviderResolverIdentityScope(
|
|
346
|
+
provider,
|
|
347
|
+
proxyClientOptions.affinityKey,
|
|
348
|
+
request.requestId,
|
|
349
|
+
);
|
|
328
350
|
let wrappedContext: ProviderContext | undefined;
|
|
329
351
|
const stealthClientOptions = {
|
|
330
352
|
upstream: proxyClientOptions.upstream,
|
|
@@ -346,6 +368,8 @@ function createProviderContext(
|
|
|
346
368
|
connectionId: resolveOperationConnectionId(request),
|
|
347
369
|
headers: request.headers ?? {},
|
|
348
370
|
};
|
|
371
|
+
const requestState = state.forConnection(requestContext.connectionId);
|
|
372
|
+
const cache = createProviderCache({ providerId: provider.id });
|
|
349
373
|
const context = wrapWithInstrumentation({
|
|
350
374
|
env,
|
|
351
375
|
credential,
|
|
@@ -357,8 +381,8 @@ function createProviderContext(
|
|
|
357
381
|
retryResponseMeta.set(wrappedContext, summary);
|
|
358
382
|
},
|
|
359
383
|
}),
|
|
360
|
-
cache
|
|
361
|
-
state,
|
|
384
|
+
cache,
|
|
385
|
+
state: requestState,
|
|
362
386
|
stealth: stealthBaseUrl
|
|
363
387
|
? stealthProfile
|
|
364
388
|
? createStealthClient(stealthBaseUrl, stealthProfile.name, stealthClientOptions)
|
|
@@ -389,13 +413,23 @@ function createProviderContext(
|
|
|
389
413
|
: {}),
|
|
390
414
|
trace: createTraceContext(),
|
|
391
415
|
auth: createAuthStub(),
|
|
416
|
+
ocr: options.ocr ?? createOcrClientFromEnv(provider.ocr),
|
|
392
417
|
stt: options.stt ?? createSttClientFromEnv(provider.stt),
|
|
418
|
+
resolver: bindResolverSignal(
|
|
419
|
+
options.resolver ??
|
|
420
|
+
createResolverClientFromEnv(provider.resolver, undefined, {
|
|
421
|
+
allowedHosts: provider.allowedHosts,
|
|
422
|
+
cache,
|
|
423
|
+
identityScope: resolverIdentityScope,
|
|
424
|
+
}),
|
|
425
|
+
signal,
|
|
426
|
+
),
|
|
393
427
|
choice: createProviderChoiceContext({
|
|
394
428
|
providerId: provider.id,
|
|
395
429
|
env,
|
|
396
430
|
request: requestContext,
|
|
397
431
|
credential,
|
|
398
|
-
state,
|
|
432
|
+
state: requestState,
|
|
399
433
|
}),
|
|
400
434
|
});
|
|
401
435
|
wrappedContext = context;
|
|
@@ -464,6 +498,11 @@ function createAuthFlowContext(
|
|
|
464
498
|
request.providerId ??
|
|
465
499
|
provider.id,
|
|
466
500
|
};
|
|
501
|
+
const resolverIdentityScope = resolveProviderResolverIdentityScope(
|
|
502
|
+
provider,
|
|
503
|
+
proxyClientOptions.affinityKey,
|
|
504
|
+
request.requestId,
|
|
505
|
+
);
|
|
467
506
|
const stealthClientOptions = {
|
|
468
507
|
upstream: proxyClientOptions.upstream,
|
|
469
508
|
affinityKey: proxyClientOptions.affinityKey,
|
|
@@ -476,6 +515,7 @@ function createAuthFlowContext(
|
|
|
476
515
|
values: request.connection.secrets,
|
|
477
516
|
})
|
|
478
517
|
: undefined;
|
|
518
|
+
const cache = createProviderCache({ providerId: provider.id });
|
|
479
519
|
|
|
480
520
|
return {
|
|
481
521
|
context: {
|
|
@@ -512,7 +552,17 @@ function createAuthFlowContext(
|
|
|
512
552
|
]),
|
|
513
553
|
credential,
|
|
514
554
|
context: flowContextStore.context,
|
|
555
|
+
ocr: options.ocr ?? createOcrClientFromEnv(provider.ocr),
|
|
515
556
|
stt: options.stt ?? createSttClientFromEnv(provider.stt),
|
|
557
|
+
resolver: bindResolverSignal(
|
|
558
|
+
options.resolver ??
|
|
559
|
+
createResolverClientFromEnv(provider.resolver, undefined, {
|
|
560
|
+
allowedHosts: provider.allowedHosts,
|
|
561
|
+
cache,
|
|
562
|
+
identityScope: resolverIdentityScope,
|
|
563
|
+
}),
|
|
564
|
+
signal,
|
|
565
|
+
),
|
|
516
566
|
auth: createAuthFlowHelpers({ signal }),
|
|
517
567
|
},
|
|
518
568
|
getPatch: flowContextStore.getPatch,
|
|
@@ -596,6 +646,10 @@ export type ProviderServerOptions = {
|
|
|
596
646
|
};
|
|
597
647
|
/** Optional STT override for tests or custom hosts; local/prod normally resolves from env. */
|
|
598
648
|
stt?: SttContext;
|
|
649
|
+
/** Optional OCR override for tests or custom hosts; local/prod normally resolves from env. */
|
|
650
|
+
ocr?: OcrContext;
|
|
651
|
+
/** Optional resolver override for tests or custom hosts; local/prod normally resolves from env. */
|
|
652
|
+
resolver?: ResolverContext;
|
|
599
653
|
/** Optional runtime state override for tests or custom hosts. Production resolves Redis from env and fails closed when unavailable. */
|
|
600
654
|
state?: ProviderRuntimeState;
|
|
601
655
|
/** Allow process-local runtime state only for local development and tests. */
|
|
@@ -1511,8 +1565,17 @@ async function handleOperation(
|
|
|
1511
1565
|
options: ProviderServerOptions = {},
|
|
1512
1566
|
state: ProviderRuntimeState = createUnsupportedProviderRuntimeState(),
|
|
1513
1567
|
proxyTelemetry?: ProxyTelemetryCollector,
|
|
1568
|
+
signal?: AbortSignal,
|
|
1514
1569
|
): Promise<Response | OperationResponse> {
|
|
1515
|
-
const ctx = createProviderContext(
|
|
1570
|
+
const ctx = createProviderContext(
|
|
1571
|
+
provider,
|
|
1572
|
+
request,
|
|
1573
|
+
operationId,
|
|
1574
|
+
options,
|
|
1575
|
+
state,
|
|
1576
|
+
proxyTelemetry,
|
|
1577
|
+
signal,
|
|
1578
|
+
);
|
|
1516
1579
|
const operation = provider.operations[operationId];
|
|
1517
1580
|
const streaming = operation?.transport?.kind && operation.transport.kind !== "json";
|
|
1518
1581
|
let cleanupCalled = false;
|
|
@@ -1551,6 +1614,7 @@ async function handleOperation(
|
|
|
1551
1614
|
operationId,
|
|
1552
1615
|
ctx,
|
|
1553
1616
|
request,
|
|
1617
|
+
signal,
|
|
1554
1618
|
})
|
|
1555
1619
|
: await executeOperation(provider, operationId, ctx, request.input);
|
|
1556
1620
|
if (streaming && operation) {
|
|
@@ -1937,7 +2001,15 @@ export function createServerApp(
|
|
|
1937
2001
|
}
|
|
1938
2002
|
const request = operationRequestFromForwardingEnvelope(envelope);
|
|
1939
2003
|
operationId = envelope.operationId;
|
|
1940
|
-
const ctx = createProviderContext(
|
|
2004
|
+
const ctx = createProviderContext(
|
|
2005
|
+
provider,
|
|
2006
|
+
request,
|
|
2007
|
+
operationId,
|
|
2008
|
+
options,
|
|
2009
|
+
state,
|
|
2010
|
+
undefined,
|
|
2011
|
+
signal,
|
|
2012
|
+
);
|
|
1941
2013
|
if (deadlineAtMs !== undefined && deadlineAtMs <= Date.now()) {
|
|
1942
2014
|
throw new StatefulRoutingDeadlineError(envelope.requestId, envelope.deadlineAt as string);
|
|
1943
2015
|
}
|
|
@@ -2005,6 +2077,7 @@ export function createServerApp(
|
|
|
2005
2077
|
options,
|
|
2006
2078
|
state,
|
|
2007
2079
|
proxyTelemetry,
|
|
2080
|
+
c.req.raw.signal,
|
|
2008
2081
|
);
|
|
2009
2082
|
if (response instanceof Response) {
|
|
2010
2083
|
logProviderSuccess(
|
|
@@ -2381,7 +2454,9 @@ export async function serve(
|
|
|
2381
2454
|
|
|
2382
2455
|
const app = createServerApp(provider, {
|
|
2383
2456
|
logger: options.logger,
|
|
2457
|
+
ocr: options.ocr,
|
|
2384
2458
|
stt: options.stt,
|
|
2459
|
+
resolver: options.resolver,
|
|
2385
2460
|
state: options.state,
|
|
2386
2461
|
allowMemoryStateFallback: options.allowMemoryStateFallback,
|
|
2387
2462
|
operationExecutor: options.operationExecutor,
|
package/src/testing/run.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { describe, expect, it } from "bun:test";
|
|
|
3
3
|
import { createProviderCache } from "../runtime/cache.js";
|
|
4
4
|
import { createTestProviderChoiceContext } from "../runtime/choice.js";
|
|
5
5
|
import { createMemoryProviderRuntimeState } from "../runtime/state.js";
|
|
6
|
+
import { createUnsupportedOcrClient } from "../runtime/ocr.js";
|
|
6
7
|
import { createUnsupportedSttClient } from "../runtime/stt.js";
|
|
7
8
|
import {
|
|
8
9
|
createNativeEgressAuthorization,
|
|
@@ -395,6 +396,8 @@ function createUpstreamContext(
|
|
|
395
396
|
},
|
|
396
397
|
}),
|
|
397
398
|
close: async () => {},
|
|
399
|
+
cookies: async () =>
|
|
400
|
+
(await browserAction("cookies")).data as Awaited<ReturnType<BrowserPage["cookies"]>>,
|
|
398
401
|
fill: async (selector, textValue) => {
|
|
399
402
|
await browserAction("fill", { selector, text: textValue });
|
|
400
403
|
},
|
|
@@ -559,9 +562,15 @@ function createUpstreamContext(
|
|
|
559
562
|
: {}),
|
|
560
563
|
trace: { span: async (_name, fn) => fn() },
|
|
561
564
|
auth: { requestField: async (name) => unsupported(`ctx.auth.requestField(${name})`) },
|
|
565
|
+
ocr: createUnsupportedOcrClient(
|
|
566
|
+
"Standard test upstream context does not support ctx.ocr.recognize",
|
|
567
|
+
),
|
|
562
568
|
stt: createUnsupportedSttClient(
|
|
563
569
|
"Standard test upstream context does not support ctx.stt.transcribe",
|
|
564
570
|
),
|
|
571
|
+
resolver: {
|
|
572
|
+
solve: async () => unsupported("ctx.resolver.solve"),
|
|
573
|
+
},
|
|
565
574
|
choice: createTestProviderChoiceContext({
|
|
566
575
|
providerId: `standard-test-${operationName}`,
|
|
567
576
|
request,
|
|
@@ -684,9 +693,15 @@ export function createSnapshotContext(rawFixture: unknown): ProviderContext {
|
|
|
684
693
|
auth: {
|
|
685
694
|
requestField: async (name) => unsupported(`ctx.auth.requestField(${name})`),
|
|
686
695
|
},
|
|
696
|
+
ocr: createUnsupportedOcrClient(
|
|
697
|
+
"Standard test snapshot context does not support ctx.ocr.recognize",
|
|
698
|
+
),
|
|
687
699
|
stt: createUnsupportedSttClient(
|
|
688
700
|
"Standard test snapshot context does not support ctx.stt.transcribe",
|
|
689
701
|
),
|
|
702
|
+
resolver: {
|
|
703
|
+
solve: async () => unsupported("ctx.resolver.solve"),
|
|
704
|
+
},
|
|
690
705
|
choice: createTestProviderChoiceContext({
|
|
691
706
|
providerId: "standard-test",
|
|
692
707
|
request,
|
package/src/types.ts
CHANGED
|
@@ -243,6 +243,61 @@ export interface SmsOtpMatcherDefinition {
|
|
|
243
243
|
extractOtp(body: string): string | null;
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
+
export interface ProviderOcrConfig {
|
|
247
|
+
readonly mode: "required" | "optional";
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export type OcrImageInput =
|
|
251
|
+
| { readonly kind: "base64"; readonly data: string; readonly mediaType?: string }
|
|
252
|
+
| { readonly kind: "url"; readonly url: string };
|
|
253
|
+
|
|
254
|
+
export interface OcrRecognizeRequest {
|
|
255
|
+
readonly image: OcrImageInput;
|
|
256
|
+
readonly hint?: "captcha" | "document" | "generic";
|
|
257
|
+
readonly prompt?: string;
|
|
258
|
+
readonly maxTokens?: number;
|
|
259
|
+
readonly timeoutMs?: number;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export interface OcrWarning {
|
|
263
|
+
readonly code: string;
|
|
264
|
+
readonly message: string;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export interface OcrResult {
|
|
268
|
+
readonly text: string;
|
|
269
|
+
readonly model: string;
|
|
270
|
+
readonly warnings?: readonly OcrWarning[];
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export interface OcrCaptchaOptions {
|
|
274
|
+
readonly length?: number;
|
|
275
|
+
/** Allowed characters. A RegExp is applied to each character, not to the whole text. */
|
|
276
|
+
readonly charset?: string | RegExp;
|
|
277
|
+
readonly caseSensitive?: boolean;
|
|
278
|
+
readonly maxCandidates?: number;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export interface OcrCaptchaCandidate {
|
|
282
|
+
readonly text: string;
|
|
283
|
+
readonly satisfiesConstraints: boolean;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export interface OcrCaptchaResult {
|
|
287
|
+
readonly text: string;
|
|
288
|
+
readonly candidates: readonly OcrCaptchaCandidate[];
|
|
289
|
+
readonly satisfiesConstraints: boolean;
|
|
290
|
+
readonly model: string;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export interface OcrContext {
|
|
294
|
+
recognize(request: OcrRecognizeRequest): Promise<OcrResult>;
|
|
295
|
+
extractCaptchaText(
|
|
296
|
+
image: OcrImageInput,
|
|
297
|
+
options?: OcrCaptchaOptions,
|
|
298
|
+
): Promise<OcrCaptchaResult>;
|
|
299
|
+
}
|
|
300
|
+
|
|
246
301
|
export type SttTranscribeMode = "general" | "otp";
|
|
247
302
|
export type SttPromptPolicy = "none" | "default-hint" | "custom-hint";
|
|
248
303
|
export type SttUnsupportedOptionPolicy = "warn" | "error";
|
|
@@ -252,6 +307,94 @@ export interface ProviderSttConfig {
|
|
|
252
307
|
mode: ProviderSttMode;
|
|
253
308
|
}
|
|
254
309
|
|
|
310
|
+
/**
|
|
311
|
+
* `browser` is the in-house CDP pool (`apps/cdp-pool`, reached through
|
|
312
|
+
* `createBrowserClient`) and is a first-class vendor rather than an escape hatch:
|
|
313
|
+
* for fingerprint-family kinds, it was measured faster than a paid vendor
|
|
314
|
+
* (4.5 s vs 17.5 s) at zero marginal cost.
|
|
315
|
+
*
|
|
316
|
+
* `2captcha` is the vendor already carrying production traffic in
|
|
317
|
+
* `apifuse-provider-tabelog`.
|
|
318
|
+
*
|
|
319
|
+
* Union order is documentation only; the effective fallback order is whatever
|
|
320
|
+
* `ProviderResolverConfig.vendors` declares.
|
|
321
|
+
*/
|
|
322
|
+
export type ProviderResolverVendor =
|
|
323
|
+
| "browser"
|
|
324
|
+
| "capsolver"
|
|
325
|
+
| "capmonster"
|
|
326
|
+
| "2captcha"
|
|
327
|
+
| "custom";
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Token-family kinds resolve to `{ form: "token" }`. Cookie-family kinds resolve
|
|
331
|
+
* to `{ form: "cookies" }`; network-identity binding is defined per kind. `aws_waf`
|
|
332
|
+
* was measured portable across residential leases on buyee, while `cf_clearance`
|
|
333
|
+
* remains unmeasured here and is treated as identity-scoped because it is widely
|
|
334
|
+
* described as IP-bound.
|
|
335
|
+
*/
|
|
336
|
+
export type ProviderChallenge =
|
|
337
|
+
| {
|
|
338
|
+
readonly kind: "turnstile";
|
|
339
|
+
readonly siteKey: string;
|
|
340
|
+
readonly pageUrl: string;
|
|
341
|
+
readonly action?: string;
|
|
342
|
+
readonly cdata?: string;
|
|
343
|
+
}
|
|
344
|
+
| {
|
|
345
|
+
readonly kind: "recaptcha_v2";
|
|
346
|
+
readonly siteKey: string;
|
|
347
|
+
readonly pageUrl: string;
|
|
348
|
+
}
|
|
349
|
+
| {
|
|
350
|
+
readonly kind: "recaptcha_v3";
|
|
351
|
+
readonly siteKey: string;
|
|
352
|
+
readonly pageUrl: string;
|
|
353
|
+
readonly action: string;
|
|
354
|
+
readonly minScore?: number;
|
|
355
|
+
}
|
|
356
|
+
| {
|
|
357
|
+
readonly kind: "hcaptcha";
|
|
358
|
+
readonly siteKey: string;
|
|
359
|
+
readonly pageUrl: string;
|
|
360
|
+
}
|
|
361
|
+
| {
|
|
362
|
+
readonly kind: "cloudflare_interstitial";
|
|
363
|
+
readonly pageUrl: string;
|
|
364
|
+
readonly blockedHtml?: string;
|
|
365
|
+
}
|
|
366
|
+
| {
|
|
367
|
+
readonly kind: "aws_waf";
|
|
368
|
+
readonly pageUrl: string;
|
|
369
|
+
readonly captchaScript?: string;
|
|
370
|
+
readonly context?: string;
|
|
371
|
+
readonly iv?: string;
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
export type ProviderChallengeKind = ProviderChallenge["kind"];
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Token solutions carry no network-identity binding. Cookie-solution binding is
|
|
378
|
+
* per challenge kind: `aws_waf` was measured portable across residential leases
|
|
379
|
+
* on buyee, while `cf_clearance` is unmeasured here and treated as scoped to the
|
|
380
|
+
* identity that produced it. The provider attaches the returned cookies to its
|
|
381
|
+
* own requests.
|
|
382
|
+
*/
|
|
383
|
+
export type ChallengeSolution =
|
|
384
|
+
| { readonly form: "token"; readonly token: string }
|
|
385
|
+
| {
|
|
386
|
+
readonly form: "cookies";
|
|
387
|
+
readonly cookies: Readonly<Record<string, string>>;
|
|
388
|
+
readonly userAgent: string;
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
export interface ProviderResolverConfig {
|
|
392
|
+
/** Ordered vendor fallback chain, tried first to last. */
|
|
393
|
+
readonly vendors: readonly ProviderResolverVendor[];
|
|
394
|
+
/** Challenge kinds this provider is permitted to request. */
|
|
395
|
+
readonly kinds: readonly ProviderChallengeKind[];
|
|
396
|
+
}
|
|
397
|
+
|
|
255
398
|
export type SttAudioInput = {
|
|
256
399
|
kind: "base64";
|
|
257
400
|
data: string;
|
|
@@ -330,6 +473,10 @@ export interface SttContext {
|
|
|
330
473
|
): VerificationCodeExtractionResult;
|
|
331
474
|
}
|
|
332
475
|
|
|
476
|
+
export interface ResolverContext {
|
|
477
|
+
solve(challenge: ProviderChallenge, signal?: AbortSignal): Promise<ChallengeSolution>;
|
|
478
|
+
}
|
|
479
|
+
|
|
333
480
|
export interface HealthJourneySchedule {
|
|
334
481
|
kind: "interval";
|
|
335
482
|
/** ISO 8601 duration, for example PT8H. */
|
|
@@ -794,10 +941,12 @@ export type ProviderProxyMode = "disabled" | "optional" | "required";
|
|
|
794
941
|
* - `decodo` — **decodo.com**, the *gateway* proxy that was named "Smartproxy"
|
|
795
942
|
* (smartproxy.com) before its 2025 rebrand to Decodo. Sticky sessions via
|
|
796
943
|
* username params. A different company from `smartproxy` above.
|
|
797
|
-
* **@deprecated** — unused; no managed adapter.
|
|
798
|
-
*
|
|
799
|
-
*
|
|
800
|
-
*
|
|
944
|
+
* **@deprecated** — unused; no managed adapter. Declare a
|
|
945
|
+
* `ProviderProxyPolicy` using `smartproxy` or `nodemaven` instead; the
|
|
946
|
+
* `smartproxy` allocator requires `APIFUSE__PROXY__SMARTPROXY_APP_KEY`.
|
|
947
|
+
* - `custom` — **@deprecated** static proxy marker with no managed adapter.
|
|
948
|
+
* Use `ProviderProxyPolicy` with `smartproxy`/`nodemaven`; the `smartproxy`
|
|
949
|
+
* allocator requires `APIFUSE__PROXY__SMARTPROXY_APP_KEY`.
|
|
801
950
|
*/
|
|
802
951
|
export type ProviderProxyProvider = "smartproxy" | "nodemaven" | "decodo" | "custom";
|
|
803
952
|
|
|
@@ -1563,6 +1712,18 @@ export interface BrowserFrame {
|
|
|
1563
1712
|
locator(selector: string): BrowserLocator;
|
|
1564
1713
|
}
|
|
1565
1714
|
|
|
1715
|
+
export interface BrowserCookie {
|
|
1716
|
+
readonly name: string;
|
|
1717
|
+
readonly value: string;
|
|
1718
|
+
readonly domain: string;
|
|
1719
|
+
readonly path: string;
|
|
1720
|
+
/** Unix seconds. Absent for a session cookie. */
|
|
1721
|
+
readonly expires?: number;
|
|
1722
|
+
readonly httpOnly: boolean;
|
|
1723
|
+
readonly secure: boolean;
|
|
1724
|
+
readonly sameSite?: "Strict" | "Lax" | "None";
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1566
1727
|
export type BrowserResourceMethod = "GET" | "HEAD";
|
|
1567
1728
|
|
|
1568
1729
|
export type BrowserResourceRequest = {
|
|
@@ -1604,6 +1765,11 @@ export type BrowserResourcePolicy = {
|
|
|
1604
1765
|
|
|
1605
1766
|
export interface BrowserPage extends BrowserFrame {
|
|
1606
1767
|
close(): Promise<void>;
|
|
1768
|
+
/**
|
|
1769
|
+
* Reads the browser context's cookie jar, including httpOnly cookies.
|
|
1770
|
+
* Cookie expiry values are Unix seconds and are absent for session cookies.
|
|
1771
|
+
*/
|
|
1772
|
+
cookies(): Promise<readonly BrowserCookie[]>;
|
|
1607
1773
|
fill(selector: string, text: string): Promise<void>;
|
|
1608
1774
|
goto(url: string): Promise<void>;
|
|
1609
1775
|
pageId?: string;
|
|
@@ -1889,7 +2055,9 @@ export interface FlowContext {
|
|
|
1889
2055
|
env: EnvContext;
|
|
1890
2056
|
credential?: CredentialContext;
|
|
1891
2057
|
context: ContextScratchpad;
|
|
2058
|
+
ocr: OcrContext;
|
|
1892
2059
|
stt: SttContext;
|
|
2060
|
+
resolver: ResolverContext;
|
|
1893
2061
|
auth: AuthFlowTerminalContext;
|
|
1894
2062
|
}
|
|
1895
2063
|
|
|
@@ -1932,7 +2100,14 @@ export type ProviderStateDurationString =
|
|
|
1932
2100
|
| `${number}${"ms" | "s" | "m" | "h" | "d"}`
|
|
1933
2101
|
| `PT${string}`;
|
|
1934
2102
|
|
|
2103
|
+
export type StateNamespaceScope = "connection" | "provider";
|
|
2104
|
+
|
|
1935
2105
|
export interface StateNamespaceOptions {
|
|
2106
|
+
/**
|
|
2107
|
+
* State isolation boundary. Connection scope is the default; provider scope
|
|
2108
|
+
* must be selected explicitly for provider-wide coordination state.
|
|
2109
|
+
*/
|
|
2110
|
+
scope?: StateNamespaceScope;
|
|
1936
2111
|
/** Default TTL used when a write omits ttl. Required to avoid unbounded state. */
|
|
1937
2112
|
defaultTtl: ProviderStateDurationString;
|
|
1938
2113
|
/** Maximum allowed TTL; writes are rejected when they exceed this policy. */
|
|
@@ -1993,6 +2168,11 @@ export interface ProviderStateNamespace {
|
|
|
1993
2168
|
}
|
|
1994
2169
|
|
|
1995
2170
|
export interface ProviderRuntimeState {
|
|
2171
|
+
/**
|
|
2172
|
+
* Returns an immutable view bound to one request connection. An unresolved
|
|
2173
|
+
* connection uses an isolated reserved sentinel, never the provider-global scope.
|
|
2174
|
+
*/
|
|
2175
|
+
forConnection(connectionId: string | undefined): ProviderRuntimeState;
|
|
1996
2176
|
namespace(
|
|
1997
2177
|
name: string,
|
|
1998
2178
|
options: StateNamespaceOptions,
|
|
@@ -2014,7 +2194,9 @@ export interface ProviderContext {
|
|
|
2014
2194
|
browser: BrowserClient;
|
|
2015
2195
|
trace: TraceContext;
|
|
2016
2196
|
auth: AuthContext;
|
|
2197
|
+
ocr: OcrContext;
|
|
2017
2198
|
stt: SttContext;
|
|
2199
|
+
resolver: ResolverContext;
|
|
2018
2200
|
choice: ProviderChoiceContext;
|
|
2019
2201
|
}
|
|
2020
2202
|
|
|
@@ -2187,7 +2369,9 @@ export interface ProviderDefinition {
|
|
|
2187
2369
|
platform: StealthPlatform;
|
|
2188
2370
|
};
|
|
2189
2371
|
proxy?: ProviderProxyConfig;
|
|
2372
|
+
ocr?: ProviderOcrConfig;
|
|
2190
2373
|
stt?: ProviderSttConfig;
|
|
2374
|
+
resolver?: ProviderResolverConfig;
|
|
2191
2375
|
browser?: {
|
|
2192
2376
|
engine: BrowserEngine;
|
|
2193
2377
|
};
|