extension 4.0.15 → 4.0.16

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/browsers.cjs CHANGED
@@ -84,6 +84,14 @@ var __webpack_modules__ = {
84
84
  if (fromBrowserSpecificSettings) return fromBrowserSpecificSettings;
85
85
  return toNormalizedId(manifest?.applications?.gecko?.id);
86
86
  }
87
+ function expectedChromiumExtensionId(outPath) {
88
+ try {
89
+ const manifest = JSON.parse(node_fs__rspack_import_1.readFileSync(node_path__rspack_import_2.join(outPath, 'manifest.json'), 'utf-8'));
90
+ const fromKey = deriveChromiumExtensionIdFromManifest(manifest);
91
+ if (fromKey) return fromKey;
92
+ } catch {}
93
+ return deriveChromiumExtensionIdFromPath(outPath);
94
+ }
87
95
  function resolveExtensionId(args) {
88
96
  const fromInfo = toNormalizedId(args.info?.extensionId);
89
97
  if (fromInfo) return fromInfo;
@@ -209,7 +217,8 @@ var __webpack_modules__ = {
209
217
  }
210
218
  __webpack_require__.d(__webpack_exports__, {
211
219
  MK: ()=>printProdBannerOnce,
212
- ai: ()=>printDevBannerOnce
220
+ ai: ()=>printDevBannerOnce,
221
+ vy: ()=>expectedChromiumExtensionId
213
222
  });
214
223
  },
215
224
  "./browsers/browsers-lib/browser-family.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
@@ -475,6 +484,12 @@ var __webpack_modules__ = {
475
484
  function chromiumManifestLoadBlockers(extensionPath, blockers) {
476
485
  return `${getLoggingPrefix('warn')} ${pintor__rspack_import_8_default().brightYellow('This manifest declares shapes Chrome refuses, the whole extension will not load.')}\n${pintor__rspack_import_8_default().gray('PATH')} ${pintor__rspack_import_8_default().underline(extensionPath)}\n` + blockers.map((blocker)=>`${pintor__rspack_import_8_default().gray('REASON')} ${pintor__rspack_import_8_default().red(blocker)}\n`).join('') + "Chrome rejects the extension at load, so no service worker or content script ever runs. Fix these in the source manifest.";
477
486
  }
487
+ function chromiumExtensionLoadRefused(extensionPath, reason) {
488
+ return `${getLoggingPrefix('error')} ${pintor__rspack_import_8_default().red('The browser refused to load this extension, so it is NOT running.')}\n${pintor__rspack_import_8_default().gray('PATH')} ${pintor__rspack_import_8_default().underline(extensionPath)}\n` + (reason ? `${pintor__rspack_import_8_default().gray('REASON')} ${pintor__rspack_import_8_default().red(reason)}\n` : '') + "No service worker, content script, or page from this extension will run, and no Extension ID was assigned. Fix the reason above and save. If the browser does not pick it up, restart the dev session.";
489
+ }
490
+ function geckoAddonLoadRefused(addonPath, reason) {
491
+ return `${getLoggingPrefix('error')} ${pintor__rspack_import_8_default().red('The browser refused to load this add-on, so it is NOT running.')}\n${pintor__rspack_import_8_default().gray('PATH')} ${pintor__rspack_import_8_default().underline(addonPath)}\n` + (reason ? `${pintor__rspack_import_8_default().gray('REASON')} ${pintor__rspack_import_8_default().red(reason)}\n` : '') + "No background script, content script, or page from this add-on will run, and no Extension ID was assigned. Fix the reason above and save. If the browser does not pick it up, restart the dev session.";
492
+ }
478
493
  function devChannelSnapshotInUse(binaryPath) {
479
494
  return `${getLoggingPrefix('warn')} ${pintor__rspack_import_8_default().brightYellow('Running a Chromium tip-of-tree snapshot (dev channel, not a stable release).')}\n${pintor__rspack_import_8_default().gray('PATH')} ${pintor__rspack_import_8_default().underline(binaryPath)}\nBehavior may differ from stable Chrome. Install a stable browser or remove the snapshot to stop using it.`;
480
495
  }
@@ -744,6 +759,7 @@ var __webpack_modules__ = {
744
759
  Cn: ()=>chromeProcessError,
745
760
  Dh: ()=>invalidGeckoBinaryPath,
746
761
  E8: ()=>chromiumDryRunFlags,
762
+ EE: ()=>geckoAddonLoadRefused,
747
763
  EI: ()=>firefoxRdpClientConnected,
748
764
  F1: ()=>cdpClientBrowserConnectionEstablished,
749
765
  F4: ()=>enhancedProcessManagementUncaughtException,
@@ -758,6 +774,7 @@ var __webpack_modules__ = {
758
774
  L: ()=>chromiumManifestLoadBlockers,
759
775
  LD: ()=>firefoxDryRunBinary,
760
776
  M3: ()=>cdpClientConnected,
777
+ M6: ()=>chromiumExtensionLoadRefused,
761
778
  MG: ()=>prettyPuppeteerInstallGuidance,
762
779
  MQ: ()=>firefoxFailedToStart,
763
780
  MS: ()=>errorConnectingToBrowser,
@@ -1111,6 +1128,21 @@ var __webpack_modules__ = {
1111
1128
  node_fs__rspack_import_0.writeFileSync(readyPath, JSON.stringify(ready, null, 2));
1112
1129
  } catch {}
1113
1130
  }
1131
+ function stampReadyExtensionLoadRefused(extensionOutputPath, reason) {
1132
+ try {
1133
+ if (!extensionOutputPath) return;
1134
+ const readyPath = readyPathFor(extensionOutputPath);
1135
+ if (!node_fs__rspack_import_0.existsSync(readyPath)) return;
1136
+ const ready = JSON.parse(node_fs__rspack_import_0.readFileSync(readyPath, 'utf-8'));
1137
+ ready.status = 'error';
1138
+ ready.code = 'extension_load_refused';
1139
+ const browserLabel = String(ready.browser || 'the browser');
1140
+ ready.message = `${browserLabel.charAt(0).toUpperCase() + browserLabel.slice(1)} refused to load the extension at ${extensionOutputPath}${reason ? `: ${reason}` : ''}`;
1141
+ ready.extensionLoadRefusedAt = new Date().toISOString();
1142
+ if (reason) ready.extensionLoadRefusedReason = reason;
1143
+ node_fs__rspack_import_0.writeFileSync(readyPath, JSON.stringify(ready, null, 2));
1144
+ } catch {}
1145
+ }
1114
1146
  function stampReadyBrowserExited(extensionOutputPath, code) {
1115
1147
  try {
1116
1148
  if (!extensionOutputPath) return;
@@ -1128,8 +1160,9 @@ var __webpack_modules__ = {
1128
1160
  } catch {}
1129
1161
  }
1130
1162
  __webpack_require__.d(__webpack_exports__, {
1131
- W: ()=>stampReadyBrowserExited,
1132
- _: ()=>stampReadyRdpPort
1163
+ Wi: ()=>stampReadyBrowserExited,
1164
+ __: ()=>stampReadyRdpPort,
1165
+ sf: ()=>stampReadyExtensionLoadRefused
1133
1166
  });
1134
1167
  },
1135
1168
  "./browsers/browsers-lib/resolve-profile.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
@@ -1335,6 +1368,9 @@ var __webpack_modules__ = {
1335
1368
  function parseEnvBrowserFlags(raw) {
1336
1369
  return String(raw || '').split(/\s+/).map((flag)=>flag.trim()).filter(Boolean);
1337
1370
  }
1371
+ function isHeadlessGuardRequested(env = process.env) {
1372
+ return /^(1|true)$/i.test(String(env.EXTENSION_HEADLESS || '').trim());
1373
+ }
1338
1374
  function mergeChromiumFeatureSwitches(flags) {
1339
1375
  const merged = [];
1340
1376
  const featureValues = {
@@ -1495,6 +1531,7 @@ var __webpack_modules__ = {
1495
1531
  Py: ()=>mergeChromiumFeatureSwitches,
1496
1532
  RE: ()=>markManagedEphemeralProfile,
1497
1533
  W0: ()=>parseEnvBrowserFlags,
1534
+ ZO: ()=>isHeadlessGuardRequested,
1498
1535
  aY: ()=>findAvailablePortNear,
1499
1536
  jl: ()=>deriveDebugPortWithInstance,
1500
1537
  ov: ()=>filterBrowserFlags,
@@ -1576,6 +1613,20 @@ var __webpack_modules__ = {
1576
1613
  let cdpController;
1577
1614
  if (enableCdp) cdpController = ctx.getController?.();
1578
1615
  return {
1616
+ getExtensionLoadRefusal () {
1617
+ return launcher.getExtensionLoadRefusal();
1618
+ },
1619
+ async retryExtensionLoad () {
1620
+ if (!cdpController?.verifyGuestLoaded) return {
1621
+ status: 'unknown'
1622
+ };
1623
+ const outcome = await cdpController.verifyGuestLoaded();
1624
+ if ('loaded' === outcome.status) {
1625
+ launcher.clearExtensionLoadRefusal();
1626
+ await launcher.printBannerOnRecovery();
1627
+ }
1628
+ return outcome;
1629
+ },
1579
1630
  async enableUnifiedLogging (logOpts) {
1580
1631
  if (cdpController?.enableUnifiedLogging) await cdpController.enableUnifiedLogging({
1581
1632
  level: logOpts.level,
@@ -1607,7 +1658,8 @@ var __webpack_modules__ = {
1607
1658
  logTimestamps: opts.logTimestamps,
1608
1659
  logColor: opts.logColor,
1609
1660
  logUrl: opts.logUrl,
1610
- logTab: opts.logTab
1661
+ logTab: opts.logTab,
1662
+ logSink: opts.logSink
1611
1663
  };
1612
1664
  const pluginOptions = {
1613
1665
  extension: opts.extensionsToLoad,
@@ -1635,6 +1687,15 @@ var __webpack_modules__ = {
1635
1687
  await launcher.runOnce(compilationLike, launchRequest);
1636
1688
  const rdpController = ctx.getController?.();
1637
1689
  return {
1690
+ getExtensionLoadRefusal () {
1691
+ return firefoxOpts.extensionLoadRefused || null;
1692
+ },
1693
+ async retryExtensionLoad () {
1694
+ if (!firefoxOpts.retryAddonInstall) return {
1695
+ status: 'unknown'
1696
+ };
1697
+ return await firefoxOpts.retryAddonInstall();
1698
+ },
1638
1699
  async enableUnifiedLogging (logOpts) {
1639
1700
  if (!rdpController?.enableUnifiedLogging) return;
1640
1701
  await rdpController.enableUnifiedLogging({
@@ -1982,6 +2043,7 @@ var __webpack_modules__ = {
1982
2043
  var output_binaries_resolver = __webpack_require__("./browsers/browsers-lib/output-binaries-resolver.ts");
1983
2044
  var process_teardown = __webpack_require__("./browsers/browsers-lib/process-teardown.ts");
1984
2045
  var ready_message = __webpack_require__("./browsers/browsers-lib/ready-message.ts");
2046
+ var ready_stamp = __webpack_require__("./browsers/browsers-lib/ready-stamp.ts");
1985
2047
  var runtime_options = __webpack_require__("./browsers/browsers-lib/runtime-options.ts");
1986
2048
  var shared_utils = __webpack_require__("./browsers/browsers-lib/shared-utils.ts");
1987
2049
  var discovery = __webpack_require__("./browsers/run-chromium/cdp/discovery.ts");
@@ -2214,6 +2276,7 @@ var __webpack_modules__ = {
2214
2276
  ...configOptions.browserFlags || [],
2215
2277
  ...(0, shared_utils.W0)(process.env.EXTENSION_BROWSER_FLAGS)
2216
2278
  ];
2279
+ if ((0, shared_utils.ZO)() && !baseFlags.some((flag)=>flag.startsWith('--headless'))) baseFlags.push('--headless=new');
2217
2280
  return (0, shared_utils.Py)(baseFlags);
2218
2281
  }
2219
2282
  function logChromiumDryRun(browserBinaryLocation, chromiumConfig) {
@@ -2394,7 +2457,6 @@ var __webpack_modules__ = {
2394
2457
  throw error;
2395
2458
  }
2396
2459
  }
2397
- var ready_stamp = __webpack_require__("./browsers/browsers-lib/ready-stamp.ts");
2398
2460
  function _define_property(obj, key, value) {
2399
2461
  if (key in obj) Object.defineProperty(obj, key, {
2400
2462
  value: value,
@@ -2425,6 +2487,15 @@ var __webpack_modules__ = {
2425
2487
  });
2426
2488
  }
2427
2489
  class ChromiumLaunchPlugin {
2490
+ getExtensionLoadRefusal() {
2491
+ return this.extensionLoadRefused || null;
2492
+ }
2493
+ clearExtensionLoadRefusal() {
2494
+ this.extensionLoadRefused = void 0;
2495
+ }
2496
+ async printBannerOnRecovery() {
2497
+ await this.bannerOnRecovery?.();
2498
+ }
2428
2499
  async runOnce(compilation, opts) {
2429
2500
  if (!this.logger) this.logger = {
2430
2501
  info: (...a)=>console.log(...a),
@@ -2449,7 +2520,7 @@ var __webpack_modules__ = {
2449
2520
  if (this.didLaunch) return;
2450
2521
  await this.launchChromium(stats.compilation);
2451
2522
  this.didLaunch = true;
2452
- if (!this.didReportReady) console.log((0, ready_message.G)(stats.compilation.options.mode, this.options.browser));
2523
+ if (!this.didReportReady && !this.extensionLoadRefused) console.log((0, ready_message.G)(stats.compilation.options.mode, this.options.browser));
2453
2524
  } catch (error) {
2454
2525
  try {
2455
2526
  this.logger.error(messages._D(this.options.browser, error));
@@ -2816,10 +2887,13 @@ var __webpack_modules__ = {
2816
2887
  }
2817
2888
  if (!portReady && 'true' === process.env.EXTENSION_AUTHOR_MODE) this.logger.warn?.(`[browser] Debug port ${selectedPort} not bound after spawn. CDP may fail`);
2818
2889
  }
2819
- if ('development' === compilation.options.mode && !this.didReportReady) {
2890
+ const reportReady = ()=>{
2891
+ if ('development' !== compilation.options.mode) return;
2892
+ if (this.didReportReady || this.extensionLoadRefused) return;
2820
2893
  console.log((0, ready_message.G)(compilation.options.mode, this.options.browser));
2821
2894
  this.didReportReady = true;
2822
- }
2895
+ };
2896
+ if (!enableCdp) reportReady();
2823
2897
  try {
2824
2898
  const mode = compilation?.options?.mode || 'development';
2825
2899
  try {
@@ -2851,12 +2925,18 @@ var __webpack_modules__ = {
2851
2925
  mod.setupCdpAfterLaunch(compilation, cdpConfig, chromiumConfig, pipeStreams),
2852
2926
  new Promise((_, reject)=>setTimeout(()=>reject(new Error(`CDP setup did not complete within ${CDP_SETUP_TIMEOUT_MS / 1000}s. Chrome likely rejected the extension at launch, open chrome://extensions in the dev browser window for the exact error. Common causes: MV3 content_security_policy with 'unsafe-inline', manifest keys Chrome does not support, or manifest references to files missing from the output. Reload/HMR cannot attach until this is fixed.`)), CDP_SETUP_TIMEOUT_MS).unref?.())
2853
2927
  ]);
2928
+ if (cdpConfig.extensionLoadRefused) {
2929
+ this.extensionLoadRefused = cdpConfig.extensionLoadRefused;
2930
+ this.bannerOnRecovery = cdpConfig.printBannerOnRecovery;
2931
+ }
2854
2932
  if (cdpConfig.cdpController) this.ctx.setController(cdpConfig.cdpController);
2855
2933
  }
2934
+ reportReady();
2856
2935
  } catch (error) {
2857
2936
  const message = String(error && error.message);
2858
2937
  const hint = /timed out|did not complete/i.test(message) ? " Chrome likely rejected the extension at launch, open chrome://extensions in the dev browser window for the exact error. Common causes: MV3 content_security_policy with 'unsafe-inline', manifest keys Chrome does not support, or manifest references to missing files. Reload/HMR cannot attach until this is fixed." : '';
2859
2938
  console.error(`[browser] ${message}${hint}`);
2939
+ reportReady();
2860
2940
  }
2861
2941
  }
2862
2942
  async launchWithDirectSpawn(binary, chromeFlags, usePipe = false) {
@@ -2907,7 +2987,7 @@ var __webpack_modules__ = {
2907
2987
  if ('true' === process.env.EXTENSION_AUTHOR_MODE) this.logger.info(messages.nn(code || 0));
2908
2988
  if (!(0, process_teardown.Op)(child)) {
2909
2989
  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.`);
2910
- (0, ready_stamp.W)(this.closeHandlerContext?.extensionOutputPath, code);
2990
+ (0, ready_stamp.Wi)(this.closeHandlerContext?.extensionOutputPath, code);
2911
2991
  }
2912
2992
  disposeSignalHandlers?.();
2913
2993
  const userDataDir = launchArgs.find((arg)=>arg.startsWith('--user-data-dir='))?.slice('--user-data-dir='.length).replace(/^"|"$/g, '');
@@ -2942,6 +3022,8 @@ var __webpack_modules__ = {
2942
3022
  _define_property(this, "ctx", void 0);
2943
3023
  _define_property(this, "didLaunch", void 0);
2944
3024
  _define_property(this, "didReportReady", void 0);
3025
+ _define_property(this, "extensionLoadRefused", void 0);
3026
+ _define_property(this, "bannerOnRecovery", void 0);
2945
3027
  _define_property(this, "logger", void 0);
2946
3028
  _define_property(this, "closeHandlerContext", void 0);
2947
3029
  this.options = options;
@@ -3132,7 +3214,7 @@ var __webpack_modules__ = {
3132
3214
  } : null;
3133
3215
  }
3134
3216
  function isFirefoxHeadlessRequested(env = process.env) {
3135
- return /^(1|true)$/i.test(String(env.MOZ_HEADLESS || '').trim());
3217
+ return /^(1|true)$/i.test(String(env.MOZ_HEADLESS || '').trim()) || (0, shared_utils.ZO)(env);
3136
3218
  }
3137
3219
  class FirefoxBinaryDetector {
3138
3220
  static generateFirefoxArgs(binaryPath, profilePath, debugPort, additionalArgs = [], headless = false) {
@@ -3154,7 +3236,9 @@ var __webpack_modules__ = {
3154
3236
  '-start-debugger-server',
3155
3237
  String(debugPort)
3156
3238
  ] : [],
3157
- '--foreground',
3239
+ ...headless ? [] : [
3240
+ '--foreground'
3241
+ ],
3158
3242
  ...additionalArgs
3159
3243
  ];
3160
3244
  return {
@@ -3175,7 +3259,9 @@ var __webpack_modules__ = {
3175
3259
  '-start-debugger-server',
3176
3260
  String(debugPort)
3177
3261
  ] : [],
3178
- '--foreground',
3262
+ ...headless ? [] : [
3263
+ '--foreground'
3264
+ ],
3179
3265
  ...additionalArgs
3180
3266
  ];
3181
3267
  return {
@@ -3418,6 +3504,22 @@ var __webpack_modules__ = {
3418
3504
  if (external_node_fs_.existsSync(external_node_path_.join(distFirefox, 'manifest.json'))) return distFirefox;
3419
3505
  return candidate;
3420
3506
  }
3507
+ function classifyAddonInstallFailure(error) {
3508
+ if (error instanceof Error) return {
3509
+ status: 'unknown'
3510
+ };
3511
+ const reply = error;
3512
+ if (!reply || 'object' != typeof reply || !reply.error) return {
3513
+ status: 'unknown'
3514
+ };
3515
+ const reason = String(reply.message || '').trim();
3516
+ return reason ? {
3517
+ status: 'refused',
3518
+ reason
3519
+ } : {
3520
+ status: 'unknown'
3521
+ };
3522
+ }
3421
3523
  async function getAddonsActorWithRetry(client, cached, tries = 40, delayMs = 250) {
3422
3524
  if (cached) return cached;
3423
3525
  let addonsActor;
@@ -4074,6 +4176,9 @@ var __webpack_modules__ = {
4074
4176
  const RETRY_INTERVAL = constants.FQ;
4075
4177
  const RETRY_LOG_EVERY_N_ATTEMPTS = 10;
4076
4178
  class RemoteFirefox {
4179
+ getAddonInstallRefusalReason() {
4180
+ return this.addonInstallRefusalReason || null;
4181
+ }
4077
4182
  selectPrimaryAddonPath(compilation, candidateAddonPaths) {
4078
4183
  const normalizedOutputPath = String(compilation?.options?.output?.path || '').replace(/\\/g, '/');
4079
4184
  if (normalizedOutputPath) {
@@ -4163,6 +4268,8 @@ var __webpack_modules__ = {
4163
4268
  if (primaryAddonPath && String(addonPath) === String(primaryAddonPath) && maybeId) primaryUserAddonId = maybeId;
4164
4269
  if (isManager) await waitForManagerWelcome(client);
4165
4270
  } catch (err) {
4271
+ const outcome = classifyAddonInstallFailure(err);
4272
+ if ('refused' === outcome.status) this.addonInstallRefusalReason = outcome.reason;
4166
4273
  const message = requestErrorToMessage(err);
4167
4274
  throw new Error(messages.WV(this.options.browser, message));
4168
4275
  }
@@ -4210,6 +4317,7 @@ var __webpack_modules__ = {
4210
4317
  remote_firefox_define_property(this, "cachedAddonsActor", void 0);
4211
4318
  remote_firefox_define_property(this, "lastInstalledAddonPath", void 0);
4212
4319
  remote_firefox_define_property(this, "derivedExtensionId", void 0);
4320
+ remote_firefox_define_property(this, "addonInstallRefusalReason", void 0);
4213
4321
  this.options = configOptions;
4214
4322
  }
4215
4323
  }
@@ -4227,6 +4335,9 @@ var __webpack_modules__ = {
4227
4335
  async ensureLoaded(compilation) {
4228
4336
  await this.remote.installAddons(compilation);
4229
4337
  }
4338
+ getAddonInstallRefusalReason() {
4339
+ return this.remote.getAddonInstallRefusalReason();
4340
+ }
4230
4341
  async enableUnifiedLogging(opts) {
4231
4342
  await this.remote.enableUnifiedLogging(opts);
4232
4343
  }
@@ -4259,6 +4370,7 @@ var __webpack_modules__ = {
4259
4370
  return await fn();
4260
4371
  } catch (error) {
4261
4372
  lastError = error;
4373
+ if (controller.getAddonInstallRefusalReason()) break;
4262
4374
  if ('true' === process.env.EXTENSION_AUTHOR_MODE) try {
4263
4375
  const msg = error?.message || String(error);
4264
4376
  console.warn(`[browser] Firefox RDP setup retry ${i + 1}/${attempts}: ${msg}`);
@@ -4268,10 +4380,19 @@ var __webpack_modules__ = {
4268
4380
  }
4269
4381
  throw lastError;
4270
4382
  };
4271
- if (plugin.rdpController) await retry(()=>plugin.rdpController.ensureLoaded?.(compilation) || Promise.resolve());
4272
- else {
4273
- await retry(()=>controller.ensureLoaded(compilation));
4274
- plugin.rdpController = controller;
4383
+ const withRefusalReason = (error)=>{
4384
+ const reason = controller.getAddonInstallRefusalReason();
4385
+ if (reason && error && 'object' == typeof error) error.extensionLoadRefusedReason = reason;
4386
+ return error;
4387
+ };
4388
+ try {
4389
+ if (plugin.rdpController) await retry(()=>plugin.rdpController.ensureLoaded?.(compilation) || Promise.resolve());
4390
+ else {
4391
+ await retry(()=>controller.ensureLoaded(compilation));
4392
+ plugin.rdpController = controller;
4393
+ }
4394
+ } catch (error) {
4395
+ throw withRefusalReason(error);
4275
4396
  }
4276
4397
  return controller;
4277
4398
  }
@@ -4354,8 +4475,8 @@ var __webpack_modules__ = {
4354
4475
  error: (...a)=>console.error(...a),
4355
4476
  debug: (...a)=>console?.debug?.(...a)
4356
4477
  };
4357
- if ('development' === options.mode) this.ctx.logger?.info?.((0, ready_message.G)(options.mode, this.host.browser));
4358
4478
  await this.launch(compilation, options);
4479
+ if ('development' === options.mode && !this.host.extensionLoadRefused) this.ctx.logger?.info?.((0, ready_message.G)(options.mode, this.host.browser));
4359
4480
  this.ctx.didLaunch = true;
4360
4481
  }
4361
4482
  apply(compiler) {
@@ -4375,8 +4496,8 @@ var __webpack_modules__ = {
4375
4496
  return;
4376
4497
  }
4377
4498
  if (this.ctx.didLaunch) return void done();
4378
- if ('development' === stats.compilation.options.mode) console.log((0, ready_message.G)(stats.compilation.options.mode, this.host.browser));
4379
4499
  await this.launch(stats.compilation, (0, runtime_options.zU)(this.host, stats.compilation.options.mode));
4500
+ if ('development' === stats.compilation.options.mode && !this.host.extensionLoadRefused) console.log((0, ready_message.G)(stats.compilation.options.mode, this.host.browser));
4380
4501
  this.ctx.didLaunch = true;
4381
4502
  } catch (error) {
4382
4503
  this.ctx.logger?.error?.(messages.MQ(error));
@@ -4537,10 +4658,24 @@ var __webpack_modules__ = {
4537
4658
  (0, shared_utils.sW)(profilePath);
4538
4659
  });
4539
4660
  this.wireChildLifecycle();
4540
- const ctrl = await setupRdpAfterLaunch(this.host, compilation, debugPort);
4661
+ let ctrl;
4662
+ try {
4663
+ ctrl = await setupRdpAfterLaunch(this.host, compilation, debugPort);
4664
+ } catch (error) {
4665
+ const reason = error?.extensionLoadRefusedReason;
4666
+ if (!reason) {
4667
+ (0, ready_stamp.__)(this.extensionOutputPath, debugPort);
4668
+ throw error;
4669
+ }
4670
+ this.reportAddonLoadRefused(reason);
4671
+ this.host.retryAddonInstall = ()=>this.retryAddonInstall(compilation, debugPort);
4672
+ (0, ready_stamp.__)(this.extensionOutputPath, debugPort);
4673
+ this.scheduleWatchTimeout();
4674
+ return;
4675
+ }
4541
4676
  this.host.rdpController = ctrl;
4542
4677
  this.ctx.setController(ctrl);
4543
- (0, ready_stamp._)(this.extensionOutputPath, debugPort);
4678
+ (0, ready_stamp.__)(this.extensionOutputPath, debugPort);
4544
4679
  this.scheduleWatchTimeout();
4545
4680
  try {
4546
4681
  if ('true' === process.env.EXTENSION_AUTHOR_MODE) {
@@ -4561,12 +4696,14 @@ var __webpack_modules__ = {
4561
4696
  ...'win32' === process.platform ? [
4562
4697
  '-wait-for-browser'
4563
4698
  ] : [],
4564
- '--foreground',
4699
+ ...isFirefoxHeadlessRequested() ? [] : [
4700
+ '--foreground'
4701
+ ],
4565
4702
  ...firefoxArgs
4566
4703
  ];
4567
4704
  this.child = await this.spawnFirefoxChild(binaryPath, args, wslFallbackBinary);
4568
4705
  this.wireChildLifecycle();
4569
- if (debugPort > 0) (0, ready_stamp._)(this.extensionOutputPath, debugPort);
4706
+ if (debugPort > 0) (0, ready_stamp.__)(this.extensionOutputPath, debugPort);
4570
4707
  this.scheduleWatchTimeout();
4571
4708
  }
4572
4709
  }
@@ -4619,7 +4756,7 @@ var __webpack_modules__ = {
4619
4756
  if ('true' === process.env.EXTENSION_AUTHOR_MODE) this.ctx.logger?.info?.(messages.Th(this.host.browser));
4620
4757
  if (!(0, process_teardown.Op)(child)) {
4621
4758
  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.`);
4622
- (0, ready_stamp.W)(this.extensionOutputPath, code);
4759
+ (0, ready_stamp.Wi)(this.extensionOutputPath, code);
4623
4760
  }
4624
4761
  this.cleanupInstance().catch((err)=>{
4625
4762
  if ('true' === process.env.EXTENSION_AUTHOR_MODE) this.ctx.logger?.error?.(`[browser] Cleanup error on child close: ${err?.message || err}`);
@@ -4629,6 +4766,36 @@ var __webpack_modules__ = {
4629
4766
  this.pipeChildOutput(child);
4630
4767
  disposeProcessHandlers = setupFirefoxProcessHandlers(this.host.browser, ()=>this.child, ()=>this.cleanupInstance());
4631
4768
  }
4769
+ async retryAddonInstall(compilation, debugPort) {
4770
+ try {
4771
+ const ctrl = await setupRdpAfterLaunch(this.host, compilation, debugPort);
4772
+ this.host.rdpController = ctrl;
4773
+ this.ctx.setController(ctrl);
4774
+ this.host.extensionLoadRefused = void 0;
4775
+ return {
4776
+ status: 'loaded'
4777
+ };
4778
+ } catch (error) {
4779
+ const reason = error?.extensionLoadRefusedReason;
4780
+ return reason ? {
4781
+ status: 'refused',
4782
+ reason
4783
+ } : {
4784
+ status: 'unknown'
4785
+ };
4786
+ }
4787
+ }
4788
+ reportAddonLoadRefused(reason) {
4789
+ const refusedPath = this.extensionOutputPath || '';
4790
+ console.error(messages.EE(refusedPath, reason));
4791
+ this.host.logSink?.({
4792
+ level: 'error',
4793
+ text: `extension_load_refused: ${refusedPath}${reason ? ` - ${reason}` : ''}`,
4794
+ source: 'browser'
4795
+ });
4796
+ (0, ready_stamp.sf)(this.extensionOutputPath, reason);
4797
+ this.host.extensionLoadRefused = reason;
4798
+ }
4632
4799
  async cleanupInstance() {
4633
4800
  (0, process_teardown.Df)(this.child, this.host.browser);
4634
4801
  }