extension 4.1.20 → 4.1.22
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 +18 -16
- package/dist/{84.cjs → 597.cjs} +80 -2
- package/dist/browsers.cjs +408 -103
- package/dist/cli.cjs +558 -148
- package/dist/extension/browsers/__spec__/safari-fake-tools.d.ts +27 -0
- package/dist/extension/browsers/browsers-lib/messages.d.ts +2 -1
- package/dist/extension/browsers/browsers-lib/process-teardown.d.ts +3 -0
- package/dist/extension/browsers/browsers-lib/ready-stamp.d.ts +1 -0
- package/dist/extension/browsers/browsers-lib/resolve-live-pid.d.ts +25 -0
- package/dist/extension/browsers/browsers-lib/write-json-atomic.d.ts +1 -0
- package/dist/extension/browsers/browsers-types.d.ts +1 -1
- package/dist/extension/browsers/index.d.ts +1 -1
- package/dist/extension/browsers/run-chromium/cdp/cdp-extension-controller/index.d.ts +2 -0
- package/dist/extension/browsers/run-chromium/cdp/ensure-developer-mode.d.ts +12 -0
- package/dist/extension/browsers/run-firefox/firefox-launch/index.d.ts +9 -0
- package/dist/extension/browsers/run-firefox/firefox-launch/process-handlers.d.ts +1 -1
- package/dist/extension/browsers/run-safari/safari-launch/index.d.ts +1 -1
- package/dist/extension/browsers/run-safari/safari-launch/tools.d.ts +17 -0
- package/dist/extension/browsers/run-safari/safari-packager.d.ts +2 -1
- package/dist/extension/browsers/run-safari/safari-types.d.ts +2 -0
- package/dist/extension/config-types.d.ts +5 -2
- package/dist/extension/helpers/messages.d.ts +7 -0
- package/dist/extension/helpers/messaging.d.ts +1 -0
- package/dist/extension/helpers/node-version-guard.d.ts +3 -1
- package/dist/extension/helpers/template-catalog.d.ts +1 -1
- package/dist/extension/helpers/template-corpus.generated.d.ts +1 -1
- package/package.json +5 -7
package/dist/cli.cjs
CHANGED
|
@@ -230,7 +230,7 @@ var __webpack_modules__ = {
|
|
|
230
230
|
(0, _helpers_messaging__rspack_import_3._w)(_messages__rspack_import_5.io());
|
|
231
231
|
}
|
|
232
232
|
} catch {
|
|
233
|
-
const provenanceNote = _messages__rspack_import_5.xX(opts.binaryProvenance);
|
|
233
|
+
const provenanceNote = _messages__rspack_import_5.xX(opts.binaryProvenance, opts.browser);
|
|
234
234
|
(0, _helpers_messaging__rspack_import_3._w)(_messages__rspack_import_5.io());
|
|
235
235
|
(0, _helpers_messaging__rspack_import_3._w)((0, _helpers_messaging__rspack_import_3.Nr)({
|
|
236
236
|
rows: [
|
|
@@ -421,6 +421,7 @@ var __webpack_modules__ = {
|
|
|
421
421
|
var pintor__rspack_import_8 = __webpack_require__("pintor");
|
|
422
422
|
var pintor__rspack_import_8_default = /*#__PURE__*/ __webpack_require__.n(pintor__rspack_import_8);
|
|
423
423
|
var _helpers_messaging__rspack_import_9 = __webpack_require__("./helpers/messaging.ts");
|
|
424
|
+
var _browser_family__rspack_import_10 = __webpack_require__("./browsers/browsers-lib/browser-family.ts");
|
|
424
425
|
const require1 = (0, node_module__rspack_import_1.createRequire)(__rslib_import_meta_url__);
|
|
425
426
|
function getLoggingPrefix(type) {
|
|
426
427
|
return (0, _helpers_messaging__rspack_import_9.Pl)(type);
|
|
@@ -750,7 +751,7 @@ var __webpack_modules__ = {
|
|
|
750
751
|
return `${getLoggingPrefix('warn')} safari-web-extension-converter reported ${pintor__rspack_import_8_default().yellow(String(warnings.length))} ${1 === warnings.length ? 'warning' : 'warnings'}, some manifest keys/APIs may not be supported by Safari:\n` + warnings.map((line)=>` ${pintor__rspack_import_8_default().gray('•')} ${line}`).join('\n') + (kept.length ? `\nExtension.js kept ${1 === kept.length ? 'one of these keys' : 'some of these keys'} on purpose:\n${keptLines}` : '');
|
|
751
752
|
}
|
|
752
753
|
function safariDefaultBundleIdNote(bundleId) {
|
|
753
|
-
return `${getLoggingPrefix('
|
|
754
|
+
return `${getLoggingPrefix('info')} Bundle id ${pintor__rspack_import_8_default().gray(bundleId)} (generated, set ${pintor__rspack_import_8_default().blue('--bundle-id')} to own it).`;
|
|
754
755
|
}
|
|
755
756
|
function safariOpenHint(appPath, appName) {
|
|
756
757
|
return `${getLoggingPrefix('info')} Launch it once to register with Safari: ${pintor__rspack_import_8_default().blue('open')} ${pintor__rspack_import_8_default().underline(`"${appPath}"`)}\nThen turn on ${pintor__rspack_import_8_default().yellow(appName)} in Safari ▸ Settings ▸ Extensions.`;
|
|
@@ -772,6 +773,9 @@ var __webpack_modules__ = {
|
|
|
772
773
|
function safariRegistered(appName) {
|
|
773
774
|
return `${getLoggingPrefix('success')} Safari recognizes ${pintor__rspack_import_8_default().yellow(appName)}, finish enabling it with the steps above.`;
|
|
774
775
|
}
|
|
776
|
+
function safariPidUnresolved(appName) {
|
|
777
|
+
return `${getLoggingPrefix('warn')} Opened ${pintor__rspack_import_8_default().yellow(appName)} but could not find its process id.\nThe session's ready.json names the app and the extension without a ${pintor__rspack_import_8_default().gray('browserPid')}.`;
|
|
778
|
+
}
|
|
775
779
|
function safariNotYetRegistered(appName) {
|
|
776
780
|
return `${getLoggingPrefix('info')} Safari hasn't picked up ${pintor__rspack_import_8_default().yellow(appName)} yet.\nOpen the app once, then check Safari ▸ Settings ▸ Extensions.`;
|
|
777
781
|
}
|
|
@@ -826,9 +830,15 @@ var __webpack_modules__ = {
|
|
|
826
830
|
if (rest.startsWith(node_path__rspack_import_3.sep) || rest.startsWith('/')) return `~${rest}`;
|
|
827
831
|
return raw;
|
|
828
832
|
}
|
|
829
|
-
function binaryProvenanceNote(provenance) {
|
|
830
|
-
if ('pinned'
|
|
831
|
-
return
|
|
833
|
+
function binaryProvenanceNote(provenance, browser) {
|
|
834
|
+
if ('pinned' !== provenance) return '';
|
|
835
|
+
return `(pinned with ${pinnedBinaryFlag(browser)})`;
|
|
836
|
+
}
|
|
837
|
+
function pinnedBinaryFlag(browser) {
|
|
838
|
+
const name = String(browser || '');
|
|
839
|
+
if ((0, _browser_family__rspack_import_10.M_)(name)) return '--gecko-binary';
|
|
840
|
+
if ('safari' === name || 'webkit-based' === name) return '--safari-binary';
|
|
841
|
+
return '--chromium-binary';
|
|
832
842
|
}
|
|
833
843
|
function runningInDevelopment(manifest, browser, message, browserVersionLine, updateSuffix, opts) {
|
|
834
844
|
const capitalize = (str)=>str.charAt(0).toUpperCase() + str.slice(1);
|
|
@@ -864,7 +874,7 @@ var __webpack_modules__ = {
|
|
|
864
874
|
const baseBrowserLabel = (0, _helpers_messaging__rspack_import_9.A6)(String(browser || 'unknown'), resolveBrowserVersionLine(browser, browserVersionLine, {
|
|
865
875
|
pinned: opts?.binaryProvenance === 'pinned'
|
|
866
876
|
}));
|
|
867
|
-
const provenanceNote = binaryProvenanceNote(opts?.binaryProvenance);
|
|
877
|
+
const provenanceNote = binaryProvenanceNote(opts?.binaryProvenance, browser);
|
|
868
878
|
const browserLabel = provenanceNote ? `${baseBrowserLabel} ${provenanceNote}` : baseBrowserLabel;
|
|
869
879
|
const cleanId = String(id || '').trim();
|
|
870
880
|
const includeExtensionId = opts?.includeExtensionId !== false;
|
|
@@ -1033,6 +1043,7 @@ var __webpack_modules__ = {
|
|
|
1033
1043
|
jR: ()=>safariBuilding,
|
|
1034
1044
|
jc: ()=>safariProjectStale,
|
|
1035
1045
|
jk: ()=>requireGeckoBinaryForGeckoBased,
|
|
1046
|
+
jn: ()=>safariPidUnresolved,
|
|
1036
1047
|
kK: ()=>preferringSystemBrowserOverSnapshot,
|
|
1037
1048
|
l9: ()=>parsingPacketError,
|
|
1038
1049
|
lO: ()=>firefoxDryRunArgs,
|
|
@@ -1322,17 +1333,21 @@ var __webpack_modules__ = {
|
|
|
1322
1333
|
var _messages__rspack_import_2 = __webpack_require__("./browsers/browsers-lib/messages.ts");
|
|
1323
1334
|
const FORCE_KILL_GRACE_MS = 5000;
|
|
1324
1335
|
const terminatedByUs = new WeakSet();
|
|
1336
|
+
const terminatedPids = new Set();
|
|
1325
1337
|
function wasTerminatedByUs(child) {
|
|
1326
1338
|
return !!child && terminatedByUs.has(child);
|
|
1327
1339
|
}
|
|
1340
|
+
function wasPidTerminatedByUs(pid) {
|
|
1341
|
+
return 'number' == typeof pid && terminatedPids.has(pid);
|
|
1342
|
+
}
|
|
1328
1343
|
function authorLog(line) {
|
|
1329
1344
|
if (line && (0, _helpers_messaging__rspack_import_1._o)()) (0, _helpers_messaging__rspack_import_1._w)(line);
|
|
1330
1345
|
}
|
|
1331
|
-
function killWindowsTree(
|
|
1332
|
-
if ('win32' !== process.platform) return;
|
|
1346
|
+
function killWindowsTree(pid, sync) {
|
|
1347
|
+
if ('win32' !== process.platform || !pid) return;
|
|
1333
1348
|
const args = [
|
|
1334
1349
|
'/PID',
|
|
1335
|
-
String(
|
|
1350
|
+
String(pid),
|
|
1336
1351
|
'/T',
|
|
1337
1352
|
'/F'
|
|
1338
1353
|
];
|
|
@@ -1347,10 +1362,37 @@ var __webpack_modules__ = {
|
|
|
1347
1362
|
}).on('error', ()=>{});
|
|
1348
1363
|
} catch {}
|
|
1349
1364
|
}
|
|
1365
|
+
function signalPid(pid, signal) {
|
|
1366
|
+
try {
|
|
1367
|
+
process.kill(pid, signal);
|
|
1368
|
+
return true;
|
|
1369
|
+
} catch {
|
|
1370
|
+
return false;
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
function gracefulTerminatePid(pid, browser) {
|
|
1374
|
+
if (!pid || terminatedPids.has(pid)) return;
|
|
1375
|
+
terminatedPids.add(pid);
|
|
1376
|
+
killWindowsTree(pid, false);
|
|
1377
|
+
authorLog(_messages__rspack_import_2.XH(browser));
|
|
1378
|
+
signalPid(pid, 'SIGTERM');
|
|
1379
|
+
const killTimer = setTimeout(()=>{
|
|
1380
|
+
authorLog(_messages__rspack_import_2.AG(browser));
|
|
1381
|
+
signalPid(pid, 'SIGKILL');
|
|
1382
|
+
}, FORCE_KILL_GRACE_MS);
|
|
1383
|
+
killTimer.unref?.();
|
|
1384
|
+
}
|
|
1385
|
+
function forceKillPidOnExit(pid, browser) {
|
|
1386
|
+
if (!pid) return;
|
|
1387
|
+
terminatedPids.add(pid);
|
|
1388
|
+
killWindowsTree(pid, true);
|
|
1389
|
+
authorLog(_messages__rspack_import_2.AG(browser));
|
|
1390
|
+
signalPid(pid, 'SIGKILL');
|
|
1391
|
+
}
|
|
1350
1392
|
function gracefulTerminateChild(child, browser) {
|
|
1351
1393
|
if (!child || child.killed) return;
|
|
1352
1394
|
terminatedByUs.add(child);
|
|
1353
|
-
killWindowsTree(child, false);
|
|
1395
|
+
killWindowsTree(child.pid, false);
|
|
1354
1396
|
authorLog(_messages__rspack_import_2.XH(browser));
|
|
1355
1397
|
child.kill('SIGTERM');
|
|
1356
1398
|
const killTimer = setTimeout(()=>{
|
|
@@ -1364,7 +1406,7 @@ var __webpack_modules__ = {
|
|
|
1364
1406
|
function forceKillChildOnExit(child, browser) {
|
|
1365
1407
|
if (!child) return;
|
|
1366
1408
|
terminatedByUs.add(child);
|
|
1367
|
-
killWindowsTree(child, true);
|
|
1409
|
+
killWindowsTree(child.pid, true);
|
|
1368
1410
|
try {
|
|
1369
1411
|
authorLog(_messages__rspack_import_2.AG(browser));
|
|
1370
1412
|
child.kill('SIGKILL');
|
|
@@ -1385,7 +1427,10 @@ var __webpack_modules__ = {
|
|
|
1385
1427
|
$Y: ()=>forceKillChildOnExit,
|
|
1386
1428
|
Df: ()=>gracefulTerminateChild,
|
|
1387
1429
|
FA: ()=>isBenignSocketTeardown,
|
|
1388
|
-
Op: ()=>wasTerminatedByUs
|
|
1430
|
+
Op: ()=>wasTerminatedByUs,
|
|
1431
|
+
PU: ()=>wasPidTerminatedByUs,
|
|
1432
|
+
Qx: ()=>forceKillPidOnExit,
|
|
1433
|
+
_T: ()=>gracefulTerminatePid
|
|
1389
1434
|
});
|
|
1390
1435
|
},
|
|
1391
1436
|
"./browsers/browsers-lib/ready-message.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
@@ -1405,6 +1450,7 @@ var __webpack_modules__ = {
|
|
|
1405
1450
|
"./browsers/browsers-lib/ready-stamp.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
1406
1451
|
var node_fs__rspack_import_0 = __webpack_require__("node:fs");
|
|
1407
1452
|
var node_path__rspack_import_1 = __webpack_require__("node:path");
|
|
1453
|
+
var _write_json_atomic__rspack_import_2 = __webpack_require__("./browsers/browsers-lib/write-json-atomic.ts");
|
|
1408
1454
|
function readyPathFor(extensionOutputPath) {
|
|
1409
1455
|
return node_path__rspack_import_1.join(node_path__rspack_import_1.dirname(extensionOutputPath), 'extension-js', node_path__rspack_import_1.basename(extensionOutputPath), 'ready.json');
|
|
1410
1456
|
}
|
|
@@ -1416,7 +1462,7 @@ var __webpack_modules__ = {
|
|
|
1416
1462
|
const ready = JSON.parse(node_fs__rspack_import_0.readFileSync(readyPath, 'utf-8'));
|
|
1417
1463
|
if (ready.rdpPort === rdpPort) return;
|
|
1418
1464
|
ready.rdpPort = rdpPort;
|
|
1419
|
-
|
|
1465
|
+
(0, _write_json_atomic__rspack_import_2.Z)(readyPath, ready);
|
|
1420
1466
|
} catch {}
|
|
1421
1467
|
}
|
|
1422
1468
|
function stampReadyBrowserLaunch(extensionOutputPath, details) {
|
|
@@ -1428,13 +1474,14 @@ var __webpack_modules__ = {
|
|
|
1428
1474
|
const profilePath = String(details?.profilePath || '').trim();
|
|
1429
1475
|
if (profilePath) ready.profilePath = profilePath;
|
|
1430
1476
|
if ('number' == typeof details?.browserPid && Number.isFinite(details.browserPid)) ready.browserPid = details.browserPid;
|
|
1477
|
+
if ('number' == typeof details?.launcherPid && Number.isFinite(details.launcherPid)) ready.launcherPid = details.launcherPid;
|
|
1431
1478
|
const extensionId = String(details?.extensionId || '').trim();
|
|
1432
1479
|
if (extensionId) ready.extensionId = extensionId;
|
|
1433
1480
|
const binary = String(details?.binary || '').trim();
|
|
1434
1481
|
if (binary) ready.binary = binary;
|
|
1435
1482
|
const provenance = String(details?.binaryProvenance || '').trim();
|
|
1436
1483
|
if (provenance) ready.binaryProvenance = provenance;
|
|
1437
|
-
|
|
1484
|
+
(0, _write_json_atomic__rspack_import_2.Z)(readyPath, ready);
|
|
1438
1485
|
} catch {}
|
|
1439
1486
|
}
|
|
1440
1487
|
function stampReadyExtensionId(extensionOutputPath, extensionId) {
|
|
@@ -1446,7 +1493,7 @@ var __webpack_modules__ = {
|
|
|
1446
1493
|
const ready = JSON.parse(node_fs__rspack_import_0.readFileSync(readyPath, 'utf-8'));
|
|
1447
1494
|
if (ready.extensionId === id) return;
|
|
1448
1495
|
ready.extensionId = id;
|
|
1449
|
-
|
|
1496
|
+
(0, _write_json_atomic__rspack_import_2.Z)(readyPath, ready);
|
|
1450
1497
|
} catch {}
|
|
1451
1498
|
}
|
|
1452
1499
|
function stampReadyExtensionLoadRefused(extensionOutputPath, reason) {
|
|
@@ -1461,7 +1508,7 @@ var __webpack_modules__ = {
|
|
|
1461
1508
|
ready.message = `${browserLabel.charAt(0).toUpperCase() + browserLabel.slice(1)} refused to load the extension at ${extensionOutputPath}${reason ? `: ${reason}` : ''}`;
|
|
1462
1509
|
ready.extensionLoadRefusedAt = new Date().toISOString();
|
|
1463
1510
|
if (reason) ready.extensionLoadRefusedReason = reason;
|
|
1464
|
-
|
|
1511
|
+
(0, _write_json_atomic__rspack_import_2.Z)(readyPath, ready);
|
|
1465
1512
|
} catch {}
|
|
1466
1513
|
}
|
|
1467
1514
|
function stampReadyProfileLocked(extensionOutputPath, details) {
|
|
@@ -1475,7 +1522,7 @@ var __webpack_modules__ = {
|
|
|
1475
1522
|
ready.message = String(details?.message || '').trim() || 'the browser profile is already in use by another session';
|
|
1476
1523
|
ready.profileLockedAt = new Date().toISOString();
|
|
1477
1524
|
if (details?.owner) ready.profileLockOwner = details.owner;
|
|
1478
|
-
|
|
1525
|
+
(0, _write_json_atomic__rspack_import_2.Z)(readyPath, ready);
|
|
1479
1526
|
} catch {}
|
|
1480
1527
|
}
|
|
1481
1528
|
function stampReadyBrowserExited(extensionOutputPath, code) {
|
|
@@ -1491,7 +1538,7 @@ var __webpack_modules__ = {
|
|
|
1491
1538
|
ready.code = 'browser_exited';
|
|
1492
1539
|
ready.message = `the ${ready.browser || 'browser'} process exited (code ${code ?? 'unknown'}); nothing is running`;
|
|
1493
1540
|
}
|
|
1494
|
-
|
|
1541
|
+
(0, _write_json_atomic__rspack_import_2.Z)(readyPath, ready);
|
|
1495
1542
|
} catch {}
|
|
1496
1543
|
}
|
|
1497
1544
|
__webpack_require__.d(__webpack_exports__, {
|
|
@@ -1955,6 +2002,27 @@ var __webpack_modules__ = {
|
|
|
1955
2002
|
yO: ()=>probeChromiumBinaryVersion
|
|
1956
2003
|
});
|
|
1957
2004
|
},
|
|
2005
|
+
"./browsers/browsers-lib/write-json-atomic.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
2006
|
+
var node_fs__rspack_import_0 = __webpack_require__("node:fs");
|
|
2007
|
+
function writeJsonAtomic(filePath, value) {
|
|
2008
|
+
const tmpPath = `${filePath}.tmp-${process.pid}`;
|
|
2009
|
+
try {
|
|
2010
|
+
node_fs__rspack_import_0.writeFileSync(tmpPath, JSON.stringify(value, null, 2), 'utf-8');
|
|
2011
|
+
node_fs__rspack_import_0.renameSync(tmpPath, filePath);
|
|
2012
|
+
return true;
|
|
2013
|
+
} catch {
|
|
2014
|
+
try {
|
|
2015
|
+
node_fs__rspack_import_0.rmSync(tmpPath, {
|
|
2016
|
+
force: true
|
|
2017
|
+
});
|
|
2018
|
+
} catch {}
|
|
2019
|
+
return false;
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
2023
|
+
Z: ()=>writeJsonAtomic
|
|
2024
|
+
});
|
|
2025
|
+
},
|
|
1958
2026
|
"./browsers/browsers-lib/wsl-support.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
1959
2027
|
__webpack_require__.d(__webpack_exports__, {
|
|
1960
2028
|
qc: ()=>external_wsl_support_namespaceObject.hasGuiDisplay,
|
|
@@ -2660,6 +2728,7 @@ var __webpack_modules__ = {
|
|
|
2660
2728
|
'--enable-features=SidePanelUpdates',
|
|
2661
2729
|
'--disable-features=DisableLoadExtensionCommandLineSwitch',
|
|
2662
2730
|
'--disable-features=ExtensionDisableUnsupportedDeveloper',
|
|
2731
|
+
'--disable-features=SafetyHubExtensionsOffStoreTrigger',
|
|
2663
2732
|
'--enable-unsafe-extension-debugging',
|
|
2664
2733
|
'--silent-debugger-extension-api'
|
|
2665
2734
|
];
|
|
@@ -3488,7 +3557,7 @@ var __webpack_modules__ = {
|
|
|
3488
3557
|
binaryProvenance
|
|
3489
3558
|
};
|
|
3490
3559
|
if (enableCdp) {
|
|
3491
|
-
const mod = await __webpack_require__.e(
|
|
3560
|
+
const mod = await __webpack_require__.e(597).then(__webpack_require__.bind(__webpack_require__, "./browsers/run-chromium/chromium-launch/setup-cdp-after-launch.ts"));
|
|
3492
3561
|
const CDP_SETUP_TIMEOUT_MS = 45000;
|
|
3493
3562
|
await Promise.race([
|
|
3494
3563
|
mod.setupCdpAfterLaunch(compilation, cdpConfig, chromiumConfig, pipeStreams),
|
|
@@ -3779,6 +3848,150 @@ var __webpack_modules__ = {
|
|
|
3779
3848
|
var process_teardown = __webpack_require__("./browsers/browsers-lib/process-teardown.ts");
|
|
3780
3849
|
var ready_message = __webpack_require__("./browsers/browsers-lib/ready-message.ts");
|
|
3781
3850
|
var ready_stamp = __webpack_require__("./browsers/browsers-lib/ready-stamp.ts");
|
|
3851
|
+
var external_node_child_process_ = __webpack_require__("node:child_process");
|
|
3852
|
+
const PS_ROW = /^\s*(\d+)\s+(\d+)\s+(.*)$/;
|
|
3853
|
+
const HELPER_PROCESS = /plugin-container|(^|\s)-contentproc(\s|$)|(^|\s)-childID(\s|$)|--type=/;
|
|
3854
|
+
function runQuiet(bin, args) {
|
|
3855
|
+
try {
|
|
3856
|
+
const result = (0, external_node_child_process_.spawnSync)(bin, args, {
|
|
3857
|
+
encoding: 'utf-8',
|
|
3858
|
+
stdio: [
|
|
3859
|
+
'ignore',
|
|
3860
|
+
'pipe',
|
|
3861
|
+
'ignore'
|
|
3862
|
+
],
|
|
3863
|
+
windowsHide: true,
|
|
3864
|
+
maxBuffer: 67108864
|
|
3865
|
+
});
|
|
3866
|
+
if (result.error || 0 !== result.status) return null;
|
|
3867
|
+
return String(result.stdout || '');
|
|
3868
|
+
} catch {
|
|
3869
|
+
return null;
|
|
3870
|
+
}
|
|
3871
|
+
}
|
|
3872
|
+
function parseProcessRows(output) {
|
|
3873
|
+
const rows = [];
|
|
3874
|
+
for (const line of String(output || '').split(/\r?\n/)){
|
|
3875
|
+
const match = PS_ROW.exec(line.replace(/\r$/, ''));
|
|
3876
|
+
if (!match) continue;
|
|
3877
|
+
const pid = Number(match[1]);
|
|
3878
|
+
const ppid = Number(match[2]);
|
|
3879
|
+
if (Number.isFinite(pid) && Number.isFinite(ppid)) rows.push({
|
|
3880
|
+
pid,
|
|
3881
|
+
ppid,
|
|
3882
|
+
command: match[3].trim()
|
|
3883
|
+
});
|
|
3884
|
+
}
|
|
3885
|
+
return rows;
|
|
3886
|
+
}
|
|
3887
|
+
function appendLinuxProfileEnv(rows) {
|
|
3888
|
+
return rows.map((row)=>{
|
|
3889
|
+
try {
|
|
3890
|
+
const environ = external_node_fs_.readFileSync(`/proc/${row.pid}/environ`, 'utf-8');
|
|
3891
|
+
const entry = environ.split('\0').find((pair)=>pair.startsWith('XRE_PROFILE_PATH='));
|
|
3892
|
+
return entry ? {
|
|
3893
|
+
...row,
|
|
3894
|
+
command: `${row.command} ${entry}`
|
|
3895
|
+
} : row;
|
|
3896
|
+
} catch {
|
|
3897
|
+
return row;
|
|
3898
|
+
}
|
|
3899
|
+
});
|
|
3900
|
+
}
|
|
3901
|
+
function listProcesses(platform = process.platform) {
|
|
3902
|
+
if ('win32' === platform) {
|
|
3903
|
+
const script = 'Get-CimInstance Win32_Process | ForEach-Object { "$($_.ProcessId) $($_.ParentProcessId) $($_.CommandLine)" }';
|
|
3904
|
+
const output = runQuiet('powershell.exe', [
|
|
3905
|
+
'-NoProfile',
|
|
3906
|
+
'-NonInteractive',
|
|
3907
|
+
'-Command',
|
|
3908
|
+
script
|
|
3909
|
+
]);
|
|
3910
|
+
return output ? parseProcessRows(output) : [];
|
|
3911
|
+
}
|
|
3912
|
+
if ('darwin' === platform) {
|
|
3913
|
+
const output = runQuiet('ps', [
|
|
3914
|
+
'-axEo',
|
|
3915
|
+
'pid=,ppid=,command='
|
|
3916
|
+
]);
|
|
3917
|
+
return output ? parseProcessRows(output) : [];
|
|
3918
|
+
}
|
|
3919
|
+
const output = runQuiet('ps', [
|
|
3920
|
+
'-axo',
|
|
3921
|
+
'pid=,ppid=,command='
|
|
3922
|
+
]);
|
|
3923
|
+
const rows = output ? parseProcessRows(output) : [];
|
|
3924
|
+
return 'linux' === platform ? appendLinuxProfileEnv(rows) : rows;
|
|
3925
|
+
}
|
|
3926
|
+
function resolve_live_pid_normalizePath(value) {
|
|
3927
|
+
return String(value || '').replace(/\\/g, '/').toLowerCase();
|
|
3928
|
+
}
|
|
3929
|
+
function carriesProfile(command, profilePath) {
|
|
3930
|
+
const haystack = resolve_live_pid_normalizePath(command);
|
|
3931
|
+
const needle = resolve_live_pid_normalizePath(profilePath);
|
|
3932
|
+
let from = 0;
|
|
3933
|
+
for(;;){
|
|
3934
|
+
const at = haystack.indexOf(needle, from);
|
|
3935
|
+
if (at < 0) return false;
|
|
3936
|
+
const before = 0 === at ? ' ' : haystack[at - 1];
|
|
3937
|
+
const after = haystack[at + needle.length] ?? ' ';
|
|
3938
|
+
if (/[\s="']/.test(before) && /[\s"']/.test(after)) return true;
|
|
3939
|
+
from = at + 1;
|
|
3940
|
+
}
|
|
3941
|
+
}
|
|
3942
|
+
function executableOf(command) {
|
|
3943
|
+
const trimmed = resolve_live_pid_normalizePath(command).trim();
|
|
3944
|
+
if (trimmed.startsWith('"')) {
|
|
3945
|
+
const end = trimmed.indexOf('"', 1);
|
|
3946
|
+
return end > 0 ? trimmed.slice(1, end) : trimmed;
|
|
3947
|
+
}
|
|
3948
|
+
const cut = trimmed.search(/\s(-|[a-z_][a-z0-9_]*=)/);
|
|
3949
|
+
return cut > 0 ? trimmed.slice(0, cut) : trimmed;
|
|
3950
|
+
}
|
|
3951
|
+
function findLiveBrowserPid(input) {
|
|
3952
|
+
const profilePath = String(input.profilePath || '').trim();
|
|
3953
|
+
const binary = resolve_live_pid_normalizePath(input.binary).trim();
|
|
3954
|
+
if (!profilePath || !binary) return null;
|
|
3955
|
+
const candidates = input.rows.filter((row)=>executableOf(row.command) === binary && carriesProfile(row.command, profilePath) && !HELPER_PROCESS.test(row.command));
|
|
3956
|
+
if (0 === candidates.length) return null;
|
|
3957
|
+
const launcher = input.launcherPid ? candidates.find((row)=>row.pid === input.launcherPid) : void 0;
|
|
3958
|
+
if (launcher) {
|
|
3959
|
+
const twin = candidates.find((row)=>row.pid !== launcher.pid);
|
|
3960
|
+
return twin ? twin.pid : launcher.pid;
|
|
3961
|
+
}
|
|
3962
|
+
const pids = new Set(candidates.map((row)=>row.pid));
|
|
3963
|
+
const roots = candidates.filter((row)=>!pids.has(row.ppid));
|
|
3964
|
+
return (roots[0] || candidates[0]).pid;
|
|
3965
|
+
}
|
|
3966
|
+
function isPidAlive(pid) {
|
|
3967
|
+
if (!pid || !Number.isFinite(pid)) return false;
|
|
3968
|
+
try {
|
|
3969
|
+
process.kill(pid, 0);
|
|
3970
|
+
return true;
|
|
3971
|
+
} catch (error) {
|
|
3972
|
+
return error?.code === 'EPERM';
|
|
3973
|
+
}
|
|
3974
|
+
}
|
|
3975
|
+
async function resolveLiveBrowserPid(input) {
|
|
3976
|
+
const list = input.list || listProcesses;
|
|
3977
|
+
const attempts = Math.max(1, input.attempts ?? 6);
|
|
3978
|
+
const intervalMs = input.intervalMs ?? 500;
|
|
3979
|
+
const sleep = input.sleep || ((ms)=>new Promise((r)=>{
|
|
3980
|
+
setTimeout(r, ms).unref?.();
|
|
3981
|
+
}));
|
|
3982
|
+
let last = null;
|
|
3983
|
+
for(let attempt = 0; attempt < attempts; attempt += 1){
|
|
3984
|
+
last = findLiveBrowserPid({
|
|
3985
|
+
profilePath: input.profilePath,
|
|
3986
|
+
binary: input.binary,
|
|
3987
|
+
launcherPid: input.launcherPid,
|
|
3988
|
+
rows: list()
|
|
3989
|
+
});
|
|
3990
|
+
if (last && last !== input.launcherPid) break;
|
|
3991
|
+
if (attempt < attempts - 1) await sleep(intervalMs);
|
|
3992
|
+
}
|
|
3993
|
+
return last;
|
|
3994
|
+
}
|
|
3782
3995
|
var runtime_options = __webpack_require__("./browsers/browsers-lib/runtime-options.ts");
|
|
3783
3996
|
var shared_utils = __webpack_require__("./browsers/browsers-lib/shared-utils.ts");
|
|
3784
3997
|
function parseFlatpakBinary(binary) {
|
|
@@ -4056,7 +4269,12 @@ var __webpack_modules__ = {
|
|
|
4056
4269
|
for (const instance of activeInstances)attemptCleanup(instance);
|
|
4057
4270
|
}
|
|
4058
4271
|
function forceKillAllOnExit() {
|
|
4059
|
-
for (const instance of activeInstances)
|
|
4272
|
+
for (const instance of activeInstances){
|
|
4273
|
+
const child = instance.childRef();
|
|
4274
|
+
const livePid = instance.livePidRef();
|
|
4275
|
+
(0, process_teardown.$Y)(child, instance.browser);
|
|
4276
|
+
if (livePid && livePid !== child?.pid) (0, process_teardown.Qx)(livePid, instance.browser);
|
|
4277
|
+
}
|
|
4060
4278
|
}
|
|
4061
4279
|
function firstBrowserLabel() {
|
|
4062
4280
|
for (const instance of activeInstances)return instance.browser;
|
|
@@ -4088,10 +4306,11 @@ var __webpack_modules__ = {
|
|
|
4088
4306
|
process.exit(1);
|
|
4089
4307
|
});
|
|
4090
4308
|
}
|
|
4091
|
-
function setupFirefoxProcessHandlers(browser, childRef, cleanupInstance) {
|
|
4309
|
+
function setupFirefoxProcessHandlers(browser, childRef, cleanupInstance, livePidRef = ()=>null) {
|
|
4092
4310
|
const instance = {
|
|
4093
4311
|
browser,
|
|
4094
4312
|
childRef,
|
|
4313
|
+
livePidRef,
|
|
4095
4314
|
cleanupInstance,
|
|
4096
4315
|
isCleaningUp: false
|
|
4097
4316
|
};
|
|
@@ -5177,7 +5396,6 @@ var __webpack_modules__ = {
|
|
|
5177
5396
|
} catch {}
|
|
5178
5397
|
return controller;
|
|
5179
5398
|
}
|
|
5180
|
-
var external_node_child_process_ = __webpack_require__("node:child_process");
|
|
5181
5399
|
var wsl_support = __webpack_require__("./browsers/browsers-lib/wsl-support.ts");
|
|
5182
5400
|
const LINUX_FIREFOX_PATHS = [
|
|
5183
5401
|
'/usr/bin/firefox',
|
|
@@ -5447,13 +5665,12 @@ var __webpack_modules__ = {
|
|
|
5447
5665
|
browserPid: this.child?.pid,
|
|
5448
5666
|
extensionId: this.extensionOutputPath ? (0, banner.MT)(this.extensionOutputPath) : void 0
|
|
5449
5667
|
});
|
|
5450
|
-
this.child.on('close', ()=>{
|
|
5451
|
-
(0, shared_utils.sW)(profilePath);
|
|
5452
|
-
});
|
|
5453
5668
|
this.wireChildLifecycle();
|
|
5669
|
+
this.trackLiveBrowserPid();
|
|
5454
5670
|
let ctrl;
|
|
5455
5671
|
try {
|
|
5456
5672
|
ctrl = await setupRdpAfterLaunch(this.host, compilation, debugPort);
|
|
5673
|
+
this.trackLiveBrowserPid(1);
|
|
5457
5674
|
} catch (error) {
|
|
5458
5675
|
const reason = error?.extensionLoadRefusedReason;
|
|
5459
5676
|
if (!reason) {
|
|
@@ -5548,24 +5765,89 @@ var __webpack_modules__ = {
|
|
|
5548
5765
|
if (process.env.VITEST || process.env.VITEST_WORKER_ID) throw new Error('Firefox startup timed out');
|
|
5549
5766
|
process.exit(1);
|
|
5550
5767
|
});
|
|
5551
|
-
let disposeProcessHandlers;
|
|
5552
5768
|
child.on('close', (code)=>{
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
}
|
|
5557
|
-
if ((0, messaging._o)()) this.ctx.logger?.info?.(messages.Th(this.host.browser));
|
|
5558
|
-
if (!(0, process_teardown.Op)(child)) {
|
|
5559
|
-
this.ctx.logger?.error?.(`[browser] ${this.host.browser} exited (code ${code ?? 'unknown'}) without being asked to. The add-on may have been rejected or the browser crashed; the session cannot be driven.`);
|
|
5560
|
-
(0, ready_stamp.Wi)(this.extensionOutputPath, code);
|
|
5561
|
-
}
|
|
5562
|
-
this.cleanupInstance().catch((err)=>{
|
|
5563
|
-
if ((0, messaging._o)()) this.ctx.logger?.error?.(`[browser] Cleanup error on child close: ${err?.message || err}`);
|
|
5564
|
-
});
|
|
5565
|
-
disposeProcessHandlers?.();
|
|
5769
|
+
const expected = (0, process_teardown.Op)(child);
|
|
5770
|
+
if (!expected && this.adoptHandedOffBrowser()) return;
|
|
5771
|
+
this.onBrowserGone(code, expected);
|
|
5566
5772
|
});
|
|
5567
5773
|
this.pipeChildOutput(child);
|
|
5568
|
-
disposeProcessHandlers = setupFirefoxProcessHandlers(this.host.browser, ()=>this.child, ()=>this.cleanupInstance());
|
|
5774
|
+
this.disposeProcessHandlers = setupFirefoxProcessHandlers(this.host.browser, ()=>this.child, ()=>this.cleanupInstance(), ()=>this.livePid);
|
|
5775
|
+
}
|
|
5776
|
+
onBrowserGone(code, expected) {
|
|
5777
|
+
if (this.browserGone) return;
|
|
5778
|
+
this.browserGone = true;
|
|
5779
|
+
if (this.watchTimeout) {
|
|
5780
|
+
clearTimeout(this.watchTimeout);
|
|
5781
|
+
this.watchTimeout = void 0;
|
|
5782
|
+
}
|
|
5783
|
+
if (this.liveExitWatcher) {
|
|
5784
|
+
clearInterval(this.liveExitWatcher);
|
|
5785
|
+
this.liveExitWatcher = void 0;
|
|
5786
|
+
}
|
|
5787
|
+
if (this.host.launchProfilePath) (0, shared_utils.sW)(this.host.launchProfilePath);
|
|
5788
|
+
if ((0, messaging._o)()) this.ctx.logger?.info?.(messages.Th(this.host.browser));
|
|
5789
|
+
if (!expected) {
|
|
5790
|
+
this.ctx.logger?.error?.(`[browser] ${this.host.browser} exited (code ${code ?? 'unknown'}) without being asked to. The add-on may have been rejected or the browser crashed; the session cannot be driven.`);
|
|
5791
|
+
(0, ready_stamp.Wi)(this.extensionOutputPath, code);
|
|
5792
|
+
}
|
|
5793
|
+
this.cleanupInstance().catch((err)=>{
|
|
5794
|
+
if ((0, messaging._o)()) this.ctx.logger?.error?.(`[browser] Cleanup error on child close: ${err?.message || err}`);
|
|
5795
|
+
});
|
|
5796
|
+
this.disposeProcessHandlers?.();
|
|
5797
|
+
this.disposeProcessHandlers = void 0;
|
|
5798
|
+
}
|
|
5799
|
+
async trackLiveBrowserPid(attempts) {
|
|
5800
|
+
const child = this.child;
|
|
5801
|
+
const profilePath = this.host.launchProfilePath;
|
|
5802
|
+
if (!child?.pid || !profilePath || this.browserGone) return;
|
|
5803
|
+
try {
|
|
5804
|
+
const pid = await resolveLiveBrowserPid({
|
|
5805
|
+
profilePath,
|
|
5806
|
+
binary: child.spawnfile,
|
|
5807
|
+
launcherPid: child.pid,
|
|
5808
|
+
attempts
|
|
5809
|
+
});
|
|
5810
|
+
if (pid && pid !== child.pid && this.child === child) this.adoptLivePid(pid);
|
|
5811
|
+
} catch {}
|
|
5812
|
+
}
|
|
5813
|
+
adoptHandedOffBrowser() {
|
|
5814
|
+
const profilePath = this.host.launchProfilePath;
|
|
5815
|
+
const child = this.child;
|
|
5816
|
+
if (!profilePath || !child || this.browserGone) return false;
|
|
5817
|
+
try {
|
|
5818
|
+
const pid = this.livePid || findLiveBrowserPid({
|
|
5819
|
+
profilePath,
|
|
5820
|
+
binary: child.spawnfile,
|
|
5821
|
+
launcherPid: child.pid,
|
|
5822
|
+
rows: listProcesses()
|
|
5823
|
+
});
|
|
5824
|
+
if (!pid || pid === this.child?.pid || !isPidAlive(pid)) return false;
|
|
5825
|
+
this.adoptLivePid(pid);
|
|
5826
|
+
return true;
|
|
5827
|
+
} catch {
|
|
5828
|
+
return false;
|
|
5829
|
+
}
|
|
5830
|
+
}
|
|
5831
|
+
adoptLivePid(pid) {
|
|
5832
|
+
if (this.livePid === pid) return;
|
|
5833
|
+
this.livePid = pid;
|
|
5834
|
+
(0, ready_stamp.M)(this.extensionOutputPath, {
|
|
5835
|
+
browserPid: pid,
|
|
5836
|
+
launcherPid: this.child?.pid
|
|
5837
|
+
});
|
|
5838
|
+
if ((0, messaging._o)()) this.ctx.logger?.info?.(`[browser] ${this.host.browser} handed the session to pid ${pid} (launcher pid ${this.child?.pid}).`);
|
|
5839
|
+
this.watchLivePidExit();
|
|
5840
|
+
}
|
|
5841
|
+
watchLivePidExit() {
|
|
5842
|
+
if (this.liveExitWatcher) clearInterval(this.liveExitWatcher);
|
|
5843
|
+
this.liveExitWatcher = setInterval(()=>{
|
|
5844
|
+
const pid = this.livePid;
|
|
5845
|
+
if (!pid || isPidAlive(pid)) return;
|
|
5846
|
+
clearInterval(this.liveExitWatcher);
|
|
5847
|
+
this.liveExitWatcher = void 0;
|
|
5848
|
+
this.onBrowserGone(null, (0, process_teardown.PU)(pid));
|
|
5849
|
+
}, 1000);
|
|
5850
|
+
this.liveExitWatcher.unref?.();
|
|
5569
5851
|
}
|
|
5570
5852
|
async retryAddonInstall(compilation, debugPort) {
|
|
5571
5853
|
try {
|
|
@@ -5600,6 +5882,7 @@ var __webpack_modules__ = {
|
|
|
5600
5882
|
}
|
|
5601
5883
|
async cleanupInstance() {
|
|
5602
5884
|
(0, process_teardown.Df)(this.child, this.host.browser);
|
|
5885
|
+
if (this.livePid && this.livePid !== this.child?.pid) (0, process_teardown._T)(this.livePid, this.host.browser);
|
|
5603
5886
|
}
|
|
5604
5887
|
scheduleWatchTimeout() {
|
|
5605
5888
|
if (this.watchTimeout) return;
|
|
@@ -5634,6 +5917,10 @@ var __webpack_modules__ = {
|
|
|
5634
5917
|
firefox_launch_define_property(this, "child", null);
|
|
5635
5918
|
firefox_launch_define_property(this, "watchTimeout", void 0);
|
|
5636
5919
|
firefox_launch_define_property(this, "extensionOutputPath", void 0);
|
|
5920
|
+
firefox_launch_define_property(this, "livePid", null);
|
|
5921
|
+
firefox_launch_define_property(this, "liveExitWatcher", void 0);
|
|
5922
|
+
firefox_launch_define_property(this, "browserGone", false);
|
|
5923
|
+
firefox_launch_define_property(this, "disposeProcessHandlers", void 0);
|
|
5637
5924
|
this.host = host;
|
|
5638
5925
|
this.ctx = ctx;
|
|
5639
5926
|
}
|
|
@@ -5807,7 +6094,6 @@ var __webpack_modules__ = {
|
|
|
5807
6094
|
QW: ()=>safariBuildPreflight,
|
|
5808
6095
|
iF: ()=>safariPreflightError
|
|
5809
6096
|
});
|
|
5810
|
-
var external_node_child_process_ = __webpack_require__("node:child_process");
|
|
5811
6097
|
var external_node_fs_ = __webpack_require__("node:fs");
|
|
5812
6098
|
var messaging = __webpack_require__("./helpers/messaging.ts");
|
|
5813
6099
|
var banner = __webpack_require__("./browsers/browsers-lib/banner.ts");
|
|
@@ -5821,6 +6107,7 @@ var __webpack_modules__ = {
|
|
|
5821
6107
|
(0, messaging._w)(messages.Aj(xcodebuildCmd));
|
|
5822
6108
|
}
|
|
5823
6109
|
var safari_config = __webpack_require__("./browsers/run-safari/safari-launch/safari-config.ts");
|
|
6110
|
+
var external_node_child_process_ = __webpack_require__("node:child_process");
|
|
5824
6111
|
function isMacOS() {
|
|
5825
6112
|
return 'darwin' === process.platform;
|
|
5826
6113
|
}
|
|
@@ -5878,20 +6165,6 @@ var __webpack_modules__ = {
|
|
|
5878
6165
|
ok: Boolean(converter && xcodebuild)
|
|
5879
6166
|
};
|
|
5880
6167
|
}
|
|
5881
|
-
function fallbackLogger() {
|
|
5882
|
-
return {
|
|
5883
|
-
info: (...a)=>(0, messaging._w)(...a),
|
|
5884
|
-
warn: (...a)=>(0, messaging.mR)(...a),
|
|
5885
|
-
error: (...a)=>(0, messaging.Gg)(...a),
|
|
5886
|
-
debug: (...a)=>console?.debug?.(...a)
|
|
5887
|
-
};
|
|
5888
|
-
}
|
|
5889
|
-
function isTestEnv() {
|
|
5890
|
-
return Boolean(process.env.VITEST || process.env.VITEST_WORKER_ID);
|
|
5891
|
-
}
|
|
5892
|
-
function delay(ms) {
|
|
5893
|
-
return new Promise((resolve)=>setTimeout(resolve, ms));
|
|
5894
|
-
}
|
|
5895
6168
|
const TOOL_TAIL_LINES = 50;
|
|
5896
6169
|
const TOOL_TAIL_BYTES = 8192;
|
|
5897
6170
|
function toolOutputTail(output) {
|
|
@@ -5930,6 +6203,60 @@ var __webpack_modules__ = {
|
|
|
5930
6203
|
}));
|
|
5931
6204
|
});
|
|
5932
6205
|
}
|
|
6206
|
+
async function resolvePidForBundle(bundleId) {
|
|
6207
|
+
for(let attempt = 0; attempt < 10; attempt += 1){
|
|
6208
|
+
const pid = await new Promise((resolve)=>{
|
|
6209
|
+
const child = (0, external_node_child_process_.spawn)("osascript", [
|
|
6210
|
+
'-e',
|
|
6211
|
+
`tell application "System Events" to get unix id of first process whose bundle identifier is "${bundleId}"`
|
|
6212
|
+
]);
|
|
6213
|
+
let out = '';
|
|
6214
|
+
child.stdout.on('data', (d)=>out += String(d));
|
|
6215
|
+
child.on('error', ()=>resolve(null));
|
|
6216
|
+
child.on('close', ()=>{
|
|
6217
|
+
const n = Number(String(out).trim());
|
|
6218
|
+
resolve(Number.isFinite(n) && n > 0 ? n : null);
|
|
6219
|
+
});
|
|
6220
|
+
});
|
|
6221
|
+
if (pid) return pid;
|
|
6222
|
+
await new Promise((r)=>setTimeout(r, 500));
|
|
6223
|
+
}
|
|
6224
|
+
return null;
|
|
6225
|
+
}
|
|
6226
|
+
function createSafariTools() {
|
|
6227
|
+
return {
|
|
6228
|
+
detectToolchain: ()=>detectSafariToolchain(),
|
|
6229
|
+
runConverter: (args)=>runTool('xcrun', args),
|
|
6230
|
+
runXcodebuild: (args)=>runTool('xcodebuild', args),
|
|
6231
|
+
openApp: (target)=>runTool('open', [
|
|
6232
|
+
target
|
|
6233
|
+
]),
|
|
6234
|
+
openSafari: (binary)=>runTool('open', [
|
|
6235
|
+
'-a',
|
|
6236
|
+
binary
|
|
6237
|
+
]),
|
|
6238
|
+
resolvePid: (bundleId)=>resolvePidForBundle(bundleId),
|
|
6239
|
+
pluginkitList: async ()=>{
|
|
6240
|
+
const { ok, output } = await runTool('pluginkit', [
|
|
6241
|
+
'-m'
|
|
6242
|
+
], {
|
|
6243
|
+
quiet: true
|
|
6244
|
+
});
|
|
6245
|
+
return ok ? output : '';
|
|
6246
|
+
}
|
|
6247
|
+
};
|
|
6248
|
+
}
|
|
6249
|
+
function fallbackLogger() {
|
|
6250
|
+
return {
|
|
6251
|
+
info: (...a)=>(0, messaging._w)(...a),
|
|
6252
|
+
warn: (...a)=>(0, messaging.mR)(...a),
|
|
6253
|
+
error: (...a)=>(0, messaging.Gg)(...a),
|
|
6254
|
+
debug: (...a)=>console?.debug?.(...a)
|
|
6255
|
+
};
|
|
6256
|
+
}
|
|
6257
|
+
function delay(ms) {
|
|
6258
|
+
return new Promise((resolve)=>setTimeout(resolve, ms));
|
|
6259
|
+
}
|
|
5933
6260
|
function converterWarnings(output) {
|
|
5934
6261
|
const lines = output.split(/\r?\n/);
|
|
5935
6262
|
const collected = [];
|
|
@@ -5950,15 +6277,11 @@ var __webpack_modules__ = {
|
|
|
5950
6277
|
}
|
|
5951
6278
|
return collected;
|
|
5952
6279
|
}
|
|
5953
|
-
async function confirmRegisteredWithSafari(bundleIdentifier) {
|
|
6280
|
+
async function confirmRegisteredWithSafari(tools, bundleIdentifier) {
|
|
5954
6281
|
const needle = `${bundleIdentifier}.Extension`;
|
|
5955
6282
|
for(let attempt = 0; attempt < 6; attempt += 1){
|
|
5956
|
-
const
|
|
5957
|
-
|
|
5958
|
-
], {
|
|
5959
|
-
quiet: true
|
|
5960
|
-
});
|
|
5961
|
-
if (ok && output.includes(needle)) return true;
|
|
6283
|
+
const listing = await tools.pluginkitList();
|
|
6284
|
+
if (listing.includes(needle)) return true;
|
|
5962
6285
|
await delay(800);
|
|
5963
6286
|
}
|
|
5964
6287
|
return false;
|
|
@@ -5973,6 +6296,10 @@ var __webpack_modules__ = {
|
|
|
5973
6296
|
macOsOnly: config.macOsOnly
|
|
5974
6297
|
};
|
|
5975
6298
|
}
|
|
6299
|
+
function completePackage(config, logger, mode) {
|
|
6300
|
+
if ('full' === mode && config.bundleIdDerived) logger.info?.(messages.$q(config.bundleIdentifier));
|
|
6301
|
+
return describePackage(config);
|
|
6302
|
+
}
|
|
5976
6303
|
function safariPreflightError() {
|
|
5977
6304
|
const tc = detectSafariToolchain();
|
|
5978
6305
|
if (!tc.platformOk) return messages.G3(process.platform);
|
|
@@ -5996,26 +6323,6 @@ var __webpack_modules__ = {
|
|
|
5996
6323
|
severity: 'ok'
|
|
5997
6324
|
};
|
|
5998
6325
|
}
|
|
5999
|
-
async function resolvePidForBundle(bundleId) {
|
|
6000
|
-
for(let attempt = 0; attempt < 10; attempt += 1){
|
|
6001
|
-
const pid = await new Promise((resolve)=>{
|
|
6002
|
-
const child = (0, external_node_child_process_.spawn)("osascript", [
|
|
6003
|
-
'-e',
|
|
6004
|
-
`tell application "System Events" to get unix id of first process whose bundle identifier is "${bundleId}"`
|
|
6005
|
-
]);
|
|
6006
|
-
let out = '';
|
|
6007
|
-
child.stdout.on('data', (d)=>out += String(d));
|
|
6008
|
-
child.on('error', ()=>resolve(null));
|
|
6009
|
-
child.on('close', ()=>{
|
|
6010
|
-
const n = Number(String(out).trim());
|
|
6011
|
-
resolve(Number.isFinite(n) && n > 0 ? n : null);
|
|
6012
|
-
});
|
|
6013
|
-
});
|
|
6014
|
-
if (pid) return pid;
|
|
6015
|
-
await new Promise((r)=>setTimeout(r, 500));
|
|
6016
|
-
}
|
|
6017
|
-
return null;
|
|
6018
|
-
}
|
|
6019
6326
|
async function announceSafariDevSession(host, config, appPath) {
|
|
6020
6327
|
try {
|
|
6021
6328
|
await (0, banner.ai)({
|
|
@@ -6031,16 +6338,16 @@ var __webpack_modules__ = {
|
|
|
6031
6338
|
} catch {}
|
|
6032
6339
|
}
|
|
6033
6340
|
async function runSafariPipeline(compilation, host, logger, mode) {
|
|
6341
|
+
const tools = host.tools || createSafariTools();
|
|
6034
6342
|
const config = (0, safari_config.F7)(compilation, host);
|
|
6035
6343
|
const converterArgs = (0, safari_config.w7)(config);
|
|
6036
6344
|
const xcodebuildArgs = (0, safari_config.vx)(config);
|
|
6037
6345
|
const isSigned = Boolean(config.developmentTeam);
|
|
6038
|
-
if (
|
|
6039
|
-
if (host.dryRun || isTestEnv()) {
|
|
6346
|
+
if (host.dryRun) {
|
|
6040
6347
|
logSafariDryRun(`xcrun ${converterArgs.join(' ')}`, `xcodebuild ${xcodebuildArgs.join(' ')}`);
|
|
6041
|
-
return
|
|
6348
|
+
return completePackage(config, logger, mode);
|
|
6042
6349
|
}
|
|
6043
|
-
const toolchain =
|
|
6350
|
+
const toolchain = tools.detectToolchain();
|
|
6044
6351
|
if (!toolchain.platformOk) {
|
|
6045
6352
|
logger.warn?.(messages.G3(process.platform));
|
|
6046
6353
|
return describePackage(config);
|
|
@@ -6064,7 +6371,7 @@ var __webpack_modules__ = {
|
|
|
6064
6371
|
}
|
|
6065
6372
|
const { saved, restore } = (0, safari_config._D)(config);
|
|
6066
6373
|
logger.info?.(messages.uK(config.extensionDir));
|
|
6067
|
-
const converted = await
|
|
6374
|
+
const converted = await tools.runConverter(converterArgs);
|
|
6068
6375
|
if (!converted.ok) {
|
|
6069
6376
|
const tail = toolOutputTail(converted.output);
|
|
6070
6377
|
logger.error?.(messages.A('safari-web-extension-converter', converted.code, tail));
|
|
@@ -6081,7 +6388,7 @@ var __webpack_modules__ = {
|
|
|
6081
6388
|
logger.info?.(messages.l_(config.projectLocation));
|
|
6082
6389
|
} else if ('full' === mode) logger.info?.(messages.oM());
|
|
6083
6390
|
if ('full' === mode) logger.info?.(messages.jR((0, safari_config.aD)(config)));
|
|
6084
|
-
const built = await
|
|
6391
|
+
const built = await tools.runXcodebuild(xcodebuildArgs);
|
|
6085
6392
|
if (!built.ok) {
|
|
6086
6393
|
const tail = toolOutputTail(built.output);
|
|
6087
6394
|
logger.error?.(messages.A('xcodebuild', built.code, tail));
|
|
@@ -6096,30 +6403,26 @@ var __webpack_modules__ = {
|
|
|
6096
6403
|
if (!config.open) {
|
|
6097
6404
|
logger.info?.(messages.aO(appPath, config.appName));
|
|
6098
6405
|
if (host.announceDevReady) await announceSafariDevSession(host, config, appPath);
|
|
6099
|
-
return
|
|
6406
|
+
return completePackage(config, logger, mode);
|
|
6100
6407
|
}
|
|
6101
6408
|
const target = external_node_fs_.existsSync(appPath) ? appPath : (0, safari_config.Gi)(config);
|
|
6102
6409
|
logger.info?.(messages.fw(target));
|
|
6103
|
-
await
|
|
6104
|
-
|
|
6105
|
-
]);
|
|
6106
|
-
if (config.safariBinary) await runTool('open', [
|
|
6107
|
-
'-a',
|
|
6108
|
-
config.safariBinary
|
|
6109
|
-
]);
|
|
6410
|
+
await tools.openApp(target);
|
|
6411
|
+
if (config.safariBinary) await tools.openSafari(config.safariBinary);
|
|
6110
6412
|
const raisedBundleId = config.safariBinary ? 'com.apple.Safari' : config.bundleIdentifier;
|
|
6111
|
-
const browserPid = await
|
|
6112
|
-
|
|
6113
|
-
browserPid,
|
|
6413
|
+
const browserPid = await tools.resolvePid(raisedBundleId);
|
|
6414
|
+
(0, ready_stamp.M)(config.extensionDir, {
|
|
6415
|
+
browserPid: browserPid || void 0,
|
|
6114
6416
|
binary: config.safariBinary || appPath,
|
|
6115
6417
|
binaryProvenance: config.safariBinary ? 'pinned' : 'system',
|
|
6116
6418
|
extensionId: `${config.bundleIdentifier}.Extension`
|
|
6117
6419
|
});
|
|
6420
|
+
if (!browserPid) logger.warn?.(messages.jn(config.appName));
|
|
6118
6421
|
logger.info?.(messages.fO(config.appName, isSigned));
|
|
6119
|
-
if (await confirmRegisteredWithSafari(config.bundleIdentifier)) logger.info?.(messages.fd(config.appName));
|
|
6422
|
+
if (await confirmRegisteredWithSafari(tools, config.bundleIdentifier)) logger.info?.(messages.fd(config.appName));
|
|
6120
6423
|
else logger.info?.(messages.qY(config.appName));
|
|
6121
6424
|
if (host.announceDevReady) await announceSafariDevSession(host, config, appPath);
|
|
6122
|
-
return
|
|
6425
|
+
return completePackage(config, logger, mode);
|
|
6123
6426
|
}
|
|
6124
6427
|
async function packageSafariExtension(host, outputPath, logger, mode = 'full') {
|
|
6125
6428
|
const compilation = {
|
|
@@ -6239,9 +6542,10 @@ var __webpack_modules__ = {
|
|
|
6239
6542
|
function manifestFingerprintPath(config) {
|
|
6240
6543
|
return node_path__rspack_import_1.join(config.projectLocation, '.manifest-fingerprint');
|
|
6241
6544
|
}
|
|
6545
|
+
const HOT_UPDATE_DIR = 'hot';
|
|
6242
6546
|
function topLevelEntries(extensionDir) {
|
|
6243
6547
|
try {
|
|
6244
|
-
return node_fs__rspack_import_0.readdirSync(extensionDir).sort();
|
|
6548
|
+
return node_fs__rspack_import_0.readdirSync(extensionDir).filter((entry)=>entry !== HOT_UPDATE_DIR).sort();
|
|
6245
6549
|
} catch {
|
|
6246
6550
|
return [];
|
|
6247
6551
|
}
|
|
@@ -6370,7 +6674,7 @@ var __webpack_modules__ = {
|
|
|
6370
6674
|
return Object.fromEntries(Object.entries(input).filter(([, value])=>void 0 !== value));
|
|
6371
6675
|
}
|
|
6372
6676
|
function createSafariPackager(options = {}) {
|
|
6373
|
-
const { browser = 'safari', noOpen = true, dryRun = false, logger, ...identity } = options;
|
|
6677
|
+
const { browser = 'safari', noOpen = true, dryRun = false, logger, tools, ...identity } = options;
|
|
6374
6678
|
return async (distPath, mode = 'full', overrides)=>await (0, _safari_launch__rspack_import_0.Ah)({
|
|
6375
6679
|
extension: [
|
|
6376
6680
|
distPath
|
|
@@ -6378,6 +6682,7 @@ var __webpack_modules__ = {
|
|
|
6378
6682
|
browser,
|
|
6379
6683
|
noOpen,
|
|
6380
6684
|
dryRun,
|
|
6685
|
+
tools,
|
|
6381
6686
|
...withoutUndefined(identity),
|
|
6382
6687
|
...withoutUndefined(overrides)
|
|
6383
6688
|
}, distPath, logger, mode);
|
|
@@ -6705,6 +7010,8 @@ var __webpack_modules__ = {
|
|
|
6705
7010
|
const MIN_NODE_MINOR = 12;
|
|
6706
7011
|
const MIN_DENO_MAJOR = 2;
|
|
6707
7012
|
const MIN_DENO_MINOR = 5;
|
|
7013
|
+
const MIN_BUN_MAJOR = 1;
|
|
7014
|
+
const MIN_BUN_MINOR = 2;
|
|
6708
7015
|
const BLOCKED_DENO_VERSIONS = [
|
|
6709
7016
|
'2.8.0'
|
|
6710
7017
|
];
|
|
@@ -6721,6 +7028,9 @@ var __webpack_modules__ = {
|
|
|
6721
7028
|
if (BLOCKED_DENO_VERSIONS.includes(version)) return false;
|
|
6722
7029
|
return meetsFloor(version, MIN_DENO_MAJOR, MIN_DENO_MINOR);
|
|
6723
7030
|
}
|
|
7031
|
+
function isSupportedBunVersion(version) {
|
|
7032
|
+
return meetsFloor(version, MIN_BUN_MAJOR, MIN_BUN_MINOR);
|
|
7033
|
+
}
|
|
6724
7034
|
function detectBunVersion(versions = process.versions) {
|
|
6725
7035
|
const bunVersion = versions.bun;
|
|
6726
7036
|
return 'string' == typeof bunVersion && bunVersion.length > 0 ? bunVersion : void 0;
|
|
@@ -6733,8 +7043,10 @@ var __webpack_modules__ = {
|
|
|
6733
7043
|
if (BLOCKED_DENO_VERSIONS.includes(version)) return `[Extension.js] Deno ${version} cannot load node:querystring inside the bundler, so every build fails on it. Deno fixed that in 2.8.1. Run deno upgrade to build the extension on Deno.`;
|
|
6734
7044
|
return `[Extension.js] Requires Deno >= ${MIN_DENO_MAJOR}.${MIN_DENO_MINOR} (you are on ${version}). Run deno upgrade, or run the extension CLI on Node.js >= ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR} instead.`;
|
|
6735
7045
|
}
|
|
6736
|
-
function
|
|
6737
|
-
|
|
7046
|
+
function unsupportedBunVersionMessage(version) {
|
|
7047
|
+
return `[Extension.js] Requires Bun >= ${MIN_BUN_MAJOR}.${MIN_BUN_MINOR} (you are on ${version}). Run bun upgrade, or run the extension CLI on Node.js >= ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR} instead.`;
|
|
7048
|
+
}
|
|
7049
|
+
function unsupportedNodeVersionMessage(version) {
|
|
6738
7050
|
return `[Extension.js] Requires Node.js >= ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR} (you are on ${version}). Upgrade Node.js to run the extension CLI.`;
|
|
6739
7051
|
}
|
|
6740
7052
|
function enforceSupportedNodeVersion(version = process.versions.node, bunVersion = detectBunVersion(), denoVersion = detectDenoVersion()) {
|
|
@@ -6744,8 +7056,14 @@ var __webpack_modules__ = {
|
|
|
6744
7056
|
process.exit(1);
|
|
6745
7057
|
return;
|
|
6746
7058
|
}
|
|
6747
|
-
if (
|
|
6748
|
-
|
|
7059
|
+
if (bunVersion) {
|
|
7060
|
+
if (isSupportedBunVersion(bunVersion)) return;
|
|
7061
|
+
console.error(unsupportedBunVersionMessage(bunVersion));
|
|
7062
|
+
process.exit(1);
|
|
7063
|
+
return;
|
|
7064
|
+
}
|
|
7065
|
+
if (isSupportedNodeVersion(version)) return;
|
|
7066
|
+
console.error(unsupportedNodeVersionMessage(version));
|
|
6749
7067
|
process.exit(1);
|
|
6750
7068
|
}
|
|
6751
7069
|
enforceSupportedNodeVersion();
|
|
@@ -7141,7 +7459,7 @@ var __webpack_modules__ = {
|
|
|
7141
7459
|
return Math.min(Math.max(n, min), max);
|
|
7142
7460
|
}
|
|
7143
7461
|
const TEMPLATE_CORPUS_REPO = 'extension-js/examples';
|
|
7144
|
-
const TEMPLATE_CORPUS_REF = '
|
|
7462
|
+
const TEMPLATE_CORPUS_REF = 'f8087f012cf195cba9aa2e3c32fd5a6729da33f0';
|
|
7145
7463
|
const TEMPLATE_CORPUS_SLUGS = [
|
|
7146
7464
|
'action',
|
|
7147
7465
|
'action-locales',
|
|
@@ -8254,7 +8572,10 @@ Docker / Devcontainers / Codespaces
|
|
|
8254
8572
|
- Use ${messages_code('--host 0.0.0.0')} to bind the dev server on all interfaces so HMR is reachable from the host.
|
|
8255
8573
|
- Use ${messages_code('--no-browser')} inside the container and load the extension manually from ${messages_code('dist/<browser>/')} in your host browser.
|
|
8256
8574
|
- Chromium sandbox flags (${messages_code('--no-sandbox')}) are added automatically when Docker, Podman, devcontainers, or Codespaces are detected.
|
|
8257
|
-
- File watching uses
|
|
8575
|
+
- File watching uses native file events by default, which keeps rebuilds fast.
|
|
8576
|
+
- Set ${messages_code(messages_arg('EXTENSION_WATCH_POLL=true'))} to poll instead when native events do not fire,
|
|
8577
|
+
as in a container, a virtual machine, or a network or bind mount.
|
|
8578
|
+
Tune it with ${messages_code(messages_arg('EXTENSION_WATCH_POLL_INTERVAL'))} (default 1000 ms).
|
|
8258
8579
|
- Example: ${messages_code('extension dev ./my-ext --host 0.0.0.0 --no-browser --port 8080')}
|
|
8259
8580
|
|
|
8260
8581
|
Flatpak Firefox
|
|
@@ -8427,7 +8748,9 @@ Cross-browser compatibility
|
|
|
8427
8748
|
],
|
|
8428
8749
|
notes: [
|
|
8429
8750
|
'Use --no-browser inside the container and load dist/<browser>/ in the host browser',
|
|
8430
|
-
'File watching uses
|
|
8751
|
+
'File watching uses native file events by default',
|
|
8752
|
+
'Set EXTENSION_WATCH_POLL=true to poll instead when native events do not fire, as in a container, a virtual machine, or a network or bind mount',
|
|
8753
|
+
'EXTENSION_WATCH_POLL_INTERVAL sets the poll interval in ms (default 1000)',
|
|
8431
8754
|
'--no-sandbox is added automatically when a container environment is detected'
|
|
8432
8755
|
]
|
|
8433
8756
|
}
|
|
@@ -8458,12 +8781,45 @@ Cross-browser compatibility
|
|
|
8458
8781
|
}
|
|
8459
8782
|
const OPEN_SURFACE_NOUN = {
|
|
8460
8783
|
popup: 'popup',
|
|
8784
|
+
options: 'options page',
|
|
8461
8785
|
sidebar: 'side panel',
|
|
8462
8786
|
action: 'action popup'
|
|
8463
8787
|
};
|
|
8464
8788
|
function openSurfaceNoun(surface) {
|
|
8465
8789
|
return OPEN_SURFACE_NOUN[surface] || surface;
|
|
8466
8790
|
}
|
|
8791
|
+
function openSurfaceAction(surface) {
|
|
8792
|
+
return 'command' === surface ? 'trigger the command' : `open the ${openSurfaceNoun(surface)}`;
|
|
8793
|
+
}
|
|
8794
|
+
function asSentence(text) {
|
|
8795
|
+
const trimmed = text.trim();
|
|
8796
|
+
const capitalized = trimmed.charAt(0).toUpperCase() + trimmed.slice(1);
|
|
8797
|
+
return capitalized.endsWith('.') ? capitalized : `${capitalized}.`;
|
|
8798
|
+
}
|
|
8799
|
+
function listenerCount(count, event) {
|
|
8800
|
+
return `${count} ${event} ${1 === count ? 'listener' : 'listeners'}`;
|
|
8801
|
+
}
|
|
8802
|
+
function openedSurface(surface) {
|
|
8803
|
+
return `${getLoggingPrefix('success')} Opened the ${openSurfaceNoun(surface)}.`;
|
|
8804
|
+
}
|
|
8805
|
+
function replayedActionClick(listeners) {
|
|
8806
|
+
return `${getLoggingPrefix('success')} Replayed ${listenerCount(listeners, 'onClicked')} without a user gesture.`;
|
|
8807
|
+
}
|
|
8808
|
+
function replayedCommand(listeners, command) {
|
|
8809
|
+
const name = command ? ` for ${messages_arg(command)}` : '';
|
|
8810
|
+
return `${getLoggingPrefix('success')} Replayed ${listenerCount(listeners, 'onCommand')}${name} without a user gesture.`;
|
|
8811
|
+
}
|
|
8812
|
+
function openSurfaceWarning(warning) {
|
|
8813
|
+
return `${getLoggingPrefix('warn')} ${asSentence(warning)}`;
|
|
8814
|
+
}
|
|
8815
|
+
function openSurfaceFailed(surface, reason, engine, remedy) {
|
|
8816
|
+
const engineNote = engine ? messages_arg(` (engine ${engine})`) : '';
|
|
8817
|
+
return [
|
|
8818
|
+
`${getLoggingPrefix('error')} Can't ${openSurfaceAction(surface)}.`,
|
|
8819
|
+
`${messaging.Sc.label('REASON')} ${messaging.Sc.val(reason)}${engineNote}`,
|
|
8820
|
+
remedy
|
|
8821
|
+
].filter(Boolean).join('\n');
|
|
8822
|
+
}
|
|
8467
8823
|
function openSurfaceGestureStep(surface) {
|
|
8468
8824
|
return `Click the extension's toolbar entry, or its row in the extensions menu, to open the ${openSurfaceNoun(surface)}.`;
|
|
8469
8825
|
}
|
|
@@ -8473,6 +8829,12 @@ Cross-browser compatibility
|
|
|
8473
8829
|
function openSurfaceNeedsGesture(surface) {
|
|
8474
8830
|
return `${getLoggingPrefix('error')} Chromium opens the ${openSurfaceNoun(surface)} only in response to a user gesture, so ${messages_code(`extension open ${surface}`)} can't open it from the command line.\n` + openSurfaceGestureStep(surface);
|
|
8475
8831
|
}
|
|
8832
|
+
function doctorHeader(browser, passes, total) {
|
|
8833
|
+
return `doctor (${browser}), ${passes}/${total} checks passed`;
|
|
8834
|
+
}
|
|
8835
|
+
function doctorRemedy(check, remediation) {
|
|
8836
|
+
return `\n${check}: ${remediation}`;
|
|
8837
|
+
}
|
|
8476
8838
|
function sessionOnPort(browser, port) {
|
|
8477
8839
|
return port ? `for ${browser} on port ${port}` : `for ${browser}`;
|
|
8478
8840
|
}
|
|
@@ -8735,11 +9097,20 @@ Cross-browser compatibility
|
|
|
8735
9097
|
if ('json' === format) return void console.log(JSON.stringify(event, null, 2));
|
|
8736
9098
|
console.log(formatPrettyLogLine(event));
|
|
8737
9099
|
}
|
|
9100
|
+
function levelToken(level) {
|
|
9101
|
+
const word = level.toUpperCase();
|
|
9102
|
+
if ('error' === level) return external_pintor_default().red(word);
|
|
9103
|
+
if ('warn' === level) return external_pintor_default().brightYellow(word);
|
|
9104
|
+
if ('info' === level) return external_pintor_default().gray(word);
|
|
9105
|
+
if ('debug' === level) return external_pintor_default().dim(external_pintor_default().gray(word));
|
|
9106
|
+
return word;
|
|
9107
|
+
}
|
|
8738
9108
|
function formatPrettyLogLine(event) {
|
|
8739
9109
|
const parts = Array.isArray(event.messageParts) ? event.messageParts.map((p)=>'string' == typeof p ? p : JSON.stringify(p)).join(' ') : '';
|
|
8740
9110
|
const code = event.code ? ` ${event.code}` : '';
|
|
8741
9111
|
const remediation = event.remediation ? `\n ↳ ${event.remediation}` : '';
|
|
8742
|
-
|
|
9112
|
+
const level = String(event.level || 'log').toLowerCase();
|
|
9113
|
+
return `[${event.seq ?? '-'}] ${levelToken(level)} ${external_pintor_default().dim(`(${event.context})`)}${code} ${parts}${remediation}`;
|
|
8743
9114
|
}
|
|
8744
9115
|
function writeFrame(frame) {
|
|
8745
9116
|
try {
|
|
@@ -8822,7 +9193,7 @@ Cross-browser compatibility
|
|
|
8822
9193
|
if (matches(event)) printEvent(event, format);
|
|
8823
9194
|
},
|
|
8824
9195
|
onGap: (gap)=>{
|
|
8825
|
-
console.error(`… ${gap.dropped} event(s) dropped (${gap.reason}), stream is behind`);
|
|
9196
|
+
console.error(external_pintor_default().dim(external_pintor_default().gray(`… ${gap.dropped} event(s) dropped (${gap.reason}), stream is behind`)));
|
|
8826
9197
|
},
|
|
8827
9198
|
onClose: (close)=>{
|
|
8828
9199
|
if (!refusals.has(close.code) && sessionStillNamed()) return;
|
|
@@ -8994,11 +9365,33 @@ Cross-browser compatibility
|
|
|
8994
9365
|
hint: openSurfaceGestureStep(surface)
|
|
8995
9366
|
};
|
|
8996
9367
|
}
|
|
8997
|
-
function
|
|
9368
|
+
function openResultLines(value) {
|
|
9369
|
+
if (!value || 'object' != typeof value) return;
|
|
9370
|
+
const reply = value;
|
|
9371
|
+
if ('string' == typeof reply.opened) return [
|
|
9372
|
+
openedSurface(reply.opened)
|
|
9373
|
+
];
|
|
9374
|
+
if ('popup' === reply.triggered) return [
|
|
9375
|
+
openedSurface('action')
|
|
9376
|
+
];
|
|
9377
|
+
if ('number' != typeof reply.listeners) return;
|
|
9378
|
+
const lines = [];
|
|
9379
|
+
if ('onClicked' === reply.triggered) lines.push(replayedActionClick(reply.listeners));
|
|
9380
|
+
else {
|
|
9381
|
+
if ('command' !== reply.triggered) return;
|
|
9382
|
+
lines.push(replayedCommand(reply.listeners, 'string' == typeof reply.command ? reply.command : void 0));
|
|
9383
|
+
}
|
|
9384
|
+
if ('string' == typeof reply.warning && reply.warning) lines.push(openSurfaceWarning(reply.warning));
|
|
9385
|
+
return lines;
|
|
9386
|
+
}
|
|
9387
|
+
function printResult(result, output, command, pretty) {
|
|
8998
9388
|
if ('json' === normalizeOutputFormat(output)) return void console.log(JSON.stringify(buildActEnvelope(command, result)));
|
|
8999
9389
|
if (result.ok) {
|
|
9000
9390
|
const value = result.value;
|
|
9001
|
-
|
|
9391
|
+
const lines = pretty?.value(value) ?? [
|
|
9392
|
+
'string' == typeof value ? value : JSON.stringify(value, null, 2)
|
|
9393
|
+
];
|
|
9394
|
+
for (const line of lines)console.log(line);
|
|
9002
9395
|
const consoleRecords = result.console;
|
|
9003
9396
|
if (Array.isArray(consoleRecords)) {
|
|
9004
9397
|
if (0 === consoleRecords.length) console.log('(no console lines captured)');
|
|
@@ -9007,6 +9400,11 @@ Cross-browser compatibility
|
|
|
9007
9400
|
if (result.truncated) console.error('… result truncated (byte cap)');
|
|
9008
9401
|
return;
|
|
9009
9402
|
}
|
|
9403
|
+
if (pretty) {
|
|
9404
|
+
const { error } = buildActEnvelope(command, result);
|
|
9405
|
+
console.error(pretty.failure(error));
|
|
9406
|
+
return;
|
|
9407
|
+
}
|
|
9010
9408
|
const err = result.error || {
|
|
9011
9409
|
name: 'Error',
|
|
9012
9410
|
message: 'command failed'
|
|
@@ -9080,7 +9478,7 @@ Cross-browser compatibility
|
|
|
9080
9478
|
if (result?.ok && input.augment) try {
|
|
9081
9479
|
Object.assign(result, input.augment(projectPath, browser, result));
|
|
9082
9480
|
} catch {}
|
|
9083
|
-
printResult(result, input.opts.output, input.command);
|
|
9481
|
+
printResult(result, input.opts.output, input.command, input.pretty);
|
|
9084
9482
|
await exitAfterDrain(result.ok ? 0 : 1);
|
|
9085
9483
|
}
|
|
9086
9484
|
function targetFrom(opts, fallback = 'background') {
|
|
@@ -9225,7 +9623,11 @@ Cross-browser compatibility
|
|
|
9225
9623
|
},
|
|
9226
9624
|
args,
|
|
9227
9625
|
opts,
|
|
9228
|
-
preflight: (bridge, projectPath, browser)=>gestureRefusal(surface, bridge, projectPath, browser)
|
|
9626
|
+
preflight: (bridge, projectPath, browser)=>gestureRefusal(surface, bridge, projectPath, browser),
|
|
9627
|
+
pretty: {
|
|
9628
|
+
value: openResultLines,
|
|
9629
|
+
failure: (error)=>openSurfaceFailed(surface, error.message, error.engine, error.hint)
|
|
9630
|
+
}
|
|
9229
9631
|
});
|
|
9230
9632
|
});
|
|
9231
9633
|
}
|
|
@@ -9264,7 +9666,7 @@ Cross-browser compatibility
|
|
|
9264
9666
|
return values.length > 0 ? values : void 0;
|
|
9265
9667
|
}
|
|
9266
9668
|
function registerBuildCommand(program) {
|
|
9267
|
-
program.command('build').arguments('[project-name]').usage('[path-to-remote-extension] [options]').description(commandDescriptions.build).option(`--browser <${BROWSER_TARGETS_HELP}>`, 'specify a browser/engine to run. Defaults to `chromium`. `safari` builds a Safari app via Xcode (macOS only)').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `false`', parseOptionalBoolean).option('--no-polyfill', 'disable the cross-browser polyfill').option('--zip [boolean]', 'whether or not to compress the extension into a ZIP file. Defaults to `false`', parseOptionalBoolean).option('--zip-source [boolean]', 'whether or not to include the source files in the ZIP file. Defaults to `false`', parseOptionalBoolean).option('--zip-filename <string>', 'specify the name of the ZIP file. Defaults to the extension name and version').option('--silent [boolean]', 'suppress the build summary output. Defaults to `false`', parseOptionalBoolean).option('--addon-lint [boolean]', 'check Firefox builds against addons.mozilla.org rules with addons-linter when it is installed. Findings print as warnings. Defaults to `true`', parseOptionalBoolean).option('--no-addon-lint', 'skip the addons.mozilla.org lint of Firefox builds').option('--install [boolean]', '[internal] install project dependencies when missing', parseOptionalBoolean).option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--mode <development|production|none>', 'bundler mode override (also sets NODE_ENV). Defaults to `production`').option('--open [boolean]', 'open the built Safari app after packaging (safari targets only). Defaults to `false`', parseOptionalBoolean).option('--app-name <name>', 'override the Safari app name (safari targets only). Defaults to the manifest `name`').option('--bundle-id <reverse.dns>', 'set a user-owned Safari bundle identifier (safari targets only). Defaults to a generated dev.extensionjs.* id').option('--development-team <id>', 'sign the Safari app with an Apple Developer team id (safari targets only). Without it the build is ad-hoc signed, which Safari loads locally with no per-launch toggle. Use a team id for a stable identity you can distribute').option('--macos-only [boolean]', 'generate a macOS-only Safari Xcode project (safari targets only). Pass `false` for a universal macOS + iOS project. Defaults to `true`', parseOptionalBoolean).option('--force-regenerate', 'regenerate the Safari Xcode project even when up to date (safari targets only)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addOption(new external_commander_namespaceObject.Option('--debug', 'print maintainer diagnostics alongside normal output')).addOption(new external_commander_namespaceObject.Option('--author, --author-mode', 'deprecated alias for --debug').hideHelp()).action(async (pathOrRemoteUrl, { browser: cliBrowser, ...buildOptions })=>{
|
|
9669
|
+
program.command('build').arguments('[project-name]').usage('[path-to-remote-extension] [options]').description(commandDescriptions.build).option(`--browser <${BROWSER_TARGETS_HELP}>`, 'specify a browser/engine to run. Defaults to `chromium`. `safari` builds a Safari app via Xcode (macOS only)').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `false`', parseOptionalBoolean).option('--no-polyfill', 'disable the cross-browser polyfill').option('--zip [boolean]', 'whether or not to compress the extension into a ZIP file. Defaults to `false`', parseOptionalBoolean).option('--zip-source [boolean]', 'whether or not to include the source files in the ZIP file. Defaults to `false`', parseOptionalBoolean).option('--zip-filename <string>', 'specify the name of the ZIP file. Defaults to the extension name and version').option('--silent [boolean]', 'suppress the build summary output. Defaults to `false`', parseOptionalBoolean).option('--addon-lint [boolean]', 'check Firefox builds against addons.mozilla.org rules with addons-linter when it is installed. Findings print as warnings. Defaults to `true`', parseOptionalBoolean).option('--no-addon-lint', 'skip the addons.mozilla.org lint of Firefox builds').option('--install [boolean]', '[internal] install project dependencies when missing', parseOptionalBoolean).option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--mode <development|production|none>', 'bundler mode override (also sets NODE_ENV). Defaults to `production`').option('--open [boolean]', 'open the built Safari app after packaging (safari targets only). Defaults to `false`', parseOptionalBoolean).option('--app-name <name>', 'override the Safari app name (safari targets only). Defaults to the manifest `name`').option('--bundle-id <reverse.dns>', 'set a user-owned Safari bundle identifier (safari targets only). Defaults to a generated dev.extensionjs.* id shared by every build of the same source, so set your own before the first submission').option('--development-team <id>', 'sign the Safari app with an Apple Developer team id (safari targets only). Without it the build is ad-hoc signed, which Safari loads locally with no per-launch toggle. Use a team id for a stable identity you can distribute').option('--macos-only [boolean]', 'generate a macOS-only Safari Xcode project (safari targets only). Pass `false` for a universal macOS + iOS project. Defaults to `true`', parseOptionalBoolean).option('--force-regenerate', 'regenerate the Safari Xcode project even when up to date (safari targets only)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addOption(new external_commander_namespaceObject.Option('--debug', 'print maintainer diagnostics alongside normal output')).addOption(new external_commander_namespaceObject.Option('--author, --author-mode', 'deprecated alias for --debug').hideHelp()).action(async (pathOrRemoteUrl, { browser: cliBrowser, ...buildOptions })=>{
|
|
9268
9670
|
const browser = cliBrowser ?? await resolveConfigBrowser(pathOrRemoteUrl || process.cwd(), 'build') ?? 'chromium';
|
|
9269
9671
|
if (buildOptions.debug || buildOptions.author || buildOptions.authorMode) {
|
|
9270
9672
|
process.env.EXTENSION_DEBUG = '1';
|
|
@@ -9826,37 +10228,45 @@ Cross-browser compatibility
|
|
|
9826
10228
|
async function waitForReadyContract(options) {
|
|
9827
10229
|
const readyPath = sessionReadyPath(options.bridge, options.projectPath, options.browser);
|
|
9828
10230
|
const start = Date.now();
|
|
10231
|
+
let lastReadFailure = '';
|
|
9829
10232
|
while(Date.now() - start < options.timeoutMs){
|
|
9830
|
-
if (external_node_fs_.existsSync(readyPath))
|
|
9831
|
-
|
|
9832
|
-
|
|
9833
|
-
|
|
9834
|
-
|
|
9835
|
-
|
|
9836
|
-
|
|
10233
|
+
if (external_node_fs_.existsSync(readyPath)) {
|
|
10234
|
+
let payload = null;
|
|
10235
|
+
try {
|
|
10236
|
+
payload = JSON.parse(external_node_fs_.readFileSync(readyPath, 'utf8'));
|
|
10237
|
+
lastReadFailure = '';
|
|
10238
|
+
} catch (error) {
|
|
10239
|
+
payload = null;
|
|
10240
|
+
lastReadFailure = error instanceof Error ? error.message : String(error);
|
|
9837
10241
|
}
|
|
9838
|
-
if (
|
|
9839
|
-
|
|
10242
|
+
if (payload) {
|
|
10243
|
+
const isLive = isProcessLikelyAlive(payload.pid);
|
|
10244
|
+
const isFresh = isFreshContractPayload(payload);
|
|
10245
|
+
if (payload.command !== options.command) {
|
|
9840
10246
|
await new Promise((resolve)=>setTimeout(resolve, 250));
|
|
9841
10247
|
continue;
|
|
9842
10248
|
}
|
|
9843
|
-
|
|
9844
|
-
|
|
9845
|
-
|
|
9846
|
-
|
|
9847
|
-
|
|
9848
|
-
|
|
10249
|
+
if (!isLive) {
|
|
10250
|
+
if ('start' !== options.command || !isFresh) {
|
|
10251
|
+
await new Promise((resolve)=>setTimeout(resolve, 250));
|
|
10252
|
+
continue;
|
|
10253
|
+
}
|
|
10254
|
+
}
|
|
10255
|
+
if ('ready' === payload.status) return payload;
|
|
10256
|
+
if ('error' === payload.status) {
|
|
10257
|
+
if (!isLive && 'start' !== options.command) {
|
|
10258
|
+
await new Promise((resolve)=>setTimeout(resolve, 250));
|
|
10259
|
+
continue;
|
|
10260
|
+
}
|
|
10261
|
+
const detail = payload.message || payload.errors?.[0] || 'unknown error';
|
|
10262
|
+
throw new WaitModeError(String(detail), messaging.Lp.E_INTERNAL);
|
|
9849
10263
|
}
|
|
9850
|
-
const detail = payload.message || payload.errors?.[0] || 'unknown error';
|
|
9851
|
-
throw new WaitModeError(String(detail), messaging.Lp.E_INTERNAL);
|
|
9852
10264
|
}
|
|
9853
|
-
} catch (error) {
|
|
9854
|
-
if (error instanceof Error) throw error;
|
|
9855
|
-
throw new Error(String(error));
|
|
9856
10265
|
}
|
|
9857
10266
|
await new Promise((resolve)=>setTimeout(resolve, 250));
|
|
9858
10267
|
}
|
|
9859
|
-
|
|
10268
|
+
const timeoutDetail = lastReadFailure ? `. The last read of the file failed to parse as JSON: ${lastReadFailure}` : '';
|
|
10269
|
+
throw new WaitModeError(`Timed out waiting for ready contract at ${readyPath} (${options.timeoutMs} ms)${timeoutDetail}`, messaging.Lp.E_READY_TIMEOUT);
|
|
9860
10270
|
}
|
|
9861
10271
|
async function runWaitMode(options) {
|
|
9862
10272
|
if (isHttpUrl(options.pathOrRemoteUrl)) throw new WaitModeError('--wait requires a local project path (remote URLs are not supported)', messaging.Lp.E_ARGS);
|
|
@@ -9900,7 +10310,7 @@ Cross-browser compatibility
|
|
|
9900
10310
|
return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : 8080;
|
|
9901
10311
|
}
|
|
9902
10312
|
function registerDevCommand(program) {
|
|
9903
|
-
program.command('dev').arguments('[project-path|remote-url]').usage('[project-path|remote-url] [options]').description(commandDescriptions.dev).addHelpText('after', "\nAdditional options:\n --no-browser stop the browser launch, the dev server still starts\n --no-reload emit a dev-mode dist without the content-script reload runtime, tabs need a manual reload to see changes\n --wait wait for ready contract and exit, pair with --output json for machine output\n" + BROWSER_LAUNCH_HELP_FOOTER).option('--profile <path-to-file | boolean>', 'what path to use for the browser profile. A boolean value of false sets the profile to the default user profile. Defaults to a fresh profile').option(`-b, --browser <${BROWSER_TARGETS_HELP}>`, 'specify a browser/engine to run. Defaults to `chromium`. `safari` builds and opens a Safari app via Xcode (macOS only)').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').addOption(geckoBinaryOption()).addOption(firefoxBinaryAliasOption()).option('--safari-binary <path-to-binary>', 'specify the Safari binary to open after packaging (safari targets only)').option('--app-name <name>', 'override the Safari app name (safari targets only). Defaults to the manifest `name`').option('--bundle-id <reverse.dns>', 'set a user-owned Safari bundle identifier (safari targets only). Defaults to a generated dev.extensionjs.* id').option('--development-team <id>', 'sign the Safari app with an Apple Developer team id (safari targets only). Without it the build is ad-hoc signed, which Safari loads locally with no per-launch toggle. Use a team id for a stable identity you can distribute').option('--macos-only [boolean]', 'generate a macOS-only Safari Xcode project (safari targets only). Pass `false` for a universal macOS + iOS project. Defaults to `true`', parseOptionalBoolean).option('--force-regenerate', 'regenerate the Safari Xcode project even when up to date (safari targets only)').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `true`', parseOptionalBoolean).option('--no-polyfill', 'disable the cross-browser polyfill').option('--no-open', NO_OPEN_FLAG_DESCRIPTION).option('--starting-url <url>', 'specify the starting URL for the browser. Defaults to `undefined`').option('--port <port>', 'specify the port to use for the development server. Defaults to `8080`').option('--host <host>', 'specify the host to bind the dev server to. Use 0.0.0.0 for Docker/devcontainers. Defaults to `127.0.0.1`').option('--public-host <host>', 'connectable host the browser (HMR + reload bridge) dials when it differs from the bind host (e.g. a remote/devcontainer). Defaults to the bind host, or 127.0.0.1 when bound to 0.0.0.0').option('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). Use `all` to include all contexts (default)').option('--logs <off|error|warn|info|debug|trace|all>', '[experimental] minimum centralized logger level to display in terminal (default: off)').option('--log-format <pretty|json|ndjson>', '[experimental] output format for logger events. Defaults to `pretty`').option('--no-log-timestamps', 'disable ISO timestamps in pretty output').option('--no-log-color', 'disable color in pretty output').option('--log-url <pattern>', '[experimental] only show logs where event.url matches this substring or regex (/re/i)').option('--log-tab <id>', 'only show logs for a specific tabId (number)').option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--install [boolean]', '[internal] install project dependencies when missing', parseOptionalBoolean).option('--wait [boolean]', 'wait for dist/extension-js/<browser>/ready.json and exit', parseOptionalBoolean).option('--wait-timeout <ms>', 'timeout in milliseconds when using --wait (default: 60000)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addOption(new external_commander_namespaceObject.Option('--wait-format <pretty|json>').hideHelp()).addOption(new external_commander_namespaceObject.Option('--debug', 'print maintainer diagnostics alongside normal output')).addOption(new external_commander_namespaceObject.Option('--author, --author-mode', 'deprecated alias for --debug').hideHelp()).option('--allow-control', 'enable the agent-bridge control channel for bounded act (storage/reload/open): see `extension reload|storage|open`').option('--allow-eval', 'additionally enable `extension eval` (implies --allow-control, runs arbitrary code in a context, writes a 0600 session token)').option('--parent-pid <pid>', 'exit when the given process dies. For wrappers that spawn `extension dev`, so a leaked dev server can never outlive its owner').action(async (pathOrRemoteUrl, options, command)=>{
|
|
10313
|
+
program.command('dev').arguments('[project-path|remote-url]').usage('[project-path|remote-url] [options]').description(commandDescriptions.dev).addHelpText('after', "\nAdditional options:\n --no-browser stop the browser launch, the dev server still starts\n --no-reload emit a dev-mode dist without the content-script reload runtime, tabs need a manual reload to see changes\n --wait wait for ready contract and exit, pair with --output json for machine output\n" + BROWSER_LAUNCH_HELP_FOOTER).option('--profile <path-to-file | boolean>', 'what path to use for the browser profile. A boolean value of false sets the profile to the default user profile. Defaults to a fresh profile').option(`-b, --browser <${BROWSER_TARGETS_HELP}>`, 'specify a browser/engine to run. Defaults to `chromium`. `safari` builds and opens a Safari app via Xcode (macOS only)').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').addOption(geckoBinaryOption()).addOption(firefoxBinaryAliasOption()).option('--safari-binary <path-to-binary>', 'specify the Safari binary to open after packaging (safari targets only)').option('--app-name <name>', 'override the Safari app name (safari targets only). Defaults to the manifest `name`').option('--bundle-id <reverse.dns>', 'set a user-owned Safari bundle identifier (safari targets only). Defaults to a generated dev.extensionjs.* id shared by every build of the same source, so set your own before the first submission').option('--development-team <id>', 'sign the Safari app with an Apple Developer team id (safari targets only). Without it the build is ad-hoc signed, which Safari loads locally with no per-launch toggle. Use a team id for a stable identity you can distribute').option('--macos-only [boolean]', 'generate a macOS-only Safari Xcode project (safari targets only). Pass `false` for a universal macOS + iOS project. Defaults to `true`', parseOptionalBoolean).option('--force-regenerate', 'regenerate the Safari Xcode project even when up to date (safari targets only)').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `true`', parseOptionalBoolean).option('--no-polyfill', 'disable the cross-browser polyfill').option('--no-open', NO_OPEN_FLAG_DESCRIPTION).option('--starting-url <url>', 'specify the starting URL for the browser. Defaults to `undefined`').option('--port <port>', 'specify the port to use for the development server. Defaults to `8080`').option('--host <host>', 'specify the host to bind the dev server to. Use 0.0.0.0 for Docker/devcontainers. Defaults to `127.0.0.1`').option('--public-host <host>', 'connectable host the browser (HMR + reload bridge) dials when it differs from the bind host (e.g. a remote/devcontainer). Defaults to the bind host, or 127.0.0.1 when bound to 0.0.0.0').option('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). Use `all` to include all contexts (default)').option('--logs <off|error|warn|info|debug|trace|all>', '[experimental] minimum centralized logger level to display in terminal (default: off)').option('--log-format <pretty|json|ndjson>', '[experimental] output format for logger events. Defaults to `pretty`').option('--no-log-timestamps', 'disable ISO timestamps in pretty output').option('--no-log-color', 'disable color in pretty output').option('--log-url <pattern>', '[experimental] only show logs where event.url matches this substring or regex (/re/i)').option('--log-tab <id>', 'only show logs for a specific tabId (number)').option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--install [boolean]', '[internal] install project dependencies when missing', parseOptionalBoolean).option('--wait [boolean]', 'wait for dist/extension-js/<browser>/ready.json and exit', parseOptionalBoolean).option('--wait-timeout <ms>', 'timeout in milliseconds when using --wait (default: 60000)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addOption(new external_commander_namespaceObject.Option('--wait-format <pretty|json>').hideHelp()).addOption(new external_commander_namespaceObject.Option('--debug', 'print maintainer diagnostics alongside normal output')).addOption(new external_commander_namespaceObject.Option('--author, --author-mode', 'deprecated alias for --debug').hideHelp()).option('--allow-control', 'enable the agent-bridge control channel for bounded act (storage/reload/open): see `extension reload|storage|open`').option('--allow-eval', 'additionally enable `extension eval` (implies --allow-control, runs arbitrary code in a context, writes a 0600 session token)').option('--parent-pid <pid>', 'exit when the given process dies. For wrappers that spawn `extension dev`, so a leaked dev server can never outlive its owner').action(async (pathOrRemoteUrl, options, command)=>{
|
|
9904
10314
|
const { browser: cliBrowser, ...devOptions } = options;
|
|
9905
10315
|
const browser = cliBrowser ?? await resolveConfigBrowser(pathOrRemoteUrl || process.cwd(), 'dev') ?? 'chromium';
|
|
9906
10316
|
if (devOptions.debug || devOptions.author || devOptions.authorMode) {
|
|
@@ -10356,19 +10766,19 @@ Cross-browser compatibility
|
|
|
10356
10766
|
});
|
|
10357
10767
|
return results;
|
|
10358
10768
|
}
|
|
10769
|
+
function checkGlyph(status) {
|
|
10770
|
+
if ('pass' === status) return external_pintor_default().green('✓');
|
|
10771
|
+
if ('fail' === status) return external_pintor_default().red('✗');
|
|
10772
|
+
if ('warn' === status) return external_pintor_default().brightYellow('!');
|
|
10773
|
+
return external_pintor_default().gray('–');
|
|
10774
|
+
}
|
|
10359
10775
|
function printPretty(results, browser) {
|
|
10360
10776
|
const passes = results.filter((r)=>'pass' === r.status).length;
|
|
10361
|
-
|
|
10362
|
-
pass: '✓',
|
|
10363
|
-
fail: '✗',
|
|
10364
|
-
warn: '!',
|
|
10365
|
-
skip: '–'
|
|
10366
|
-
};
|
|
10367
|
-
console.log(`doctor (${browser}), ${passes}/${results.length} checks passed`);
|
|
10777
|
+
console.log(doctorHeader(browser, passes, results.length));
|
|
10368
10778
|
const width = Math.max(...results.map((r)=>r.check.length));
|
|
10369
|
-
for (const r of results)console.log(` ${
|
|
10779
|
+
for (const r of results)console.log(` ${checkGlyph(r.status)} ${r.check.padEnd(width)} ${r.detail}`);
|
|
10370
10780
|
const advisory = results.find((r)=>'fail' === r.status) ?? results.find((r)=>'warn' === r.status);
|
|
10371
|
-
if (advisory?.remediation) console.log(
|
|
10781
|
+
if (advisory?.remediation) console.log(doctorRemedy(advisory.check, advisory.remediation));
|
|
10372
10782
|
}
|
|
10373
10783
|
const CHECK_CODES = {
|
|
10374
10784
|
'ready-contract': messaging.Lp.E_SESSION_NOT_FOUND,
|