extension 4.1.21 → 4.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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);
@@ -829,9 +830,15 @@ var __webpack_modules__ = {
829
830
  if (rest.startsWith(node_path__rspack_import_3.sep) || rest.startsWith('/')) return `~${rest}`;
830
831
  return raw;
831
832
  }
832
- function binaryProvenanceNote(provenance) {
833
- if ('pinned' === provenance) return '(pinned with --chromium-binary)';
834
- 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';
835
842
  }
836
843
  function runningInDevelopment(manifest, browser, message, browserVersionLine, updateSuffix, opts) {
837
844
  const capitalize = (str)=>str.charAt(0).toUpperCase() + str.slice(1);
@@ -867,7 +874,7 @@ var __webpack_modules__ = {
867
874
  const baseBrowserLabel = (0, _helpers_messaging__rspack_import_9.A6)(String(browser || 'unknown'), resolveBrowserVersionLine(browser, browserVersionLine, {
868
875
  pinned: opts?.binaryProvenance === 'pinned'
869
876
  }));
870
- const provenanceNote = binaryProvenanceNote(opts?.binaryProvenance);
877
+ const provenanceNote = binaryProvenanceNote(opts?.binaryProvenance, browser);
871
878
  const browserLabel = provenanceNote ? `${baseBrowserLabel} ${provenanceNote}` : baseBrowserLabel;
872
879
  const cleanId = String(id || '').trim();
873
880
  const includeExtensionId = opts?.includeExtensionId !== false;
@@ -1326,17 +1333,21 @@ var __webpack_modules__ = {
1326
1333
  var _messages__rspack_import_2 = __webpack_require__("./browsers/browsers-lib/messages.ts");
1327
1334
  const FORCE_KILL_GRACE_MS = 5000;
1328
1335
  const terminatedByUs = new WeakSet();
1336
+ const terminatedPids = new Set();
1329
1337
  function wasTerminatedByUs(child) {
1330
1338
  return !!child && terminatedByUs.has(child);
1331
1339
  }
1340
+ function wasPidTerminatedByUs(pid) {
1341
+ return 'number' == typeof pid && terminatedPids.has(pid);
1342
+ }
1332
1343
  function authorLog(line) {
1333
1344
  if (line && (0, _helpers_messaging__rspack_import_1._o)()) (0, _helpers_messaging__rspack_import_1._w)(line);
1334
1345
  }
1335
- function killWindowsTree(child, sync) {
1336
- if ('win32' !== process.platform) return;
1346
+ function killWindowsTree(pid, sync) {
1347
+ if ('win32' !== process.platform || !pid) return;
1337
1348
  const args = [
1338
1349
  '/PID',
1339
- String(child.pid),
1350
+ String(pid),
1340
1351
  '/T',
1341
1352
  '/F'
1342
1353
  ];
@@ -1351,10 +1362,37 @@ var __webpack_modules__ = {
1351
1362
  }).on('error', ()=>{});
1352
1363
  } catch {}
1353
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
+ }
1354
1392
  function gracefulTerminateChild(child, browser) {
1355
1393
  if (!child || child.killed) return;
1356
1394
  terminatedByUs.add(child);
1357
- killWindowsTree(child, false);
1395
+ killWindowsTree(child.pid, false);
1358
1396
  authorLog(_messages__rspack_import_2.XH(browser));
1359
1397
  child.kill('SIGTERM');
1360
1398
  const killTimer = setTimeout(()=>{
@@ -1368,7 +1406,7 @@ var __webpack_modules__ = {
1368
1406
  function forceKillChildOnExit(child, browser) {
1369
1407
  if (!child) return;
1370
1408
  terminatedByUs.add(child);
1371
- killWindowsTree(child, true);
1409
+ killWindowsTree(child.pid, true);
1372
1410
  try {
1373
1411
  authorLog(_messages__rspack_import_2.AG(browser));
1374
1412
  child.kill('SIGKILL');
@@ -1389,7 +1427,10 @@ var __webpack_modules__ = {
1389
1427
  $Y: ()=>forceKillChildOnExit,
1390
1428
  Df: ()=>gracefulTerminateChild,
1391
1429
  FA: ()=>isBenignSocketTeardown,
1392
- Op: ()=>wasTerminatedByUs
1430
+ Op: ()=>wasTerminatedByUs,
1431
+ PU: ()=>wasPidTerminatedByUs,
1432
+ Qx: ()=>forceKillPidOnExit,
1433
+ _T: ()=>gracefulTerminatePid
1393
1434
  });
1394
1435
  },
1395
1436
  "./browsers/browsers-lib/ready-message.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
@@ -1433,6 +1474,7 @@ var __webpack_modules__ = {
1433
1474
  const profilePath = String(details?.profilePath || '').trim();
1434
1475
  if (profilePath) ready.profilePath = profilePath;
1435
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;
1436
1478
  const extensionId = String(details?.extensionId || '').trim();
1437
1479
  if (extensionId) ready.extensionId = extensionId;
1438
1480
  const binary = String(details?.binary || '').trim();
@@ -2686,6 +2728,7 @@ var __webpack_modules__ = {
2686
2728
  '--enable-features=SidePanelUpdates',
2687
2729
  '--disable-features=DisableLoadExtensionCommandLineSwitch',
2688
2730
  '--disable-features=ExtensionDisableUnsupportedDeveloper',
2731
+ '--disable-features=SafetyHubExtensionsOffStoreTrigger',
2689
2732
  '--enable-unsafe-extension-debugging',
2690
2733
  '--silent-debugger-extension-api'
2691
2734
  ];
@@ -3514,7 +3557,7 @@ var __webpack_modules__ = {
3514
3557
  binaryProvenance
3515
3558
  };
3516
3559
  if (enableCdp) {
3517
- const mod = await __webpack_require__.e(84).then(__webpack_require__.bind(__webpack_require__, "./browsers/run-chromium/chromium-launch/setup-cdp-after-launch.ts"));
3560
+ const mod = await __webpack_require__.e(597).then(__webpack_require__.bind(__webpack_require__, "./browsers/run-chromium/chromium-launch/setup-cdp-after-launch.ts"));
3518
3561
  const CDP_SETUP_TIMEOUT_MS = 45000;
3519
3562
  await Promise.race([
3520
3563
  mod.setupCdpAfterLaunch(compilation, cdpConfig, chromiumConfig, pipeStreams),
@@ -3805,6 +3848,150 @@ var __webpack_modules__ = {
3805
3848
  var process_teardown = __webpack_require__("./browsers/browsers-lib/process-teardown.ts");
3806
3849
  var ready_message = __webpack_require__("./browsers/browsers-lib/ready-message.ts");
3807
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
+ }
3808
3995
  var runtime_options = __webpack_require__("./browsers/browsers-lib/runtime-options.ts");
3809
3996
  var shared_utils = __webpack_require__("./browsers/browsers-lib/shared-utils.ts");
3810
3997
  function parseFlatpakBinary(binary) {
@@ -4082,7 +4269,12 @@ var __webpack_modules__ = {
4082
4269
  for (const instance of activeInstances)attemptCleanup(instance);
4083
4270
  }
4084
4271
  function forceKillAllOnExit() {
4085
- for (const instance of activeInstances)(0, process_teardown.$Y)(instance.childRef(), instance.browser);
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
+ }
4086
4278
  }
4087
4279
  function firstBrowserLabel() {
4088
4280
  for (const instance of activeInstances)return instance.browser;
@@ -4114,10 +4306,11 @@ var __webpack_modules__ = {
4114
4306
  process.exit(1);
4115
4307
  });
4116
4308
  }
4117
- function setupFirefoxProcessHandlers(browser, childRef, cleanupInstance) {
4309
+ function setupFirefoxProcessHandlers(browser, childRef, cleanupInstance, livePidRef = ()=>null) {
4118
4310
  const instance = {
4119
4311
  browser,
4120
4312
  childRef,
4313
+ livePidRef,
4121
4314
  cleanupInstance,
4122
4315
  isCleaningUp: false
4123
4316
  };
@@ -5203,7 +5396,6 @@ var __webpack_modules__ = {
5203
5396
  } catch {}
5204
5397
  return controller;
5205
5398
  }
5206
- var external_node_child_process_ = __webpack_require__("node:child_process");
5207
5399
  var wsl_support = __webpack_require__("./browsers/browsers-lib/wsl-support.ts");
5208
5400
  const LINUX_FIREFOX_PATHS = [
5209
5401
  '/usr/bin/firefox',
@@ -5473,13 +5665,12 @@ var __webpack_modules__ = {
5473
5665
  browserPid: this.child?.pid,
5474
5666
  extensionId: this.extensionOutputPath ? (0, banner.MT)(this.extensionOutputPath) : void 0
5475
5667
  });
5476
- this.child.on('close', ()=>{
5477
- (0, shared_utils.sW)(profilePath);
5478
- });
5479
5668
  this.wireChildLifecycle();
5669
+ this.trackLiveBrowserPid();
5480
5670
  let ctrl;
5481
5671
  try {
5482
5672
  ctrl = await setupRdpAfterLaunch(this.host, compilation, debugPort);
5673
+ this.trackLiveBrowserPid(1);
5483
5674
  } catch (error) {
5484
5675
  const reason = error?.extensionLoadRefusedReason;
5485
5676
  if (!reason) {
@@ -5574,24 +5765,89 @@ var __webpack_modules__ = {
5574
5765
  if (process.env.VITEST || process.env.VITEST_WORKER_ID) throw new Error('Firefox startup timed out');
5575
5766
  process.exit(1);
5576
5767
  });
5577
- let disposeProcessHandlers;
5578
5768
  child.on('close', (code)=>{
5579
- if (this.watchTimeout) {
5580
- clearTimeout(this.watchTimeout);
5581
- this.watchTimeout = void 0;
5582
- }
5583
- if ((0, messaging._o)()) this.ctx.logger?.info?.(messages.Th(this.host.browser));
5584
- if (!(0, process_teardown.Op)(child)) {
5585
- 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.`);
5586
- (0, ready_stamp.Wi)(this.extensionOutputPath, code);
5587
- }
5588
- this.cleanupInstance().catch((err)=>{
5589
- if ((0, messaging._o)()) this.ctx.logger?.error?.(`[browser] Cleanup error on child close: ${err?.message || err}`);
5590
- });
5591
- disposeProcessHandlers?.();
5769
+ const expected = (0, process_teardown.Op)(child);
5770
+ if (!expected && this.adoptHandedOffBrowser()) return;
5771
+ this.onBrowserGone(code, expected);
5592
5772
  });
5593
5773
  this.pipeChildOutput(child);
5594
- 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?.();
5595
5851
  }
5596
5852
  async retryAddonInstall(compilation, debugPort) {
5597
5853
  try {
@@ -5626,6 +5882,7 @@ var __webpack_modules__ = {
5626
5882
  }
5627
5883
  async cleanupInstance() {
5628
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);
5629
5886
  }
5630
5887
  scheduleWatchTimeout() {
5631
5888
  if (this.watchTimeout) return;
@@ -5660,6 +5917,10 @@ var __webpack_modules__ = {
5660
5917
  firefox_launch_define_property(this, "child", null);
5661
5918
  firefox_launch_define_property(this, "watchTimeout", void 0);
5662
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);
5663
5924
  this.host = host;
5664
5925
  this.ctx = ctx;
5665
5926
  }
@@ -6474,6 +6735,10 @@ var __webpack_modules__ = {
6474
6735
  if ('debug' === type) return pintor__rspack_import_0_default().dim(pintor__rspack_import_0_default().gray(DEBUG_GLYPH));
6475
6736
  return pintor__rspack_import_0_default().gray(GLYPH);
6476
6737
  }
6738
+ const ANSI_PATTERN = /\[[0-9;]*m/g;
6739
+ function hasChannelPrefix(text) {
6740
+ return String(text || '').replace(ANSI_PATTERN, '').trimStart().startsWith(GLYPH);
6741
+ }
6477
6742
  const MACHINE_OUTPUT_VALUES = new Set([
6478
6743
  'json',
6479
6744
  'ndjson'
@@ -6506,7 +6771,8 @@ var __webpack_modules__ = {
6506
6771
  truncate (input, max = 800) {
6507
6772
  const s = (()=>{
6508
6773
  try {
6509
- return 'string' == typeof input ? input : JSON.stringify(input);
6774
+ if ('string' == typeof input) return input;
6775
+ return JSON.stringify(input) ?? String(input);
6510
6776
  } catch {
6511
6777
  return String(input);
6512
6778
  }
@@ -6732,6 +6998,7 @@ var __webpack_modules__ = {
6732
6998
  Gg: ()=>humanError,
6733
6999
  Nr: ()=>card,
6734
7000
  Pl: ()=>prefix,
7001
+ Qi: ()=>hasChannelPrefix,
6735
7002
  T_: ()=>artifactNoun,
6736
7003
  VR: ()=>isCardKeyClaimed,
6737
7004
  _o: ()=>isDebug,
@@ -7198,7 +7465,7 @@ var __webpack_modules__ = {
7198
7465
  return Math.min(Math.max(n, min), max);
7199
7466
  }
7200
7467
  const TEMPLATE_CORPUS_REPO = 'extension-js/examples';
7201
- const TEMPLATE_CORPUS_REF = '06d33e35894516a460409dca06d1614e291e6252';
7468
+ const TEMPLATE_CORPUS_REF = 'f8087f012cf195cba9aa2e3c32fd5a6729da33f0';
7202
7469
  const TEMPLATE_CORPUS_SLUGS = [
7203
7470
  'action',
7204
7471
  'action-locales',
@@ -8077,8 +8344,13 @@ var __webpack_modules__ = {
8077
8344
  function availableCommandsBlock() {
8078
8345
  return COMMANDS.map(commandHelpEntry).join('\n\n');
8079
8346
  }
8347
+ function projectCliVersionMismatch(running, declared, range, installCommand) {
8348
+ return `${getLoggingPrefix('warn')} Running ${messages_code(`extension ${running}`)}, this project declares ${messages_code(`${declared}@${range}`)}.\nRun ${messages_code(installCommand)} so the project's own version runs.`;
8349
+ }
8080
8350
  function unhandledError(err) {
8081
- const message = err instanceof Error ? err.stack || err.message : 'string' == typeof err ? err : messaging.Sc.truncate(err);
8351
+ const rendered = err instanceof Error ? err.message : '';
8352
+ if ((0, messaging.Qi)(rendered)) return rendered;
8353
+ const message = err instanceof Error ? err.stack || err.message : 'string' == typeof err ? err : null == err ? '' : messaging.Sc.truncate(err);
8082
8354
  return `${getLoggingPrefix('error')} ${external_pintor_default().red(String(message || 'Unknown error'))}`;
8083
8355
  }
8084
8356
  function updateFailed(err) {
@@ -9404,6 +9676,102 @@ Cross-browser compatibility
9404
9676
  const values = String(raw).split(',').map((value)=>value.trim()).filter((value)=>value.length > 0);
9405
9677
  return values.length > 0 ? values : void 0;
9406
9678
  }
9679
+ const external_semver_namespaceObject = require("semver");
9680
+ var external_semver_default = /*#__PURE__*/ __webpack_require__.n(external_semver_namespaceObject);
9681
+ const CLI_PACKAGES = [
9682
+ 'extension',
9683
+ 'extension-develop'
9684
+ ];
9685
+ const LOCKFILE_COMMANDS = [
9686
+ [
9687
+ 'pnpm-lock.yaml',
9688
+ 'pnpm install'
9689
+ ],
9690
+ [
9691
+ 'yarn.lock',
9692
+ 'yarn install'
9693
+ ],
9694
+ [
9695
+ 'bun.lock',
9696
+ 'bun install'
9697
+ ],
9698
+ [
9699
+ 'bun.lockb',
9700
+ 'bun install'
9701
+ ],
9702
+ [
9703
+ 'deno.lock',
9704
+ 'deno install'
9705
+ ],
9706
+ [
9707
+ 'package-lock.json',
9708
+ 'npm install'
9709
+ ]
9710
+ ];
9711
+ function installCommandFor(files) {
9712
+ for (const [lockfile, command] of LOCKFILE_COMMANDS)if (files.includes(lockfile)) return command;
9713
+ return 'npm install';
9714
+ }
9715
+ function declaredCliDependency(manifest) {
9716
+ for (const field of [
9717
+ manifest?.dependencies,
9718
+ manifest?.devDependencies
9719
+ ])for (const name of CLI_PACKAGES){
9720
+ const range = field?.[name];
9721
+ if ('string' == typeof range && range.length > 0) return {
9722
+ name,
9723
+ range
9724
+ };
9725
+ }
9726
+ return null;
9727
+ }
9728
+ function isComparableRange(range) {
9729
+ const trimmed = range.trim();
9730
+ if (!trimmed || '*' === trimmed || 'latest' === trimmed) return false;
9731
+ if (/^(workspace|file|link|git|github|npm):/i.test(trimmed)) return false;
9732
+ if (/^[./]/.test(trimmed)) return false;
9733
+ return null !== external_semver_default().validRange(trimmed);
9734
+ }
9735
+ function versionMismatch(input) {
9736
+ const declared = declaredCliDependency(input.manifest);
9737
+ if (!declared) return null;
9738
+ if (!isComparableRange(declared.range)) return null;
9739
+ if (!external_semver_default().valid(input.running)) return null;
9740
+ const comparable = external_semver_default().prerelease(input.running) ? external_semver_default().coerce(input.running)?.version ?? input.running : input.running;
9741
+ if (external_semver_default().satisfies(comparable, declared.range, {
9742
+ includePrerelease: true
9743
+ })) return null;
9744
+ return {
9745
+ declared: declared.name,
9746
+ range: declared.range,
9747
+ running: input.running
9748
+ };
9749
+ }
9750
+ function readProjectManifest(projectPath) {
9751
+ try {
9752
+ return JSON.parse(external_node_fs_.readFileSync(external_node_path_.join(projectPath, 'package.json'), 'utf-8'));
9753
+ } catch {
9754
+ return null;
9755
+ }
9756
+ }
9757
+ function checkProjectCliVersion(projectPath, running) {
9758
+ let files = [];
9759
+ try {
9760
+ files = external_node_fs_.readdirSync(projectPath);
9761
+ } catch {
9762
+ return null;
9763
+ }
9764
+ if (!files.includes('package.json')) return null;
9765
+ const mismatch = versionMismatch({
9766
+ manifest: readProjectManifest(projectPath),
9767
+ running
9768
+ });
9769
+ if (!mismatch) return null;
9770
+ return {
9771
+ ...mismatch,
9772
+ command: installCommandFor(files)
9773
+ };
9774
+ }
9407
9775
  function registerBuildCommand(program) {
9408
9776
  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 })=>{
9409
9777
  const browser = cliBrowser ?? await resolveConfigBrowser(pathOrRemoteUrl || process.cwd(), 'build') ?? 'chromium';
@@ -9471,6 +9839,8 @@ Cross-browser compatibility
9471
9839
  }
9472
9840
  const { extensionBuild } = await loadExtensionDevelopModule();
9473
9841
  const asJson = isJsonOutput(buildOptions);
9842
+ const cliVersion = checkProjectCliVersion(external_node_path_.resolve(pathOrRemoteUrl || process.cwd()), getCliPackageJson().version);
9843
+ if (cliVersion) console.warn(projectCliVersionMismatch(cliVersion.running, cliVersion.declared, cliVersion.range, cliVersion.command));
9474
9844
  if (asJson) process.env.EXTENSION_OUTPUT = 'json';
9475
9845
  const built = [];
9476
9846
  const summaries = [];
@@ -10058,6 +10428,8 @@ Cross-browser compatibility
10058
10428
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
10059
10429
  }
10060
10430
  const asJson = 'json' === resolveOutputFormat(devOptions);
10431
+ const cliVersion = checkProjectCliVersion(external_node_path_.resolve(pathOrRemoteUrl || process.cwd()), getCliPackageJson().version);
10432
+ if (cliVersion) console.warn(projectCliVersionMismatch(cliVersion.running, cliVersion.declared, cliVersion.range, cliVersion.command));
10061
10433
  if (void 0 !== devOptions.parentPid) {
10062
10434
  const parentPid = parseParentPid(devOptions.parentPid);
10063
10435
  if (void 0 === parentPid) {
@@ -10998,6 +11370,8 @@ Cross-browser compatibility
10998
11370
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
10999
11371
  }
11000
11372
  const asJson = 'json' === resolveOutputFormat(startOptions);
11373
+ const cliVersion = checkProjectCliVersion(external_node_path_.resolve(pathOrRemoteUrl || process.cwd()), getCliPackageJson().version);
11374
+ if (cliVersion) console.warn(projectCliVersionMismatch(cliVersion.running, cliVersion.declared, cliVersion.range, cliVersion.command));
11001
11375
  if (asJson) process.env.EXTENSION_OUTPUT = 'json';
11002
11376
  const list = vendors(browser);
11003
11377
  let unsupportedBrowser = '';
@@ -11171,7 +11545,6 @@ Cross-browser compatibility
11171
11545
  await exitAfterDrain(1);
11172
11546
  });
11173
11547
  }
11174
- const external_semver_namespaceObject = require("semver");
11175
11548
  const external_update_check_namespaceObject = require("update-check");
11176
11549
  var external_update_check_default = /*#__PURE__*/ __webpack_require__.n(external_update_check_namespaceObject);
11177
11550
  function isStableVersion(version) {