extension 4.1.25 → 4.1.27

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
@@ -71,14 +71,27 @@ var __webpack_modules__ = {
71
71
  return '';
72
72
  }
73
73
  }
74
+ function registeredDirectoryPath(dir, platform) {
75
+ const absolute = node_path__rspack_import_2.resolve(dir);
76
+ if ('win32' === platform) return absolute;
77
+ try {
78
+ return node_fs__rspack_import_1.realpathSync.native(absolute);
79
+ } catch {
80
+ return absolute;
81
+ }
82
+ }
83
+ function upperCaseDriveLetter(windowsPath) {
84
+ return /^[a-z]:/.test(windowsPath) ? windowsPath[0].toUpperCase() + windowsPath.slice(1) : windowsPath;
85
+ }
86
+ function chromiumExtensionIdFromRegisteredPath(registeredPath, platform = process.platform) {
87
+ const bytes = 'win32' === platform ? Buffer.from(upperCaseDriveLetter(registeredPath.replace(/\//g, '\\')), 'utf16le') : Buffer.from(registeredPath, 'utf8');
88
+ const digest = (0, node_crypto__rspack_import_0.createHash)('sha256').update(bytes).digest().subarray(0, 16);
89
+ return encodeChromiumExtensionIdFromDigest(digest);
90
+ }
74
91
  function deriveChromiumExtensionIdFromPath(extensionPath) {
75
92
  if (!extensionPath || 'string' != typeof extensionPath) return '';
76
93
  try {
77
- const absolute = node_path__rspack_import_2.resolve(extensionPath);
78
- const isWindows = 'win32' === process.platform;
79
- const seedBuffer = isWindows ? Buffer.from(absolute.replace(/\//g, '\\'), 'utf16le') : Buffer.from(absolute, 'utf8');
80
- const digest = (0, node_crypto__rspack_import_0.createHash)('sha256').update(seedBuffer).digest().subarray(0, 16);
81
- return encodeChromiumExtensionIdFromDigest(digest);
94
+ return chromiumExtensionIdFromRegisteredPath(registeredDirectoryPath(extensionPath, process.platform), process.platform);
82
95
  } catch {
83
96
  return '';
84
97
  }
@@ -275,6 +288,8 @@ var __webpack_modules__ = {
275
288
  'firefox',
276
289
  'waterfox',
277
290
  'librewolf',
291
+ 'zen',
292
+ 'floorp',
278
293
  'gecko-based',
279
294
  'firefox-based'
280
295
  ]);
@@ -284,8 +299,15 @@ var __webpack_modules__ = {
284
299
  function isFirefoxBrowser(browser) {
285
300
  return FIREFOX_BROWSERS.has(String(browser));
286
301
  }
302
+ const EMULATOR_BROWSERS = new Set([
303
+ 'chromium-emulator'
304
+ ]);
305
+ function isEmulatorBrowser(browser) {
306
+ return EMULATOR_BROWSERS.has(String(browser));
307
+ }
287
308
  __webpack_require__.d(__webpack_exports__, {
288
309
  M_: ()=>isFirefoxBrowser,
310
+ eP: ()=>isEmulatorBrowser,
289
311
  rG: ()=>isChromiumBrowser
290
312
  });
291
313
  },
@@ -421,7 +443,8 @@ var __webpack_modules__ = {
421
443
  var pintor__rspack_import_8 = __webpack_require__("pintor");
422
444
  var pintor__rspack_import_8_default = /*#__PURE__*/ __webpack_require__.n(pintor__rspack_import_8);
423
445
  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");
446
+ var _run_firefox_firefox_launch_librewolf_overrides__rspack_import_10 = __webpack_require__("./browsers/run-firefox/firefox-launch/librewolf-overrides.ts");
447
+ var _browser_family__rspack_import_11 = __webpack_require__("./browsers/browsers-lib/browser-family.ts");
425
448
  const require1 = (0, node_module__rspack_import_1.createRequire)(__rslib_import_meta_url__);
426
449
  function getLoggingPrefix(type) {
427
450
  return (0, _helpers_messaging__rspack_import_9.Pl)(type);
@@ -497,7 +520,7 @@ var __webpack_modules__ = {
497
520
  return browser;
498
521
  }
499
522
  function capitalizedBrowserName(browser) {
500
- return `${browser.charAt(0).toUpperCase() + browser.slice(1)}`;
523
+ return (0, _helpers_messaging__rspack_import_9.QZ)(String(browser));
501
524
  }
502
525
  function resolveBrowserVersionLine(browser, pinnedLine, opts) {
503
526
  const pinned = String(pinnedLine || '').trim();
@@ -546,6 +569,10 @@ var __webpack_modules__ = {
546
569
  })();
547
570
  return `${getLoggingPrefix('error')} ${isUnreachable}${pintor__rspack_import_8_default().gray('NOT FOUND')} ${pintor__rspack_import_8_default().underline(browserBinaryLocation || `${capitalizedBrowserName(browser)}BROWSER`)}\nInstall the missing browser, or choose another one with ${pintor__rspack_import_8_default().blue('--browser')} ${pintor__rspack_import_8_default().gray('<chrome|edge|firefox>')}.` + wslHint;
548
571
  }
572
+ function geckoForkNotInstalled(browser, guidance) {
573
+ const steps = String(guidance || '').split('\n').map((line)=>line.trimEnd()).filter((line)=>line && !/^We couldn't find/i.test(line)).filter((line)=>!/^Re-run your command/i.test(line)).join('\n');
574
+ return `${getLoggingPrefix('error')} ${capitalizedBrowserName(browser)} isn't installed.\n${steps}\nOr point at a binary with ${pintor__rspack_import_8_default().blue('--gecko-binary')} ${pintor__rspack_import_8_default().gray('<path>')}, or choose another browser with ${pintor__rspack_import_8_default().blue('--browser')} ${pintor__rspack_import_8_default().gray('<firefox|waterfox|librewolf|zen|floorp>')}.`;
575
+ }
549
576
  function usingManagedChromiumFamilyFallback(requestedBrowser, _fallbackBrowser, _binaryPath) {
550
577
  return `${getLoggingPrefix('warn')} ${managedBrowserDisplayName(requestedBrowser)} isn't installed.\nRun ${pintor__rspack_import_8_default().blue(`npx extension install ${requestedBrowser}`)} to use ${managedBrowserDisplayName(requestedBrowser)} itself.`;
551
578
  }
@@ -686,8 +713,11 @@ var __webpack_modules__ = {
686
713
  body.push("Run your command again after the install finishes.");
687
714
  return `${body.join('\n')}\n`;
688
715
  }
689
- function firefoxLaunchCalled() {
690
- return `${getLoggingPrefix('debug')} browser launch browser=firefox`;
716
+ function firefoxLaunchCalled(browser = 'firefox') {
717
+ return `${getLoggingPrefix('debug')} browser launch browser=${browser}`;
718
+ }
719
+ function librewolfRemoteDebuggingLocked(overridesPath) {
720
+ return `${getLoggingPrefix('error')} LibreWolf keeps remote debugging off, so Extension.js can't reach it.\nLibreWolf resets ${pintor__rspack_import_8_default().gray('devtools.debugger.remote-enabled')} to false at every start. Add these two lines to ${pintor__rspack_import_8_default().underline(overridesPath)} and run the command again:\n` + _run_firefox_firefox_launch_librewolf_overrides__rspack_import_10.Tu.map((line)=>` ${pintor__rspack_import_8_default().blue(line)}\n`).join('') + `Or choose another browser with ${pintor__rspack_import_8_default().blue('--browser')} ${pintor__rspack_import_8_default().gray('<firefox|waterfox|zen|floorp>')}.`;
691
721
  }
692
722
  function firefoxFailedToStart(error) {
693
723
  return `${getLoggingPrefix('error')} Firefox failed to start.\n${pintor__rspack_import_8_default().red(errorDetail(error))}`;
@@ -836,7 +866,7 @@ var __webpack_modules__ = {
836
866
  }
837
867
  function pinnedBinaryFlag(browser) {
838
868
  const name = String(browser || '');
839
- if ((0, _browser_family__rspack_import_10.M_)(name)) return '--gecko-binary';
869
+ if ((0, _browser_family__rspack_import_11.M_)(name)) return '--gecko-binary';
840
870
  if ('safari' === name || 'webkit-based' === name) return '--safari-binary';
841
871
  return '--chromium-binary';
842
872
  }
@@ -852,11 +882,8 @@ var __webpack_modules__ = {
852
882
  case 'edge':
853
883
  browserDevToolsUrl = 'edge://extensions';
854
884
  break;
855
- case 'firefox':
856
- browserDevToolsUrl = 'about:debugging#/runtime/this-firefox';
857
- break;
858
885
  default:
859
- browserDevToolsUrl = '';
886
+ browserDevToolsUrl = (0, _browser_family__rspack_import_11.M_)(browser) ? 'about:debugging#/runtime/this-firefox' : '';
860
887
  }
861
888
  if (!message.data) return `${getLoggingPrefix('error')} No client data received for ${manifestName}.\n\n${pintor__rspack_import_8_default().red("Extension.js can't read data from your extension.")}\n${pintor__rspack_import_8_default().red('To fix, ensure that:')}\n\n- Your extension is enabled in ${pintor__rspack_import_8_default().underline(browserDevToolsUrl)}\n- No previous ${capitalize(browser)} browser instance is open\n\nIf both hold, restart the ${pintor__rspack_import_8_default().yellow(manifest.name || '')} and the\n${pintor__rspack_import_8_default().yellow('Manager Extension')} in ${pintor__rspack_import_8_default().underline(browserDevToolsUrl)} and try again.\nIf the issue persists, report a bug:\n` + pintor__rspack_import_8_default().underline("https://github.com/extension-js/extension.js/issues");
862
889
  const { id = '', management } = message.data;
@@ -1025,6 +1052,7 @@ var __webpack_modules__ = {
1025
1052
  _D: ()=>browserLaunchError,
1026
1053
  aI: ()=>devChromeProfilePath,
1027
1054
  aO: ()=>safariOpenHint,
1055
+ bC: ()=>librewolfRemoteDebuggingLocked,
1028
1056
  bv: ()=>cdpUnifiedExtensionLog,
1029
1057
  cD: ()=>targetActorHasActiveRequestError,
1030
1058
  cF: ()=>safariRebuilt,
@@ -1062,6 +1090,7 @@ var __webpack_modules__ = {
1062
1090
  sP: ()=>mv2NotSupportedByChromium,
1063
1091
  sY: ()=>creatingUserProfile,
1064
1092
  uK: ()=>safariConverting,
1093
+ v5: ()=>geckoForkNotInstalled,
1065
1094
  wk: ()=>chromeFailedToSpawn,
1066
1095
  xX: ()=>binaryProvenanceNote,
1067
1096
  xy: ()=>chromeInitializingEnhancedReload,
@@ -1139,7 +1168,7 @@ var __webpack_modules__ = {
1139
1168
  const root = String(cacheRoot || '').trim();
1140
1169
  if (!root) return {};
1141
1170
  if ('safari' === browser || 'webkit-based' === browser) return {};
1142
- if ('brave' === browser || 'opera' === browser || 'vivaldi' === browser || 'yandex' === browser || 'waterfox' === browser || 'librewolf' === browser) return {};
1171
+ if ('brave' === browser || 'opera' === browser || 'vivaldi' === browser || 'yandex' === browser || 'waterfox' === browser || 'librewolf' === browser || 'zen' === browser || 'floorp' === browser) return {};
1143
1172
  if ('chrome' === browser) return {
1144
1173
  PUPPETEER_CACHE_DIR: node_path__rspack_import_1.join(root, 'chrome', 'chrome')
1145
1174
  };
@@ -2032,13 +2061,113 @@ var __webpack_modules__ = {
2032
2061
  const external_wsl_support_namespaceObject = require("wsl-support");
2033
2062
  },
2034
2063
  "./browsers/index.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
2035
- var _browsers_lib_browser_family__rspack_import_0 = __webpack_require__("./browsers/browsers-lib/browser-family.ts");
2036
- var _browsers_lib_output_binaries_resolver__rspack_import_1 = __webpack_require__("./browsers/browsers-lib/output-binaries-resolver.ts");
2037
- var _browsers_lib_runtime_options__rspack_import_10 = __webpack_require__("./browsers/browsers-lib/runtime-options.ts");
2038
- var _run_chromium_chromium_context__rspack_import_8 = __webpack_require__("./browsers/run-chromium/chromium-context/index.ts");
2039
- var _run_chromium_chromium_launch__rspack_import_2 = __webpack_require__("./browsers/run-chromium/chromium-launch/index.ts");
2040
- var _run_firefox_firefox_context__rspack_import_9 = __webpack_require__("./browsers/run-firefox/firefox-context/index.ts");
2041
- var _run_firefox_firefox_launch__rspack_import_3 = __webpack_require__("./browsers/run-firefox/firefox-launch/index.ts");
2064
+ __webpack_require__.d(__webpack_exports__, {
2065
+ launchBrowser: ()=>launchBrowser
2066
+ });
2067
+ var browser_family = __webpack_require__("./browsers/browsers-lib/browser-family.ts");
2068
+ var output_binaries_resolver = __webpack_require__("./browsers/browsers-lib/output-binaries-resolver.ts");
2069
+ var runtime_options = __webpack_require__("./browsers/browsers-lib/runtime-options.ts");
2070
+ var chromium_context = __webpack_require__("./browsers/run-chromium/chromium-context/index.ts");
2071
+ var chromium_launch = __webpack_require__("./browsers/run-chromium/chromium-launch/index.ts");
2072
+ var external_node_child_process_ = __webpack_require__("node:child_process");
2073
+ var external_pintor_ = __webpack_require__("pintor");
2074
+ var external_pintor_default = /*#__PURE__*/ __webpack_require__.n(external_pintor_);
2075
+ var emulator_session = __webpack_require__("./helpers/emulator-session.ts");
2076
+ var messaging = __webpack_require__("./helpers/messaging.ts");
2077
+ function emulatorViewerUrlLine(url) {
2078
+ return `${(0, messaging.Pl)('info')} Emulated Chromium runs in a web page. Open this address to load your extension:\n${external_pintor_default().underline(url)}`;
2079
+ }
2080
+ function emulatorLogsLimitLine() {
2081
+ return `${(0, messaging.Pl)('warn')} --logs has no effect here: ${emulator_session.fg}`;
2082
+ }
2083
+ function openCommandFor(url, platform = process.platform) {
2084
+ if ('darwin' === platform) return {
2085
+ command: 'open',
2086
+ args: [
2087
+ url
2088
+ ]
2089
+ };
2090
+ if ('win32' === platform) return {
2091
+ command: 'rundll32',
2092
+ args: [
2093
+ 'url.dll,FileProtocolHandler',
2094
+ url
2095
+ ]
2096
+ };
2097
+ return {
2098
+ command: 'xdg-open',
2099
+ args: [
2100
+ url
2101
+ ]
2102
+ };
2103
+ }
2104
+ function engineVersionUrl(viewerUrl) {
2105
+ try {
2106
+ const parsed = new URL(viewerUrl);
2107
+ const base = parsed.pathname.endsWith('/') ? parsed.pathname : `${parsed.pathname.replace(/[^/]*$/, '')}`;
2108
+ return `${parsed.origin}${base}version.json`;
2109
+ } catch {
2110
+ return null;
2111
+ }
2112
+ }
2113
+ async function probeEngineOrigin(viewerUrl, fetchImpl = (url, init)=>fetch(url, init), timeoutMs = 3000) {
2114
+ const url = engineVersionUrl(viewerUrl);
2115
+ if (!url) return 'unknown';
2116
+ const controller = new AbortController();
2117
+ const timer = setTimeout(()=>controller.abort(), timeoutMs);
2118
+ try {
2119
+ const response = await fetchImpl(url, {
2120
+ signal: controller.signal
2121
+ });
2122
+ if (429 === response.status) return 'throttled';
2123
+ if (503 === response.status) return 'held';
2124
+ if (200 !== response.status) return 'unknown';
2125
+ const report = await response.json();
2126
+ return report && 'held' === report.hold ? 'held' : 'open';
2127
+ } catch {
2128
+ return 'unknown';
2129
+ } finally{
2130
+ clearTimeout(timer);
2131
+ }
2132
+ }
2133
+ function engineOriginLine(verdict) {
2134
+ if ('held' === verdict) return `${(0, messaging.Pl)('warn')} emulated Chromium is not open to the public yet, so this address answers 503 until it is. Run this project with --browser=chrome in the meantime.`;
2135
+ if ('throttled' === verdict) return `${(0, messaging.Pl)('warn')} the emulated Chromium origin is rate limiting this address (HTTP 429). Wait a minute, then run extension dev again, or run this project with --browser=chrome.`;
2136
+ return null;
2137
+ }
2138
+ function openInDefaultBrowser(url) {
2139
+ const { command, args } = openCommandFor(url);
2140
+ try {
2141
+ const child = (0, external_node_child_process_.spawn)(command, args, {
2142
+ detached: true,
2143
+ stdio: 'ignore',
2144
+ windowsHide: true
2145
+ });
2146
+ child.on('error', ()=>{});
2147
+ child.unref();
2148
+ } catch {
2149
+ return;
2150
+ }
2151
+ }
2152
+ async function launchEmulator(opts, opener = openInDefaultBrowser, probe = probeEngineOrigin) {
2153
+ if ('development' !== (opts.mode || 'production')) throw new Error('emulated Chromium needs the dev server that serves the files the page reads. Run extension dev instead.');
2154
+ const url = opts.emulatorViewerUrl;
2155
+ if (!url) throw new Error('this version of extension-develop does not serve emulated Chromium. Update extension-develop so it matches the CLI, then run extension dev again.');
2156
+ console.log(emulatorViewerUrlLine(url));
2157
+ const willOpen = !opts.noOpen && !opts.dryRun;
2158
+ const verdict = willOpen ? await probe(url) : 'unknown';
2159
+ const originLine = engineOriginLine(verdict);
2160
+ if (originLine) console.warn(originLine);
2161
+ if (willOpen && !originLine) opener(url);
2162
+ const logsRequested = Boolean(opts.logLevel && 'off' !== opts.logLevel);
2163
+ return {
2164
+ async enableUnifiedLogging () {
2165
+ if (logsRequested) console.warn(emulatorLogsLimitLine());
2166
+ }
2167
+ };
2168
+ }
2169
+ var firefox_context = __webpack_require__("./browsers/run-firefox/firefox-context/index.ts");
2170
+ var firefox_launch = __webpack_require__("./browsers/run-firefox/firefox-launch/index.ts");
2042
2171
  __webpack_require__("./browsers/run-only.ts");
2043
2172
  __webpack_require__("./browsers/run-safari/safari-launch/index.ts");
2044
2173
  __webpack_require__("./browsers/run-safari/safari-launch/safari-config.ts");
@@ -2058,11 +2187,12 @@ var __webpack_modules__ = {
2058
2187
  };
2059
2188
  }
2060
2189
  async function launchBrowser(opts) {
2190
+ if ((0, browser_family.eP)(opts.browser)) return launchEmulator(opts);
2061
2191
  const compilationLike = createCompilationLike(opts);
2062
2192
  const mode = opts.mode || 'production';
2063
- (0, _browsers_lib_output_binaries_resolver__rspack_import_1.LB)(compilationLike);
2064
- if ((0, _browsers_lib_browser_family__rspack_import_0.rG)(opts.browser)) return launchChromium(opts, compilationLike, mode);
2065
- if ((0, _browsers_lib_browser_family__rspack_import_0.M_)(opts.browser)) return launchFirefox(opts, compilationLike, mode);
2193
+ (0, output_binaries_resolver.LB)(compilationLike);
2194
+ if ((0, browser_family.rG)(opts.browser)) return launchChromium(opts, compilationLike, mode);
2195
+ if ((0, browser_family.M_)(opts.browser)) return launchFirefox(opts, compilationLike, mode);
2066
2196
  throw new Error(`Unsupported browser: ${String(opts.browser)}`);
2067
2197
  }
2068
2198
  async function launchChromium(opts, compilationLike, mode) {
@@ -2091,8 +2221,8 @@ var __webpack_modules__ = {
2091
2221
  logTab: opts.logTab,
2092
2222
  logSink: opts.logSink
2093
2223
  };
2094
- const ctx = (0, _run_chromium_chromium_context__rspack_import_8.g)();
2095
- const launcher = new _run_chromium_chromium_launch__rspack_import_2.f(chromiumOpts, ctx);
2224
+ const ctx = (0, chromium_context.g)();
2225
+ const launcher = new chromium_launch.f(chromiumOpts, ctx);
2096
2226
  const enableCdp = 'development' === mode;
2097
2227
  await launcher.runOnce(compilationLike, {
2098
2228
  enableCdpPostLaunch: enableCdp
@@ -2166,9 +2296,9 @@ var __webpack_modules__ = {
2166
2296
  port: opts.port,
2167
2297
  dryRun: opts.dryRun
2168
2298
  };
2169
- const ctx = (0, _run_firefox_firefox_context__rspack_import_9.D)();
2170
- const launcher = new _run_firefox_firefox_launch__rspack_import_3.c(firefoxOpts, ctx);
2171
- const launchRequest = (0, _browsers_lib_runtime_options__rspack_import_10.zU)(pluginOptions, mode, {
2299
+ const ctx = (0, firefox_context.D)();
2300
+ const launcher = new firefox_launch.c(firefoxOpts, ctx);
2301
+ const launchRequest = (0, runtime_options.zU)(pluginOptions, mode, {
2172
2302
  persistProfile: opts.persistProfile,
2173
2303
  geckoBinary: opts.geckoBinary
2174
2304
  });
@@ -2198,9 +2328,6 @@ var __webpack_modules__ = {
2198
2328
  }
2199
2329
  };
2200
2330
  }
2201
- __webpack_require__.d(__webpack_exports__, {
2202
- launchBrowser: ()=>launchBrowser
2203
- });
2204
2331
  },
2205
2332
  "./browsers/run-chromium/cdp/discovery.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
2206
2333
  __webpack_require__.d(__webpack_exports__, {
@@ -3625,10 +3752,11 @@ var __webpack_modules__ = {
3625
3752
  stderrStream.on('error', ()=>{});
3626
3753
  }
3627
3754
  let disposeSignalHandlers;
3628
- child.on('close', (code)=>{
3755
+ child.on('close', (code, signal)=>{
3629
3756
  if ((0, messaging._o)()) this.logger.info(messages.nn(code || 0));
3757
+ const how = null == code ? `signal ${signal || 'unknown'}` : `code ${code}`;
3630
3758
  if (!(0, process_teardown.Op)(child)) {
3631
- this.logger.error(this.closeHandlerContext?.isDevMode ? `[browser] ${this.options.browser} exited mid-session (code ${code ?? 'unknown'}). The dev server is still running but reloads cannot be delivered, restart "extension dev" to relaunch the browser.` : `[browser] ${this.options.browser} exited (code ${code ?? 'unknown'}); the preview session is over.`);
3759
+ this.logger.error(this.closeHandlerContext?.isDevMode ? `[browser] ${this.options.browser} exited mid-session (${how}). The dev server is still running but reloads cannot be delivered, restart "extension dev" to relaunch the browser.` : `[browser] ${this.options.browser} exited (${how}); the preview session is over.`);
3632
3760
  (0, ready_stamp.Wi)(this.closeHandlerContext?.extensionOutputPath, code);
3633
3761
  }
3634
3762
  disposeSignalHandlers?.();
@@ -3836,10 +3964,14 @@ var __webpack_modules__ = {
3836
3964
  var external_node_fs_ = __webpack_require__("node:fs");
3837
3965
  var external_firefox_location2_ = __webpack_require__("firefox-location2");
3838
3966
  var external_firefox_location2_default = /*#__PURE__*/ __webpack_require__.n(external_firefox_location2_);
3967
+ const external_floorp_location_namespaceObject = require("floorp-location");
3968
+ var external_floorp_location_default = /*#__PURE__*/ __webpack_require__.n(external_floorp_location_namespaceObject);
3839
3969
  const external_librewolf_location_namespaceObject = require("librewolf-location");
3840
3970
  var external_librewolf_location_default = /*#__PURE__*/ __webpack_require__.n(external_librewolf_location_namespaceObject);
3841
3971
  const external_waterfox_location_namespaceObject = require("waterfox-location");
3842
3972
  var external_waterfox_location_default = /*#__PURE__*/ __webpack_require__.n(external_waterfox_location_namespaceObject);
3973
+ const external_zen_location_namespaceObject = require("zen-location");
3974
+ var external_zen_location_default = /*#__PURE__*/ __webpack_require__.n(external_zen_location_namespaceObject);
3843
3975
  var messaging = __webpack_require__("./helpers/messaging.ts");
3844
3976
  var banner = __webpack_require__("./browsers/browsers-lib/banner.ts");
3845
3977
  var instance_registry = __webpack_require__("./browsers/browsers-lib/instance-registry.ts");
@@ -4245,12 +4377,30 @@ var __webpack_modules__ = {
4245
4377
  extensionsToLoad
4246
4378
  };
4247
4379
  }
4380
+ function attachChildOutput(child, opts) {
4381
+ const sinks = opts.sinks || {
4382
+ stdout: process.stdout,
4383
+ stderr: process.stderr
4384
+ };
4385
+ for (const [stream, sink] of [
4386
+ [
4387
+ child.stdout,
4388
+ sinks.stdout
4389
+ ],
4390
+ [
4391
+ child.stderr,
4392
+ sinks.stderr
4393
+ ]
4394
+ ])if (stream) if (opts.debug) stream.pipe(sink);
4395
+ else stream.resume();
4396
+ }
4248
4397
  function logFirefoxDryRun(browserBinaryLocation, launchArgs) {
4249
4398
  if ((0, messaging._o)()) (0, messaging._w)(messages.A9());
4250
4399
  (0, messaging._w)(messages.qn());
4251
4400
  (0, messaging._w)(messages.LD(browserBinaryLocation));
4252
4401
  (0, messaging._w)(messages.lO(launchArgs.join(' ')));
4253
4402
  }
4403
+ var librewolf_overrides = __webpack_require__("./browsers/run-firefox/firefox-launch/librewolf-overrides.ts");
4254
4404
  const activeInstances = new Set();
4255
4405
  let globalHandlersInstalled = false;
4256
4406
  async function attemptCleanup(instance) {
@@ -5257,7 +5407,7 @@ var __webpack_modules__ = {
5257
5407
  }
5258
5408
  } catch {}
5259
5409
  this.lastInstalledAddonPath = primaryAddonPath;
5260
- const bannerPrinted = await printRunningInDevelopmentSummary(candidateAddonPaths, 'firefox', this.derivedExtensionId, this.options.browserVersionLine, {
5410
+ const bannerPrinted = await printRunningInDevelopmentSummary(candidateAddonPaths, this.options.browser, this.derivedExtensionId, this.options.browserVersionLine, {
5261
5411
  profilePath: this.options.launchProfilePath,
5262
5412
  binaryPath: this.options.launchBinaryPath,
5263
5413
  binaryProvenance: this.options.launchBinaryProvenance
@@ -5509,12 +5659,13 @@ var __webpack_modules__ = {
5509
5659
  async launch(compilation, options) {
5510
5660
  const compilationErrors = compilation?.errors || [];
5511
5661
  if (compilationErrors.length > 0) return void this.ctx.logger?.info?.(messages.y7());
5512
- if ((0, messaging._o)()) this.ctx.logger?.info?.(messages.A9());
5662
+ if ((0, messaging._o)()) this.ctx.logger?.info?.(messages.A9(this.host.browser));
5513
5663
  const normalizePath = (value)=>{
5514
5664
  const normalized = value ? (0, wsl_support.f7)(value) : null;
5515
5665
  return normalized && external_node_fs_.existsSync(normalized) ? normalized : null;
5516
5666
  };
5517
- const resolveManagedBinary = ()=>normalizePath((0, output_binaries_resolver.kI)(compilation, 'firefox') || null);
5667
+ const isNamedGeckoFork = 'waterfox' === this.host.browser || 'librewolf' === this.host.browser || 'zen' === this.host.browser || 'floorp' === this.host.browser;
5668
+ const resolveManagedBinary = ()=>isNamedGeckoFork ? null : normalizePath((0, output_binaries_resolver.kI)(compilation, 'firefox') || null);
5518
5669
  const resolveWslFallback = ()=>resolveWslWindowsBinary();
5519
5670
  const getInstallGuidanceText = ()=>{
5520
5671
  try {
@@ -5544,6 +5695,14 @@ var __webpack_modules__ = {
5544
5695
  const dryRun = Boolean(this.host.dryRun);
5545
5696
  if (inTestRunner && !dryRun) return void logFirefoxDryRun('firefox-mock-binary', []);
5546
5697
  if (inTestRunner && dryRun) return void await this.printDryRunPlan(compilation, options, this.host.geckoBinary ? (0, wsl_support.f7)(String(this.host.geckoBinary)) : 'firefox-mock-binary');
5698
+ if ('librewolf' === this.host.browser) {
5699
+ const remoteDebugging = (0, librewolf_overrides.u5)(external_node_fs_, process.env, process.platform);
5700
+ if (!remoteDebugging.enabled) {
5701
+ (0, messaging.Gg)(messages.bC(remoteDebugging.expectedPath));
5702
+ if (inTestRunner) throw new Error('LibreWolf remote debugging is disabled');
5703
+ process.exit(1);
5704
+ }
5705
+ }
5547
5706
  let browserBinaryLocation = resolveManagedBinary();
5548
5707
  let skipDetection = Boolean(browserBinaryLocation);
5549
5708
  const engineBased = 'gecko-based' === this.host.browser || 'firefox-based' === this.host.browser;
@@ -5582,6 +5741,18 @@ var __webpack_modules__ = {
5582
5741
  });
5583
5742
  const normalized = normalizePath(located);
5584
5743
  if (normalized) browserBinaryLocation = normalized;
5744
+ } else if ('zen' === this.host.browser) {
5745
+ const located = external_zen_location_default()(true, {
5746
+ env: process.env
5747
+ });
5748
+ const normalized = normalizePath(located);
5749
+ if (normalized) browserBinaryLocation = normalized;
5750
+ } else if ('floorp' === this.host.browser) {
5751
+ const located = external_floorp_location_default()(true, {
5752
+ env: process.env
5753
+ });
5754
+ const normalized = normalizePath(located);
5755
+ if (normalized) browserBinaryLocation = normalized;
5585
5756
  } else {
5586
5757
  const cacheRoot = (0, output_binaries_resolver.LB)(compilation);
5587
5758
  const env = {
@@ -5753,9 +5924,9 @@ var __webpack_modules__ = {
5753
5924
  });
5754
5925
  }
5755
5926
  pipeChildOutput(child) {
5756
- if (!(0, messaging._o)()) return;
5757
- child.stdout?.pipe(process.stdout);
5758
- child.stderr?.pipe(process.stderr);
5927
+ attachChildOutput(child, {
5928
+ debug: (0, messaging._o)()
5929
+ });
5759
5930
  }
5760
5931
  wireChildLifecycle() {
5761
5932
  const child = this.child;
@@ -5765,15 +5936,15 @@ var __webpack_modules__ = {
5765
5936
  if (process.env.VITEST || process.env.VITEST_WORKER_ID) throw new Error('Firefox startup timed out');
5766
5937
  process.exit(1);
5767
5938
  });
5768
- child.on('close', (code)=>{
5939
+ child.on('close', (code, signal)=>{
5769
5940
  const expected = (0, process_teardown.Op)(child);
5770
5941
  if (!expected && this.adoptHandedOffBrowser()) return;
5771
- this.onBrowserGone(code, expected);
5942
+ this.onBrowserGone(code, expected, signal);
5772
5943
  });
5773
5944
  this.pipeChildOutput(child);
5774
5945
  this.disposeProcessHandlers = setupFirefoxProcessHandlers(this.host.browser, ()=>this.child, ()=>this.cleanupInstance(), ()=>this.livePid);
5775
5946
  }
5776
- onBrowserGone(code, expected) {
5947
+ onBrowserGone(code, expected, signal) {
5777
5948
  if (this.browserGone) return;
5778
5949
  this.browserGone = true;
5779
5950
  if (this.watchTimeout) {
@@ -5787,7 +5958,7 @@ var __webpack_modules__ = {
5787
5958
  if (this.host.launchProfilePath) (0, shared_utils.sW)(this.host.launchProfilePath);
5788
5959
  if ((0, messaging._o)()) this.ctx.logger?.info?.(messages.Th(this.host.browser));
5789
5960
  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.`);
5961
+ this.ctx.logger?.error?.(`[browser] ${this.host.browser} exited (${null == code ? `signal ${signal || 'unknown'}` : `code ${code}`}) without being asked to. The add-on may have been rejected or the browser crashed; the session cannot be driven.`);
5791
5962
  (0, ready_stamp.Wi)(this.extensionOutputPath, code);
5792
5963
  }
5793
5964
  this.cleanupInstance().catch((err)=>{
@@ -5903,6 +6074,8 @@ var __webpack_modules__ = {
5903
6074
  if ('function' == typeof this.watchTimeout.unref) this.watchTimeout.unref();
5904
6075
  }
5905
6076
  printInstallHint(compilation, raw) {
6077
+ const forkGuidance = geckoForkInstallGuidance(this.host.browser);
6078
+ if (null !== forkGuidance) return void (0, messaging.Gg)(messages.v5(this.host.browser, forkGuidance));
5906
6079
  try {
5907
6080
  const displayCacheDir = (0, output_binaries_resolver.LB)(compilation);
5908
6081
  const pretty = messages.MG(this.host.browser || 'firefox', raw, displayCacheDir);
@@ -5925,6 +6098,69 @@ var __webpack_modules__ = {
5925
6098
  this.ctx = ctx;
5926
6099
  }
5927
6100
  }
6101
+ function geckoForkInstallGuidance(browser) {
6102
+ const read = (fn)=>{
6103
+ try {
6104
+ return fn();
6105
+ } catch {
6106
+ return '';
6107
+ }
6108
+ };
6109
+ switch(browser){
6110
+ case 'waterfox':
6111
+ return read(()=>(0, external_waterfox_location_namespaceObject.getInstallGuidance)());
6112
+ case 'librewolf':
6113
+ return read(()=>(0, external_librewolf_location_namespaceObject.getInstallGuidance)());
6114
+ case 'zen':
6115
+ return read(()=>(0, external_zen_location_namespaceObject.getInstallGuidance)());
6116
+ case 'floorp':
6117
+ return read(()=>(0, external_floorp_location_namespaceObject.getInstallGuidance)());
6118
+ default:
6119
+ return null;
6120
+ }
6121
+ }
6122
+ },
6123
+ "./browsers/run-firefox/firefox-launch/librewolf-overrides.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
6124
+ var node_path__rspack_import_0 = __webpack_require__("node:path");
6125
+ const LIBREWOLF_REMOTE_DEBUGGING_LINES = [
6126
+ 'pref("devtools.debugger.remote-enabled", true);',
6127
+ 'pref("devtools.debugger.prompt-connection", false);'
6128
+ ];
6129
+ const OVERRIDES_FILE = 'librewolf.overrides.cfg';
6130
+ function librewolfOverridesCandidates(env, platform) {
6131
+ const home = String(env.HOME || env.USERPROFILE || '').trim();
6132
+ const candidates = [];
6133
+ if ('win32' === platform) {
6134
+ if (home) candidates.push(node_path__rspack_import_0.join(home, '.librewolf', OVERRIDES_FILE));
6135
+ return candidates;
6136
+ }
6137
+ if (home) candidates.push(node_path__rspack_import_0.join(home, '.librewolf', OVERRIDES_FILE));
6138
+ const xdg = String(env.XDG_CONFIG_HOME || '').trim();
6139
+ if (xdg) candidates.push(node_path__rspack_import_0.join(xdg, 'librewolf', 'librewolf', OVERRIDES_FILE));
6140
+ if (home) candidates.push(node_path__rspack_import_0.join(home, '.config', 'librewolf', 'librewolf', OVERRIDES_FILE));
6141
+ return candidates;
6142
+ }
6143
+ function librewolfRemoteDebuggingEnabled(fsLike, env, platform) {
6144
+ const candidates = librewolfOverridesCandidates(env, platform);
6145
+ const expectedPath = candidates[0] || node_path__rspack_import_0.join('~', '.librewolf', OVERRIDES_FILE);
6146
+ const enabledLine = /^\s*(?:pref|defaultPref|lockPref)\(\s*"devtools\.debugger\.remote-enabled"\s*,\s*true\s*\)/m;
6147
+ for (const candidate of candidates)try {
6148
+ if (!fsLike.existsSync(candidate)) continue;
6149
+ if (enabledLine.test(fsLike.readFileSync(candidate, 'utf-8'))) return {
6150
+ enabled: true,
6151
+ expectedPath: candidate
6152
+ };
6153
+ } catch {}
6154
+ return {
6155
+ enabled: false,
6156
+ expectedPath
6157
+ };
6158
+ }
6159
+ __webpack_require__.d(__webpack_exports__, {
6160
+ u5: ()=>librewolfRemoteDebuggingEnabled
6161
+ }, {
6162
+ Tu: LIBREWOLF_REMOTE_DEBUGGING_LINES
6163
+ });
5928
6164
  },
5929
6165
  "./browsers/run-only.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
5930
6166
  var node_fs__rspack_import_0 = __webpack_require__("node:fs");
@@ -6710,6 +6946,32 @@ var __webpack_modules__ = {
6710
6946
  w6: ()=>readBrowserInstall
6711
6947
  });
6712
6948
  },
6949
+ "./helpers/emulator-session.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
6950
+ var _vendors__rspack_import_0 = __webpack_require__("./helpers/vendors.ts");
6951
+ const EMULATOR_LOGS_REFUSAL = 'emulated Chromium runs in a web page, so extension logs has nothing to attach to. Open your browser devtools on that page to read the console.';
6952
+ function emulatorRefusalFor(command) {
6953
+ if ('logs' === command) return EMULATOR_LOGS_REFUSAL;
6954
+ return `emulated Chromium runs in a web page and speaks no debugging protocol, so extension ${command} cannot reach it. Work in the page the dev server printed, or run this project with --browser=chrome.`;
6955
+ }
6956
+ function isEmulatorSession(bridge, projectPath, browser, env = process.env) {
6957
+ if ((0, _vendors__rspack_import_0.CM)(browser) && (0, _vendors__rspack_import_0.hs)(env)) return true;
6958
+ const reader = bridge?.readReadyContractDocument;
6959
+ if ('function' != typeof reader) return false;
6960
+ try {
6961
+ return reader(projectPath, browser)?.engine === 'emulator';
6962
+ } catch {
6963
+ return false;
6964
+ }
6965
+ }
6966
+ function emulatorSessionRefusal(bridge, projectPath, browser, command, env = process.env) {
6967
+ return isEmulatorSession(bridge, projectPath, browser, env) ? emulatorRefusalFor(command) : null;
6968
+ }
6969
+ __webpack_require__.d(__webpack_exports__, {
6970
+ MC: ()=>emulatorSessionRefusal
6971
+ }, {
6972
+ fg: EMULATOR_LOGS_REFUSAL
6973
+ });
6974
+ },
6713
6975
  "./helpers/messaging.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
6714
6976
  var pintor__rspack_import_0 = __webpack_require__("pintor");
6715
6977
  var pintor__rspack_import_0_default = /*#__PURE__*/ __webpack_require__.n(pintor__rspack_import_0);
@@ -6795,9 +7057,20 @@ var __webpack_modules__ = {
6795
7057
  ...body
6796
7058
  ].join('\n');
6797
7059
  }
6798
- function browserRowValue(browser, versionLine) {
7060
+ const BRAND_SPELLINGS = {
7061
+ librewolf: 'LibreWolf',
7062
+ chromium: 'Chromium',
7063
+ 'chromium-based': 'Chromium-based',
7064
+ 'gecko-based': 'Gecko-based',
7065
+ 'firefox-based': 'Firefox-based',
7066
+ 'webkit-based': 'WebKit-based'
7067
+ };
7068
+ function browserDisplayName(browser) {
6799
7069
  const name = String(browser || '').trim() || 'unknown';
6800
- const display = name.charAt(0).toUpperCase() + name.slice(1);
7070
+ return BRAND_SPELLINGS[name] || name.charAt(0).toUpperCase() + name.slice(1);
7071
+ }
7072
+ function browserRowValue(browser, versionLine) {
7073
+ const display = browserDisplayName(browser);
6801
7074
  const line = String(versionLine || '').trim();
6802
7075
  if (!line) return display;
6803
7076
  if (!/[a-zA-Z]/.test(line)) return `${display} ${line}`;
@@ -6821,6 +7094,8 @@ var __webpack_modules__ = {
6821
7094
  'firefox-based',
6822
7095
  'gecko-based',
6823
7096
  'librewolf',
7097
+ 'zen',
7098
+ 'floorp',
6824
7099
  'waterfox'
6825
7100
  ]);
6826
7101
  function artifactNoun(browser) {
@@ -6998,6 +7273,7 @@ var __webpack_modules__ = {
6998
7273
  Gg: ()=>humanError,
6999
7274
  Nr: ()=>card,
7000
7275
  Pl: ()=>prefix,
7276
+ QZ: ()=>browserDisplayName,
7001
7277
  Qi: ()=>hasChannelPrefix,
7002
7278
  T_: ()=>artifactNoun,
7003
7279
  VR: ()=>isCardKeyClaimed,
@@ -7011,6 +7287,134 @@ var __webpack_modules__ = {
7011
7287
  Sc: fmt
7012
7288
  });
7013
7289
  },
7290
+ "./helpers/vendors.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
7291
+ const EMULATOR_BROWSER_TARGET = 'chromium-emulator';
7292
+ function isEmulatorLaneEnabled(env = process.env) {
7293
+ const value = String(env.EXTENSION_EXPERIMENTAL_EMULATOR || '').trim().toLowerCase();
7294
+ return '1' === value || 'true' === value;
7295
+ }
7296
+ function isEmulatorVendor(value) {
7297
+ return value === EMULATOR_BROWSER_TARGET;
7298
+ }
7299
+ function isSafariVendor(value) {
7300
+ return 'safari' === value || 'webkit-based' === value;
7301
+ }
7302
+ const SUPPORTED_BROWSER_TARGETS = [
7303
+ 'chrome',
7304
+ 'chromium',
7305
+ 'edge',
7306
+ 'firefox',
7307
+ 'brave',
7308
+ 'opera',
7309
+ 'vivaldi',
7310
+ 'yandex',
7311
+ 'waterfox',
7312
+ 'librewolf',
7313
+ 'zen',
7314
+ 'floorp',
7315
+ 'chromium-based',
7316
+ 'gecko-based',
7317
+ 'firefox-based',
7318
+ 'safari',
7319
+ 'webkit-based'
7320
+ ];
7321
+ const BROWSER_TARGETS_HELP = SUPPORTED_BROWSER_TARGETS.join(' | ');
7322
+ function supportedBrowserTargets(env = process.env) {
7323
+ return isEmulatorLaneEnabled(env) ? [
7324
+ ...SUPPORTED_BROWSER_TARGETS,
7325
+ EMULATOR_BROWSER_TARGET
7326
+ ] : [
7327
+ ...SUPPORTED_BROWSER_TARGETS
7328
+ ];
7329
+ }
7330
+ const SESSION_BROWSER_TARGETS_HELP = "chrome | chromium | edge | firefox | safari";
7331
+ const NO_SAFARI_BROWSER_TARGETS_HELP = SUPPORTED_BROWSER_TARGETS.filter((target)=>!isSafariVendor(target)).join(' | ');
7332
+ function parseOptionalBoolean(value) {
7333
+ if (void 0 === value) return true;
7334
+ const normalized = String(value).trim().toLowerCase();
7335
+ return ![
7336
+ 'false',
7337
+ '0',
7338
+ 'no',
7339
+ 'off'
7340
+ ].includes(normalized);
7341
+ }
7342
+ const vendors = (browser)=>{
7343
+ const value = browser ?? 'chromium';
7344
+ return 'all' === value ? [
7345
+ 'chrome',
7346
+ 'edge',
7347
+ 'firefox'
7348
+ ] : String(value).split(',').map((part)=>part.trim()).filter(Boolean);
7349
+ };
7350
+ const MANAGED_INSTALL_TARGETS = [
7351
+ 'chrome',
7352
+ 'chromium',
7353
+ 'edge',
7354
+ 'firefox',
7355
+ 'chromium-based',
7356
+ 'gecko-based',
7357
+ 'firefox-based'
7358
+ ];
7359
+ const MANAGED_INSTALL_TARGETS_HELP = [
7360
+ ...MANAGED_INSTALL_TARGETS,
7361
+ 'all'
7362
+ ].join(' | ');
7363
+ const MANAGED_INSTALL_BINARIES = [
7364
+ 'chrome',
7365
+ 'chromium',
7366
+ 'edge',
7367
+ 'firefox'
7368
+ ];
7369
+ const installTargets = (browser)=>'all' === browser ? [
7370
+ ...MANAGED_INSTALL_BINARIES
7371
+ ] : vendors(browser);
7372
+ function validateVendors(vendorsList, onInvalid, options = {}) {
7373
+ const supported = false === options.allowEmulator ? [
7374
+ ...SUPPORTED_BROWSER_TARGETS
7375
+ ] : supportedBrowserTargets();
7376
+ for (const v of vendorsList)if (!supported.includes(v)) {
7377
+ onInvalid(v, supported);
7378
+ return false;
7379
+ }
7380
+ return true;
7381
+ }
7382
+ const MANAGED_INSTALL_TARGET_SET = new Set(MANAGED_INSTALL_TARGETS);
7383
+ const SUPPORTED_BROWSER_TARGET_SET = new Set(SUPPORTED_BROWSER_TARGETS);
7384
+ function classifyManagedInstallTarget(name) {
7385
+ const value = String(name || '').trim().toLowerCase();
7386
+ if (!value) return 'unknown';
7387
+ if (MANAGED_INSTALL_TARGET_SET.has(value)) return 'managed';
7388
+ if (SUPPORTED_BROWSER_TARGET_SET.has(value)) return 'not-installable';
7389
+ return 'unknown';
7390
+ }
7391
+ function firstNonManagedInstallTarget(targetsList) {
7392
+ for (const name of targetsList){
7393
+ const kind = classifyManagedInstallTarget(name);
7394
+ if ('managed' !== kind) return {
7395
+ name,
7396
+ kind
7397
+ };
7398
+ }
7399
+ return null;
7400
+ }
7401
+ __webpack_require__.d(__webpack_exports__, {
7402
+ $q: ()=>isSafariVendor,
7403
+ CM: ()=>isEmulatorVendor,
7404
+ RY: ()=>firstNonManagedInstallTarget,
7405
+ hs: ()=>isEmulatorLaneEnabled,
7406
+ sJ: ()=>parseOptionalBoolean,
7407
+ sS: ()=>validateVendors
7408
+ }, {
7409
+ DB: NO_SAFARI_BROWSER_TARGETS_HELP,
7410
+ I9: BROWSER_TARGETS_HELP,
7411
+ L_: MANAGED_INSTALL_TARGETS,
7412
+ OB: installTargets,
7413
+ Xf: SESSION_BROWSER_TARGETS_HELP,
7414
+ b_: MANAGED_INSTALL_TARGETS_HELP,
7415
+ oJ: vendors
7416
+ });
7417
+ },
7014
7418
  "./index.ts" (__unused_rspack_module, __unused_rspack___webpack_exports__, __webpack_require__) {
7015
7419
  const MIN_NODE_MAJOR = 22;
7016
7420
  const MIN_NODE_MINOR = 12;
@@ -7078,6 +7482,7 @@ var __webpack_modules__ = {
7078
7482
  var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_);
7079
7483
  var external_node_path_ = __webpack_require__("node:path");
7080
7484
  var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_);
7485
+ var emulator_session = __webpack_require__("./helpers/emulator-session.ts");
7081
7486
  var external_pintor_ = __webpack_require__("pintor");
7082
7487
  var external_pintor_default = /*#__PURE__*/ __webpack_require__.n(external_pintor_);
7083
7488
  var browser_install_outcome = __webpack_require__("./helpers/browser-install-outcome.ts");
@@ -8406,6 +8811,7 @@ Build options
8406
8811
  - ${messages_code('--zip-source')} ${messages_arg('[boolean]')} Include source files in ZIP
8407
8812
  - ${messages_code('--zip-filename')} ${messages_arg('<name>')} Custom ZIP filename
8408
8813
  - ${messages_code('--no-addon-lint')} Skip the addons.mozilla.org lint of Firefox builds (runs when addons-linter is installed)
8814
+ - ${messages_code('--no-minify')} Ship readable first-party code (the default for ${messages_code('--browser=opera')}, whose store rejects minified code)
8409
8815
 
8410
8816
  ${external_pintor_default().underline('Centralized logger (terminal output)')}
8411
8817
  - The manager extension embeds a centralized logger that streams events to the CLI.
@@ -8922,96 +9328,7 @@ Cross-browser compatibility
8922
9328
  function sessionLogsPath(bridge, projectPath, browser) {
8923
9329
  return sessionFilePath(bridge, 'logsPath', projectPath, browser, 'logs.ndjson');
8924
9330
  }
8925
- function isSafariVendor(value) {
8926
- return 'safari' === value || 'webkit-based' === value;
8927
- }
8928
- const SUPPORTED_BROWSER_TARGETS = [
8929
- 'chrome',
8930
- 'chromium',
8931
- 'edge',
8932
- 'firefox',
8933
- 'brave',
8934
- 'opera',
8935
- 'vivaldi',
8936
- 'yandex',
8937
- 'waterfox',
8938
- 'librewolf',
8939
- 'chromium-based',
8940
- 'gecko-based',
8941
- 'firefox-based',
8942
- 'safari',
8943
- 'webkit-based'
8944
- ];
8945
- const BROWSER_TARGETS_HELP = SUPPORTED_BROWSER_TARGETS.join(' | ');
8946
- const SESSION_BROWSER_TARGETS_HELP = "chrome | chromium | edge | firefox | safari";
8947
- const NO_SAFARI_BROWSER_TARGETS_HELP = SUPPORTED_BROWSER_TARGETS.filter((target)=>!isSafariVendor(target)).join(' | ');
8948
- function parseOptionalBoolean(value) {
8949
- if (void 0 === value) return true;
8950
- const normalized = String(value).trim().toLowerCase();
8951
- return ![
8952
- 'false',
8953
- '0',
8954
- 'no',
8955
- 'off'
8956
- ].includes(normalized);
8957
- }
8958
- const vendors = (browser)=>{
8959
- const value = browser ?? 'chromium';
8960
- return 'all' === value ? [
8961
- 'chrome',
8962
- 'edge',
8963
- 'firefox'
8964
- ] : String(value).split(',').map((part)=>part.trim()).filter(Boolean);
8965
- };
8966
- const MANAGED_INSTALL_TARGETS = [
8967
- 'chrome',
8968
- 'chromium',
8969
- 'edge',
8970
- 'firefox',
8971
- 'chromium-based',
8972
- 'gecko-based',
8973
- 'firefox-based'
8974
- ];
8975
- const MANAGED_INSTALL_TARGETS_HELP = [
8976
- ...MANAGED_INSTALL_TARGETS,
8977
- 'all'
8978
- ].join(' | ');
8979
- const MANAGED_INSTALL_BINARIES = [
8980
- 'chrome',
8981
- 'chromium',
8982
- 'edge',
8983
- 'firefox'
8984
- ];
8985
- const installTargets = (browser)=>'all' === browser ? [
8986
- ...MANAGED_INSTALL_BINARIES
8987
- ] : vendors(browser);
8988
- function validateVendors(vendorsList, onInvalid) {
8989
- const supported = SUPPORTED_BROWSER_TARGETS;
8990
- for (const v of vendorsList)if (!supported.includes(v)) {
8991
- onInvalid(v, supported);
8992
- return false;
8993
- }
8994
- return true;
8995
- }
8996
- const MANAGED_INSTALL_TARGET_SET = new Set(MANAGED_INSTALL_TARGETS);
8997
- const SUPPORTED_BROWSER_TARGET_SET = new Set(SUPPORTED_BROWSER_TARGETS);
8998
- function classifyManagedInstallTarget(name) {
8999
- const value = String(name || '').trim().toLowerCase();
9000
- if (!value) return 'unknown';
9001
- if (MANAGED_INSTALL_TARGET_SET.has(value)) return 'managed';
9002
- if (SUPPORTED_BROWSER_TARGET_SET.has(value)) return 'not-installable';
9003
- return 'unknown';
9004
- }
9005
- function firstNonManagedInstallTarget(targetsList) {
9006
- for (const name of targetsList){
9007
- const kind = classifyManagedInstallTarget(name);
9008
- if ('managed' !== kind) return {
9009
- name,
9010
- kind
9011
- };
9012
- }
9013
- return null;
9014
- }
9331
+ var vendors = __webpack_require__("./helpers/vendors.ts");
9015
9332
  function parseLogSinceLocal(value) {
9016
9333
  if (null == value || '' === value) return null;
9017
9334
  if ('number' == typeof value) return Number.isFinite(value) ? {
@@ -9131,7 +9448,7 @@ Cross-browser compatibility
9131
9448
  }
9132
9449
  }
9133
9450
  function registerLogsCommand(program) {
9134
- program.command('logs').arguments('[project-path]').usage('[project-path] [options]').description(commandDescriptions.logs).option(`--browser <${SESSION_BROWSER_TARGETS_HELP}>`, 'which dist/extension-js/<browser> to read. Defaults to `chromium`').option('--follow', 'stream live via the control channel instead of printing and exiting').option('--context <list>', 'comma-separated contexts (background, content, popup, options, sidebar, devtools, page)').option('--level <off|error|warn|info|debug|trace|all>', 'minimum severity to show. Defaults to `all`').option('--signals-only', '[experimental] show only structured dx.signal diagnostics. No emitter ships yet, so this currently prints nothing').option('--since <seq|iso>', 'only show events after this sequence number or ISO timestamp').option('--url <glob|substring>', 'only events whose url/hostname matches (glob with * or plain substring)').option('--tab <id>', 'only events from this tab id').option('--output <pretty|json|ndjson>', 'output format. Defaults to pretty on a TTY, ndjson when piped').action(async (projectPathArg, options)=>{
9451
+ program.command('logs').arguments('[project-path]').usage('[project-path] [options]').description(commandDescriptions.logs).option(`--browser <${vendors.Xf}>`, 'which dist/extension-js/<browser> to read. Defaults to `chromium`').option('--follow', 'stream live via the control channel instead of printing and exiting').option('--context <list>', 'comma-separated contexts (background, content, popup, options, sidebar, devtools, page)').option('--level <off|error|warn|info|debug|trace|all>', 'minimum severity to show. Defaults to `all`').option('--signals-only', '[experimental] show only structured dx.signal diagnostics. No emitter ships yet, so this currently prints nothing').option('--since <seq|iso>', 'only show events after this sequence number or ISO timestamp').option('--url <glob|substring>', 'only events whose url/hostname matches (glob with * or plain substring)').option('--tab <id>', 'only events from this tab id').option('--output <pretty|json|ndjson>', 'output format. Defaults to pretty on a TTY, ndjson when piped').action(async (projectPathArg, options)=>{
9135
9452
  const bridge = await loadExtensionDevelopBridgeModule();
9136
9453
  const projectPath = resolveSessionProjectPath(bridge, projectPathArg);
9137
9454
  const browser = options.browser || 'chromium';
@@ -9148,6 +9465,16 @@ Cross-browser compatibility
9148
9465
  }));
9149
9466
  process.exit(1);
9150
9467
  }
9468
+ const emulatorRefusal = (0, emulator_session.MC)(bridge, projectPath, browser, 'logs');
9469
+ if (emulatorRefusal) {
9470
+ console.error(emulatorRefusal);
9471
+ if ('pretty' !== format) writeFrame(messaging.Pr.fail('logs', 'failed', {
9472
+ code: messaging.Lp.E_COMMAND_UNSUPPORTED_FOR_TARGET,
9473
+ message: emulatorRefusal,
9474
+ name: 'CliError'
9475
+ }));
9476
+ process.exit(1);
9477
+ }
9151
9478
  const matches = makeFilter(options, since ?? null, helpers);
9152
9479
  if (options.signalsOnly) console.error("extension logs --signals-only: no signals emitter ships in this build, so dev sessions record no dx.signal events and this filter will print nothing.");
9153
9480
  if (options.follow) return void await followLogs(projectPath, browser, format, matches);
@@ -9439,6 +9766,11 @@ Cross-browser compatibility
9439
9766
  plain: refusal.plain,
9440
9767
  hint: refusal.hint
9441
9768
  });
9769
+ const emulatorRefusal = (0, emulator_session.MC)(bridge, projectPath, browser, input.command);
9770
+ if (emulatorRefusal) fail(emulatorRefusal, {
9771
+ ...outputFrame,
9772
+ code: messaging.Lp.E_COMMAND_UNSUPPORTED_FOR_TARGET
9773
+ });
9442
9774
  const ready = readReadyContract(projectPath, browser);
9443
9775
  if (!ready) fail(`No active control channel found for ${browser}. Looked at ${sessionReadyPath(bridge, projectPath, browser)}. Run \`extension dev --browser=${browser} ${unlockFlag}\` first.`, {
9444
9776
  ...outputFrame,
@@ -9501,7 +9833,7 @@ Cross-browser compatibility
9501
9833
  if (null != opts.tab && '' !== opts.tab) target.tabId = Number(opts.tab);
9502
9834
  return target;
9503
9835
  }
9504
- const commonOptions = (cmd)=>cmd.option(`--browser <${SESSION_BROWSER_TARGETS_HELP}>`, 'which session to target (default chromium)').option('--timeout <ms>', 'command timeout in milliseconds (default 5000)').option('--output <pretty|json>', 'output format (default pretty)');
9836
+ const commonOptions = (cmd)=>cmd.option(`--browser <${vendors.Xf}>`, 'which session to target (default chromium)').option('--timeout <ms>', 'command timeout in milliseconds (default 5000)').option('--output <pretty|json>', 'output format (default pretty)');
9505
9837
  function registerActCommands(program) {
9506
9838
  commonOptions(program.command('eval').arguments('<expression> [project-path]').description(commandDescriptions.eval).option('--context <background|popup|options|sidebar|devtools|newtab|history|bookmarks|content|page>', 'target context (default background). Extension pages (popup/options/sidebar/devtools/newtab/history/bookmarks) answer via their own in-page relay and must be open').option('--url <glob|substring>', 'for content/page: document to target (resolved to its tab)').option('--tab <id>', 'for content/page: a specific tab (default: the --url match, else the active tab)')).action(async (expression, projectPathArg, opts)=>{
9507
9839
  await runCommand({
@@ -9773,15 +10105,15 @@ Cross-browser compatibility
9773
10105
  };
9774
10106
  }
9775
10107
  function registerBuildCommand(program) {
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 })=>{
10108
+ program.command('build').arguments('[project-name]').usage('[path-to-remote-extension] [options]').description(commandDescriptions.build).option(`--browser <${vendors.I9}>`, '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`', vendors.sJ).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`', vendors.sJ).option('--zip-source [boolean]', 'whether or not to include the source files in the ZIP file. Defaults to `false`', vendors.sJ).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`', vendors.sJ).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`', vendors.sJ).option('--no-addon-lint', 'skip the addons.mozilla.org lint of Firefox builds').option('--minify [boolean]', 'minify first-party code in production builds. Defaults to `true`, and to `false` for `opera`, whose store rejects minified code', vendors.sJ).option('--no-minify', 'ship readable first-party code, the Opera Add-ons review requirement').option('--install [boolean]', '[internal] install project dependencies when missing', vendors.sJ).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`', vendors.sJ).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`', vendors.sJ).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 })=>{
9777
10109
  const browser = cliBrowser ?? await resolveConfigBrowser(pathOrRemoteUrl || process.cwd(), 'build') ?? 'chromium';
9778
10110
  if (buildOptions.debug || buildOptions.author || buildOptions.authorMode) {
9779
10111
  process.env.EXTENSION_DEBUG = '1';
9780
10112
  process.env.EXTENSION_AUTHOR_MODE = 'true';
9781
10113
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
9782
10114
  }
9783
- const list = vendors(browser);
9784
- const vendorsAreSupported = validateVendors(list, (invalid, supported)=>{
10115
+ const list = (0, vendors.oJ)(browser);
10116
+ const vendorsAreSupported = (0, vendors.sS)(list, (invalid, supported)=>{
9785
10117
  console.error(unsupportedBrowserFlag(invalid, supported));
9786
10118
  });
9787
10119
  if (!vendorsAreSupported) process.exit(1);
@@ -9817,7 +10149,7 @@ Cross-browser compatibility
9817
10149
  ]
9818
10150
  ].filter(([, value])=>void 0 !== value && false !== value).map(([flag])=>flag);
9819
10151
  if (void 0 !== buildOptions.macosOnly) safariOnlyFlags.push('--macos-only');
9820
- if (safariOnlyFlags.length > 0 && !list.some(isSafariVendor)) {
10152
+ if (safariOnlyFlags.length > 0 && !list.some(vendors.$q)) {
9821
10153
  console.error(safariOnlyOption(safariOnlyFlags));
9822
10154
  process.exit(1);
9823
10155
  }
@@ -9826,7 +10158,7 @@ Cross-browser compatibility
9826
10158
  process.exit(1);
9827
10159
  }
9828
10160
  let safariPackagingEnabled = true;
9829
- if (list.some(isSafariVendor)) {
10161
+ if (list.some(vendors.$q)) {
9830
10162
  const preflight = (0, safari_launch.QW)();
9831
10163
  if ('fatal' === preflight.severity) {
9832
10164
  console.error(preflight.message);
@@ -9854,6 +10186,7 @@ Cross-browser compatibility
9854
10186
  zipFilename: buildOptions.zipFilename,
9855
10187
  silent: buildOptions.silent,
9856
10188
  addonLint: buildOptions.addonLint,
10189
+ minify: buildOptions.minify,
9857
10190
  install: buildOptions.install,
9858
10191
  extensions: parseExtensionsList(buildOptions.extensions),
9859
10192
  mode,
@@ -9939,7 +10272,7 @@ Cross-browser compatibility
9939
10272
  return messaging.Lp.E_INTERNAL;
9940
10273
  }
9941
10274
  function registerCreateCommand(program) {
9942
- program.command('create').arguments('<project-name|project-path>').usage('<project-name|project-path> [options]').description(commandDescriptions.create).option('-t, --template <template-name>', `catalog name, GitHub URL, or ZIP URL to scaffold from; every catalog name is listed below (default: ${DEFAULT_TEMPLATE})`).option('--install [boolean]', 'whether or not to install the dependencies after creating the project (disabled by default, pass --install to opt in)', parseOptionalBoolean, false).option('--source <source>', 'attribution tag for where this create was initiated (e.g. cli, templates); recorded in anonymous telemetry only').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addHelpText('after', renderCreateTemplateHelp()).action(async (pathOrRemoteUrl, { template, install, output })=>{
10275
+ program.command('create').arguments('<project-name|project-path>').usage('<project-name|project-path> [options]').description(commandDescriptions.create).option('-t, --template <template-name>', `catalog name, GitHub URL, or ZIP URL to scaffold from; every catalog name is listed below (default: ${DEFAULT_TEMPLATE})`).option('--install [boolean]', 'whether or not to install the dependencies after creating the project (disabled by default, pass --install to opt in)', vendors.sJ, false).option('--source <source>', 'attribution tag for where this create was initiated (e.g. cli, templates); recorded in anonymous telemetry only').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addHelpText('after', renderCreateTemplateHelp()).action(async (pathOrRemoteUrl, { template, install, output })=>{
9943
10276
  const asJson = isJsonOutput({
9944
10277
  output
9945
10278
  });
@@ -10419,7 +10752,7 @@ Cross-browser compatibility
10419
10752
  return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : 8080;
10420
10753
  }
10421
10754
  function registerDevCommand(program) {
10422
- 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)=>{
10755
+ 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 <${vendors.I9}>`, '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`', vendors.sJ).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`', vendors.sJ).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', vendors.sJ).option('--wait [boolean]', 'wait for dist/extension-js/<browser>/ready.json and exit', vendors.sJ).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)=>{
10423
10756
  const { browser: cliBrowser, ...devOptions } = options;
10424
10757
  const browser = cliBrowser ?? await resolveConfigBrowser(pathOrRemoteUrl || process.cwd(), 'dev') ?? 'chromium';
10425
10758
  if (devOptions.debug || devOptions.author || devOptions.authorMode) {
@@ -10442,9 +10775,9 @@ Cross-browser compatibility
10442
10775
  }
10443
10776
  setupParentWatchdog(parentPid);
10444
10777
  }
10445
- const list = vendors(browser);
10778
+ const list = (0, vendors.oJ)(browser);
10446
10779
  let unsupportedBrowser = '';
10447
- const vendorsAreSupported = validateVendors(list, (invalid, supported)=>{
10780
+ const vendorsAreSupported = (0, vendors.sS)(list, (invalid, supported)=>{
10448
10781
  unsupportedBrowser = invalid;
10449
10782
  console.error(unsupportedBrowserFlag(invalid, supported));
10450
10783
  });
@@ -10476,7 +10809,7 @@ Cross-browser compatibility
10476
10809
  ]
10477
10810
  ].filter(([, value])=>void 0 !== value && false !== value).map(([flag])=>flag);
10478
10811
  if (void 0 !== opts.macosOnly) safariOnlyFlags.push('--macos-only');
10479
- if (safariOnlyFlags.length > 0 && !list.some(isSafariVendor)) {
10812
+ if (safariOnlyFlags.length > 0 && !list.some(vendors.$q)) {
10480
10813
  console.error(safariOnlyOption(safariOnlyFlags));
10481
10814
  failAndExit(asJson, 'usage', {
10482
10815
  code: messaging.Lp.E_INVALID_OPTION,
@@ -10490,7 +10823,7 @@ Cross-browser compatibility
10490
10823
  message: `--bundle-id expects a reverse-DNS identifier, got: ${opts.bundleId}`
10491
10824
  });
10492
10825
  }
10493
- if (list.some(isSafariVendor)) {
10826
+ if (list.some(vendors.$q)) {
10494
10827
  const issue = (0, safari_launch.iF)();
10495
10828
  if (issue) {
10496
10829
  console.error(issue);
@@ -10666,6 +10999,15 @@ Cross-browser compatibility
10666
10999
  detail: `multiple live sessions found (${sessionBrowsers.join(', ')}), diagnosing ${browser}`,
10667
11000
  remediation: 'Pass --browser=<name> to diagnose a specific session'
10668
11001
  });
11002
+ const emulatorRefusal = (0, emulator_session.MC)(bridge, projectPath, browser, 'doctor');
11003
+ if (emulatorRefusal) {
11004
+ results.push({
11005
+ check: 'engine',
11006
+ status: 'fail',
11007
+ detail: emulatorRefusal
11008
+ });
11009
+ return results;
11010
+ }
10669
11011
  const skip = (check, blockedBy)=>{
10670
11012
  results.push({
10671
11013
  check,
@@ -10898,10 +11240,11 @@ Cross-browser compatibility
10898
11240
  'control-channel': messaging.Lp.E_CONTROL_UNAVAILABLE,
10899
11241
  'eval-token': messaging.Lp.E_TOKEN_MISSING,
10900
11242
  executor: messaging.Lp.E_CONTROL_UNAVAILABLE,
10901
- browser: messaging.Lp.E_BROWSER_LAUNCH
11243
+ browser: messaging.Lp.E_BROWSER_LAUNCH,
11244
+ engine: messaging.Lp.E_COMMAND_UNSUPPORTED_FOR_TARGET
10902
11245
  };
10903
11246
  function registerDoctorCommand(program) {
10904
- program.command('doctor').argument('[project-path]', 'path to the extension project root or the folder holding its manifest').option(`--browser <${SESSION_BROWSER_TARGETS_HELP}>`, 'which session to diagnose (defaults to the single live session, else chromium)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').description(commandDescriptions.doctor).action(async (projectPathArg, opts)=>{
11247
+ program.command('doctor').argument('[project-path]', 'path to the extension project root or the folder holding its manifest').option(`--browser <${vendors.Xf}>`, 'which session to diagnose (defaults to the single live session, else chromium)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').description(commandDescriptions.doctor).action(async (projectPathArg, opts)=>{
10905
11248
  const asJson = isJsonOutput(opts);
10906
11249
  let results;
10907
11250
  try {
@@ -10949,7 +11292,7 @@ Cross-browser compatibility
10949
11292
  await exitAfterDrain(1);
10950
11293
  }
10951
11294
  async function refuseIfNotManagedTarget(command, browserList, asJson) {
10952
- const bad = firstNonManagedInstallTarget(browserList);
11295
+ const bad = (0, vendors.RY)(browserList);
10953
11296
  if (!bad) return false;
10954
11297
  if ('not-installable' === bad.kind) {
10955
11298
  const message = browserNotInstallablePlain(bad.name);
@@ -10966,7 +11309,7 @@ Cross-browser compatibility
10966
11309
  message: `Unsupported browser: ${bad.name}.`
10967
11310
  }));
10968
11311
  else console.error(unsupportedBrowserFlag(bad.name, [
10969
- ...MANAGED_INSTALL_TARGETS
11312
+ ...vendors.L_
10970
11313
  ]));
10971
11314
  await exitAfterDrain(1);
10972
11315
  return true;
@@ -10983,11 +11326,11 @@ Cross-browser compatibility
10983
11326
  await exitAfterDrain(1);
10984
11327
  }
10985
11328
  function registerInstallCommand(program) {
10986
- program.command('install').arguments('[browser-name]').usage('[browser-name] [options]').description(commandDescriptions.install).option(`--browser <${MANAGED_INSTALL_TARGETS_HELP}>`, 'override the positional browser name. Supports comma-separated values and `all`.').option('--where', 'print the resolved managed browser cache root').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').action(async (browserArg, options)=>{
11329
+ program.command('install').arguments('[browser-name]').usage('[browser-name] [options]').description(commandDescriptions.install).option(`--browser <${vendors.b_}>`, 'override the positional browser name. Supports comma-separated values and `all`.').option('--where', 'print the resolved managed browser cache root').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').action(async (browserArg, options)=>{
10987
11330
  const asJson = isJsonOutput(options);
10988
11331
  const named = Boolean(options.browser || browserArg);
10989
11332
  const selectedBrowser = options.browser || browserArg || 'chromium';
10990
- const browserList = installTargets(selectedBrowser);
11333
+ const browserList = (0, vendors.OB)(selectedBrowser);
10991
11334
  if (!(options.where && !named)) {
10992
11335
  if (await refuseIfNotManagedTarget('install', browserList, asJson)) return;
10993
11336
  }
@@ -11023,7 +11366,7 @@ Cross-browser compatibility
11023
11366
  browsers: installed
11024
11367
  }));
11025
11368
  });
11026
- program.command('uninstall').usage('<browser-name> | --all | --where').description(commandDescriptions.uninstall).option(`--browser <${MANAGED_INSTALL_TARGETS_HELP}>`, 'browser(s) to uninstall. Supports comma-separated values and `all`.').option('--all', 'remove all managed browser binaries').option('--where', 'print the resolved managed browser cache root').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').argument('[browser-name]').action(async (browserArg, { browser, all, where, output })=>{
11369
+ program.command('uninstall').usage('<browser-name> | --all | --where').description(commandDescriptions.uninstall).option(`--browser <${vendors.b_}>`, 'browser(s) to uninstall. Supports comma-separated values and `all`.').option('--all', 'remove all managed browser binaries').option('--where', 'print the resolved managed browser cache root').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').argument('[browser-name]').action(async (browserArg, { browser, all, where, output })=>{
11027
11370
  const asJson = isJsonOutput({
11028
11371
  output
11029
11372
  });
@@ -11050,7 +11393,7 @@ Cross-browser compatibility
11050
11393
  await exitAfterDrain(1);
11051
11394
  return;
11052
11395
  }
11053
- const browserList = installTargets(selected);
11396
+ const browserList = (0, vendors.OB)(selected);
11054
11397
  if (await refuseIfNotManagedTarget('uninstall', browserList, asJson)) return;
11055
11398
  if (where) {
11056
11399
  let paths;
@@ -11094,7 +11437,7 @@ Cross-browser compatibility
11094
11437
  'Manifest file not found'
11095
11438
  ];
11096
11439
  function registerPreviewCommand(program) {
11097
- program.command('preview').arguments('[project-name]').usage('[path-to-remote-extension] [options]').description(commandDescriptions.preview).addHelpText('after', "\nAdditional options:\n --no-browser stop the browser launch\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(`--browser <${NO_SAFARI_BROWSER_TARGETS_HELP}>`, 'specify a browser/engine to run. Defaults to `chromium`').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('--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('--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('--output-path <dir>', 'path to an existing unpacked extension directory. Defaults to dist/<browser> when available').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, options, command)=>{
11440
+ program.command('preview').arguments('[project-name]').usage('[path-to-remote-extension] [options]').description(commandDescriptions.preview).addHelpText('after', "\nAdditional options:\n --no-browser stop the browser launch\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(`--browser <${vendors.DB}>`, 'specify a browser/engine to run. Defaults to `chromium`').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('--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('--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('--output-path <dir>', 'path to an existing unpacked extension directory. Defaults to dist/<browser> when available').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, options, command)=>{
11098
11441
  const { browser: cliBrowser, ...previewOptions } = options;
11099
11442
  const browser = cliBrowser ?? await resolveConfigBrowser(pathOrRemoteUrl || process.cwd(), 'preview') ?? 'chromium';
11100
11443
  if (previewOptions.debug || previewOptions.author || previewOptions.authorMode) {
@@ -11107,12 +11450,14 @@ Cross-browser compatibility
11107
11450
  const emit = (frame)=>{
11108
11451
  console.log(JSON.stringify(frame));
11109
11452
  };
11110
- const list = vendors(browser);
11453
+ const list = (0, vendors.oJ)(browser);
11111
11454
  let unsupported = '';
11112
- const vendorsAreSupported = validateVendors(list, (invalid, supported)=>{
11455
+ const vendorsAreSupported = (0, vendors.sS)(list, (invalid, supported)=>{
11113
11456
  unsupported = invalid;
11114
11457
  if (asJson) return;
11115
11458
  console.error(unsupportedBrowserFlag(invalid, supported));
11459
+ }, {
11460
+ allowEmulator: false
11116
11461
  });
11117
11462
  if (!vendorsAreSupported) {
11118
11463
  if (asJson) emit(messaging.Pr.fail('preview', 'usage', {
@@ -11122,7 +11467,7 @@ Cross-browser compatibility
11122
11467
  await exitAfterDrain(1);
11123
11468
  return;
11124
11469
  }
11125
- if (list.some(isSafariVendor)) {
11470
+ if (list.some(vendors.$q)) {
11126
11471
  if (asJson) emit(messaging.Pr.fail('preview', 'usage', {
11127
11472
  code: messaging.Lp.E_COMMAND_UNSUPPORTED_FOR_TARGET,
11128
11473
  message: 'Safari is not supported by preview.'
@@ -11361,7 +11706,7 @@ Cross-browser compatibility
11361
11706
  return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : 8080;
11362
11707
  }
11363
11708
  function registerStartCommand(program) {
11364
- program.command('start').arguments('[project-path|remote-url]').usage('[project-path|remote-url] [options]').description(commandDescriptions.start).addHelpText('after', "\nAdditional options:\n --no-browser stop the browser launch, the build still runs\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(`--browser <${NO_SAFARI_BROWSER_TARGETS_HELP}>`, 'specify a browser/engine to run. Defaults to `chromium`').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('--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('--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()).action(async (pathOrRemoteUrl, options, command)=>{
11709
+ program.command('start').arguments('[project-path|remote-url]').usage('[project-path|remote-url] [options]').description(commandDescriptions.start).addHelpText('after', "\nAdditional options:\n --no-browser stop the browser launch, the build still runs\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(`--browser <${vendors.DB}>`, 'specify a browser/engine to run. Defaults to `chromium`').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `true`', vendors.sJ).option('--no-polyfill', 'disable the cross-browser polyfill').option('--no-open', NO_OPEN_FLAG_DESCRIPTION).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('--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', vendors.sJ).option('--wait [boolean]', 'wait for dist/extension-js/<browser>/ready.json and exit', vendors.sJ).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()).action(async (pathOrRemoteUrl, options, command)=>{
11365
11710
  const { browser: cliBrowser, ...startOptions } = options;
11366
11711
  const browser = cliBrowser ?? await resolveConfigBrowser(pathOrRemoteUrl || process.cwd(), 'start') ?? 'chromium';
11367
11712
  if (startOptions.debug || startOptions.author || startOptions.authorMode) {
@@ -11373,18 +11718,20 @@ Cross-browser compatibility
11373
11718
  const cliVersion = checkProjectCliVersion(external_node_path_.resolve(pathOrRemoteUrl || process.cwd()), getCliPackageJson().version);
11374
11719
  if (cliVersion) console.warn(projectCliVersionMismatch(cliVersion.running, cliVersion.declared, cliVersion.range, cliVersion.command));
11375
11720
  if (asJson) process.env.EXTENSION_OUTPUT = 'json';
11376
- const list = vendors(browser);
11721
+ const list = (0, vendors.oJ)(browser);
11377
11722
  let unsupportedBrowser = '';
11378
- const vendorsAreSupported = validateVendors(list, (invalid, supported)=>{
11723
+ const vendorsAreSupported = (0, vendors.sS)(list, (invalid, supported)=>{
11379
11724
  unsupportedBrowser = invalid;
11380
11725
  if (asJson) return;
11381
11726
  console.error(unsupportedBrowserFlag(invalid, supported));
11727
+ }, {
11728
+ allowEmulator: false
11382
11729
  });
11383
11730
  if (!vendorsAreSupported) start_failAndExit(asJson, 'usage', {
11384
11731
  code: messaging.Lp.E_UNSUPPORTED_BROWSER,
11385
11732
  message: `Unsupported browser: ${unsupportedBrowser}`
11386
11733
  });
11387
- if (list.some(isSafariVendor)) {
11734
+ if (list.some(vendors.$q)) {
11388
11735
  if (!asJson) console.error(safariCommandNotSupported('start'));
11389
11736
  start_failAndExit(asJson, 'usage', {
11390
11737
  code: messaging.Lp.E_COMMAND_UNSUPPORTED_FOR_TARGET,