@orkestrel/browser 0.0.23 → 0.0.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/dist/bin/main.js +9 -3
- package/dist/bin/main.js.map +1 -1
- package/dist/src/core/index.cjs +58 -13
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +18 -10
- package/dist/src/core/index.d.ts +18 -10
- package/dist/src/core/index.js +58 -13
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +392 -84
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +58 -4
- package/dist/src/server/index.d.ts +58 -4
- package/dist/src/server/index.js +390 -86
- package/dist/src/server/index.js.map +1 -1
- package/package.json +4 -4
package/dist/src/server/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BROWSER_DEFAULT_TIMEOUT_MS, BROWSER_JOURNEY_FORMAT_VERSION, BROWSER_JOURNEY_NAME_PATTERN, BROWSER_JOURNEY_TOOL_NAMES, BROWSER_RUN_ID_PATTERN, BROWSER_TOOL_COPY, BROWSER_TOOL_NAMES, BrowserConnectionError, BrowserContext, BrowserError, BrowserTransition, CDPClient, createBrowserToolset, createCDPClient, generateBrowserRunId, isBrowserConnectionError, isBrowserError, isCDPTimeoutError, normalizeBrowserJourneyReason, validateBrowserContextOptions, validateBrowserJourney, validateBrowserRun, validateBrowserStorePage } from "../core/index.js";
|
|
2
|
-
import { attempt, isArray, isError, isInstance, isInteger, isNumber, isRecord, isString, parseJSON } from "@orkestrel/contract";
|
|
2
|
+
import { attempt, isArray, isError, isInstance, isInteger, isNumber, isRecord, isString, parseInteger, parseJSON } from "@orkestrel/contract";
|
|
3
3
|
import { existsSync, globSync, realpathSync } from "node:fs";
|
|
4
4
|
import { lstat, mkdir, mkdtemp, open, readFile, readdir, rename, rm, rmdir, unlink, writeFile } from "node:fs/promises";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
@@ -236,6 +236,84 @@ var BROWSER_SERVER_OPTIONS = "BROWSER_SERVER_OPTIONS";
|
|
|
236
236
|
var BROWSER_SERVER_CRASH = "BROWSER_SERVER_CRASH";
|
|
237
237
|
/** Names an interrupted call whose outcome is unknown. */
|
|
238
238
|
var BROWSER_SERVER_UNRESOLVED = "BROWSER_SERVER_UNRESOLVED";
|
|
239
|
+
/** Names the refusal when every browser is admitted to a holder. */
|
|
240
|
+
var BROWSER_SERVER_BUSY = "BROWSER_SERVER_BUSY";
|
|
241
|
+
/** Names the refusal for an unknown or ended holder. */
|
|
242
|
+
var BROWSER_SERVER_HOLDER = "BROWSER_SERVER_HOLDER";
|
|
243
|
+
/** Defines the holder tools independently of the shared browser's vocabulary. */
|
|
244
|
+
var BROWSER_SERVER_COPY = Object.freeze({
|
|
245
|
+
acquire: Object.freeze({
|
|
246
|
+
name: "acquire",
|
|
247
|
+
description: "Acquires an independent browser and returns its holder id and tool catalog. Destroy the holder when its work ends.",
|
|
248
|
+
parameters: Object.freeze({
|
|
249
|
+
type: "object",
|
|
250
|
+
properties: Object.freeze({ purpose: Object.freeze({
|
|
251
|
+
type: "string",
|
|
252
|
+
description: "The work this browser will serve."
|
|
253
|
+
}) }),
|
|
254
|
+
required: Object.freeze(["purpose"])
|
|
255
|
+
})
|
|
256
|
+
}),
|
|
257
|
+
execute: Object.freeze({
|
|
258
|
+
name: "execute",
|
|
259
|
+
description: "Runs a tool on the selected holder, with that tool’s arguments inside arguments. Get its available tools with tools.",
|
|
260
|
+
parameters: Object.freeze({
|
|
261
|
+
type: "object",
|
|
262
|
+
properties: Object.freeze({
|
|
263
|
+
holder: Object.freeze({
|
|
264
|
+
type: "string",
|
|
265
|
+
description: "The holder id returned by acquire."
|
|
266
|
+
}),
|
|
267
|
+
name: Object.freeze({
|
|
268
|
+
type: "string",
|
|
269
|
+
description: "The tool name from this holder’s catalog."
|
|
270
|
+
}),
|
|
271
|
+
arguments: Object.freeze({
|
|
272
|
+
type: "object",
|
|
273
|
+
description: "The arguments for the selected tool."
|
|
274
|
+
})
|
|
275
|
+
}),
|
|
276
|
+
required: Object.freeze([
|
|
277
|
+
"holder",
|
|
278
|
+
"name",
|
|
279
|
+
"arguments"
|
|
280
|
+
])
|
|
281
|
+
}),
|
|
282
|
+
annotations: Object.freeze({
|
|
283
|
+
pure: false,
|
|
284
|
+
untrusted: true
|
|
285
|
+
})
|
|
286
|
+
}),
|
|
287
|
+
tools: Object.freeze({
|
|
288
|
+
name: "tools",
|
|
289
|
+
description: "Lists the selected holder’s tools, including tools supplied by its page.",
|
|
290
|
+
parameters: Object.freeze({
|
|
291
|
+
type: "object",
|
|
292
|
+
properties: Object.freeze({ holder: Object.freeze({
|
|
293
|
+
type: "string",
|
|
294
|
+
description: "The holder id returned by acquire."
|
|
295
|
+
}) }),
|
|
296
|
+
required: Object.freeze(["holder"])
|
|
297
|
+
}),
|
|
298
|
+
annotations: Object.freeze({
|
|
299
|
+
pure: true,
|
|
300
|
+
untrusted: true
|
|
301
|
+
})
|
|
302
|
+
}),
|
|
303
|
+
destroy: Object.freeze({
|
|
304
|
+
name: "destroy",
|
|
305
|
+
description: "Ends the selected holder and destroys its browser. Calls still running on that holder report an unresolved outcome.",
|
|
306
|
+
parameters: Object.freeze({
|
|
307
|
+
type: "object",
|
|
308
|
+
properties: Object.freeze({ holder: Object.freeze({
|
|
309
|
+
type: "string",
|
|
310
|
+
description: "The holder id returned by acquire."
|
|
311
|
+
}) }),
|
|
312
|
+
required: Object.freeze(["holder"])
|
|
313
|
+
}),
|
|
314
|
+
annotations: Object.freeze({ pure: false })
|
|
315
|
+
})
|
|
316
|
+
});
|
|
239
317
|
//#endregion
|
|
240
318
|
//#region src/server/errors.ts
|
|
241
319
|
/**
|
|
@@ -279,6 +357,25 @@ function isBrowserDestroyedError(value) {
|
|
|
279
357
|
//#endregion
|
|
280
358
|
//#region src/server/helpers.ts
|
|
281
359
|
/**
|
|
360
|
+
* Parses positive integer viewport dimensions in WIDTHxHEIGHT form.
|
|
361
|
+
* @param value - The viewport environment variable, or undefined when unset
|
|
362
|
+
* @returns The viewport, or undefined when absent or malformed
|
|
363
|
+
* @example
|
|
364
|
+
* parseBrowserViewport('1280x720') // { width: 1280, height: 720 }
|
|
365
|
+
*/
|
|
366
|
+
function parseBrowserViewport(value) {
|
|
367
|
+
if (value === void 0) return void 0;
|
|
368
|
+
const match = /^([0-9]+)x([0-9]+)$/u.exec(value);
|
|
369
|
+
if (match === null || match[0] !== value) return void 0;
|
|
370
|
+
const width = parseInteger(match[1]);
|
|
371
|
+
const height = parseInteger(match[2]);
|
|
372
|
+
if (width === void 0 || height === void 0 || !Number.isSafeInteger(width) || !Number.isSafeInteger(height) || width <= 0 || height <= 0) return void 0;
|
|
373
|
+
return {
|
|
374
|
+
width,
|
|
375
|
+
height
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
282
379
|
* Probes whether a process has not been confirmed absent.
|
|
283
380
|
* @param pid - Process identifier to probe with signal zero
|
|
284
381
|
* @returns True if the host has not confirmed absence with ESRCH; false otherwise
|
|
@@ -944,7 +1041,7 @@ var FileBrowserWriter = class {
|
|
|
944
1041
|
};
|
|
945
1042
|
//#endregion
|
|
946
1043
|
//#region package.json
|
|
947
|
-
var version = "0.0.
|
|
1044
|
+
var version = "0.0.24";
|
|
948
1045
|
//#endregion
|
|
949
1046
|
//#region src/server/BrowserMCPServer.ts
|
|
950
1047
|
/**
|
|
@@ -959,8 +1056,11 @@ var version = "0.0.23";
|
|
|
959
1056
|
* absent. After the launch, a tool the toolset's manager adds under another name, such as a page
|
|
960
1057
|
* tool it adopts, is mirrored as a dispatcher with that tool's definition, and the mirror is
|
|
961
1058
|
* removed when the toolset withdraws the tool, so the server's tool list changes and a subscribed
|
|
962
|
-
* client is notified.
|
|
963
|
-
*
|
|
1059
|
+
* client is notified. The server also advertises `acquire`, `execute`, `tools`, and `destroy` with
|
|
1060
|
+
* `BROWSER_SERVER_COPY`. Startup warms the pool and leases the shared browser. The legacy
|
|
1061
|
+
* handshake and browser calls await that setup. Named holders each own a lease, a pending grant,
|
|
1062
|
+
* and loss notices; concurrent calls on a holder share its replacement grant. Ending a holder
|
|
1063
|
+
* destroys its token, and admission counts that holder until disposal settles.
|
|
964
1064
|
* A launch creates `ROOT/.profiles/PID-UUID/` exclusively, connects a browser that never attaches to an
|
|
965
1065
|
* existing endpoint, opens one page in an isolated context, and constructs the page toolset with
|
|
966
1066
|
* that context and the file journey and run stores under the root, on a manager the toolset owns.
|
|
@@ -970,6 +1070,8 @@ var version = "0.0.23";
|
|
|
970
1070
|
* A disconnect or current-page crash retires its slot. A failed call receives a liveness ping;
|
|
971
1071
|
* loss makes its outcome unresolved, while a known success remains successful. Pending losses
|
|
972
1072
|
* prefix the next outcome on a successor, or a refusal, and calls are never repeated.
|
|
1073
|
+
* Concurrent checks share one ping per slot. Cancelling a call ends only its wait; the ping keeps
|
|
1074
|
+
* its deadline and records loss for the next call.
|
|
973
1075
|
*
|
|
974
1076
|
* `start()` serves stdio and destroys the server at the end of its input, on `SIGINT`, and on
|
|
975
1077
|
* `SIGTERM`. `destroy()` stops reading requests and removes every dispatcher, then destroys every
|
|
@@ -993,6 +1095,7 @@ var BrowserMCPServer = class {
|
|
|
993
1095
|
#root;
|
|
994
1096
|
#headless;
|
|
995
1097
|
#executable;
|
|
1098
|
+
#viewport;
|
|
996
1099
|
#readonly;
|
|
997
1100
|
#launcher;
|
|
998
1101
|
#input;
|
|
@@ -1001,22 +1104,32 @@ var BrowserMCPServer = class {
|
|
|
1001
1104
|
#abort = new AbortController();
|
|
1002
1105
|
#signal;
|
|
1003
1106
|
#vocabulary;
|
|
1004
|
-
#
|
|
1005
|
-
#removed;
|
|
1006
|
-
#cleared;
|
|
1107
|
+
#mirrored;
|
|
1007
1108
|
#pool;
|
|
1008
1109
|
#log;
|
|
1009
1110
|
#folders = /* @__PURE__ */ new Set();
|
|
1010
1111
|
#faults = /* @__PURE__ */ new Set();
|
|
1011
1112
|
#losses = /* @__PURE__ */ new WeakMap();
|
|
1113
|
+
#pings = /* @__PURE__ */ new WeakMap();
|
|
1012
1114
|
#watches = /* @__PURE__ */ new Map();
|
|
1013
|
-
#
|
|
1115
|
+
#shared = {
|
|
1116
|
+
id: "shared",
|
|
1117
|
+
purpose: "Shared browser",
|
|
1118
|
+
abort: this.#abort
|
|
1119
|
+
};
|
|
1120
|
+
#holders = /* @__PURE__ */ new Map([[this.#shared.id, this.#shared]]);
|
|
1121
|
+
#leases = /* @__PURE__ */ new Map();
|
|
1122
|
+
#grants = /* @__PURE__ */ new Map();
|
|
1123
|
+
#notices = /* @__PURE__ */ new Map();
|
|
1124
|
+
#disposals = /* @__PURE__ */ new Map();
|
|
1125
|
+
#drains = /* @__PURE__ */ new Map();
|
|
1126
|
+
#readers = /* @__PURE__ */ new Map();
|
|
1127
|
+
#writers = /* @__PURE__ */ new Set();
|
|
1128
|
+
#size;
|
|
1014
1129
|
#reference;
|
|
1015
1130
|
#references = 0;
|
|
1016
1131
|
#failure;
|
|
1017
1132
|
#stranded;
|
|
1018
|
-
#lease;
|
|
1019
|
-
#granting;
|
|
1020
1133
|
#starting;
|
|
1021
1134
|
#sweeping;
|
|
1022
1135
|
#closing;
|
|
@@ -1028,6 +1141,7 @@ var BrowserMCPServer = class {
|
|
|
1028
1141
|
constructor(options) {
|
|
1029
1142
|
const size = options?.pool?.size ?? 1;
|
|
1030
1143
|
if (!isInteger(size) || size < 1 || size > 3) throw new BrowserError(`pool.size must be an integer from 1 through 3`, BROWSER_SERVER_OPTIONS);
|
|
1144
|
+
this.#size = size;
|
|
1031
1145
|
this.#log = options?.log ?? process.stderr;
|
|
1032
1146
|
this.#reference = this.#issue.bind(this);
|
|
1033
1147
|
this.#pool = createPool({
|
|
@@ -1042,15 +1156,32 @@ var BrowserMCPServer = class {
|
|
|
1042
1156
|
this.#root = resolve(options?.root ?? "tmp/browsers");
|
|
1043
1157
|
this.#headless = options?.headless ?? true;
|
|
1044
1158
|
this.#executable = options?.executable;
|
|
1159
|
+
this.#viewport = options?.viewport;
|
|
1045
1160
|
this.#readonly = options?.readonly ?? false;
|
|
1046
1161
|
this.#launcher = options?.launch ?? createBrowser;
|
|
1047
1162
|
this.#input = options?.stdio?.input ?? process.stdin;
|
|
1048
1163
|
this.#tools = createToolManager();
|
|
1049
1164
|
const names = [...BROWSER_TOOL_NAMES, ...BROWSER_JOURNEY_TOOL_NAMES];
|
|
1050
|
-
this.#vocabulary = new Set(names);
|
|
1165
|
+
this.#vocabulary = /* @__PURE__ */ new Set([...names, ...Object.keys(BROWSER_SERVER_COPY)]);
|
|
1051
1166
|
for (const name of names) this.#tools.add(createTool({
|
|
1052
1167
|
...BROWSER_TOOL_COPY[name],
|
|
1053
|
-
execute: this.#forward.bind(this, name)
|
|
1168
|
+
execute: this.#forward.bind(this, this.#shared, name)
|
|
1169
|
+
}));
|
|
1170
|
+
this.#tools.add(createTool({
|
|
1171
|
+
...BROWSER_SERVER_COPY.acquire,
|
|
1172
|
+
execute: this.#acquire.bind(this)
|
|
1173
|
+
}));
|
|
1174
|
+
this.#tools.add(createTool({
|
|
1175
|
+
...BROWSER_SERVER_COPY.execute,
|
|
1176
|
+
execute: this.#dispatch.bind(this)
|
|
1177
|
+
}));
|
|
1178
|
+
this.#tools.add(createTool({
|
|
1179
|
+
...BROWSER_SERVER_COPY.tools,
|
|
1180
|
+
execute: this.#catalog.bind(this)
|
|
1181
|
+
}));
|
|
1182
|
+
this.#tools.add(createTool({
|
|
1183
|
+
...BROWSER_SERVER_COPY.destroy,
|
|
1184
|
+
execute: this.#dispose.bind(this)
|
|
1054
1185
|
}));
|
|
1055
1186
|
const server = createMCPServer({
|
|
1056
1187
|
identity: {
|
|
@@ -1066,9 +1197,6 @@ var BrowserMCPServer = class {
|
|
|
1066
1197
|
...options?.stdio?.output === void 0 ? {} : { output: options.stdio.output }
|
|
1067
1198
|
});
|
|
1068
1199
|
this.#signal = this.#end.bind(this);
|
|
1069
|
-
this.#added = this.#mirror.bind(this);
|
|
1070
|
-
this.#removed = this.#withdraw.bind(this);
|
|
1071
|
-
this.#cleared = this.#clear.bind(this);
|
|
1072
1200
|
}
|
|
1073
1201
|
async start() {
|
|
1074
1202
|
if (this.#closing !== void 0) throw this.#ended();
|
|
@@ -1089,7 +1217,7 @@ var BrowserMCPServer = class {
|
|
|
1089
1217
|
if (this.#closing !== void 0) return;
|
|
1090
1218
|
this.#sweeping = this.#sweep();
|
|
1091
1219
|
const warming = this.#pool.start().then(void 0, (error) => error);
|
|
1092
|
-
await this.#grant(this.#abort.signal);
|
|
1220
|
+
await this.#grant(this.#shared, this.#abort.signal);
|
|
1093
1221
|
if (this.#closing !== void 0) return;
|
|
1094
1222
|
warming.then(this.#exhaust.bind(this));
|
|
1095
1223
|
} catch (error) {
|
|
@@ -1105,13 +1233,16 @@ var BrowserMCPServer = class {
|
|
|
1105
1233
|
this.#transport.stop();
|
|
1106
1234
|
for (const tool of this.#tools.tools()) this.#tools.remove(tool.name);
|
|
1107
1235
|
this.#unmirror();
|
|
1108
|
-
this.#
|
|
1236
|
+
this.#leases.clear();
|
|
1237
|
+
for (const holder of this.#holders.values()) holder.abort.abort();
|
|
1109
1238
|
this.#abort.abort();
|
|
1110
1239
|
const barrier = this.#pool.destroy().catch((error) => {
|
|
1111
1240
|
for (const failure of isPoolError(error) ? error.context?.failures ?? [error] : [error]) this.#faults.add(failure);
|
|
1112
1241
|
});
|
|
1113
1242
|
await this.#starting?.catch(() => void 0);
|
|
1114
1243
|
await barrier;
|
|
1244
|
+
await Promise.allSettled(this.#disposals.values());
|
|
1245
|
+
this.#holders.clear();
|
|
1115
1246
|
await this.#sweeping;
|
|
1116
1247
|
if (this.#stranded !== void 0) this.#faults.add(this.#stranded);
|
|
1117
1248
|
for (const folder of this.#folders) {
|
|
@@ -1156,22 +1287,141 @@ var BrowserMCPServer = class {
|
|
|
1156
1287
|
process.exitCode = 1;
|
|
1157
1288
|
this.#write(`browse: ${describeBrowserServerLoss(BROWSER_SERVER_TEARDOWN, error)}`);
|
|
1158
1289
|
}
|
|
1159
|
-
async #
|
|
1290
|
+
async #acquire(args, context) {
|
|
1291
|
+
context.signal.throwIfAborted();
|
|
1292
|
+
if (this.#closing !== void 0) throw this.#ended();
|
|
1293
|
+
const purpose = args["purpose"];
|
|
1294
|
+
if (!isString(purpose) || purpose.trim().length === 0) throw new BrowserError("purpose must describe the work", "BROWSER_TOOLSET_ARGUMENT");
|
|
1295
|
+
if (this.#holders.size >= this.#size) throw new BrowserError(`${BROWSER_SERVER_BUSY}: ${[...this.#holders.values()].map((holder) => `${holder.id} (${holder.purpose})`).join(", ")}. Call destroy for a holder no longer needed or call the named tools to share the shared browser.`, BROWSER_SERVER_BUSY);
|
|
1296
|
+
const holder = {
|
|
1297
|
+
id: randomUUID(),
|
|
1298
|
+
purpose,
|
|
1299
|
+
abort: new AbortController()
|
|
1300
|
+
};
|
|
1301
|
+
this.#holders.set(holder.id, holder);
|
|
1302
|
+
const listener = addAbortListener(context.signal, () => holder.abort.abort(context.signal.reason));
|
|
1303
|
+
try {
|
|
1304
|
+
const slot = await this.#serve(holder, context.signal);
|
|
1305
|
+
context.signal.throwIfAborted();
|
|
1306
|
+
if (holder.abort.signal.aborted || this.#holders.get(holder.id) !== holder) throw this.#ended();
|
|
1307
|
+
if (this.#leases.get(holder)?.value !== slot) throw this.#unavailable(this.#losses.get(slot)?.cause);
|
|
1308
|
+
const catalog = {
|
|
1309
|
+
holder: holder.id,
|
|
1310
|
+
tools: slot.toolset.tools.definitions()
|
|
1311
|
+
};
|
|
1312
|
+
return JSON.stringify(catalog);
|
|
1313
|
+
} catch (error) {
|
|
1314
|
+
await this.#retire(holder).catch(this.#fault.bind(this));
|
|
1315
|
+
throw error;
|
|
1316
|
+
} finally {
|
|
1317
|
+
listener[Symbol.dispose]();
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
#holder(value) {
|
|
1321
|
+
const holder = isString(value) ? this.#holders.get(value) : void 0;
|
|
1322
|
+
if (holder === void 0 || holder === this.#shared || holder.abort.signal.aborted) throw new BrowserError(`${BROWSER_SERVER_HOLDER}: unknown or ended holder`, BROWSER_SERVER_HOLDER);
|
|
1323
|
+
return holder;
|
|
1324
|
+
}
|
|
1325
|
+
async #dispatch(args, context) {
|
|
1326
|
+
const holder = this.#holder(args["holder"]);
|
|
1327
|
+
const name = args["name"];
|
|
1328
|
+
const parameters = args["arguments"];
|
|
1329
|
+
if (!isString(name) || !isRecord(parameters)) throw new BrowserError("execute requires name and arguments", "BROWSER_TOOLSET_ARGUMENT");
|
|
1330
|
+
return this.#forward(holder, name, parameters, context);
|
|
1331
|
+
}
|
|
1332
|
+
async #catalog(args, context) {
|
|
1333
|
+
const holder = this.#holder(args["holder"]);
|
|
1334
|
+
const signal = AbortSignal.any([context.signal, holder.abort.signal]);
|
|
1335
|
+
try {
|
|
1336
|
+
const slot = await this.#serve(holder, signal);
|
|
1337
|
+
signal.throwIfAborted();
|
|
1338
|
+
if (this.#leases.get(holder)?.value !== slot) throw this.#unavailable(this.#losses.get(slot)?.cause);
|
|
1339
|
+
const catalog = {
|
|
1340
|
+
holder: holder.id,
|
|
1341
|
+
tools: slot.toolset.tools.definitions()
|
|
1342
|
+
};
|
|
1343
|
+
return this.#annotate(holder, JSON.stringify(catalog));
|
|
1344
|
+
} catch (error) {
|
|
1345
|
+
context.signal.throwIfAborted();
|
|
1346
|
+
if (holder.abort.signal.aborted) throw new BrowserError(`${BROWSER_SERVER_UNRESOLVED}: the holder ended during the call`, BROWSER_SERVER_UNRESOLVED);
|
|
1347
|
+
if (isBrowserError(error)) throw new BrowserError(this.#annotate(holder, `${error.code}: ${error.message}`), error.code);
|
|
1348
|
+
throw error;
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
async #dispose(args) {
|
|
1352
|
+
const id = args["holder"];
|
|
1353
|
+
await ((isString(id) ? this.#disposals.get(id) : void 0) ?? this.#retire(this.#holder(id)));
|
|
1354
|
+
return "Holder destroyed.";
|
|
1355
|
+
}
|
|
1356
|
+
#retire(holder) {
|
|
1357
|
+
const pending = this.#disposals.get(holder.id);
|
|
1358
|
+
if (pending !== void 0) return pending;
|
|
1359
|
+
holder.abort.abort();
|
|
1360
|
+
const token = this.#leases.get(holder);
|
|
1361
|
+
this.#leases.delete(holder);
|
|
1362
|
+
const disposal = Promise.resolve().then(async () => {
|
|
1363
|
+
try {
|
|
1364
|
+
await this.#grants.get(holder)?.catch(() => void 0);
|
|
1365
|
+
await token?.destroy();
|
|
1366
|
+
await Promise.all(this.#drains.get(holder) ?? []);
|
|
1367
|
+
} catch (error) {
|
|
1368
|
+
this.#faults.add(error);
|
|
1369
|
+
} finally {
|
|
1370
|
+
if (this.#holders.get(holder.id) === holder) this.#holders.delete(holder.id);
|
|
1371
|
+
this.#notices.delete(holder);
|
|
1372
|
+
this.#drains.delete(holder);
|
|
1373
|
+
}
|
|
1374
|
+
});
|
|
1375
|
+
this.#disposals.set(holder.id, disposal);
|
|
1376
|
+
return disposal;
|
|
1377
|
+
}
|
|
1378
|
+
async #forward(holder, name, args, context) {
|
|
1379
|
+
context.signal.throwIfAborted();
|
|
1380
|
+
const journey = args["journey"];
|
|
1381
|
+
if (name !== "replay" && name !== "forget" || !isString(journey)) return this.#perform(holder, name, args, context);
|
|
1382
|
+
if (this.#writers.has(journey) || name === "forget" && this.#readers.has(journey)) throw new BrowserError(`BROWSER_JOURNEY_LOCKED: Journey ${journey} is locked; call ${name} again.`, "BROWSER_JOURNEY_LOCKED", { name: journey });
|
|
1383
|
+
const reader = Symbol(journey);
|
|
1384
|
+
if (name === "forget") this.#writers.add(journey);
|
|
1385
|
+
else {
|
|
1386
|
+
const readers = this.#readers.get(journey) ?? /* @__PURE__ */ new Set();
|
|
1387
|
+
readers.add(reader);
|
|
1388
|
+
this.#readers.set(journey, readers);
|
|
1389
|
+
}
|
|
1390
|
+
try {
|
|
1391
|
+
return await this.#perform(holder, name, args, context);
|
|
1392
|
+
} finally {
|
|
1393
|
+
if (name === "forget") this.#writers.delete(journey);
|
|
1394
|
+
else {
|
|
1395
|
+
const readers = this.#readers.get(journey);
|
|
1396
|
+
readers?.delete(reader);
|
|
1397
|
+
if (readers?.size === 0) this.#readers.delete(journey);
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
async #perform(holder, name, args, context) {
|
|
1402
|
+
const signal = holder === this.#shared ? context.signal : AbortSignal.any([context.signal, holder.abort.signal]);
|
|
1160
1403
|
let slot;
|
|
1161
1404
|
try {
|
|
1162
|
-
slot = await this.#serve(
|
|
1405
|
+
slot = await this.#serve(holder, signal);
|
|
1163
1406
|
} catch (error) {
|
|
1164
1407
|
context.signal.throwIfAborted();
|
|
1165
|
-
if (
|
|
1408
|
+
if (holder !== this.#shared && holder.abort.signal.aborted) throw new BrowserError(`${BROWSER_SERVER_UNRESOLVED}: the holder ended during the call`, BROWSER_SERVER_UNRESOLVED);
|
|
1409
|
+
if (isBrowserError(error)) throw new BrowserError(this.#annotate(holder, `${error.code}: ${error.message}`), error.code);
|
|
1166
1410
|
throw error;
|
|
1167
1411
|
}
|
|
1168
1412
|
let result;
|
|
1169
1413
|
try {
|
|
1170
|
-
|
|
1414
|
+
const execution = slot.toolset.tools.execute({
|
|
1171
1415
|
id: name,
|
|
1172
1416
|
name,
|
|
1173
1417
|
arguments: args
|
|
1174
|
-
},
|
|
1418
|
+
}, {
|
|
1419
|
+
...context,
|
|
1420
|
+
signal
|
|
1421
|
+
});
|
|
1422
|
+
const outcome = await (name === "replay" || name === "forget" ? execution : this.#race(execution, signal));
|
|
1423
|
+
if (outcome === void 0) throw this.#ended();
|
|
1424
|
+
result = outcome;
|
|
1175
1425
|
} catch (error) {
|
|
1176
1426
|
result = {
|
|
1177
1427
|
id: name,
|
|
@@ -1181,28 +1431,27 @@ var BrowserMCPServer = class {
|
|
|
1181
1431
|
};
|
|
1182
1432
|
}
|
|
1183
1433
|
context.signal.throwIfAborted();
|
|
1434
|
+
if (holder !== this.#shared && holder.abort.signal.aborted) throw new BrowserError(BROWSER_SERVER_UNRESOLVED + ": the holder ended during the call", BROWSER_SERVER_UNRESOLVED);
|
|
1184
1435
|
if (!result.success) {
|
|
1185
|
-
if (this.#
|
|
1186
|
-
await
|
|
1187
|
-
} catch
|
|
1188
|
-
if (!context.signal.aborted && !this.#abort.signal.aborted) this.#lose(slot, error);
|
|
1189
|
-
}
|
|
1436
|
+
if (this.#leases.get(holder)?.value === slot && !context.signal.aborted) try {
|
|
1437
|
+
await this.#race(this.#ping(slot), context.signal);
|
|
1438
|
+
} catch {}
|
|
1190
1439
|
context.signal.throwIfAborted();
|
|
1191
|
-
if (this.#
|
|
1440
|
+
if (this.#leases.get(holder)?.value !== slot) {
|
|
1192
1441
|
const loss = this.#losses.get(slot);
|
|
1193
|
-
throw new BrowserError(this.#annotate(describeBrowserServerLoss(BROWSER_SERVER_UNRESOLVED, loss?.cause, loss?.url), slot), BROWSER_SERVER_UNRESOLVED);
|
|
1442
|
+
throw new BrowserError(this.#annotate(holder, describeBrowserServerLoss(BROWSER_SERVER_UNRESOLVED, loss?.cause, loss?.url), slot), BROWSER_SERVER_UNRESOLVED);
|
|
1194
1443
|
}
|
|
1195
|
-
throw new BrowserError(this.#annotate(result.error, slot));
|
|
1444
|
+
throw new BrowserError(this.#annotate(holder, result.error, slot));
|
|
1196
1445
|
}
|
|
1197
|
-
return typeof result.value === "string" ? this.#annotate(result.value, slot) : result.value;
|
|
1446
|
+
return typeof result.value === "string" ? this.#annotate(holder, result.value, slot) : result.value;
|
|
1198
1447
|
}
|
|
1199
|
-
#annotate(value, slot) {
|
|
1448
|
+
#annotate(holder, value, slot) {
|
|
1200
1449
|
const notes = [];
|
|
1201
|
-
for (const lost of this.#
|
|
1450
|
+
for (const lost of this.#notices.get(holder) ?? []) {
|
|
1202
1451
|
if (lost === slot) continue;
|
|
1203
1452
|
const loss = this.#losses.get(lost);
|
|
1204
1453
|
notes.push(describeBrowserServerLoss(BROWSER_SERVER_CRASH, loss?.cause, loss?.url));
|
|
1205
|
-
this.#
|
|
1454
|
+
this.#notices.get(holder)?.delete(lost);
|
|
1206
1455
|
}
|
|
1207
1456
|
return [...notes, value].join("\n");
|
|
1208
1457
|
}
|
|
@@ -1226,52 +1475,66 @@ var BrowserMCPServer = class {
|
|
|
1226
1475
|
listener[Symbol.dispose]();
|
|
1227
1476
|
}
|
|
1228
1477
|
}
|
|
1229
|
-
async #grant(signal) {
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1478
|
+
async #grant(holder, signal) {
|
|
1479
|
+
const held = this.#leases.get(holder);
|
|
1480
|
+
if (held !== void 0) return held;
|
|
1481
|
+
let granting = this.#grants.get(holder);
|
|
1482
|
+
if (granting === void 0) {
|
|
1483
|
+
granting = this.#pool.acquire(holder.abort.signal).then(this.#hold.bind(this, holder));
|
|
1484
|
+
this.#grants.set(holder, granting);
|
|
1485
|
+
granting.finally(() => {
|
|
1486
|
+
if (this.#grants.get(holder) === granting) this.#grants.delete(holder);
|
|
1487
|
+
}).catch(() => void 0);
|
|
1488
|
+
}
|
|
1489
|
+
const token = await this.#race(granting, signal);
|
|
1233
1490
|
if (token === void 0) throw this.#ended();
|
|
1234
1491
|
return token;
|
|
1235
1492
|
}
|
|
1236
|
-
#hold(token) {
|
|
1237
|
-
this.#
|
|
1238
|
-
|
|
1493
|
+
async #hold(holder, token) {
|
|
1494
|
+
if (this.#closing !== void 0 || this.#holders.get(holder.id) !== holder || holder.abort.signal.aborted) {
|
|
1495
|
+
await token.destroy();
|
|
1496
|
+
throw this.#ended();
|
|
1497
|
+
}
|
|
1239
1498
|
if (this.#losses.has(token.value)) {
|
|
1240
|
-
token.destroy().catch(() => void 0);
|
|
1499
|
+
await token.destroy().catch(() => void 0);
|
|
1241
1500
|
throw this.#unavailable(this.#losses.get(token.value)?.cause);
|
|
1242
1501
|
}
|
|
1243
|
-
this.#
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1502
|
+
this.#leases.set(holder, token);
|
|
1503
|
+
if (holder === this.#shared) {
|
|
1504
|
+
const tools = token.value.toolset.tools;
|
|
1505
|
+
const mirrored = {
|
|
1506
|
+
token,
|
|
1507
|
+
added: this.#mirror.bind(this, token),
|
|
1508
|
+
removed: this.#withdraw.bind(this, token),
|
|
1509
|
+
cleared: this.#clear.bind(this, token)
|
|
1510
|
+
};
|
|
1511
|
+
this.#mirrored = mirrored;
|
|
1512
|
+
for (const tool of tools.tools()) this.#mirror(token, tool);
|
|
1513
|
+
tools.emitter.on("add", mirrored.added);
|
|
1514
|
+
tools.emitter.on("remove", mirrored.removed);
|
|
1515
|
+
tools.emitter.on("clear", mirrored.cleared);
|
|
1516
|
+
}
|
|
1249
1517
|
return token;
|
|
1250
1518
|
}
|
|
1251
|
-
#
|
|
1252
|
-
this.#
|
|
1253
|
-
throw error;
|
|
1254
|
-
}
|
|
1255
|
-
async #serve(signal) {
|
|
1256
|
-
if (this.#closing !== void 0) throw this.#ended();
|
|
1519
|
+
async #serve(holder, signal) {
|
|
1520
|
+
if (this.#closing !== void 0 || holder.abort.signal.aborted) throw this.#ended();
|
|
1257
1521
|
await this.#race(this.#starting, signal);
|
|
1258
|
-
if (this.#closing !== void 0) throw this.#ended();
|
|
1259
|
-
const held = this.#
|
|
1522
|
+
if (this.#closing !== void 0 || holder.abort.signal.aborted) throw this.#ended();
|
|
1523
|
+
const held = this.#leases.get(holder);
|
|
1260
1524
|
if (held !== void 0) try {
|
|
1261
|
-
await held.value
|
|
1262
|
-
if (this.#
|
|
1263
|
-
} catch
|
|
1525
|
+
await this.#race(this.#ping(held.value), signal);
|
|
1526
|
+
if (this.#leases.get(holder) === held) return held.value;
|
|
1527
|
+
} catch {
|
|
1264
1528
|
signal.throwIfAborted();
|
|
1265
|
-
if (
|
|
1266
|
-
this.#lose(held.value, error);
|
|
1529
|
+
if (holder.abort.signal.aborted) throw this.#ended();
|
|
1267
1530
|
}
|
|
1268
1531
|
try {
|
|
1269
|
-
const token = await this.#grant(signal);
|
|
1270
|
-
if (this.#
|
|
1532
|
+
const token = await this.#grant(holder, signal);
|
|
1533
|
+
if (this.#leases.get(holder) !== token) throw this.#unavailable(this.#losses.get(token.value)?.cause);
|
|
1271
1534
|
return token.value;
|
|
1272
1535
|
} catch (error) {
|
|
1273
1536
|
signal.throwIfAborted();
|
|
1274
|
-
if (
|
|
1537
|
+
if (holder.abort.signal.aborted || isPoolError(error) && error.code === "destroyed") throw this.#ended();
|
|
1275
1538
|
if (isPoolError(error) && (error.code === "create" || error.code === "cleanup")) {
|
|
1276
1539
|
this.#exhaust(error);
|
|
1277
1540
|
throw this.#unavailable(error.cause ?? this.#failure);
|
|
@@ -1279,6 +1542,15 @@ var BrowserMCPServer = class {
|
|
|
1279
1542
|
throw error;
|
|
1280
1543
|
}
|
|
1281
1544
|
}
|
|
1545
|
+
#ping(slot) {
|
|
1546
|
+
const pending = this.#pings.get(slot);
|
|
1547
|
+
if (pending !== void 0) return pending;
|
|
1548
|
+
const ping = slot.browser.ping({ signal: this.#abort.signal }).catch((error) => {
|
|
1549
|
+
if (!this.#abort.signal.aborted) this.#lose(slot, error);
|
|
1550
|
+
}).finally(() => this.#pings.delete(slot));
|
|
1551
|
+
this.#pings.set(slot, ping);
|
|
1552
|
+
return ping;
|
|
1553
|
+
}
|
|
1282
1554
|
async #validate(slot) {
|
|
1283
1555
|
try {
|
|
1284
1556
|
await slot.browser.ping({ signal: this.#abort.signal });
|
|
@@ -1295,12 +1567,19 @@ var BrowserMCPServer = class {
|
|
|
1295
1567
|
url: slot.toolset.view.url
|
|
1296
1568
|
});
|
|
1297
1569
|
this.#failure = cause;
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1570
|
+
for (const [holder, token] of this.#leases) {
|
|
1571
|
+
if (token.value !== slot || this.#holders.get(holder.id) !== holder) continue;
|
|
1572
|
+
if (holder === this.#shared) this.#unmirror();
|
|
1573
|
+
this.#leases.delete(holder);
|
|
1574
|
+
const notices = this.#notices.get(holder) ?? /* @__PURE__ */ new Set();
|
|
1575
|
+
notices.add(slot);
|
|
1576
|
+
this.#notices.set(holder, notices);
|
|
1577
|
+
const drain = token.destroy();
|
|
1578
|
+
const drains = this.#drains.get(holder) ?? /* @__PURE__ */ new Set();
|
|
1579
|
+
drains.add(drain);
|
|
1580
|
+
this.#drains.set(holder, drains);
|
|
1581
|
+
drain.finally(() => drains.delete(drain)).catch(() => void 0);
|
|
1582
|
+
}
|
|
1304
1583
|
}
|
|
1305
1584
|
#watch(slot, signal) {
|
|
1306
1585
|
const loss = Promise.withResolvers();
|
|
@@ -1373,6 +1652,7 @@ var BrowserMCPServer = class {
|
|
|
1373
1652
|
cdp: { discover: false },
|
|
1374
1653
|
signal: this.#abort.signal,
|
|
1375
1654
|
...this.#executable === void 0 ? {} : { executable: this.#executable },
|
|
1655
|
+
...this.#viewport === void 0 ? {} : { viewport: this.#viewport },
|
|
1376
1656
|
...process.platform === "linux" && process.getuid?.() === 0 ? { args: ["--no-sandbox"] } : {}
|
|
1377
1657
|
});
|
|
1378
1658
|
await browser.connect();
|
|
@@ -1384,7 +1664,11 @@ var BrowserMCPServer = class {
|
|
|
1384
1664
|
}));
|
|
1385
1665
|
await rename(`${record}.tmp`, record);
|
|
1386
1666
|
}
|
|
1387
|
-
const context = await browser.isolate({
|
|
1667
|
+
const context = await browser.isolate({
|
|
1668
|
+
reference: this.#reference,
|
|
1669
|
+
downloads: { path: join(profile, "downloads") },
|
|
1670
|
+
...this.#viewport === void 0 ? {} : { emulation: { viewport: this.#viewport } }
|
|
1671
|
+
});
|
|
1388
1672
|
const page = await context.create();
|
|
1389
1673
|
toolset = createBrowserToolset(page, {
|
|
1390
1674
|
context,
|
|
@@ -1491,29 +1775,31 @@ var BrowserMCPServer = class {
|
|
|
1491
1775
|
#issue() {
|
|
1492
1776
|
return `e${++this.#references}`;
|
|
1493
1777
|
}
|
|
1494
|
-
#mirror(tool) {
|
|
1495
|
-
if (this.#vocabulary.has(tool.name)) return;
|
|
1778
|
+
#mirror(token, tool) {
|
|
1779
|
+
if (this.#leases.get(this.#shared) !== token || this.#vocabulary.has(tool.name)) return;
|
|
1496
1780
|
this.#tools.add(createTool({
|
|
1497
1781
|
...toolToDefinition(tool),
|
|
1498
|
-
execute: this.#forward.bind(this, tool.name)
|
|
1782
|
+
execute: this.#forward.bind(this, this.#shared, tool.name)
|
|
1499
1783
|
}));
|
|
1500
1784
|
}
|
|
1501
|
-
#withdraw(tool) {
|
|
1502
|
-
if (this.#vocabulary.has(tool.name)) return;
|
|
1503
|
-
const current =
|
|
1785
|
+
#withdraw(token, tool) {
|
|
1786
|
+
if (this.#leases.get(this.#shared) !== token || this.#vocabulary.has(tool.name)) return;
|
|
1787
|
+
const current = token.value.toolset.tools.tool(tool.name);
|
|
1504
1788
|
if (current === void 0) this.#tools.remove(tool.name);
|
|
1505
|
-
else this.#mirror(current);
|
|
1789
|
+
else this.#mirror(token, current);
|
|
1506
1790
|
}
|
|
1507
|
-
#clear(tools) {
|
|
1508
|
-
for (const tool of tools) this.#withdraw(tool);
|
|
1791
|
+
#clear(token, tools) {
|
|
1792
|
+
for (const tool of tools) this.#withdraw(token, tool);
|
|
1509
1793
|
}
|
|
1510
1794
|
#unmirror() {
|
|
1511
|
-
const mirrored = this.#
|
|
1795
|
+
const mirrored = this.#mirrored;
|
|
1512
1796
|
if (mirrored === void 0) return;
|
|
1513
|
-
|
|
1514
|
-
mirrored.
|
|
1515
|
-
|
|
1516
|
-
|
|
1797
|
+
this.#mirrored = void 0;
|
|
1798
|
+
const tools = mirrored.token.value.toolset.tools;
|
|
1799
|
+
for (const tool of tools.tools()) if (!this.#vocabulary.has(tool.name)) this.#tools.remove(tool.name);
|
|
1800
|
+
tools.emitter.off("add", mirrored.added);
|
|
1801
|
+
tools.emitter.off("remove", mirrored.removed);
|
|
1802
|
+
tools.emitter.off("clear", mirrored.cleared);
|
|
1517
1803
|
}
|
|
1518
1804
|
#ended() {
|
|
1519
1805
|
return new BrowserError("the browser session ended", "BROWSER_TOOLSET_ENDED");
|
|
@@ -1951,6 +2237,24 @@ var FileBrowserRunStore = class {
|
|
|
1951
2237
|
constructor(options) {
|
|
1952
2238
|
this.#files = new FileBrowserStore(options);
|
|
1953
2239
|
}
|
|
2240
|
+
async snapshot(bytes, options) {
|
|
2241
|
+
options?.signal?.throwIfAborted();
|
|
2242
|
+
const owned = new Uint8Array(bytes);
|
|
2243
|
+
const directory = await this.#files.allocate(this.#files.resolvePath(BROWSER_RUN_DIRECTORY), generateBrowserRunId, options);
|
|
2244
|
+
const path = this.#files.resolvePath(directory.path, "view.png");
|
|
2245
|
+
try {
|
|
2246
|
+
await this.#files.check(path, options);
|
|
2247
|
+
options?.signal?.throwIfAborted();
|
|
2248
|
+
await writeFile(path, owned, {
|
|
2249
|
+
flag: "wx",
|
|
2250
|
+
signal: options?.signal
|
|
2251
|
+
});
|
|
2252
|
+
return path;
|
|
2253
|
+
} catch (error) {
|
|
2254
|
+
options?.signal?.throwIfAborted();
|
|
2255
|
+
throw this.#files.translateError(path, error);
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
1954
2258
|
async open(name, options) {
|
|
1955
2259
|
options?.signal?.throwIfAborted();
|
|
1956
2260
|
this.#files.validateName(name);
|
|
@@ -2981,6 +3285,6 @@ var Browser = class {
|
|
|
2981
3285
|
}
|
|
2982
3286
|
};
|
|
2983
3287
|
//#endregion
|
|
2984
|
-
export { BROWSER_CDP_LIST_PATH, BROWSER_CDP_PROTOCOL, BROWSER_CDP_VERSION_PATH, BROWSER_DEFAULT_CDP_PORT, BROWSER_DEFAULT_HOST, BROWSER_DEVTOOLS_PATTERN, BROWSER_DRAIN_INTERVAL_MS, BROWSER_ENGINE_HINTS, BROWSER_ENV_PATH_KEYS, BROWSER_EXECUTABLE_NAMES, BROWSER_EXECUTABLE_PATHS, BROWSER_FILE_STORE_LIMIT, BROWSER_HEADLESS_ARG, BROWSER_JOURNEY_LOCK_ATTEMPTS, BROWSER_JOURNEY_LOCK_DIRECTORY, BROWSER_JOURNEY_REVISION_FILE, BROWSER_JOURNEY_SNAPSHOT_FILE, BROWSER_KILL_GRACE_MS, BROWSER_LAUNCH_ARGS, BROWSER_PORT_PROBE_TIMEOUT_MS, BROWSER_PROCESS_EXIT_CAUSE, BROWSER_PROFILE_PREFIX, BROWSER_RUN_DIRECTORY, BROWSER_RUN_FILE, BROWSER_SERVER_CRASH, BROWSER_SERVER_EXHAUSTED, BROWSER_SERVER_LAUNCH, BROWSER_SERVER_OPTIONS, BROWSER_SERVER_POOL_LIMIT, BROWSER_SERVER_POOL_SIZE, BROWSER_SERVER_RECORD, BROWSER_SERVER_RESTARTS, BROWSER_SERVER_SWEEP, BROWSER_SERVER_TEARDOWN, BROWSER_SERVER_UNAVAILABLE, BROWSER_SERVER_UNRESOLVED, BROWSER_STORE_CACHE_DIRS, BROWSER_STORE_DEFAULT_DIRS, BROWSER_STORE_ENV_KEY, BROWSER_STORE_GLOBS, BROWSER_STORE_LINK_NAME, BROWSER_TRANSPORT_LOSS_CAUSE, BROWSER_TRANSPORT_LOSS_DEFER_MS, BROWSER_WINDOWS_ROOT_FALLBACKS, BROWSER_WINDOWS_SUFFIXES, Browser, BrowserDestroyedError, BrowserMCPServer, BrowserNotConnectedError, FileBrowserJourneyStore, FileBrowserRunStore, FileBrowserWriter, WebSocketCDPTransport, browserToEngine, buildInstallPaths, buildStoreBases, buildWindowsRoots, createBrowser, createBrowserMCPServer, createBrowserProfile, createBrowserWriter, createCDPTransport, createFileBrowserJourneyStore, createFileBrowserRunStore, describeBrowserServerLoss, fetchCDPTargets, findEnvOverrides, findInstallPaths, findStorePaths, findSystemBrowser, findSystemBrowsers, formatBrowserLockEntry, isBrowserDestroyedError, isBrowserNotConnectedError, launchBrowserProcess, normalizeExecutablePath, parseBrowserEngine, parseBrowserLockEntry, parseBrowserProfileRecord, probePathNames, probeProcess, readBrowserEndpoint, readFirstLine, removeBrowserProfile };
|
|
3288
|
+
export { BROWSER_CDP_LIST_PATH, BROWSER_CDP_PROTOCOL, BROWSER_CDP_VERSION_PATH, BROWSER_DEFAULT_CDP_PORT, BROWSER_DEFAULT_HOST, BROWSER_DEVTOOLS_PATTERN, BROWSER_DRAIN_INTERVAL_MS, BROWSER_ENGINE_HINTS, BROWSER_ENV_PATH_KEYS, BROWSER_EXECUTABLE_NAMES, BROWSER_EXECUTABLE_PATHS, BROWSER_FILE_STORE_LIMIT, BROWSER_HEADLESS_ARG, BROWSER_JOURNEY_LOCK_ATTEMPTS, BROWSER_JOURNEY_LOCK_DIRECTORY, BROWSER_JOURNEY_REVISION_FILE, BROWSER_JOURNEY_SNAPSHOT_FILE, BROWSER_KILL_GRACE_MS, BROWSER_LAUNCH_ARGS, BROWSER_PORT_PROBE_TIMEOUT_MS, BROWSER_PROCESS_EXIT_CAUSE, BROWSER_PROFILE_PREFIX, BROWSER_RUN_DIRECTORY, BROWSER_RUN_FILE, BROWSER_SERVER_BUSY, BROWSER_SERVER_COPY, BROWSER_SERVER_CRASH, BROWSER_SERVER_EXHAUSTED, BROWSER_SERVER_HOLDER, BROWSER_SERVER_LAUNCH, BROWSER_SERVER_OPTIONS, BROWSER_SERVER_POOL_LIMIT, BROWSER_SERVER_POOL_SIZE, BROWSER_SERVER_RECORD, BROWSER_SERVER_RESTARTS, BROWSER_SERVER_SWEEP, BROWSER_SERVER_TEARDOWN, BROWSER_SERVER_UNAVAILABLE, BROWSER_SERVER_UNRESOLVED, BROWSER_STORE_CACHE_DIRS, BROWSER_STORE_DEFAULT_DIRS, BROWSER_STORE_ENV_KEY, BROWSER_STORE_GLOBS, BROWSER_STORE_LINK_NAME, BROWSER_TRANSPORT_LOSS_CAUSE, BROWSER_TRANSPORT_LOSS_DEFER_MS, BROWSER_WINDOWS_ROOT_FALLBACKS, BROWSER_WINDOWS_SUFFIXES, Browser, BrowserDestroyedError, BrowserMCPServer, BrowserNotConnectedError, FileBrowserJourneyStore, FileBrowserRunStore, FileBrowserWriter, WebSocketCDPTransport, browserToEngine, buildInstallPaths, buildStoreBases, buildWindowsRoots, createBrowser, createBrowserMCPServer, createBrowserProfile, createBrowserWriter, createCDPTransport, createFileBrowserJourneyStore, createFileBrowserRunStore, describeBrowserServerLoss, fetchCDPTargets, findEnvOverrides, findInstallPaths, findStorePaths, findSystemBrowser, findSystemBrowsers, formatBrowserLockEntry, isBrowserDestroyedError, isBrowserNotConnectedError, launchBrowserProcess, normalizeExecutablePath, parseBrowserEngine, parseBrowserLockEntry, parseBrowserProfileRecord, parseBrowserViewport, probePathNames, probeProcess, readBrowserEndpoint, readFirstLine, removeBrowserProfile };
|
|
2985
3289
|
|
|
2986
3290
|
//# sourceMappingURL=index.js.map
|