@orkestrel/browser 0.0.5 → 0.0.6
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/README.md +12 -3
- package/dist/src/core/index.cjs +6556 -629
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +2906 -309
- package/dist/src/core/index.d.ts +2906 -309
- package/dist/src/core/index.js +6406 -631
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +144 -31
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +43 -0
- package/dist/src/server/index.d.ts +43 -0
- package/dist/src/server/index.js +144 -34
- package/dist/src/server/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
let _src_core = require("../core/index.cjs");
|
|
3
|
+
let _orkestrel_contract = require("@orkestrel/contract");
|
|
3
4
|
let node_fs = require("node:fs");
|
|
5
|
+
let node_fs_promises = require("node:fs/promises");
|
|
6
|
+
let node_os = require("node:os");
|
|
4
7
|
let node_path = require("node:path");
|
|
5
8
|
let node_child_process = require("node:child_process");
|
|
6
9
|
let node_timers_promises = require("node:timers/promises");
|
|
7
|
-
let _orkestrel_contract = require("@orkestrel/contract");
|
|
8
10
|
let node_crypto = require("node:crypto");
|
|
9
11
|
let node_http = require("node:http");
|
|
10
12
|
let node_https = require("node:https");
|
|
11
13
|
let _orkestrel_emitter = require("@orkestrel/emitter");
|
|
12
14
|
let _orkestrel_websocket = require("@orkestrel/websocket");
|
|
13
15
|
let node_events = require("node:events");
|
|
14
|
-
let node_fs_promises = require("node:fs/promises");
|
|
15
16
|
//#region src/server/constants.ts
|
|
16
17
|
/** Default CDP port probed for an existing browser and used for launches. */
|
|
17
18
|
var BROWSER_DEFAULT_CDP_PORT = 9222;
|
|
@@ -27,6 +28,8 @@ var BROWSER_CDP_LIST_PATH = "/json/list";
|
|
|
27
28
|
var BROWSER_LAUNCH_ARGS = Object.freeze(["--no-first-run", "--no-default-browser-check"]);
|
|
28
29
|
/** Flag enabling headless mode on a launched browser process. */
|
|
29
30
|
var BROWSER_HEADLESS_ARG = "--headless=new";
|
|
31
|
+
/** Prefix for isolated browser profiles created beneath the operating-system temp directory. */
|
|
32
|
+
var BROWSER_PROFILE_PREFIX = "orkestrel-browser-";
|
|
30
33
|
/** Grace period after SIGTERM before a launched process is escalated to SIGKILL during teardown. */
|
|
31
34
|
var BROWSER_KILL_GRACE_MS = 3e3;
|
|
32
35
|
/** Bound for the `discover: false` port-occupancy probe before launching — short, since it only needs to detect an already-listening CDP endpoint, not perform full discovery. */
|
|
@@ -158,7 +161,7 @@ var BrowserDestroyedError = class extends _src_core.BrowserError {
|
|
|
158
161
|
* @returns True when value is a BrowserConnectionError instance
|
|
159
162
|
*/
|
|
160
163
|
function isBrowserConnectionError(value) {
|
|
161
|
-
return value
|
|
164
|
+
return (0, _orkestrel_contract.isInstance)(value, BrowserConnectionError);
|
|
162
165
|
}
|
|
163
166
|
/**
|
|
164
167
|
* Narrow an unknown value to BrowserNotConnectedError.
|
|
@@ -167,7 +170,7 @@ function isBrowserConnectionError(value) {
|
|
|
167
170
|
* @returns True when value is a BrowserNotConnectedError instance
|
|
168
171
|
*/
|
|
169
172
|
function isBrowserNotConnectedError(value) {
|
|
170
|
-
return value
|
|
173
|
+
return (0, _orkestrel_contract.isInstance)(value, BrowserNotConnectedError);
|
|
171
174
|
}
|
|
172
175
|
/**
|
|
173
176
|
* Narrow an unknown value to BrowserDestroyedError.
|
|
@@ -176,7 +179,7 @@ function isBrowserNotConnectedError(value) {
|
|
|
176
179
|
* @returns True when value is a BrowserDestroyedError instance
|
|
177
180
|
*/
|
|
178
181
|
function isBrowserDestroyedError(value) {
|
|
179
|
-
return value
|
|
182
|
+
return (0, _orkestrel_contract.isInstance)(value, BrowserDestroyedError);
|
|
180
183
|
}
|
|
181
184
|
//#endregion
|
|
182
185
|
//#region src/server/helpers.ts
|
|
@@ -264,6 +267,44 @@ function browserToEngine(browser) {
|
|
|
264
267
|
if (browser?.includes("Chrome/") === true) return "chrome";
|
|
265
268
|
return "chromium";
|
|
266
269
|
}
|
|
270
|
+
/**
|
|
271
|
+
* Resolve a persistent caller profile or create an isolated temporary one.
|
|
272
|
+
*
|
|
273
|
+
* @param path - Optional caller-owned persistent user-data directory
|
|
274
|
+
* @returns The resolved profile and whether the library owns its lifecycle
|
|
275
|
+
*/
|
|
276
|
+
async function createBrowserProfile(path) {
|
|
277
|
+
if (path !== void 0) return {
|
|
278
|
+
path,
|
|
279
|
+
temporary: false
|
|
280
|
+
};
|
|
281
|
+
return {
|
|
282
|
+
path: await (0, node_fs_promises.mkdtemp)((0, node_path.join)((0, node_os.tmpdir)(), BROWSER_PROFILE_PREFIX)),
|
|
283
|
+
temporary: true
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Remove a library-owned isolated browser profile.
|
|
288
|
+
*
|
|
289
|
+
* @remarks
|
|
290
|
+
* The path must remain a direct child of the operating-system temp directory
|
|
291
|
+
* with {@link BROWSER_PROFILE_PREFIX}; this defensive check prevents a
|
|
292
|
+
* malformed profile value from widening recursive deletion.
|
|
293
|
+
*
|
|
294
|
+
* @param profile - Resolved profile lifecycle result
|
|
295
|
+
*/
|
|
296
|
+
async function removeBrowserProfile(profile) {
|
|
297
|
+
if (!profile.temporary) return;
|
|
298
|
+
const path = (0, node_path.resolve)(profile.path);
|
|
299
|
+
const temporary = (0, node_path.resolve)((0, node_os.tmpdir)());
|
|
300
|
+
if ((0, node_path.dirname)(path) !== temporary || !(0, node_path.basename)(path).startsWith("orkestrel-browser-")) throw new Error("Refusing to remove an unsafe browser profile path");
|
|
301
|
+
await (0, node_fs_promises.rm)(path, {
|
|
302
|
+
recursive: true,
|
|
303
|
+
force: true,
|
|
304
|
+
maxRetries: 3,
|
|
305
|
+
retryDelay: 100
|
|
306
|
+
});
|
|
307
|
+
}
|
|
267
308
|
/** Check the env-override keys (`PLAYWRIGHT_EXECUTABLE_PATH`, `CHROME_PATH`) in order for an existing file. */
|
|
268
309
|
function findEnvOverride(env) {
|
|
269
310
|
return findAllEnvOverrides(env)[0];
|
|
@@ -416,7 +457,7 @@ async function fetchCDPTargets(port, timeout, host = BROWSER_DEFAULT_HOST) {
|
|
|
416
457
|
const response = await fetch(url, { signal: controller.signal });
|
|
417
458
|
if (!response.ok) return [];
|
|
418
459
|
const list = await response.json();
|
|
419
|
-
if (!
|
|
460
|
+
if (!(0, _orkestrel_contract.isArray)(list)) return [];
|
|
420
461
|
const targets = [];
|
|
421
462
|
for (const entry of list) {
|
|
422
463
|
if (!(0, _orkestrel_contract.isRecord)(entry)) continue;
|
|
@@ -480,12 +521,12 @@ var WebSocketCDPTransport = class {
|
|
|
480
521
|
}
|
|
481
522
|
this.#socket?.destroy();
|
|
482
523
|
this.#socket = void 0;
|
|
483
|
-
const
|
|
484
|
-
this.#starting =
|
|
524
|
+
const transition = this.#open();
|
|
525
|
+
this.#starting = transition;
|
|
485
526
|
try {
|
|
486
|
-
await
|
|
527
|
+
await transition;
|
|
487
528
|
} finally {
|
|
488
|
-
if (this.#starting ===
|
|
529
|
+
if (this.#starting === transition) this.#starting = void 0;
|
|
489
530
|
}
|
|
490
531
|
}
|
|
491
532
|
async send(data) {
|
|
@@ -499,16 +540,21 @@ var WebSocketCDPTransport = class {
|
|
|
499
540
|
await active;
|
|
500
541
|
return;
|
|
501
542
|
}
|
|
502
|
-
const
|
|
503
|
-
this.#closing =
|
|
543
|
+
const transition = this.#stop();
|
|
544
|
+
this.#closing = transition;
|
|
504
545
|
try {
|
|
505
|
-
await
|
|
546
|
+
await transition;
|
|
506
547
|
} finally {
|
|
507
|
-
if (this.#closing ===
|
|
548
|
+
if (this.#closing === transition) this.#closing = void 0;
|
|
508
549
|
}
|
|
509
550
|
}
|
|
510
551
|
async #open() {
|
|
511
|
-
const
|
|
552
|
+
const parsed = (0, _orkestrel_contract.attempt)(() => new URL(this.#url));
|
|
553
|
+
if (!parsed.success) throw new BrowserConnectionError(`WebSocket CDP URL is invalid: ${this.#url}`, {
|
|
554
|
+
url: this.#url,
|
|
555
|
+
error: parsed.error
|
|
556
|
+
});
|
|
557
|
+
const url = parsed.value;
|
|
512
558
|
if (url.protocol !== "ws:" && url.protocol !== "wss:") throw new BrowserConnectionError(`WebSocket CDP connection requires a ws: or wss: URL: ${this.#url}`, { url: this.#url });
|
|
513
559
|
const key = (0, node_crypto.randomBytes)(16).toString("base64");
|
|
514
560
|
const deferred = Promise.withResolvers();
|
|
@@ -670,6 +716,9 @@ function createScreenshotWriter() {
|
|
|
670
716
|
}
|
|
671
717
|
//#endregion
|
|
672
718
|
//#region src/server/Browser.ts
|
|
719
|
+
/**
|
|
720
|
+
* Discovers, launches, connects to, and owns Chromium-family browser sessions.
|
|
721
|
+
*/
|
|
673
722
|
var Browser = class {
|
|
674
723
|
#emitter;
|
|
675
724
|
#options;
|
|
@@ -683,6 +732,7 @@ var Browser = class {
|
|
|
683
732
|
#endpoint;
|
|
684
733
|
#client;
|
|
685
734
|
#process;
|
|
735
|
+
#profile;
|
|
686
736
|
#contexts = [];
|
|
687
737
|
#destroyed = false;
|
|
688
738
|
#connecting;
|
|
@@ -780,6 +830,35 @@ var Browser = class {
|
|
|
780
830
|
contexts() {
|
|
781
831
|
return [...this.#contexts];
|
|
782
832
|
}
|
|
833
|
+
async isolate(options) {
|
|
834
|
+
if (this.#destroyed) throw new BrowserDestroyedError();
|
|
835
|
+
const client = this.#client;
|
|
836
|
+
if (this.#status !== "connected" || client === void 0) throw new BrowserNotConnectedError();
|
|
837
|
+
(0, _src_core.validateBrowserContextOptions)(options);
|
|
838
|
+
const params = { disposeOnDetach: false };
|
|
839
|
+
if (options?.proxy !== void 0) {
|
|
840
|
+
params["proxyServer"] = options.proxy.server;
|
|
841
|
+
if (options.proxy.bypass !== void 0) params["proxyBypassList"] = options.proxy.bypass.join(",");
|
|
842
|
+
}
|
|
843
|
+
if (options?.origins !== void 0) params["originsWithUniversalNetworkAccess"] = [...options.origins];
|
|
844
|
+
const result = await client.send("Target.createBrowserContext", params);
|
|
845
|
+
if (!(0, _orkestrel_contract.isRecord)(result) || !(0, _orkestrel_contract.isString)(result["browserContextId"])) throw new BrowserConnectionError("Failed to create isolated browser context");
|
|
846
|
+
const id = result["browserContextId"];
|
|
847
|
+
const context = new _src_core.BrowserContext(client, id, options?.emulation?.viewport ?? this.#options.viewport, createScreenshotWriter(), options?.emulation, options?.downloads);
|
|
848
|
+
try {
|
|
849
|
+
if (options?.downloads !== void 0) await client.send("Browser.setDownloadBehavior", {
|
|
850
|
+
behavior: options.downloads.named === true ? "allowAndName" : "allow",
|
|
851
|
+
browserContextId: id,
|
|
852
|
+
downloadPath: options.downloads.path,
|
|
853
|
+
eventsEnabled: true
|
|
854
|
+
});
|
|
855
|
+
} catch (error) {
|
|
856
|
+
await context.close().catch(() => void 0);
|
|
857
|
+
throw error;
|
|
858
|
+
}
|
|
859
|
+
this.#registerContext(context);
|
|
860
|
+
return context;
|
|
861
|
+
}
|
|
783
862
|
async create(options) {
|
|
784
863
|
if (this.#destroyed) throw new BrowserDestroyedError();
|
|
785
864
|
const client = this.#client;
|
|
@@ -787,7 +866,7 @@ var Browser = class {
|
|
|
787
866
|
let context = this.#contexts[0];
|
|
788
867
|
if (context === void 0) {
|
|
789
868
|
context = new _src_core.BrowserContext(client, void 0, this.#options.viewport, createScreenshotWriter());
|
|
790
|
-
this.#
|
|
869
|
+
this.#registerContext(context);
|
|
791
870
|
}
|
|
792
871
|
const page = await context.create(options);
|
|
793
872
|
this.#emitter.emit("page", page);
|
|
@@ -840,8 +919,8 @@ var Browser = class {
|
|
|
840
919
|
if (this.#destroyed) throw new BrowserDestroyedError();
|
|
841
920
|
this.#status = "error";
|
|
842
921
|
this.#emitter.emit("error", error);
|
|
843
|
-
if (error
|
|
844
|
-
throw new BrowserConnectionError(error
|
|
922
|
+
if (isBrowserConnectionError(error)) throw error;
|
|
923
|
+
throw new BrowserConnectionError((0, _orkestrel_contract.isError)(error) ? error.message : String(error), { executable: this.#options.executable });
|
|
845
924
|
}
|
|
846
925
|
}
|
|
847
926
|
async #detach() {
|
|
@@ -890,6 +969,7 @@ var Browser = class {
|
|
|
890
969
|
this.#unbindTransport();
|
|
891
970
|
this.#unbindProcess();
|
|
892
971
|
this.#process = void 0;
|
|
972
|
+
this.#releaseProfile().catch((error) => this.#emitter.emit("error", error));
|
|
893
973
|
this.#client = void 0;
|
|
894
974
|
this.#contexts = [];
|
|
895
975
|
this.#connection = void 0;
|
|
@@ -1064,8 +1144,16 @@ var Browser = class {
|
|
|
1064
1144
|
}
|
|
1065
1145
|
if (executable === void 0) throw new BrowserConnectionError("No Chromium browser found. Install Chrome, Edge, or Chromium.", requestedEngine === void 0 ? void 0 : { engine: requestedEngine });
|
|
1066
1146
|
this.#engine = resolvedEngine ?? "chromium";
|
|
1067
|
-
|
|
1068
|
-
const
|
|
1147
|
+
await this.#releaseProfile();
|
|
1148
|
+
const profile = await createBrowserProfile(this.#options.profile);
|
|
1149
|
+
this.#profile = profile;
|
|
1150
|
+
let process;
|
|
1151
|
+
try {
|
|
1152
|
+
process = launchBrowserProcess(executable, this.#cdpPort, this.#options.headless ?? true, profile.path, this.#options.args);
|
|
1153
|
+
} catch (error) {
|
|
1154
|
+
await this.#releaseProfile();
|
|
1155
|
+
throw error;
|
|
1156
|
+
}
|
|
1069
1157
|
this.#process = process;
|
|
1070
1158
|
let client;
|
|
1071
1159
|
try {
|
|
@@ -1079,7 +1167,7 @@ var Browser = class {
|
|
|
1079
1167
|
timeout: this.#timeout()
|
|
1080
1168
|
});
|
|
1081
1169
|
await this.#raceAbort(client.connect());
|
|
1082
|
-
const connection = profile === void 0 ? "launch" : "persistent";
|
|
1170
|
+
const connection = this.#options.profile === void 0 ? "launch" : "persistent";
|
|
1083
1171
|
this.#client = client;
|
|
1084
1172
|
this.#endpoint = endpoint;
|
|
1085
1173
|
this.#connection = connection;
|
|
@@ -1095,6 +1183,7 @@ var Browser = class {
|
|
|
1095
1183
|
this.#unbindProcess();
|
|
1096
1184
|
await this.#closeClient(client);
|
|
1097
1185
|
await this.#terminate(process);
|
|
1186
|
+
await this.#releaseProfile();
|
|
1098
1187
|
this.#process = void 0;
|
|
1099
1188
|
this.#client = void 0;
|
|
1100
1189
|
this.#endpoint = void 0;
|
|
@@ -1111,16 +1200,16 @@ var Browser = class {
|
|
|
1111
1200
|
const signal = AbortSignal.any([controller.signal, this.#signal()]);
|
|
1112
1201
|
const ready = waitForCDPReady(this.#cdpPort, this.#timeout(), this.#cdpHost, signal);
|
|
1113
1202
|
const exited = (0, node_events.once)(process, "exit", { signal }).then((values) => {
|
|
1114
|
-
const code =
|
|
1115
|
-
const exitSignal =
|
|
1203
|
+
const code = (0, _orkestrel_contract.isInteger)(values[0]) ? values[0] : null;
|
|
1204
|
+
const exitSignal = (0, _orkestrel_contract.isString)(values[1]) ? values[1] : null;
|
|
1116
1205
|
throw new BrowserConnectionError(this.#formatLaunchExit(code, exitSignal), context);
|
|
1117
1206
|
});
|
|
1118
1207
|
try {
|
|
1119
1208
|
return await Promise.race([ready, exited]);
|
|
1120
1209
|
} catch (error) {
|
|
1121
|
-
if (error
|
|
1210
|
+
if (isBrowserConnectionError(error)) throw error;
|
|
1122
1211
|
if (this.#signal().aborted) throw new BrowserConnectionError("Connection aborted", context);
|
|
1123
|
-
throw new BrowserConnectionError(error
|
|
1212
|
+
throw new BrowserConnectionError((0, _orkestrel_contract.isError)(error) ? error.message : String(error), context);
|
|
1124
1213
|
} finally {
|
|
1125
1214
|
controller.abort();
|
|
1126
1215
|
ready.catch(() => void 0);
|
|
@@ -1145,7 +1234,7 @@ var Browser = class {
|
|
|
1145
1234
|
} catch {
|
|
1146
1235
|
return;
|
|
1147
1236
|
}
|
|
1148
|
-
if (!(0, _orkestrel_contract.isRecord)(result) || !
|
|
1237
|
+
if (!(0, _orkestrel_contract.isRecord)(result) || !(0, _orkestrel_contract.isArray)(result["targetInfos"])) return;
|
|
1149
1238
|
const pages = [];
|
|
1150
1239
|
for (const target of result["targetInfos"]) {
|
|
1151
1240
|
if (!(0, _orkestrel_contract.isRecord)(target) || !(0, _orkestrel_contract.isString)(target["targetId"]) || target["type"] !== "page" || !(0, _orkestrel_contract.isString)(target["title"]) || !(0, _orkestrel_contract.isString)(target["url"])) continue;
|
|
@@ -1159,7 +1248,7 @@ var Browser = class {
|
|
|
1159
1248
|
if (pages.length === 0 || this.#contexts.length > 0) return;
|
|
1160
1249
|
const context = new _src_core.BrowserContext(client, void 0, this.#options.viewport, createScreenshotWriter());
|
|
1161
1250
|
await context.sync(pages);
|
|
1162
|
-
this.#
|
|
1251
|
+
this.#registerContext(context);
|
|
1163
1252
|
}
|
|
1164
1253
|
async #destroyResources() {
|
|
1165
1254
|
try {
|
|
@@ -1177,7 +1266,11 @@ var Browser = class {
|
|
|
1177
1266
|
await this.#closeClient(client);
|
|
1178
1267
|
this.#client = void 0;
|
|
1179
1268
|
} finally {
|
|
1180
|
-
|
|
1269
|
+
try {
|
|
1270
|
+
await this.#releaseProfile();
|
|
1271
|
+
} finally {
|
|
1272
|
+
this.#finish();
|
|
1273
|
+
}
|
|
1181
1274
|
}
|
|
1182
1275
|
}
|
|
1183
1276
|
async #closeResources() {
|
|
@@ -1197,7 +1290,11 @@ var Browser = class {
|
|
|
1197
1290
|
await this.#closeClient(client);
|
|
1198
1291
|
this.#client = void 0;
|
|
1199
1292
|
} finally {
|
|
1200
|
-
|
|
1293
|
+
try {
|
|
1294
|
+
await this.#releaseProfile();
|
|
1295
|
+
} finally {
|
|
1296
|
+
this.#finish();
|
|
1297
|
+
}
|
|
1201
1298
|
}
|
|
1202
1299
|
}
|
|
1203
1300
|
async #settle() {
|
|
@@ -1229,12 +1326,20 @@ var Browser = class {
|
|
|
1229
1326
|
if (temporary) await this.#closeClient(remote);
|
|
1230
1327
|
}
|
|
1231
1328
|
async #closeContexts() {
|
|
1232
|
-
for (const context of this.#contexts) try {
|
|
1329
|
+
for (const context of [...this.#contexts]) try {
|
|
1233
1330
|
await context.close();
|
|
1234
1331
|
} catch {}
|
|
1235
1332
|
}
|
|
1236
1333
|
async #destroyContexts() {
|
|
1237
|
-
await this.#destroyContextList(this.#contexts);
|
|
1334
|
+
await this.#destroyContextList([...this.#contexts]);
|
|
1335
|
+
}
|
|
1336
|
+
#registerContext(context) {
|
|
1337
|
+
this.#contexts.push(context);
|
|
1338
|
+
context.emitter.on("close", () => {
|
|
1339
|
+
const index = this.#contexts.indexOf(context);
|
|
1340
|
+
if (index >= 0) this.#contexts.splice(index, 1);
|
|
1341
|
+
});
|
|
1342
|
+
this.#emitter.emit("context", context);
|
|
1238
1343
|
}
|
|
1239
1344
|
async #destroyContextList(contexts) {
|
|
1240
1345
|
for (const context of contexts) try {
|
|
@@ -1247,6 +1352,11 @@ var Browser = class {
|
|
|
1247
1352
|
await client.close();
|
|
1248
1353
|
} catch {}
|
|
1249
1354
|
}
|
|
1355
|
+
async #releaseProfile() {
|
|
1356
|
+
const profile = this.#profile;
|
|
1357
|
+
this.#profile = void 0;
|
|
1358
|
+
if (profile !== void 0) await removeBrowserProfile(profile);
|
|
1359
|
+
}
|
|
1250
1360
|
async #waitForProcess(process) {
|
|
1251
1361
|
if (process.exitCode !== null || process.signalCode !== null) return;
|
|
1252
1362
|
await (0, node_events.once)(process, "exit");
|
|
@@ -1306,6 +1416,7 @@ exports.BROWSER_KILL_GRACE_MS = BROWSER_KILL_GRACE_MS;
|
|
|
1306
1416
|
exports.BROWSER_LAUNCH_ARGS = BROWSER_LAUNCH_ARGS;
|
|
1307
1417
|
exports.BROWSER_PORT_PROBE_TIMEOUT_MS = BROWSER_PORT_PROBE_TIMEOUT_MS;
|
|
1308
1418
|
exports.BROWSER_PROCESS_EXIT_CAUSE = BROWSER_PROCESS_EXIT_CAUSE;
|
|
1419
|
+
exports.BROWSER_PROFILE_PREFIX = BROWSER_PROFILE_PREFIX;
|
|
1309
1420
|
exports.BROWSER_STORE_CACHE_DIRS = BROWSER_STORE_CACHE_DIRS;
|
|
1310
1421
|
exports.BROWSER_STORE_DEFAULT_DIRS = BROWSER_STORE_DEFAULT_DIRS;
|
|
1311
1422
|
exports.BROWSER_STORE_ENV_KEY = BROWSER_STORE_ENV_KEY;
|
|
@@ -1322,6 +1433,7 @@ exports.BrowserNotConnectedError = BrowserNotConnectedError;
|
|
|
1322
1433
|
exports.WebSocketCDPTransport = WebSocketCDPTransport;
|
|
1323
1434
|
exports.browserToEngine = browserToEngine;
|
|
1324
1435
|
exports.createBrowser = createBrowser;
|
|
1436
|
+
exports.createBrowserProfile = createBrowserProfile;
|
|
1325
1437
|
exports.createCDPTransport = createCDPTransport;
|
|
1326
1438
|
exports.createScreenshotWriter = createScreenshotWriter;
|
|
1327
1439
|
exports.defaultInstallPaths = defaultInstallPaths;
|
|
@@ -1343,6 +1455,7 @@ exports.normalizeExecutablePath = normalizeExecutablePath;
|
|
|
1343
1455
|
exports.parseBrowserEngine = parseBrowserEngine;
|
|
1344
1456
|
exports.probeAllPathNames = probeAllPathNames;
|
|
1345
1457
|
exports.probePathNames = probePathNames;
|
|
1458
|
+
exports.removeBrowserProfile = removeBrowserProfile;
|
|
1346
1459
|
exports.waitForCDPReady = waitForCDPReady;
|
|
1347
1460
|
exports.windowsRoots = windowsRoots;
|
|
1348
1461
|
|