@apifuse/provider-sdk 2.2.0-beta.2 → 2.2.0-beta.4
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/AUTHORING.md +14 -0
- package/CHANGELOG.md +8 -0
- package/bin/apifuse-check.ts +18 -58
- package/bin/apifuse-create.ts +1 -1
- package/bin/apifuse-dev.ts +27 -52
- package/bin/apifuse-pack-smoke.ts +22 -81
- package/bin/apifuse-pack-types.ts +266 -0
- package/bin/apifuse-perf.ts +45 -127
- package/bin/apifuse-record.ts +23 -61
- package/bin/apifuse-submit-check.ts +73 -30
- package/bin/apifuse.ts +1 -1
- package/bin/submit-check-xml-semantics.ts +204 -0
- package/bin/submit-check-xml.ts +134 -0
- package/dist/auth-turn/index.d.ts +1 -1
- package/dist/auth.d.ts +2 -2
- package/dist/auth.js +9 -18
- package/dist/ceremonies/index.d.ts +1 -1
- package/dist/ceremonies/index.js +8 -18
- package/dist/config/loader.d.ts +2 -2
- package/dist/config/loader.js +19 -42
- package/dist/contract-serialization.d.ts +2 -2
- package/dist/contract-serialization.js +3 -6
- package/dist/contract-types.d.ts +2 -2
- package/dist/contract.d.ts +3 -3
- package/dist/contract.js +4 -6
- package/dist/define.d.ts +8 -1
- package/dist/define.js +57 -115
- package/dist/dev.d.ts +1 -1
- package/dist/dev.js +1 -1
- package/dist/errors.d.ts +4 -1
- package/dist/errors.js +48 -0
- package/dist/i18n/catalog.d.ts +2 -2
- package/dist/i18n/catalog.js +4 -10
- package/dist/i18n/index.d.ts +2 -2
- package/dist/i18n/index.js +2 -2
- package/dist/i18n/keys.d.ts +2 -2
- package/dist/index.d.ts +43 -42
- package/dist/index.js +38 -37
- package/dist/lint.js +8 -15
- package/dist/provider.d.ts +11 -11
- package/dist/provider.js +9 -9
- package/dist/public-schema-field-lint.d.ts +1 -1
- package/dist/recipes/gov-api.js +1 -1
- package/dist/runtime/auth-flow.d.ts +1 -1
- package/dist/runtime/auth-flow.js +3 -3
- package/dist/runtime/browser.d.ts +1 -1
- package/dist/runtime/browser.js +15 -29
- package/dist/runtime/cache.d.ts +1 -1
- package/dist/runtime/cache.js +4 -8
- package/dist/runtime/choice.d.ts +1 -1
- package/dist/runtime/choice.js +12 -34
- package/dist/runtime/credential.d.ts +1 -1
- package/dist/runtime/credential.js +1 -1
- package/dist/runtime/env.d.ts +1 -1
- package/dist/runtime/executor.d.ts +1 -1
- package/dist/runtime/executor.js +8 -3
- package/dist/runtime/http.d.ts +2 -2
- package/dist/runtime/http.js +5 -5
- package/dist/runtime/insights.d.ts +1 -1
- package/dist/runtime/insights.js +6 -13
- package/dist/runtime/instrumentation.d.ts +2 -2
- package/dist/runtime/instrumentation.js +5 -15
- package/dist/runtime/keyring.js +1 -1
- package/dist/runtime/namespace.js +1 -1
- package/dist/runtime/otlp.d.ts +1 -1
- package/dist/runtime/perf.d.ts +1 -1
- package/dist/runtime/provider.d.ts +1 -1
- package/dist/runtime/provider.js +1 -2
- package/dist/runtime/proxy-errors.d.ts +1 -1
- package/dist/runtime/proxy-errors.js +3 -5
- package/dist/runtime/proxy-retry-policy.d.ts +2 -2
- package/dist/runtime/proxy-retry-policy.js +2 -2
- package/dist/runtime/proxy-telemetry.d.ts +1 -1
- package/dist/runtime/proxy-telemetry.js +16 -48
- package/dist/runtime/redis.d.ts +1 -1
- package/dist/runtime/redis.js +2 -4
- package/dist/runtime/request-options.d.ts +1 -1
- package/dist/runtime/state.d.ts +2 -2
- package/dist/runtime/state.js +3 -3
- package/dist/runtime/stealth.d.ts +2 -2
- package/dist/runtime/stealth.js +6 -6
- package/dist/runtime/stt.d.ts +1 -1
- package/dist/runtime/stt.js +11 -15
- package/dist/runtime/trace.d.ts +2 -2
- package/dist/runtime/trace.js +2 -4
- package/dist/runtime/waterfall.d.ts +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +7 -15
- package/dist/serve.d.ts +1 -1
- package/dist/serve.js +1 -1
- package/dist/server/index.d.ts +7 -7
- package/dist/server/index.js +6 -6
- package/dist/server/self-test-redaction.d.ts +1 -1
- package/dist/server/self-test-redaction.js +1 -1
- package/dist/server/self-test.d.ts +3 -3
- package/dist/server/self-test.js +3 -3
- package/dist/server/serve.d.ts +3 -3
- package/dist/server/serve.js +49 -57
- package/dist/server/types.js +2 -7
- package/dist/stealth/profiles.d.ts +1 -1
- package/dist/stealth/profiles.js +5 -14
- package/dist/stream.d.ts +1 -1
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +2 -2
- package/dist/testing/run.d.ts +1 -1
- package/dist/testing/run.js +7 -14
- package/dist/types.d.ts +57 -0
- package/dist/user-input.d.ts +30 -0
- package/dist/user-input.js +66 -0
- package/package.json +7 -4
- package/src/auth-turn/index.ts +1 -1
- package/src/auth.ts +28 -86
- package/src/ceremonies/index.ts +24 -78
- package/src/config/loader.ts +58 -176
- package/src/contract-serialization.ts +5 -11
- package/src/contract-types.ts +2 -2
- package/src/contract.ts +12 -28
- package/src/define.ts +174 -495
- package/src/dev.ts +4 -9
- package/src/errors.ts +58 -5
- package/src/i18n/catalog.ts +10 -32
- package/src/i18n/index.ts +2 -2
- package/src/i18n/keys.ts +5 -11
- package/src/index.ts +44 -42
- package/src/lint.ts +89 -159
- package/src/provider.ts +15 -11
- package/src/public-schema-field-lint.ts +7 -33
- package/src/recipes/gov-api.ts +2 -5
- package/src/runtime/auth-flow.ts +5 -7
- package/src/runtime/browser.ts +64 -187
- package/src/runtime/cache.ts +20 -67
- package/src/runtime/choice.ts +55 -129
- package/src/runtime/credential.ts +2 -2
- package/src/runtime/env.ts +1 -1
- package/src/runtime/executor.ts +15 -20
- package/src/runtime/http.ts +7 -7
- package/src/runtime/insights.ts +15 -53
- package/src/runtime/instrumentation.ts +19 -58
- package/src/runtime/keyring.ts +7 -19
- package/src/runtime/namespace.ts +2 -7
- package/src/runtime/otlp.ts +12 -23
- package/src/runtime/perf.ts +1 -1
- package/src/runtime/provider.ts +4 -9
- package/src/runtime/proxy-errors.ts +17 -38
- package/src/runtime/proxy-retry-policy.ts +3 -3
- package/src/runtime/proxy-telemetry.ts +23 -72
- package/src/runtime/redis.ts +4 -12
- package/src/runtime/request-options.ts +4 -13
- package/src/runtime/state.ts +30 -109
- package/src/runtime/stealth.ts +8 -8
- package/src/runtime/stt.ts +38 -94
- package/src/runtime/trace.ts +14 -44
- package/src/runtime/waterfall.ts +5 -18
- package/src/schema.ts +23 -84
- package/src/serve.ts +1 -1
- package/src/server/index.ts +7 -7
- package/src/server/self-test-redaction.ts +2 -2
- package/src/server/self-test.ts +5 -5
- package/src/server/serve.ts +103 -252
- package/src/server/types.ts +6 -19
- package/src/stealth/profiles.ts +10 -26
- package/src/stream.ts +8 -19
- package/src/testing/index.ts +2 -2
- package/src/testing/run.ts +19 -67
- package/src/types.ts +58 -0
- package/src/user-input.ts +118 -0
package/src/runtime/browser.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import type { Frame, LaunchOptions, Locator, Page, Request, Route } from "playwright";
|
|
3
3
|
|
|
4
|
-
import { ProviderError } from "../errors";
|
|
4
|
+
import { ProviderError } from "../errors.js";
|
|
5
5
|
import type {
|
|
6
6
|
BrowserChallengeRequest,
|
|
7
7
|
BrowserChallengeResult,
|
|
@@ -16,7 +16,7 @@ import type {
|
|
|
16
16
|
BrowserResourceMethod,
|
|
17
17
|
BrowserResourcePolicy,
|
|
18
18
|
BrowserResourceRequest,
|
|
19
|
-
} from "../types";
|
|
19
|
+
} from "../types.js";
|
|
20
20
|
|
|
21
21
|
const require = createRequire(import.meta.url);
|
|
22
22
|
const DEFAULT_WAIT_TIMEOUT_MS = 30_000;
|
|
@@ -29,9 +29,7 @@ type PlaywrightExtraModule = {
|
|
|
29
29
|
chromium: PlaywrightModule["chromium"] & { use(plugin: unknown): unknown };
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
type StealthPluginFactory = (options?: {
|
|
33
|
-
enabledEvasions?: Set<string>;
|
|
34
|
-
}) => unknown;
|
|
32
|
+
type StealthPluginFactory = (options?: { enabledEvasions?: Set<string> }) => unknown;
|
|
35
33
|
|
|
36
34
|
type PoolAcquireResponse = {
|
|
37
35
|
browserContextId?: string;
|
|
@@ -81,9 +79,7 @@ type CdpFetchFulfillParams = {
|
|
|
81
79
|
|
|
82
80
|
type BrowserPageContract = BrowserPage;
|
|
83
81
|
|
|
84
|
-
function toResourceBody(
|
|
85
|
-
body: BrowserResourceBody | undefined,
|
|
86
|
-
): Buffer | string | undefined {
|
|
82
|
+
function toResourceBody(body: BrowserResourceBody | undefined): Buffer | string | undefined {
|
|
87
83
|
if (body === undefined || typeof body === "string" || Buffer.isBuffer(body)) {
|
|
88
84
|
return body;
|
|
89
85
|
}
|
|
@@ -99,9 +95,7 @@ function isResourceMethod(method: string): method is BrowserResourceMethod {
|
|
|
99
95
|
return method === "GET" || method === "HEAD";
|
|
100
96
|
}
|
|
101
97
|
|
|
102
|
-
async function toResourceRequest(
|
|
103
|
-
request: Request,
|
|
104
|
-
): Promise<BrowserResourceRequest | null> {
|
|
98
|
+
async function toResourceRequest(request: Request): Promise<BrowserResourceRequest | null> {
|
|
105
99
|
const method = request.method().toUpperCase();
|
|
106
100
|
if (!isResourceMethod(method)) {
|
|
107
101
|
return null;
|
|
@@ -139,8 +133,7 @@ function toCdpResourceRequest(
|
|
|
139
133
|
request: {
|
|
140
134
|
headers: toCdpResourceHeaders(rawRequest.headers),
|
|
141
135
|
method,
|
|
142
|
-
resourceType:
|
|
143
|
-
typeof params.resourceType === "string" ? params.resourceType : undefined,
|
|
136
|
+
resourceType: typeof params.resourceType === "string" ? params.resourceType : undefined,
|
|
144
137
|
url,
|
|
145
138
|
},
|
|
146
139
|
};
|
|
@@ -189,15 +182,14 @@ function toCdpFulfillParams(
|
|
|
189
182
|
): CdpFetchFulfillParams {
|
|
190
183
|
const body = toResourceBody(decision.body);
|
|
191
184
|
return {
|
|
192
|
-
...(body === undefined
|
|
193
|
-
? {}
|
|
194
|
-
: { body: Buffer.from(body).toString("base64") }),
|
|
185
|
+
...(body === undefined ? {} : { body: Buffer.from(body).toString("base64") }),
|
|
195
186
|
...(decision.headers === undefined
|
|
196
187
|
? {}
|
|
197
188
|
: {
|
|
198
|
-
responseHeaders: Object.entries(decision.headers).map(
|
|
199
|
-
|
|
200
|
-
|
|
189
|
+
responseHeaders: Object.entries(decision.headers).map(([name, value]) => ({
|
|
190
|
+
name,
|
|
191
|
+
value,
|
|
192
|
+
})),
|
|
201
193
|
}),
|
|
202
194
|
requestId,
|
|
203
195
|
responseCode: decision.status ?? 200,
|
|
@@ -228,18 +220,14 @@ type SupportedBrowserClient = {
|
|
|
228
220
|
close(): Promise<void>;
|
|
229
221
|
newPage(): Promise<BrowserPageContract>;
|
|
230
222
|
rawPage(): Promise<BrowserPageContract>;
|
|
231
|
-
withIsolatedContext<T>(
|
|
232
|
-
handler: (page: BrowserPageContract) => Promise<T>,
|
|
233
|
-
): Promise<T>;
|
|
223
|
+
withIsolatedContext<T>(handler: (page: BrowserPageContract) => Promise<T>): Promise<T>;
|
|
234
224
|
};
|
|
235
225
|
|
|
236
226
|
function getDefaultCdpPoolUrl(env = process.env): string | undefined {
|
|
237
227
|
return env.APIFUSE__CDP_POOL__URL;
|
|
238
228
|
}
|
|
239
229
|
|
|
240
|
-
async function importOptionalModule<T extends object>(
|
|
241
|
-
moduleName: string,
|
|
242
|
-
): Promise<T> {
|
|
230
|
+
async function importOptionalModule<T extends object>(moduleName: string): Promise<T> {
|
|
243
231
|
return (await import(moduleName)) as T;
|
|
244
232
|
}
|
|
245
233
|
|
|
@@ -369,9 +357,7 @@ async function loadPlaywright(): Promise<PlaywrightModule> {
|
|
|
369
357
|
}
|
|
370
358
|
|
|
371
359
|
try {
|
|
372
|
-
return unwrapModuleDefault(
|
|
373
|
-
await importOptionalModule<PlaywrightModule>("playwright"),
|
|
374
|
-
);
|
|
360
|
+
return unwrapModuleDefault(await importOptionalModule<PlaywrightModule>("playwright"));
|
|
375
361
|
} catch (error) {
|
|
376
362
|
if (isModuleNotFoundError(error)) {
|
|
377
363
|
throw new ProviderError("Playwright is not installed", {
|
|
@@ -419,19 +405,14 @@ async function loadPlaywrightExtra(): Promise<PlaywrightExtraModule> {
|
|
|
419
405
|
async function loadStealthPluginFactory(): Promise<StealthPluginFactory> {
|
|
420
406
|
try {
|
|
421
407
|
return unwrapModuleDefault(
|
|
422
|
-
await importOptionalModule<StealthPluginFactory>(
|
|
423
|
-
"puppeteer-extra-plugin-stealth",
|
|
424
|
-
),
|
|
408
|
+
await importOptionalModule<StealthPluginFactory>("puppeteer-extra-plugin-stealth"),
|
|
425
409
|
);
|
|
426
410
|
} catch (error) {
|
|
427
411
|
if (isModuleNotFoundError(error)) {
|
|
428
|
-
throw new ProviderError(
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
fix: "Run: bun add playwright-extra puppeteer-extra-plugin-stealth",
|
|
433
|
-
},
|
|
434
|
-
);
|
|
412
|
+
throw new ProviderError("puppeteer-extra-plugin-stealth is not installed", {
|
|
413
|
+
cause: error instanceof Error ? error : undefined,
|
|
414
|
+
fix: "Run: bun add playwright-extra puppeteer-extra-plugin-stealth",
|
|
415
|
+
});
|
|
435
416
|
}
|
|
436
417
|
|
|
437
418
|
throw error;
|
|
@@ -503,10 +484,7 @@ class PlaywrightBrowserPage implements BrowserPageContract {
|
|
|
503
484
|
return await this.page.evaluate(fn);
|
|
504
485
|
}
|
|
505
486
|
|
|
506
|
-
async waitForSelector(
|
|
507
|
-
selector: string,
|
|
508
|
-
options?: { timeout?: number },
|
|
509
|
-
): Promise<void> {
|
|
487
|
+
async waitForSelector(selector: string, options?: { timeout?: number }): Promise<void> {
|
|
510
488
|
await this.page.waitForSelector(selector, options);
|
|
511
489
|
}
|
|
512
490
|
|
|
@@ -551,13 +529,8 @@ class PlaywrightBrowserPage implements BrowserPageContract {
|
|
|
551
529
|
await this.page.close();
|
|
552
530
|
}
|
|
553
531
|
|
|
554
|
-
async withResourcePolicy<T>(
|
|
555
|
-
policy
|
|
556
|
-
run: () => Promise<T>,
|
|
557
|
-
): Promise<T> {
|
|
558
|
-
const allowedMethods = new Set(
|
|
559
|
-
policy.allowedMethods ?? DEFAULT_RESOURCE_METHODS,
|
|
560
|
-
);
|
|
532
|
+
async withResourcePolicy<T>(policy: BrowserResourcePolicy, run: () => Promise<T>): Promise<T> {
|
|
533
|
+
const allowedMethods = new Set(policy.allowedMethods ?? DEFAULT_RESOURCE_METHODS);
|
|
561
534
|
const handler = async (route: Route): Promise<void> => {
|
|
562
535
|
const request = await toResourceRequest(route.request());
|
|
563
536
|
if (!request || !allowedMethods.has(request.method)) {
|
|
@@ -623,9 +596,7 @@ class PlaywrightBrowserClient implements SupportedBrowserClient {
|
|
|
623
596
|
});
|
|
624
597
|
}
|
|
625
598
|
|
|
626
|
-
async withIsolatedContext<T>(
|
|
627
|
-
handler: (page: BrowserPageContract) => Promise<T>,
|
|
628
|
-
): Promise<T> {
|
|
599
|
+
async withIsolatedContext<T>(handler: (page: BrowserPageContract) => Promise<T>): Promise<T> {
|
|
629
600
|
const browser = await this.ensureBrowser();
|
|
630
601
|
const context = await browser.newContext();
|
|
631
602
|
const page = await context.newPage();
|
|
@@ -673,10 +644,7 @@ function normalizeWebSocketEndpoint(endpoint: string): string {
|
|
|
673
644
|
class JsonRpcWebSocketClient {
|
|
674
645
|
private nextId = 1;
|
|
675
646
|
private readonly endpoint: string;
|
|
676
|
-
private readonly listeners = new Map<
|
|
677
|
-
string,
|
|
678
|
-
Set<(params: unknown) => void>
|
|
679
|
-
>();
|
|
647
|
+
private readonly listeners = new Map<string, Set<(params: unknown) => void>>();
|
|
680
648
|
private readonly pending = new Map<
|
|
681
649
|
JsonRpcId,
|
|
682
650
|
{
|
|
@@ -770,9 +738,7 @@ class JsonRpcWebSocketClient {
|
|
|
770
738
|
this.pending.delete(payload.id);
|
|
771
739
|
|
|
772
740
|
if (payload.error) {
|
|
773
|
-
pending.reject(
|
|
774
|
-
new Error(payload.error.message ?? "JSON-RPC command failed"),
|
|
775
|
-
);
|
|
741
|
+
pending.reject(new Error(payload.error.message ?? "JSON-RPC command failed"));
|
|
776
742
|
return;
|
|
777
743
|
}
|
|
778
744
|
|
|
@@ -800,11 +766,7 @@ class JsonRpcWebSocketClient {
|
|
|
800
766
|
});
|
|
801
767
|
|
|
802
768
|
socket.addEventListener("error", () => {
|
|
803
|
-
reject(
|
|
804
|
-
new Error(
|
|
805
|
-
`Unable to connect to WebSocket endpoint: ${this.endpoint}`,
|
|
806
|
-
),
|
|
807
|
-
);
|
|
769
|
+
reject(new Error(`Unable to connect to WebSocket endpoint: ${this.endpoint}`));
|
|
808
770
|
});
|
|
809
771
|
});
|
|
810
772
|
|
|
@@ -843,19 +805,14 @@ function parsePoolAcquireResponse(value: unknown): PoolAcquireResponse {
|
|
|
843
805
|
});
|
|
844
806
|
}
|
|
845
807
|
|
|
846
|
-
if (
|
|
847
|
-
value.browserContextId !== undefined &&
|
|
848
|
-
typeof value.browserContextId !== "string"
|
|
849
|
-
) {
|
|
808
|
+
if (value.browserContextId !== undefined && typeof value.browserContextId !== "string") {
|
|
850
809
|
throw new ProviderError("CDP Pool returned an invalid acquire response", {
|
|
851
810
|
code: "BROWSER_RUNTIME_UNSUPPORTED",
|
|
852
811
|
});
|
|
853
812
|
}
|
|
854
813
|
|
|
855
814
|
return {
|
|
856
|
-
...(value.browserContextId
|
|
857
|
-
? { browserContextId: value.browserContextId }
|
|
858
|
-
: {}),
|
|
815
|
+
...(value.browserContextId ? { browserContextId: value.browserContextId } : {}),
|
|
859
816
|
pageId: value.pageId,
|
|
860
817
|
wsEndpoint: value.wsEndpoint,
|
|
861
818
|
};
|
|
@@ -881,10 +838,7 @@ function parseCdpFrameTreeNode(value: unknown): CdpFrameTreeNode | undefined {
|
|
|
881
838
|
frame: {
|
|
882
839
|
id: frameId,
|
|
883
840
|
name: typeof value.frame.name === "string" ? value.frame.name : undefined,
|
|
884
|
-
parentId:
|
|
885
|
-
typeof value.frame.parentId === "string"
|
|
886
|
-
? value.frame.parentId
|
|
887
|
-
: undefined,
|
|
841
|
+
parentId: typeof value.frame.parentId === "string" ? value.frame.parentId : undefined,
|
|
888
842
|
url: typeof value.frame.url === "string" ? value.frame.url : undefined,
|
|
889
843
|
},
|
|
890
844
|
...(childFrames ? { childFrames } : {}),
|
|
@@ -902,10 +856,7 @@ function getCdpExecutionContext(params: unknown): {
|
|
|
902
856
|
const contextId = params.context.id;
|
|
903
857
|
const auxData = params.context.auxData;
|
|
904
858
|
return {
|
|
905
|
-
frameId:
|
|
906
|
-
isRecord(auxData) && typeof auxData.frameId === "string"
|
|
907
|
-
? auxData.frameId
|
|
908
|
-
: undefined,
|
|
859
|
+
frameId: isRecord(auxData) && typeof auxData.frameId === "string" ? auxData.frameId : undefined,
|
|
909
860
|
id: typeof contextId === "number" ? contextId : undefined,
|
|
910
861
|
};
|
|
911
862
|
}
|
|
@@ -914,10 +865,7 @@ class CdpBrowserLocator implements BrowserLocator {
|
|
|
914
865
|
constructor(
|
|
915
866
|
private readonly frame: {
|
|
916
867
|
evaluate<T>(fn: string | (() => T)): Promise<T>;
|
|
917
|
-
waitForSelector?(
|
|
918
|
-
selector: string,
|
|
919
|
-
options?: { timeout?: number },
|
|
920
|
-
): Promise<void>;
|
|
868
|
+
waitForSelector?(selector: string, options?: { timeout?: number }): Promise<void>;
|
|
921
869
|
},
|
|
922
870
|
private readonly selector: string,
|
|
923
871
|
) {}
|
|
@@ -989,9 +937,7 @@ class CdpBrowserFrame implements BrowserFrame {
|
|
|
989
937
|
) {}
|
|
990
938
|
|
|
991
939
|
async url(): Promise<string> {
|
|
992
|
-
const evaluatedUrl = await this.evaluate<string | undefined>(
|
|
993
|
-
"window.location.href",
|
|
994
|
-
);
|
|
940
|
+
const evaluatedUrl = await this.evaluate<string | undefined>("window.location.href");
|
|
995
941
|
return evaluatedUrl || this.initialUrl;
|
|
996
942
|
}
|
|
997
943
|
|
|
@@ -1011,10 +957,7 @@ class CdpBrowserFrame implements BrowserFrame {
|
|
|
1011
957
|
return new CdpBrowserLocator(this, selector);
|
|
1012
958
|
}
|
|
1013
959
|
|
|
1014
|
-
async waitForSelector(
|
|
1015
|
-
selector: string,
|
|
1016
|
-
options?: { timeout?: number },
|
|
1017
|
-
): Promise<void> {
|
|
960
|
+
async waitForSelector(selector: string, options?: { timeout?: number }): Promise<void> {
|
|
1018
961
|
await this.page.waitForSelectorInFrame(this.id, selector, options);
|
|
1019
962
|
}
|
|
1020
963
|
|
|
@@ -1049,10 +992,7 @@ class CdpPoolBrowserPage implements BrowserPageContract {
|
|
|
1049
992
|
|
|
1050
993
|
try {
|
|
1051
994
|
await this.pageClient.send("Page.navigate", { url });
|
|
1052
|
-
await this.waitForDocumentReady(
|
|
1053
|
-
startedAt + DEFAULT_WAIT_TIMEOUT_MS,
|
|
1054
|
-
() => loadEventSeen,
|
|
1055
|
-
);
|
|
995
|
+
await this.waitForDocumentReady(startedAt + DEFAULT_WAIT_TIMEOUT_MS, () => loadEventSeen);
|
|
1056
996
|
} finally {
|
|
1057
997
|
unsubscribe();
|
|
1058
998
|
}
|
|
@@ -1063,10 +1003,7 @@ class CdpPoolBrowserPage implements BrowserPageContract {
|
|
|
1063
1003
|
return await this.evaluateWithContext<T>(fn);
|
|
1064
1004
|
}
|
|
1065
1005
|
|
|
1066
|
-
async evaluateInFrame<T>(
|
|
1067
|
-
frameId: string,
|
|
1068
|
-
fn: string | (() => T),
|
|
1069
|
-
): Promise<T> {
|
|
1006
|
+
async evaluateInFrame<T>(frameId: string, fn: string | (() => T)): Promise<T> {
|
|
1070
1007
|
await this.initialize();
|
|
1071
1008
|
const contextId = await this.getFrameExecutionContextId(frameId);
|
|
1072
1009
|
return await this.evaluateWithContext<T>(fn, contextId);
|
|
@@ -1096,10 +1033,7 @@ class CdpPoolBrowserPage implements BrowserPageContract {
|
|
|
1096
1033
|
throw new Error(`Timed out waiting for selector: ${selector}`);
|
|
1097
1034
|
}
|
|
1098
1035
|
|
|
1099
|
-
private async evaluateWithContext<T>(
|
|
1100
|
-
fn: string | (() => T),
|
|
1101
|
-
contextId?: number,
|
|
1102
|
-
): Promise<T> {
|
|
1036
|
+
private async evaluateWithContext<T>(fn: string | (() => T), contextId?: number): Promise<T> {
|
|
1103
1037
|
const result = await this.pageClient.send("Runtime.evaluate", {
|
|
1104
1038
|
awaitPromise: true,
|
|
1105
1039
|
...(contextId === undefined ? {} : { contextId }),
|
|
@@ -1109,20 +1043,14 @@ class CdpPoolBrowserPage implements BrowserPageContract {
|
|
|
1109
1043
|
|
|
1110
1044
|
if (result.exceptionDetails) {
|
|
1111
1045
|
throw new Error(
|
|
1112
|
-
String(
|
|
1113
|
-
(result.exceptionDetails as { text?: string }).text ??
|
|
1114
|
-
"Browser evaluation failed",
|
|
1115
|
-
),
|
|
1046
|
+
String((result.exceptionDetails as { text?: string }).text ?? "Browser evaluation failed"),
|
|
1116
1047
|
);
|
|
1117
1048
|
}
|
|
1118
1049
|
|
|
1119
1050
|
return (result.result as { value?: T } | undefined)?.value as T;
|
|
1120
1051
|
}
|
|
1121
1052
|
|
|
1122
|
-
async waitForSelector(
|
|
1123
|
-
selector: string,
|
|
1124
|
-
options?: { timeout?: number },
|
|
1125
|
-
): Promise<void> {
|
|
1053
|
+
async waitForSelector(selector: string, options?: { timeout?: number }): Promise<void> {
|
|
1126
1054
|
const timeout = options?.timeout ?? DEFAULT_WAIT_TIMEOUT_MS;
|
|
1127
1055
|
const deadline = Date.now() + timeout;
|
|
1128
1056
|
|
|
@@ -1188,14 +1116,7 @@ class CdpPoolBrowserPage implements BrowserPageContract {
|
|
|
1188
1116
|
const result = await this.pageClient.send("Page.getFrameTree");
|
|
1189
1117
|
const frames = flattenCdpFrameTree(parseCdpFrameTreeNode(result.frameTree));
|
|
1190
1118
|
return frames.map(
|
|
1191
|
-
(frame) =>
|
|
1192
|
-
new CdpBrowserFrame(
|
|
1193
|
-
frame.id,
|
|
1194
|
-
this,
|
|
1195
|
-
frame.url ?? "",
|
|
1196
|
-
frame.name,
|
|
1197
|
-
frame.parentId,
|
|
1198
|
-
),
|
|
1119
|
+
(frame) => new CdpBrowserFrame(frame.id, this, frame.url ?? "", frame.name, frame.parentId),
|
|
1199
1120
|
);
|
|
1200
1121
|
}
|
|
1201
1122
|
|
|
@@ -1209,8 +1130,7 @@ class CdpPoolBrowserPage implements BrowserPageContract {
|
|
|
1209
1130
|
|
|
1210
1131
|
async url(): Promise<string> {
|
|
1211
1132
|
const [mainFrame] = await this.frames();
|
|
1212
|
-
const frameUrl =
|
|
1213
|
-
mainFrame instanceof CdpBrowserFrame ? mainFrame.fallbackUrl() : "";
|
|
1133
|
+
const frameUrl = mainFrame instanceof CdpBrowserFrame ? mainFrame.fallbackUrl() : "";
|
|
1214
1134
|
return frameUrl || (await this.evaluate<string>("window.location.href"));
|
|
1215
1135
|
}
|
|
1216
1136
|
|
|
@@ -1238,9 +1158,7 @@ class CdpPoolBrowserPage implements BrowserPageContract {
|
|
|
1238
1158
|
|
|
1239
1159
|
try {
|
|
1240
1160
|
await this.release({
|
|
1241
|
-
...(this.browserContextId
|
|
1242
|
-
? { browserContextId: this.browserContextId }
|
|
1243
|
-
: {}),
|
|
1161
|
+
...(this.browserContextId ? { browserContextId: this.browserContextId } : {}),
|
|
1244
1162
|
pageId: this.pageId,
|
|
1245
1163
|
});
|
|
1246
1164
|
} finally {
|
|
@@ -1248,25 +1166,13 @@ class CdpPoolBrowserPage implements BrowserPageContract {
|
|
|
1248
1166
|
}
|
|
1249
1167
|
}
|
|
1250
1168
|
|
|
1251
|
-
async withResourcePolicy<T>(
|
|
1252
|
-
policy
|
|
1253
|
-
run: () => Promise<T>,
|
|
1254
|
-
): Promise<T> {
|
|
1255
|
-
const allowedMethods = new Set(
|
|
1256
|
-
policy.allowedMethods ?? DEFAULT_RESOURCE_METHODS,
|
|
1257
|
-
);
|
|
1169
|
+
async withResourcePolicy<T>(policy: BrowserResourcePolicy, run: () => Promise<T>): Promise<T> {
|
|
1170
|
+
const allowedMethods = new Set(policy.allowedMethods ?? DEFAULT_RESOURCE_METHODS);
|
|
1258
1171
|
const handlePausedRequest = (params: unknown): void => {
|
|
1259
|
-
void this.handleResourcePolicyPausedRequest(
|
|
1260
|
-
params,
|
|
1261
|
-
policy,
|
|
1262
|
-
allowedMethods,
|
|
1263
|
-
);
|
|
1172
|
+
void this.handleResourcePolicyPausedRequest(params, policy, allowedMethods);
|
|
1264
1173
|
};
|
|
1265
1174
|
|
|
1266
|
-
const unsubscribe = this.pageClient.on(
|
|
1267
|
-
"Fetch.requestPaused",
|
|
1268
|
-
handlePausedRequest,
|
|
1269
|
-
);
|
|
1175
|
+
const unsubscribe = this.pageClient.on("Fetch.requestPaused", handlePausedRequest);
|
|
1270
1176
|
|
|
1271
1177
|
try {
|
|
1272
1178
|
await this.pageClient.send("Fetch.enable", {
|
|
@@ -1376,9 +1282,7 @@ class CdpPoolBrowserPage implements BrowserPageContract {
|
|
|
1376
1282
|
});
|
|
1377
1283
|
const contextId = result.executionContextId;
|
|
1378
1284
|
if (typeof contextId !== "number") {
|
|
1379
|
-
throw new Error(
|
|
1380
|
-
`Unable to resolve execution context for frame: ${frameId}`,
|
|
1381
|
-
);
|
|
1285
|
+
throw new Error(`Unable to resolve execution context for frame: ${frameId}`);
|
|
1382
1286
|
}
|
|
1383
1287
|
|
|
1384
1288
|
this.frameExecutionContexts.set(frameId, contextId);
|
|
@@ -1424,17 +1328,11 @@ class CdpPoolBrowserClient implements SupportedBrowserClient {
|
|
|
1424
1328
|
return await this.acquirePage({ isolatedContext: true });
|
|
1425
1329
|
}
|
|
1426
1330
|
|
|
1427
|
-
private async acquirePage(options?: {
|
|
1428
|
-
isolatedContext?: boolean;
|
|
1429
|
-
}): Promise<BrowserPageContract> {
|
|
1331
|
+
private async acquirePage(options?: { isolatedContext?: boolean }): Promise<BrowserPageContract> {
|
|
1430
1332
|
const acquireResult = parsePoolAcquireResponse(
|
|
1431
1333
|
await this.poolClient.send("acquire", {
|
|
1432
|
-
...(this.allowedHosts.length > 0
|
|
1433
|
-
|
|
1434
|
-
: {}),
|
|
1435
|
-
...(options?.isolatedContext
|
|
1436
|
-
? { isolationMode: "browserContext" }
|
|
1437
|
-
: {}),
|
|
1334
|
+
...(this.allowedHosts.length > 0 ? { allowedHosts: this.allowedHosts } : {}),
|
|
1335
|
+
...(options?.isolatedContext ? { isolationMode: "browserContext" } : {}),
|
|
1438
1336
|
}),
|
|
1439
1337
|
);
|
|
1440
1338
|
const pageClient = new JsonRpcWebSocketClient(acquireResult.wsEndpoint);
|
|
@@ -1463,9 +1361,7 @@ class CdpPoolBrowserClient implements SupportedBrowserClient {
|
|
|
1463
1361
|
return await this.newPage();
|
|
1464
1362
|
}
|
|
1465
1363
|
|
|
1466
|
-
async withIsolatedContext<T>(
|
|
1467
|
-
handler: (page: BrowserPageContract) => Promise<T>,
|
|
1468
|
-
): Promise<T> {
|
|
1364
|
+
async withIsolatedContext<T>(handler: (page: BrowserPageContract) => Promise<T>): Promise<T> {
|
|
1469
1365
|
const page = await this.acquirePage({ isolatedContext: true });
|
|
1470
1366
|
|
|
1471
1367
|
try {
|
|
@@ -1481,9 +1377,7 @@ class CdpPoolBrowserClient implements SupportedBrowserClient {
|
|
|
1481
1377
|
}
|
|
1482
1378
|
|
|
1483
1379
|
class UnsupportedBrowserEngineClient implements SupportedBrowserClient {
|
|
1484
|
-
constructor(
|
|
1485
|
-
readonly engine: Extract<BrowserEngine, "nodriver" | "selenium-uc">,
|
|
1486
|
-
) {}
|
|
1380
|
+
constructor(readonly engine: Extract<BrowserEngine, "nodriver" | "selenium-uc">) {}
|
|
1487
1381
|
|
|
1488
1382
|
async newPage(): Promise<never> {
|
|
1489
1383
|
if (this.engine === "nodriver") {
|
|
@@ -1510,15 +1404,11 @@ class UnsupportedBrowserEngineClient implements SupportedBrowserClient {
|
|
|
1510
1404
|
async close(): Promise<void> {}
|
|
1511
1405
|
}
|
|
1512
1406
|
|
|
1513
|
-
function createPlaywrightStealthClient(
|
|
1514
|
-
options: BrowserClientOptions = {},
|
|
1515
|
-
): SupportedBrowserClient {
|
|
1407
|
+
function createPlaywrightStealthClient(options: BrowserClientOptions = {}): SupportedBrowserClient {
|
|
1516
1408
|
return new PlaywrightBrowserClient(options);
|
|
1517
1409
|
}
|
|
1518
1410
|
|
|
1519
|
-
function createCdpPoolBrowserClient(
|
|
1520
|
-
options: BrowserClientOptions,
|
|
1521
|
-
): SupportedBrowserClient {
|
|
1411
|
+
function createCdpPoolBrowserClient(options: BrowserClientOptions): SupportedBrowserClient {
|
|
1522
1412
|
return new CdpPoolBrowserClient(options);
|
|
1523
1413
|
}
|
|
1524
1414
|
|
|
@@ -1547,13 +1437,10 @@ export class BrowserClient implements BrowserClientContract {
|
|
|
1547
1437
|
this.cdpUrl = resolvedOptions.cdpUrl;
|
|
1548
1438
|
|
|
1549
1439
|
if (resolvedOptions.requireCdpPool && !resolvedOptions.cdpUrl) {
|
|
1550
|
-
throw new ProviderError(
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
fix: "Set APIFUSE__CDP_POOL__URL for deployed browser providers. Local standalone development may omit it.",
|
|
1555
|
-
},
|
|
1556
|
-
);
|
|
1440
|
+
throw new ProviderError("Managed CDP Pool is required for browser providers in production", {
|
|
1441
|
+
code: "BROWSER_CDP_POOL_REQUIRED",
|
|
1442
|
+
fix: "Set APIFUSE__CDP_POOL__URL for deployed browser providers. Local standalone development may omit it.",
|
|
1443
|
+
});
|
|
1557
1444
|
}
|
|
1558
1445
|
|
|
1559
1446
|
switch (engine) {
|
|
@@ -1591,9 +1478,7 @@ export class BrowserClient implements BrowserClientContract {
|
|
|
1591
1478
|
return this.activatePage(page);
|
|
1592
1479
|
}
|
|
1593
1480
|
|
|
1594
|
-
async withIsolatedContext<T>(
|
|
1595
|
-
handler: (page: BrowserPageContract) => Promise<T>,
|
|
1596
|
-
): Promise<T> {
|
|
1481
|
+
async withIsolatedContext<T>(handler: (page: BrowserPageContract) => Promise<T>): Promise<T> {
|
|
1597
1482
|
const previousActivePage = this.activePage;
|
|
1598
1483
|
let trackedPage: BrowserPageContract | undefined;
|
|
1599
1484
|
|
|
@@ -1638,16 +1523,11 @@ export class BrowserClient implements BrowserClientContract {
|
|
|
1638
1523
|
return trackedPage;
|
|
1639
1524
|
}
|
|
1640
1525
|
|
|
1641
|
-
async solveChallenge(
|
|
1642
|
-
request: BrowserChallengeRequest,
|
|
1643
|
-
): Promise<BrowserChallengeResult> {
|
|
1526
|
+
async solveChallenge(request: BrowserChallengeRequest): Promise<BrowserChallengeResult> {
|
|
1644
1527
|
if (request.type !== "recaptcha") {
|
|
1645
|
-
throw new ProviderError(
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
code: "BROWSER_RUNTIME_UNSUPPORTED",
|
|
1649
|
-
},
|
|
1650
|
-
);
|
|
1528
|
+
throw new ProviderError(`Unsupported browser challenge: ${request.type}`, {
|
|
1529
|
+
code: "BROWSER_RUNTIME_UNSUPPORTED",
|
|
1530
|
+
});
|
|
1651
1531
|
}
|
|
1652
1532
|
|
|
1653
1533
|
if (this.activePage) {
|
|
@@ -1709,8 +1589,7 @@ async function findRecaptchaFrame(
|
|
|
1709
1589
|
for (const frame of frames) {
|
|
1710
1590
|
const url = await frame.url();
|
|
1711
1591
|
const matchesRecaptcha =
|
|
1712
|
-
url.includes("google.com/recaptcha") ||
|
|
1713
|
-
url.includes("recaptcha.net/recaptcha");
|
|
1592
|
+
url.includes("google.com/recaptcha") || url.includes("recaptcha.net/recaptcha");
|
|
1714
1593
|
const matchesSiteKey = !siteKey || url.includes(siteKey);
|
|
1715
1594
|
if (matchesRecaptcha && matchesSiteKey) {
|
|
1716
1595
|
return frame;
|
|
@@ -1720,8 +1599,6 @@ async function findRecaptchaFrame(
|
|
|
1720
1599
|
return undefined;
|
|
1721
1600
|
}
|
|
1722
1601
|
|
|
1723
|
-
export function createBrowserClient(
|
|
1724
|
-
options: BrowserClientOptions = {},
|
|
1725
|
-
): BrowserClient {
|
|
1602
|
+
export function createBrowserClient(options: BrowserClientOptions = {}): BrowserClient {
|
|
1726
1603
|
return new BrowserClient(options);
|
|
1727
1604
|
}
|