@agenticmail/enterprise 0.5.430 → 0.5.432

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.
@@ -0,0 +1,615 @@
1
+ import {
2
+ getPwAiModule,
3
+ movePathToTrash,
4
+ resolveBrowserConfig,
5
+ resolveProfile
6
+ } from "./chunk-EEQPXSY5.js";
7
+ import {
8
+ InvalidBrowserNavigationUrlError,
9
+ appendCdpPath,
10
+ assertBrowserNavigationAllowed,
11
+ createTargetViaCdp,
12
+ ensureChromeExtensionRelayServer,
13
+ fetchJson,
14
+ fetchOk,
15
+ isChromeCdpReady,
16
+ isChromeReachable,
17
+ launchAgenticMailChrome,
18
+ normalizeCdpWsUrl,
19
+ resolveAgenticMailUserDataDir,
20
+ stopAgenticMailChrome,
21
+ stopChromeExtensionRelayServer,
22
+ withBrowserNavigationPolicy
23
+ } from "./chunk-MCZNCJQ2.js";
24
+ import {
25
+ SsrFBlockedError,
26
+ createConfigIO,
27
+ loadConfig
28
+ } from "./chunk-A3PUJDNH.js";
29
+
30
+ // src/browser/server-context.ts
31
+ import fs from "fs";
32
+
33
+ // src/browser/resolved-config-refresh.ts
34
+ function applyResolvedConfig(current, freshResolved) {
35
+ current.resolved = freshResolved;
36
+ for (const [name, runtime] of current.profiles) {
37
+ const nextProfile = resolveProfile(freshResolved, name);
38
+ if (nextProfile) {
39
+ runtime.profile = nextProfile;
40
+ continue;
41
+ }
42
+ if (!runtime.running) {
43
+ current.profiles.delete(name);
44
+ }
45
+ }
46
+ }
47
+ function refreshResolvedBrowserConfigFromDisk(params) {
48
+ if (!params.refreshConfigFromDisk) {
49
+ return;
50
+ }
51
+ const cfg = params.mode === "fresh" ? createConfigIO().load() : loadConfig();
52
+ const freshResolved = resolveBrowserConfig(cfg.browser, cfg);
53
+ applyResolvedConfig(params.current, freshResolved);
54
+ }
55
+ function resolveBrowserProfileWithHotReload(params) {
56
+ refreshResolvedBrowserConfigFromDisk({
57
+ current: params.current,
58
+ refreshConfigFromDisk: params.refreshConfigFromDisk,
59
+ mode: "cached"
60
+ });
61
+ let profile = resolveProfile(params.current.resolved, params.name);
62
+ if (profile) {
63
+ return profile;
64
+ }
65
+ refreshResolvedBrowserConfigFromDisk({
66
+ current: params.current,
67
+ refreshConfigFromDisk: params.refreshConfigFromDisk,
68
+ mode: "fresh"
69
+ });
70
+ profile = resolveProfile(params.current.resolved, params.name);
71
+ return profile;
72
+ }
73
+
74
+ // src/browser/target-id.ts
75
+ function resolveTargetIdFromTabs(input, tabs) {
76
+ const needle = input.trim();
77
+ if (!needle) {
78
+ return { ok: false, reason: "not_found" };
79
+ }
80
+ const exact = tabs.find((t) => t.targetId === needle);
81
+ if (exact) {
82
+ return { ok: true, targetId: exact.targetId };
83
+ }
84
+ const lower = needle.toLowerCase();
85
+ const matches = tabs.map((t) => t.targetId).filter((id) => id.toLowerCase().startsWith(lower));
86
+ const only = matches.length === 1 ? matches[0] : void 0;
87
+ if (only) {
88
+ return { ok: true, targetId: only };
89
+ }
90
+ if (matches.length === 0) {
91
+ return { ok: false, reason: "not_found" };
92
+ }
93
+ return { ok: false, reason: "ambiguous", matches };
94
+ }
95
+
96
+ // src/browser/server-context.ts
97
+ function listKnownProfileNames(state) {
98
+ const names = new Set(Object.keys(state.resolved.profiles));
99
+ for (const name of state.profiles.keys()) {
100
+ names.add(name);
101
+ }
102
+ return [...names];
103
+ }
104
+ function normalizeWsUrl(raw, cdpBaseUrl) {
105
+ if (!raw) {
106
+ return void 0;
107
+ }
108
+ try {
109
+ return normalizeCdpWsUrl(raw, cdpBaseUrl);
110
+ } catch {
111
+ return raw;
112
+ }
113
+ }
114
+ function createProfileContext(opts, profile) {
115
+ const state = () => {
116
+ const current = opts.getState();
117
+ if (!current) {
118
+ throw new Error("Browser server not started");
119
+ }
120
+ return current;
121
+ };
122
+ const getProfileState = () => {
123
+ const current = state();
124
+ let profileState = current.profiles.get(profile.name);
125
+ if (!profileState) {
126
+ profileState = { profile, running: null, lastTargetId: null };
127
+ current.profiles.set(profile.name, profileState);
128
+ }
129
+ return profileState;
130
+ };
131
+ const setProfileRunning = (running) => {
132
+ const profileState = getProfileState();
133
+ profileState.running = running;
134
+ };
135
+ const listTabs = async () => {
136
+ if (!profile.cdpIsLoopback) {
137
+ const mod = await getPwAiModule({ mode: "strict" });
138
+ const listPagesViaPlaywright = mod?.listPagesViaPlaywright;
139
+ if (typeof listPagesViaPlaywright === "function") {
140
+ const pages = await listPagesViaPlaywright({ cdpUrl: profile.cdpUrl });
141
+ return pages.map((p) => ({
142
+ targetId: p.targetId,
143
+ title: p.title,
144
+ url: p.url,
145
+ type: p.type
146
+ }));
147
+ }
148
+ }
149
+ const raw = await fetchJson(appendCdpPath(profile.cdpUrl, "/json/list"));
150
+ return raw.map((t) => ({
151
+ targetId: t.id ?? "",
152
+ title: t.title ?? "",
153
+ url: t.url ?? "",
154
+ wsUrl: normalizeWsUrl(t.webSocketDebuggerUrl, profile.cdpUrl),
155
+ type: t.type
156
+ })).filter((t) => Boolean(t.targetId));
157
+ };
158
+ const openTab = async (url) => {
159
+ const ssrfPolicyOpts = withBrowserNavigationPolicy(state().resolved.ssrfPolicy);
160
+ await assertBrowserNavigationAllowed({ url, ...ssrfPolicyOpts });
161
+ if (!profile.cdpIsLoopback) {
162
+ const mod = await getPwAiModule({ mode: "strict" });
163
+ const createPageViaPlaywright = mod?.createPageViaPlaywright;
164
+ if (typeof createPageViaPlaywright === "function") {
165
+ const page = await createPageViaPlaywright({
166
+ cdpUrl: profile.cdpUrl,
167
+ url,
168
+ ...ssrfPolicyOpts,
169
+ navigationChecked: true
170
+ });
171
+ const profileState2 = getProfileState();
172
+ profileState2.lastTargetId = page.targetId;
173
+ return {
174
+ targetId: page.targetId,
175
+ title: page.title,
176
+ url: page.url,
177
+ type: page.type
178
+ };
179
+ }
180
+ }
181
+ const createdViaCdp = await createTargetViaCdp({
182
+ cdpUrl: profile.cdpUrl,
183
+ url,
184
+ ...ssrfPolicyOpts,
185
+ navigationChecked: true
186
+ }).then((r) => r.targetId).catch(() => null);
187
+ if (createdViaCdp) {
188
+ const profileState2 = getProfileState();
189
+ profileState2.lastTargetId = createdViaCdp;
190
+ const deadline = Date.now() + 2e3;
191
+ while (Date.now() < deadline) {
192
+ const tabs = await listTabs().catch(() => []);
193
+ const found = tabs.find((t) => t.targetId === createdViaCdp);
194
+ if (found) {
195
+ return found;
196
+ }
197
+ await new Promise((r) => setTimeout(r, 100));
198
+ }
199
+ return { targetId: createdViaCdp, title: "", url, type: "page" };
200
+ }
201
+ const encoded = encodeURIComponent(url);
202
+ const endpointUrl = new URL(appendCdpPath(profile.cdpUrl, "/json/new"));
203
+ const endpoint = endpointUrl.search ? (() => {
204
+ endpointUrl.searchParams.set("url", url);
205
+ return endpointUrl.toString();
206
+ })() : `${endpointUrl.toString()}?${encoded}`;
207
+ const created = await fetchJson(endpoint, 1500, {
208
+ method: "PUT"
209
+ }).catch(async (err) => {
210
+ if (String(err).includes("HTTP 405")) {
211
+ return await fetchJson(endpoint, 1500);
212
+ }
213
+ throw err;
214
+ });
215
+ if (!created.id) {
216
+ throw new Error("Failed to open tab (missing id)");
217
+ }
218
+ const profileState = getProfileState();
219
+ profileState.lastTargetId = created.id;
220
+ return {
221
+ targetId: created.id,
222
+ title: created.title ?? "",
223
+ url: created.url ?? url,
224
+ wsUrl: normalizeWsUrl(created.webSocketDebuggerUrl, profile.cdpUrl),
225
+ type: created.type
226
+ };
227
+ };
228
+ const resolveRemoteHttpTimeout = (timeoutMs) => {
229
+ if (profile.cdpIsLoopback) {
230
+ return timeoutMs ?? 300;
231
+ }
232
+ const resolved = state().resolved;
233
+ if (typeof timeoutMs === "number" && Number.isFinite(timeoutMs)) {
234
+ return Math.max(Math.floor(timeoutMs), resolved.remoteCdpTimeoutMs);
235
+ }
236
+ return resolved.remoteCdpTimeoutMs;
237
+ };
238
+ const resolveRemoteWsTimeout = (timeoutMs) => {
239
+ if (profile.cdpIsLoopback) {
240
+ const base = timeoutMs ?? 300;
241
+ return Math.max(200, Math.min(2e3, base * 2));
242
+ }
243
+ const resolved = state().resolved;
244
+ if (typeof timeoutMs === "number" && Number.isFinite(timeoutMs)) {
245
+ return Math.max(Math.floor(timeoutMs) * 2, resolved.remoteCdpHandshakeTimeoutMs);
246
+ }
247
+ return resolved.remoteCdpHandshakeTimeoutMs;
248
+ };
249
+ const isReachable = async (timeoutMs) => {
250
+ const httpTimeout = resolveRemoteHttpTimeout(timeoutMs);
251
+ const wsTimeout = resolveRemoteWsTimeout(timeoutMs);
252
+ return await isChromeCdpReady(profile.cdpUrl, httpTimeout, wsTimeout);
253
+ };
254
+ const isHttpReachable = async (timeoutMs) => {
255
+ const httpTimeout = resolveRemoteHttpTimeout(timeoutMs);
256
+ return await isChromeReachable(profile.cdpUrl, httpTimeout);
257
+ };
258
+ const attachRunning = (running) => {
259
+ setProfileRunning(running);
260
+ running.proc.on("exit", () => {
261
+ if (!opts.getState()) {
262
+ return;
263
+ }
264
+ const profileState = getProfileState();
265
+ if (profileState.running?.pid === running.pid) {
266
+ setProfileRunning(null);
267
+ }
268
+ });
269
+ };
270
+ const ensureBrowserAvailable = async () => {
271
+ const current = state();
272
+ const remoteCdp = !profile.cdpIsLoopback;
273
+ const isExtension = profile.driver === "extension";
274
+ const profileState = getProfileState();
275
+ const httpReachable = await isHttpReachable();
276
+ if (isExtension && remoteCdp) {
277
+ throw new Error(
278
+ `Profile "${profile.name}" uses driver=extension but cdpUrl is not loopback (${profile.cdpUrl}).`
279
+ );
280
+ }
281
+ if (isExtension) {
282
+ if (!httpReachable) {
283
+ await ensureChromeExtensionRelayServer({ cdpUrl: profile.cdpUrl });
284
+ if (await isHttpReachable(1200)) {
285
+ } else {
286
+ throw new Error(
287
+ `Chrome extension relay for profile "${profile.name}" is not reachable at ${profile.cdpUrl}.`
288
+ );
289
+ }
290
+ }
291
+ if (await isReachable(600)) {
292
+ return;
293
+ }
294
+ throw new Error(
295
+ `Chrome extension relay is running, but no tab is connected. Click the AgenticMail Chrome extension icon on a tab to attach it (profile "${profile.name}").`
296
+ );
297
+ }
298
+ if (!httpReachable) {
299
+ if ((current.resolved.attachOnly || remoteCdp) && opts.onEnsureAttachTarget) {
300
+ await opts.onEnsureAttachTarget(profile);
301
+ if (await isHttpReachable(1200)) {
302
+ return;
303
+ }
304
+ }
305
+ if (current.resolved.attachOnly || remoteCdp) {
306
+ throw new Error(
307
+ remoteCdp ? `Remote CDP for profile "${profile.name}" is not reachable at ${profile.cdpUrl}.` : `Browser attachOnly is enabled and profile "${profile.name}" is not running.`
308
+ );
309
+ }
310
+ const launched = await launchAgenticMailChrome(current.resolved, profile);
311
+ attachRunning(launched);
312
+ return;
313
+ }
314
+ if (await isReachable()) {
315
+ return;
316
+ }
317
+ if (!profileState.running) {
318
+ throw new Error(
319
+ `Port ${profile.cdpPort} is in use for profile "${profile.name}" but not by agenticmail. Run action=reset-profile profile=${profile.name} to kill the process.`
320
+ );
321
+ }
322
+ if (current.resolved.attachOnly || remoteCdp) {
323
+ if (opts.onEnsureAttachTarget) {
324
+ await opts.onEnsureAttachTarget(profile);
325
+ if (await isReachable(1200)) {
326
+ return;
327
+ }
328
+ }
329
+ throw new Error(
330
+ remoteCdp ? `Remote CDP websocket for profile "${profile.name}" is not reachable.` : `Browser attachOnly is enabled and CDP websocket for profile "${profile.name}" is not reachable.`
331
+ );
332
+ }
333
+ await stopAgenticMailChrome(profileState.running);
334
+ setProfileRunning(null);
335
+ const relaunched = await launchAgenticMailChrome(current.resolved, profile);
336
+ attachRunning(relaunched);
337
+ if (!await isReachable(600)) {
338
+ throw new Error(
339
+ `Chrome CDP websocket for profile "${profile.name}" is not reachable after restart.`
340
+ );
341
+ }
342
+ };
343
+ const ensureTabAvailable = async (targetId) => {
344
+ await ensureBrowserAvailable();
345
+ const profileState = getProfileState();
346
+ const tabs1 = await listTabs();
347
+ if (tabs1.length === 0) {
348
+ if (profile.driver === "extension") {
349
+ throw new Error(
350
+ `tab not found (no attached Chrome tabs for profile "${profile.name}"). Click the AgenticMail Browser Relay toolbar icon on the tab you want to control (badge ON).`
351
+ );
352
+ }
353
+ await openTab("about:blank");
354
+ }
355
+ const tabs = await listTabs();
356
+ const candidates = profile.driver === "extension" || !profile.cdpIsLoopback ? tabs : tabs.filter((t) => Boolean(t.wsUrl));
357
+ const resolveById = (raw) => {
358
+ const resolved = resolveTargetIdFromTabs(raw, candidates);
359
+ if (!resolved.ok) {
360
+ if (resolved.reason === "ambiguous") {
361
+ return "AMBIGUOUS";
362
+ }
363
+ return null;
364
+ }
365
+ return candidates.find((t) => t.targetId === resolved.targetId) ?? null;
366
+ };
367
+ const pickDefault = () => {
368
+ const last = profileState.lastTargetId?.trim() || "";
369
+ const lastResolved = last ? resolveById(last) : null;
370
+ if (lastResolved && lastResolved !== "AMBIGUOUS") {
371
+ return lastResolved;
372
+ }
373
+ const page = candidates.find((t) => (t.type ?? "page") === "page");
374
+ return page ?? candidates.at(0) ?? null;
375
+ };
376
+ let chosen = targetId ? resolveById(targetId) : pickDefault();
377
+ if (!chosen && profile.driver === "extension" && candidates.length === 1) {
378
+ chosen = candidates[0] ?? null;
379
+ }
380
+ if (chosen === "AMBIGUOUS") {
381
+ throw new Error("ambiguous target id prefix");
382
+ }
383
+ if (!chosen) {
384
+ throw new Error("tab not found");
385
+ }
386
+ profileState.lastTargetId = chosen.targetId;
387
+ return chosen;
388
+ };
389
+ const focusTab = async (targetId) => {
390
+ const tabs = await listTabs();
391
+ const resolved = resolveTargetIdFromTabs(targetId, tabs);
392
+ if (!resolved.ok) {
393
+ if (resolved.reason === "ambiguous") {
394
+ throw new Error("ambiguous target id prefix");
395
+ }
396
+ throw new Error("tab not found");
397
+ }
398
+ if (!profile.cdpIsLoopback) {
399
+ const mod = await getPwAiModule({ mode: "strict" });
400
+ const focusPageByTargetIdViaPlaywright = mod?.focusPageByTargetIdViaPlaywright;
401
+ if (typeof focusPageByTargetIdViaPlaywright === "function") {
402
+ await focusPageByTargetIdViaPlaywright({
403
+ cdpUrl: profile.cdpUrl,
404
+ targetId: resolved.targetId
405
+ });
406
+ const profileState2 = getProfileState();
407
+ profileState2.lastTargetId = resolved.targetId;
408
+ return;
409
+ }
410
+ }
411
+ await fetchOk(appendCdpPath(profile.cdpUrl, `/json/activate/${resolved.targetId}`));
412
+ const profileState = getProfileState();
413
+ profileState.lastTargetId = resolved.targetId;
414
+ };
415
+ const closeTab = async (targetId) => {
416
+ const tabs = await listTabs();
417
+ const resolved = resolveTargetIdFromTabs(targetId, tabs);
418
+ if (!resolved.ok) {
419
+ if (resolved.reason === "ambiguous") {
420
+ throw new Error("ambiguous target id prefix");
421
+ }
422
+ throw new Error("tab not found");
423
+ }
424
+ if (!profile.cdpIsLoopback) {
425
+ const mod = await getPwAiModule({ mode: "strict" });
426
+ const closePageByTargetIdViaPlaywright = mod?.closePageByTargetIdViaPlaywright;
427
+ if (typeof closePageByTargetIdViaPlaywright === "function") {
428
+ await closePageByTargetIdViaPlaywright({
429
+ cdpUrl: profile.cdpUrl,
430
+ targetId: resolved.targetId
431
+ });
432
+ return;
433
+ }
434
+ }
435
+ await fetchOk(appendCdpPath(profile.cdpUrl, `/json/close/${resolved.targetId}`));
436
+ };
437
+ const stopRunningBrowser = async () => {
438
+ if (profile.driver === "extension") {
439
+ const stopped = await stopChromeExtensionRelayServer({
440
+ cdpUrl: profile.cdpUrl
441
+ });
442
+ return { stopped };
443
+ }
444
+ const profileState = getProfileState();
445
+ if (!profileState.running) {
446
+ return { stopped: false };
447
+ }
448
+ await stopAgenticMailChrome(profileState.running);
449
+ setProfileRunning(null);
450
+ return { stopped: true };
451
+ };
452
+ const resetProfile = async () => {
453
+ if (profile.driver === "extension") {
454
+ await stopChromeExtensionRelayServer({ cdpUrl: profile.cdpUrl }).catch(() => {
455
+ });
456
+ return { moved: false, from: profile.cdpUrl };
457
+ }
458
+ if (!profile.cdpIsLoopback) {
459
+ throw new Error(
460
+ `reset-profile is only supported for local profiles (profile "${profile.name}" is remote).`
461
+ );
462
+ }
463
+ const userDataDir = resolveAgenticMailUserDataDir(profile.name);
464
+ const profileState = getProfileState();
465
+ const httpReachable = await isHttpReachable(300);
466
+ if (httpReachable && !profileState.running) {
467
+ try {
468
+ const mod = await import("./pw-ai-UQSZWCVQ.js");
469
+ await mod.closePlaywrightBrowserConnection();
470
+ } catch {
471
+ }
472
+ }
473
+ if (profileState.running) {
474
+ await stopRunningBrowser();
475
+ }
476
+ try {
477
+ const mod = await import("./pw-ai-UQSZWCVQ.js");
478
+ await mod.closePlaywrightBrowserConnection();
479
+ } catch {
480
+ }
481
+ if (!fs.existsSync(userDataDir)) {
482
+ return { moved: false, from: userDataDir };
483
+ }
484
+ const moved = await movePathToTrash(userDataDir);
485
+ return { moved: true, from: userDataDir, to: moved };
486
+ };
487
+ return {
488
+ profile,
489
+ ensureBrowserAvailable,
490
+ ensureTabAvailable,
491
+ isHttpReachable,
492
+ isReachable,
493
+ listTabs,
494
+ openTab,
495
+ focusTab,
496
+ closeTab,
497
+ stopRunningBrowser,
498
+ resetProfile
499
+ };
500
+ }
501
+ function createBrowserRouteContext(opts) {
502
+ const refreshConfigFromDisk = opts.refreshConfigFromDisk === true;
503
+ const state = () => {
504
+ const current = opts.getState();
505
+ if (!current) {
506
+ throw new Error("Browser server not started");
507
+ }
508
+ return current;
509
+ };
510
+ const forProfile = (profileName) => {
511
+ const current = state();
512
+ const name = profileName ?? current.resolved.defaultProfile;
513
+ const profile = resolveBrowserProfileWithHotReload({
514
+ current,
515
+ refreshConfigFromDisk,
516
+ name
517
+ });
518
+ if (!profile) {
519
+ const available = Object.keys(current.resolved.profiles).join(", ");
520
+ throw new Error(`Profile "${name}" not found. Available profiles: ${available || "(none)"}`);
521
+ }
522
+ return createProfileContext(opts, profile);
523
+ };
524
+ const listProfiles = async () => {
525
+ const current = state();
526
+ refreshResolvedBrowserConfigFromDisk({
527
+ current,
528
+ refreshConfigFromDisk,
529
+ mode: "cached"
530
+ });
531
+ const result = [];
532
+ for (const name of Object.keys(current.resolved.profiles)) {
533
+ const profileState = current.profiles.get(name);
534
+ const profile = resolveProfile(current.resolved, name);
535
+ if (!profile) {
536
+ continue;
537
+ }
538
+ let tabCount = 0;
539
+ let running = false;
540
+ if (profileState?.running) {
541
+ running = true;
542
+ try {
543
+ const ctx = createProfileContext(opts, profile);
544
+ const tabs = await ctx.listTabs();
545
+ tabCount = tabs.filter((t) => t.type === "page").length;
546
+ } catch {
547
+ }
548
+ } else {
549
+ try {
550
+ const reachable = await isChromeReachable(profile.cdpUrl, 200);
551
+ if (reachable) {
552
+ running = true;
553
+ const ctx = createProfileContext(opts, profile);
554
+ const tabs = await ctx.listTabs().catch(() => []);
555
+ tabCount = tabs.filter((t) => t.type === "page").length;
556
+ }
557
+ } catch {
558
+ }
559
+ }
560
+ result.push({
561
+ name,
562
+ cdpPort: profile.cdpPort,
563
+ cdpUrl: profile.cdpUrl,
564
+ color: profile.color,
565
+ running,
566
+ tabCount,
567
+ isDefault: name === current.resolved.defaultProfile,
568
+ isRemote: !profile.cdpIsLoopback
569
+ });
570
+ }
571
+ return result;
572
+ };
573
+ const getDefaultContext = () => forProfile();
574
+ const mapTabError = (err) => {
575
+ if (err instanceof SsrFBlockedError) {
576
+ return { status: 400, message: err.message };
577
+ }
578
+ if (err instanceof InvalidBrowserNavigationUrlError) {
579
+ return { status: 400, message: err.message };
580
+ }
581
+ const msg = String(err);
582
+ if (msg.includes("ambiguous target id prefix")) {
583
+ return { status: 409, message: "ambiguous target id prefix" };
584
+ }
585
+ if (msg.includes("tab not found")) {
586
+ return { status: 404, message: msg };
587
+ }
588
+ if (msg.includes("not found")) {
589
+ return { status: 404, message: msg };
590
+ }
591
+ return null;
592
+ };
593
+ return {
594
+ state,
595
+ forProfile,
596
+ listProfiles,
597
+ // Legacy methods delegate to default profile
598
+ ensureBrowserAvailable: () => getDefaultContext().ensureBrowserAvailable(),
599
+ ensureTabAvailable: (targetId) => getDefaultContext().ensureTabAvailable(targetId),
600
+ isHttpReachable: (timeoutMs) => getDefaultContext().isHttpReachable(timeoutMs),
601
+ isReachable: (timeoutMs) => getDefaultContext().isReachable(timeoutMs),
602
+ listTabs: () => getDefaultContext().listTabs(),
603
+ openTab: (url) => getDefaultContext().openTab(url),
604
+ focusTab: (targetId) => getDefaultContext().focusTab(targetId),
605
+ closeTab: (targetId) => getDefaultContext().closeTab(targetId),
606
+ stopRunningBrowser: () => getDefaultContext().stopRunningBrowser(),
607
+ resetProfile: () => getDefaultContext().resetProfile(),
608
+ mapTabError
609
+ };
610
+ }
611
+
612
+ export {
613
+ listKnownProfileNames,
614
+ createBrowserRouteContext
615
+ };