@apifuse/provider-sdk 2.1.0-beta.3 → 2.1.0-beta.5
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 +187 -8
- package/CHANGELOG.md +13 -1
- package/README.md +40 -18
- package/SUBMISSION.md +4 -4
- package/bin/apifuse-dev.ts +12 -5
- package/bin/apifuse-pack-check.ts +9 -2
- package/bin/apifuse-pack-smoke.ts +127 -6
- package/bin/apifuse-perf.ts +76 -31
- package/bin/apifuse-record.ts +148 -94
- package/bin/apifuse-submit-check.ts +243 -7
- package/bin/apifuse.ts +1 -1
- package/package.json +17 -8
- package/src/choice-token.ts +164 -0
- package/src/cli/commands.ts +4 -7
- package/src/cli/create.ts +180 -51
- package/src/cli/templates/provider/.dockerignore.tpl +22 -0
- package/src/cli/templates/provider/.gitignore.tpl +22 -0
- package/src/cli/templates/provider/README.md.tpl +42 -7
- package/src/cli/templates/provider/dev.ts.tpl +1 -1
- package/src/cli/templates/provider/domain/README.md.tpl +3 -0
- package/src/cli/templates/provider/index.ts.tpl +5 -47
- package/src/cli/templates/provider/mappers/README.md.tpl +3 -0
- package/src/cli/templates/provider/meta.ts.tpl +7 -0
- package/src/cli/templates/provider/operations/index.ts.tpl +5 -0
- package/src/cli/templates/provider/operations/ping.ts.tpl +23 -0
- package/src/cli/templates/provider/schemas/ping.ts.tpl +16 -0
- package/src/cli/templates/provider/start.ts.tpl +1 -1
- package/src/cli/templates/provider/upstream/README.md.tpl +3 -0
- package/src/config/loader.ts +1206 -9
- package/src/define.ts +1620 -106
- package/src/errors.ts +12 -0
- package/src/i18n/catalog.ts +121 -0
- package/src/i18n/index.ts +2 -0
- package/src/i18n/keys.ts +64 -0
- package/src/index.ts +149 -8
- package/src/lint.ts +306 -51
- package/src/observability.ts +41 -0
- package/src/provider.ts +60 -3
- package/src/public-schema-field-lint.ts +237 -0
- package/src/runtime/auth-flow.ts +7 -0
- package/src/runtime/browser.ts +77 -21
- package/src/runtime/cache.ts +582 -0
- package/src/runtime/executor.ts +13 -1
- package/src/runtime/http.ts +939 -195
- package/src/runtime/insights.ts +11 -11
- package/src/runtime/instrumentation.ts +12 -4
- package/src/runtime/key-derivation.ts +1 -1
- package/src/runtime/keyring.ts +4 -3
- package/src/runtime/proxy-errors.ts +132 -0
- package/src/runtime/proxy-telemetry.ts +253 -0
- package/src/runtime/request-options.ts +66 -0
- package/src/runtime/state.ts +76 -0
- package/src/runtime/stealth.ts +1145 -0
- package/src/runtime/stt.ts +629 -0
- package/src/runtime/trace.ts +1 -1
- package/src/schema.ts +363 -1
- package/src/server/serve.ts +816 -58
- package/src/server/types.ts +35 -0
- package/src/stream.ts +210 -0
- package/src/testing/run.ts +17 -4
- package/src/types.ts +876 -53
- package/src/runtime/tls.ts +0 -434
- package/src/types/playwright-stealth.d.ts +0 -9
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import type { ZodType } from "zod";
|
|
2
|
+
|
|
3
|
+
import type { LintDiagnostic } from "./lint";
|
|
4
|
+
|
|
5
|
+
type SchemaLike = ZodType & {
|
|
6
|
+
def?: Record<string, unknown>;
|
|
7
|
+
_def?: Record<string, unknown>;
|
|
8
|
+
shape?: Record<string, SchemaLike> | (() => Record<string, SchemaLike>);
|
|
9
|
+
element?: SchemaLike;
|
|
10
|
+
items?: SchemaLike[];
|
|
11
|
+
options?: SchemaLike[] | Set<SchemaLike> | Map<string, SchemaLike>;
|
|
12
|
+
innerType?: SchemaLike;
|
|
13
|
+
sourceType?: () => SchemaLike;
|
|
14
|
+
unwrap?: () => SchemaLike;
|
|
15
|
+
in?: SchemaLike;
|
|
16
|
+
out?: SchemaLike;
|
|
17
|
+
left?: SchemaLike;
|
|
18
|
+
right?: SchemaLike;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const ESTABLISHED_APIFUSE_PROTOCOL_FIELDS = new Set(["externalRef"]);
|
|
22
|
+
|
|
23
|
+
const UPSTREAM_FIELD_REPLACEMENTS = new Map<string, string>([
|
|
24
|
+
["display", "limit"],
|
|
25
|
+
["start", "offset"],
|
|
26
|
+
["sort", "sort_by"],
|
|
27
|
+
["lprice", "lowest_price"],
|
|
28
|
+
["hprice", "highest_price"],
|
|
29
|
+
["mallName", "mall_name"],
|
|
30
|
+
["productId", "product_id"],
|
|
31
|
+
["productType", "product_type_code"],
|
|
32
|
+
["lastBuildDate", "upstream_generated_at"],
|
|
33
|
+
["meta", "summary"],
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
function isSchema(value: unknown): value is SchemaLike {
|
|
37
|
+
return (
|
|
38
|
+
!!value &&
|
|
39
|
+
typeof value === "object" &&
|
|
40
|
+
"safeParse" in value &&
|
|
41
|
+
typeof value.safeParse === "function"
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function getSchemaDef(schema: SchemaLike): Record<string, unknown> {
|
|
46
|
+
const def = schema.def ?? schema._def;
|
|
47
|
+
return def && typeof def === "object" ? def : {};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function isSchemaRecord(value: unknown): value is Record<string, SchemaLike> {
|
|
51
|
+
if (!value || typeof value !== "object") {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return Object.values(value).every(isSchema);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getObjectShape(schema: SchemaLike): Record<string, SchemaLike> {
|
|
58
|
+
const rawShape =
|
|
59
|
+
typeof schema.shape === "function" ? schema.shape() : schema.shape;
|
|
60
|
+
if (isSchemaRecord(rawShape)) {
|
|
61
|
+
return rawShape;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const defShape = getSchemaDef(schema).shape;
|
|
65
|
+
if (typeof defShape === "function") {
|
|
66
|
+
const resolved = defShape();
|
|
67
|
+
return isSchemaRecord(resolved) ? resolved : {};
|
|
68
|
+
}
|
|
69
|
+
return isSchemaRecord(defShape) ? defShape : {};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function appendSchemaChildren(
|
|
73
|
+
children: SchemaLike[],
|
|
74
|
+
value: unknown,
|
|
75
|
+
): SchemaLike[] {
|
|
76
|
+
if (isSchema(value)) {
|
|
77
|
+
children.push(value);
|
|
78
|
+
return children;
|
|
79
|
+
}
|
|
80
|
+
if (Array.isArray(value)) {
|
|
81
|
+
children.push(...value.filter(isSchema));
|
|
82
|
+
return children;
|
|
83
|
+
}
|
|
84
|
+
if (value instanceof Set) {
|
|
85
|
+
children.push(...Array.from(value).filter(isSchema));
|
|
86
|
+
return children;
|
|
87
|
+
}
|
|
88
|
+
if (value instanceof Map) {
|
|
89
|
+
children.push(...Array.from(value.values()).filter(isSchema));
|
|
90
|
+
return children;
|
|
91
|
+
}
|
|
92
|
+
return children;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function safeSourceType(schema: SchemaLike): SchemaLike | undefined {
|
|
96
|
+
try {
|
|
97
|
+
return schema.sourceType?.();
|
|
98
|
+
} catch {
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function safeUnwrap(schema: SchemaLike): SchemaLike | undefined {
|
|
104
|
+
try {
|
|
105
|
+
return schema.unwrap?.();
|
|
106
|
+
} catch {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function getTransparentChildSchemas(schema: SchemaLike): SchemaLike[] {
|
|
112
|
+
const def = getSchemaDef(schema);
|
|
113
|
+
const children: SchemaLike[] = [];
|
|
114
|
+
for (const value of [
|
|
115
|
+
schema.element,
|
|
116
|
+
schema.items,
|
|
117
|
+
schema.options,
|
|
118
|
+
schema.innerType,
|
|
119
|
+
safeSourceType(schema),
|
|
120
|
+
safeUnwrap(schema),
|
|
121
|
+
schema.in,
|
|
122
|
+
schema.out,
|
|
123
|
+
schema.left,
|
|
124
|
+
schema.right,
|
|
125
|
+
def.schema,
|
|
126
|
+
def.innerType,
|
|
127
|
+
def.type,
|
|
128
|
+
def.valueType,
|
|
129
|
+
def.item,
|
|
130
|
+
def.items,
|
|
131
|
+
def.rest,
|
|
132
|
+
def.catchall,
|
|
133
|
+
def.option,
|
|
134
|
+
def.options,
|
|
135
|
+
def.pipe,
|
|
136
|
+
def.payload,
|
|
137
|
+
def.sourceType,
|
|
138
|
+
def.left,
|
|
139
|
+
def.right,
|
|
140
|
+
]) {
|
|
141
|
+
appendSchemaChildren(children, value);
|
|
142
|
+
}
|
|
143
|
+
return children;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function recommendedReplacement(fieldName: string): string | undefined {
|
|
147
|
+
if (/^category\d+$/.test(fieldName)) {
|
|
148
|
+
return "category_path";
|
|
149
|
+
}
|
|
150
|
+
if (UPSTREAM_FIELD_REPLACEMENTS.has(fieldName)) {
|
|
151
|
+
return UPSTREAM_FIELD_REPLACEMENTS.get(fieldName);
|
|
152
|
+
}
|
|
153
|
+
if (/[a-z][A-Z]/.test(fieldName)) {
|
|
154
|
+
return fieldName.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
|
|
155
|
+
}
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function collectPublicSchemaFieldDiagnostics(
|
|
160
|
+
providerId: string,
|
|
161
|
+
operationId: string,
|
|
162
|
+
schema: unknown,
|
|
163
|
+
basePath: string,
|
|
164
|
+
seen = new Set<SchemaLike>(),
|
|
165
|
+
): LintDiagnostic[] {
|
|
166
|
+
if (!isSchema(schema) || seen.has(schema)) {
|
|
167
|
+
return [];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
seen.add(schema);
|
|
171
|
+
const diagnostics: LintDiagnostic[] = [];
|
|
172
|
+
for (const [fieldName, child] of Object.entries(getObjectShape(schema))) {
|
|
173
|
+
const fieldPath = `${basePath}.${fieldName}`;
|
|
174
|
+
const replacement = ESTABLISHED_APIFUSE_PROTOCOL_FIELDS.has(fieldName)
|
|
175
|
+
? undefined
|
|
176
|
+
: recommendedReplacement(fieldName);
|
|
177
|
+
if (replacement) {
|
|
178
|
+
diagnostics.push({
|
|
179
|
+
rule: "public-schema-upstream-field",
|
|
180
|
+
level: "error",
|
|
181
|
+
field: fieldPath,
|
|
182
|
+
message: `Provider "${providerId}" operation "${operationId}" public schema field "${fieldPath}" uses upstream-shaped field "${fieldName}"; use APIFuse field "${replacement}" instead.`,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
diagnostics.push(
|
|
186
|
+
...collectPublicSchemaFieldDiagnostics(
|
|
187
|
+
providerId,
|
|
188
|
+
operationId,
|
|
189
|
+
child,
|
|
190
|
+
fieldPath,
|
|
191
|
+
seen,
|
|
192
|
+
),
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
for (const child of getTransparentChildSchemas(schema)) {
|
|
197
|
+
const childPath = schema.element === child ? `${basePath}[]` : basePath;
|
|
198
|
+
diagnostics.push(
|
|
199
|
+
...collectPublicSchemaFieldDiagnostics(
|
|
200
|
+
providerId,
|
|
201
|
+
operationId,
|
|
202
|
+
child,
|
|
203
|
+
childPath,
|
|
204
|
+
seen,
|
|
205
|
+
),
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return diagnostics;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export function lintPublicSchemaFieldNames(
|
|
213
|
+
providerId: string | undefined,
|
|
214
|
+
operationId: string,
|
|
215
|
+
input: unknown,
|
|
216
|
+
output: unknown,
|
|
217
|
+
enforce: boolean,
|
|
218
|
+
): LintDiagnostic[] {
|
|
219
|
+
if (!providerId || !enforce) {
|
|
220
|
+
return [];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return [
|
|
224
|
+
...collectPublicSchemaFieldDiagnostics(
|
|
225
|
+
providerId,
|
|
226
|
+
operationId,
|
|
227
|
+
input,
|
|
228
|
+
"input",
|
|
229
|
+
),
|
|
230
|
+
...collectPublicSchemaFieldDiagnostics(
|
|
231
|
+
providerId,
|
|
232
|
+
operationId,
|
|
233
|
+
output,
|
|
234
|
+
"output",
|
|
235
|
+
),
|
|
236
|
+
];
|
|
237
|
+
}
|
package/src/runtime/auth-flow.ts
CHANGED
|
@@ -4,7 +4,10 @@ import type {
|
|
|
4
4
|
EnvContext,
|
|
5
5
|
FlowContext,
|
|
6
6
|
HttpClient,
|
|
7
|
+
StealthClient,
|
|
8
|
+
SttContext,
|
|
7
9
|
} from "../types";
|
|
10
|
+
import { createUnsupportedSttClient } from "./stt";
|
|
8
11
|
|
|
9
12
|
function normalizeAllowedKeys(allowedKeys: string[]): Set<string> {
|
|
10
13
|
return new Set(allowedKeys.filter((key) => key.trim().length > 0));
|
|
@@ -47,6 +50,7 @@ export function createScratchpad(
|
|
|
47
50
|
|
|
48
51
|
export function createFlowContext(options: {
|
|
49
52
|
http: HttpClient;
|
|
53
|
+
stealth: StealthClient;
|
|
50
54
|
env: EnvContext;
|
|
51
55
|
tenantId: string;
|
|
52
56
|
providerId: string;
|
|
@@ -54,6 +58,7 @@ export function createFlowContext(options: {
|
|
|
54
58
|
externalRef?: string;
|
|
55
59
|
allowedKeys: string[];
|
|
56
60
|
initialContext?: Record<string, unknown>;
|
|
61
|
+
stt?: SttContext;
|
|
57
62
|
}): FlowContext {
|
|
58
63
|
return {
|
|
59
64
|
connectionId: options.connectionId,
|
|
@@ -61,7 +66,9 @@ export function createFlowContext(options: {
|
|
|
61
66
|
tenantId: options.tenantId,
|
|
62
67
|
providerId: options.providerId,
|
|
63
68
|
http: options.http,
|
|
69
|
+
stealth: options.stealth,
|
|
64
70
|
env: options.env,
|
|
65
71
|
context: createScratchpad(options.allowedKeys, options.initialContext),
|
|
72
|
+
stt: options.stt ?? createUnsupportedSttClient(),
|
|
66
73
|
};
|
|
67
74
|
}
|
package/src/runtime/browser.ts
CHANGED
|
@@ -13,10 +13,14 @@ const DEFAULT_WAIT_TIMEOUT_MS = 30_000;
|
|
|
13
13
|
const SELECTOR_POLL_INTERVAL_MS = 100;
|
|
14
14
|
|
|
15
15
|
type PlaywrightModule = typeof import("playwright");
|
|
16
|
-
type
|
|
17
|
-
|
|
16
|
+
type PlaywrightExtraModule = {
|
|
17
|
+
chromium: PlaywrightModule["chromium"] & { use(plugin: unknown): unknown };
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
type StealthPluginFactory = (options?: {
|
|
21
|
+
enabledEvasions?: Set<string>;
|
|
22
|
+
}) => unknown;
|
|
23
|
+
|
|
20
24
|
type PoolAcquireResponse = {
|
|
21
25
|
pageId: string;
|
|
22
26
|
wsEndpoint: string;
|
|
@@ -65,7 +69,7 @@ type SupportedBrowserClient = BrowserClientContract & {
|
|
|
65
69
|
};
|
|
66
70
|
|
|
67
71
|
function getDefaultCdpPoolUrl(env = process.env): string | undefined {
|
|
68
|
-
return env.
|
|
72
|
+
return env.APIFUSE__CDP_POOL__URL;
|
|
69
73
|
}
|
|
70
74
|
|
|
71
75
|
async function importOptionalModule<T extends object>(
|
|
@@ -89,11 +93,16 @@ function unwrapModuleDefault<T extends object>(module: T): T {
|
|
|
89
93
|
}
|
|
90
94
|
|
|
91
95
|
function isModuleNotFoundError(error: unknown): boolean {
|
|
96
|
+
if (!(error instanceof Error)) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const code = "code" in error ? error.code : undefined;
|
|
92
101
|
return (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
102
|
+
code === "MODULE_NOT_FOUND" ||
|
|
103
|
+
code === "ERR_MODULE_NOT_FOUND" ||
|
|
104
|
+
error.message.includes("Cannot find module") ||
|
|
105
|
+
error.message.includes("Cannot find package")
|
|
97
106
|
);
|
|
98
107
|
}
|
|
99
108
|
|
|
@@ -120,7 +129,7 @@ function toLaunchOptions(options: BrowserClientOptions): LaunchOptions {
|
|
|
120
129
|
|
|
121
130
|
async function loadPlaywright(): Promise<PlaywrightModule> {
|
|
122
131
|
try {
|
|
123
|
-
|
|
132
|
+
await importOptionalModule<PlaywrightModule>("playwright");
|
|
124
133
|
} catch (error) {
|
|
125
134
|
if (isModuleNotFoundError(error)) {
|
|
126
135
|
throw new ProviderError("Playwright is not installed", {
|
|
@@ -148,16 +157,31 @@ async function loadPlaywright(): Promise<PlaywrightModule> {
|
|
|
148
157
|
}
|
|
149
158
|
}
|
|
150
159
|
|
|
151
|
-
|
|
160
|
+
const playwrightExtraStealthLaunchers = new WeakSet<object>();
|
|
161
|
+
|
|
162
|
+
async function loadPlaywrightExtra(): Promise<PlaywrightExtraModule> {
|
|
163
|
+
try {
|
|
164
|
+
require("playwright");
|
|
165
|
+
} catch (error) {
|
|
166
|
+
if (isModuleNotFoundError(error)) {
|
|
167
|
+
throw new ProviderError("Playwright is not installed", {
|
|
168
|
+
cause: error instanceof Error ? error : undefined,
|
|
169
|
+
fix: "Run: bun add playwright",
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
|
|
152
176
|
try {
|
|
153
177
|
return unwrapModuleDefault(
|
|
154
|
-
await importOptionalModule<
|
|
178
|
+
await importOptionalModule<PlaywrightExtraModule>("playwright-extra"),
|
|
155
179
|
);
|
|
156
180
|
} catch (error) {
|
|
157
181
|
if (isModuleNotFoundError(error)) {
|
|
158
|
-
throw new ProviderError("playwright-
|
|
182
|
+
throw new ProviderError("playwright-extra is not installed", {
|
|
159
183
|
cause: error instanceof Error ? error : undefined,
|
|
160
|
-
fix: "Run: bun add playwright-stealth",
|
|
184
|
+
fix: "Run: bun add playwright-extra puppeteer-extra-plugin-stealth",
|
|
161
185
|
});
|
|
162
186
|
}
|
|
163
187
|
|
|
@@ -165,6 +189,45 @@ async function loadPlaywrightStealth(): Promise<PlaywrightStealthModule> {
|
|
|
165
189
|
}
|
|
166
190
|
}
|
|
167
191
|
|
|
192
|
+
async function loadStealthPluginFactory(): Promise<StealthPluginFactory> {
|
|
193
|
+
try {
|
|
194
|
+
return unwrapModuleDefault(
|
|
195
|
+
await importOptionalModule<StealthPluginFactory>(
|
|
196
|
+
"puppeteer-extra-plugin-stealth",
|
|
197
|
+
),
|
|
198
|
+
);
|
|
199
|
+
} catch (error) {
|
|
200
|
+
if (isModuleNotFoundError(error)) {
|
|
201
|
+
throw new ProviderError(
|
|
202
|
+
"puppeteer-extra-plugin-stealth is not installed",
|
|
203
|
+
{
|
|
204
|
+
cause: error instanceof Error ? error : undefined,
|
|
205
|
+
fix: "Run: bun add playwright-extra puppeteer-extra-plugin-stealth",
|
|
206
|
+
},
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
throw error;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async function loadChromiumLauncher(
|
|
215
|
+
options: BrowserClientOptions,
|
|
216
|
+
): Promise<PlaywrightModule["chromium"]> {
|
|
217
|
+
if (!(options.stealth ?? true)) {
|
|
218
|
+
return (await loadPlaywright()).chromium;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const playwrightExtra = await loadPlaywrightExtra();
|
|
222
|
+
if (!playwrightExtraStealthLaunchers.has(playwrightExtra.chromium)) {
|
|
223
|
+
const createStealthPlugin = await loadStealthPluginFactory();
|
|
224
|
+
playwrightExtra.chromium.use(createStealthPlugin());
|
|
225
|
+
playwrightExtraStealthLaunchers.add(playwrightExtra.chromium);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return playwrightExtra.chromium;
|
|
229
|
+
}
|
|
230
|
+
|
|
168
231
|
async function loadNodriver(): Promise<void> {
|
|
169
232
|
try {
|
|
170
233
|
await importOptionalModule("nodriver");
|
|
@@ -256,10 +319,8 @@ class PlaywrightBrowserClient implements SupportedBrowserClient {
|
|
|
256
319
|
return this.browser;
|
|
257
320
|
}
|
|
258
321
|
|
|
259
|
-
const
|
|
260
|
-
this.browser = await
|
|
261
|
-
toLaunchOptions(this.options),
|
|
262
|
-
);
|
|
322
|
+
const chromium = await loadChromiumLauncher(this.options);
|
|
323
|
+
this.browser = await chromium.launch(toLaunchOptions(this.options));
|
|
263
324
|
return this.browser;
|
|
264
325
|
}
|
|
265
326
|
|
|
@@ -267,11 +328,6 @@ class PlaywrightBrowserClient implements SupportedBrowserClient {
|
|
|
267
328
|
const browser = await this.ensureBrowser();
|
|
268
329
|
const page = await browser.newPage();
|
|
269
330
|
|
|
270
|
-
if (this.options.stealth ?? true) {
|
|
271
|
-
const { stealth } = await loadPlaywrightStealth();
|
|
272
|
-
await stealth(page);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
331
|
return new PlaywrightBrowserPage(page);
|
|
276
332
|
}
|
|
277
333
|
|