extension 4.1.12 → 4.1.14

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.
Files changed (30) hide show
  1. package/dist/49.cjs +2 -10
  2. package/dist/browsers.cjs +355 -111
  3. package/dist/cli.cjs +1012 -518
  4. package/dist/extension/browsers/browsers-lib/messages.d.ts +1 -1
  5. package/dist/extension/browsers/browsers-lib/newtab-override.d.ts +1 -0
  6. package/dist/extension/browsers/browsers-lib/resolve-profile.d.ts +1 -0
  7. package/dist/extension/browsers/run-chromium/chromium-launch/browser-config.d.ts +8 -1
  8. package/dist/extension/browsers/run-chromium/chromium-launch/index.d.ts +1 -0
  9. package/dist/extension/browsers/run-firefox/firefox-launch/binary-detector.d.ts +10 -0
  10. package/dist/extension/browsers/run-firefox/firefox-launch/browser-config.d.ts +9 -0
  11. package/dist/extension/browsers/run-firefox/firefox-launch/dry-run.d.ts +1 -1
  12. package/dist/extension/browsers/run-firefox/firefox-launch/index.d.ts +1 -0
  13. package/dist/extension/browsers/run-firefox/firefox-types.d.ts +1 -1
  14. package/dist/extension/browsers/run-firefox/rdp/rdp-extension-controller/index.d.ts +1 -0
  15. package/dist/extension/browsers/run-firefox/rdp/remote-firefox/index.d.ts +1 -0
  16. package/dist/extension/browsers/run-firefox/rdp/remote-firefox/manager-tab.d.ts +10 -0
  17. package/dist/extension/browsers/run-firefox/rdp/remote-firefox/messaging-client.d.ts +1 -0
  18. package/dist/extension/browsers/run-firefox/rdp/remote-firefox/transport.d.ts +3 -1
  19. package/dist/extension/commands/doctor.d.ts +1 -1
  20. package/dist/extension/helpers/cli-argv.d.ts +8 -0
  21. package/dist/extension/helpers/cli-options.d.ts +7 -0
  22. package/dist/extension/helpers/messages.d.ts +5 -0
  23. package/dist/extension/helpers/msg-placeholders.d.ts +2 -0
  24. package/dist/extension/helpers/output-flag.d.ts +6 -0
  25. package/dist/extension/helpers/session-project-path.d.ts +4 -0
  26. package/dist/extension/helpers/telemetry-cli.d.ts +1 -0
  27. package/dist/extension/helpers/template-catalog.d.ts +1 -1
  28. package/package.json +4 -4
  29. package/types/assets.d.ts +65 -0
  30. package/types/index.d.ts +1 -60
package/dist/browsers.cjs CHANGED
@@ -641,12 +641,6 @@ var __webpack_modules__ = {
641
641
  function firefoxLaunchCalled() {
642
642
  return `${getLoggingPrefix('debug')} browser launch browser=firefox`;
643
643
  }
644
- function firefoxBinaryArgsExtracted(args) {
645
- return `${getLoggingPrefix('debug')} browser args="${args}"`;
646
- }
647
- function firefoxNoBinaryArgsFound() {
648
- return `${getLoggingPrefix('debug')} browser args=none`;
649
- }
650
644
  function firefoxFailedToStart(error) {
651
645
  return `${getLoggingPrefix('error')} Firefox failed to start.\n${pintor__rspack_import_8_default().red(errorDetail(error))}`;
652
646
  }
@@ -656,8 +650,8 @@ var __webpack_modules__ = {
656
650
  function firefoxDryRunBinary(path) {
657
651
  return `${getLoggingPrefix('info')} ${pintor__rspack_import_8_default().gray('PATH')} ${pintor__rspack_import_8_default().underline(path)}`;
658
652
  }
659
- function firefoxDryRunConfig(cfg) {
660
- return `${getLoggingPrefix('info')} ${pintor__rspack_import_8_default().gray('CONFIG')} ${pintor__rspack_import_8_default().gray(cfg)}`;
653
+ function firefoxDryRunArgs(args) {
654
+ return `${getLoggingPrefix('info')} ${pintor__rspack_import_8_default().gray('ARGS')} ${pintor__rspack_import_8_default().gray(args)}`;
661
655
  }
662
656
  function safariBuildCalled() {
663
657
  return `${getLoggingPrefix('debug')} browser build browser=safari`;
@@ -957,7 +951,6 @@ var __webpack_modules__ = {
957
951
  bv: ()=>cdpUnifiedExtensionLog,
958
952
  cD: ()=>targetActorHasActiveRequestError,
959
953
  cF: ()=>safariRebuilt,
960
- dN: ()=>firefoxNoBinaryArgsFound,
961
954
  dk: ()=>generalBrowserError,
962
955
  dw: ()=>devFirefoxProfilePath,
963
956
  e_: ()=>runningInDevelopment,
@@ -968,14 +961,13 @@ var __webpack_modules__ = {
968
961
  fw: ()=>safariOpening,
969
962
  hE: ()=>cdpClientConnectionClosed,
970
963
  io: ()=>emptyLine,
971
- iv: ()=>firefoxBinaryArgsExtracted,
972
964
  jP: ()=>rdpInvalidRequestPayload,
973
965
  jR: ()=>safariBuilding,
974
966
  jc: ()=>safariProjectStale,
975
967
  jk: ()=>requireGeckoBinaryForGeckoBased,
976
- k6: ()=>firefoxDryRunConfig,
977
968
  kK: ()=>preferringSystemBrowserOverSnapshot,
978
969
  l9: ()=>parsingPacketError,
970
+ lO: ()=>firefoxDryRunArgs,
979
971
  l_: ()=>safariConverted,
980
972
  ne: ()=>requireChromiumBinaryForChromiumBased,
981
973
  nn: ()=>chromeProcessExited,
@@ -998,6 +990,22 @@ var __webpack_modules__ = {
998
990
  yc: ()=>safariDryRunNotBuilding
999
991
  });
1000
992
  },
993
+ "./browsers/browsers-lib/newtab-override.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
994
+ var node_fs__rspack_import_0 = __webpack_require__("node:fs");
995
+ var node_path__rspack_import_1 = __webpack_require__("node:path");
996
+ function manifestDeclaresNewtabOverride(outPath) {
997
+ try {
998
+ const manifest = JSON.parse(node_fs__rspack_import_0.readFileSync(node_path__rspack_import_1.join(outPath, 'manifest.json'), 'utf-8'));
999
+ const overrides = manifest?.chrome_url_overrides || manifest?.['chromium:chrome_url_overrides'] || manifest?.['chrome:chrome_url_overrides'] || manifest?.['gecko:chrome_url_overrides'] || manifest?.['firefox:chrome_url_overrides'];
1000
+ return Boolean(overrides && 'string' == typeof overrides.newtab && overrides.newtab.trim().length > 0);
1001
+ } catch {
1002
+ return false;
1003
+ }
1004
+ }
1005
+ __webpack_require__.d(__webpack_exports__, {
1006
+ c: ()=>manifestDeclaresNewtabOverride
1007
+ });
1008
+ },
1001
1009
  "./browsers/browsers-lib/output-binaries-resolver.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1002
1010
  var node_fs__rspack_import_0 = __webpack_require__("node:fs");
1003
1011
  var node_path__rspack_import_1 = __webpack_require__("node:path");
@@ -1472,6 +1480,7 @@ var __webpack_modules__ = {
1472
1480
  }
1473
1481
  function resolveProfileConfig(input) {
1474
1482
  const { managedBaseDir, useSystemProfile, persistProfile, keepProfileChanges, copyFromProfile, resolveExplicit } = input;
1483
+ const provision = false !== input.provision;
1475
1484
  const rawProfile = normalizeProfileOption(input.rawProfile);
1476
1485
  if (false === rawProfile || useSystemProfile) return {
1477
1486
  kind: 'system',
@@ -1502,6 +1511,14 @@ var __webpack_modules__ = {
1502
1511
  profilePath = external_node_path_.join(managedBaseDir, human);
1503
1512
  }
1504
1513
  const isFreshTarget = !external_node_fs_.existsSync(profilePath) || 0 === external_node_fs_.readdirSync(profilePath).length;
1514
+ if (!provision) return {
1515
+ kind: 'managed',
1516
+ profilePath,
1517
+ persisted,
1518
+ ...hasCopyFrom(copyFromProfile) && isFreshTarget ? {
1519
+ seededFrom: copyFromProfile.trim()
1520
+ } : {}
1521
+ };
1505
1522
  external_node_fs_.mkdirSync(profilePath, {
1506
1523
  recursive: true
1507
1524
  });
@@ -1975,6 +1992,7 @@ var __webpack_modules__ = {
1975
1992
  preferences: opts.preferences,
1976
1993
  browserFlags: opts.browserFlags,
1977
1994
  startingUrl: opts.startingUrl,
1995
+ noOpen: opts.noOpen,
1978
1996
  geckoBinary: opts.geckoBinary,
1979
1997
  instanceId: opts.instanceId,
1980
1998
  port: opts.port,
@@ -2179,6 +2197,38 @@ var __webpack_modules__ = {
2179
2197
  var messaging = __webpack_require__("./helpers/messaging.ts");
2180
2198
  var banner = __webpack_require__("./browsers/browsers-lib/banner.ts");
2181
2199
  var instance_registry = __webpack_require__("./browsers/browsers-lib/instance-registry.ts");
2200
+ const MSG_REFERENCE = /__MSG_([A-Za-z0-9_@]+?)__/g;
2201
+ function collectMsgReferences(value) {
2202
+ const found = [];
2203
+ const seen = new Set();
2204
+ const visit = (node)=>{
2205
+ if ('string' == typeof node) {
2206
+ MSG_REFERENCE.lastIndex = 0;
2207
+ let match = MSG_REFERENCE.exec(node);
2208
+ while(null !== match){
2209
+ const name = match[1];
2210
+ if (name && !name.startsWith('@@') && !seen.has(name)) {
2211
+ seen.add(name);
2212
+ found.push(name);
2213
+ }
2214
+ match = MSG_REFERENCE.exec(node);
2215
+ }
2216
+ return;
2217
+ }
2218
+ if (Array.isArray(node)) {
2219
+ for (const item of node)visit(item);
2220
+ return;
2221
+ }
2222
+ if (node && 'object' == typeof node) for (const item of Object.values(node))visit(item);
2223
+ };
2224
+ visit(value);
2225
+ return found;
2226
+ }
2227
+ function findUndefinedMsgReferences(value, catalogKeys) {
2228
+ const lower = new Set();
2229
+ for (const key of catalogKeys)lower.add(String(key).toLowerCase());
2230
+ return collectMsgReferences(value).filter((name)=>!lower.has(name.toLowerCase()));
2231
+ }
2182
2232
  function diagnoseChromiumManifestRefusal(manifest) {
2183
2233
  const m = manifest;
2184
2234
  if (2 === Number(m?.manifest_version)) return 'mv2';
@@ -2313,7 +2363,7 @@ var __webpack_modules__ = {
2313
2363
  if (external_node_fs_.existsSync(catalogPath)) try {
2314
2364
  const raw = external_node_fs_.readFileSync(catalogPath, 'utf8').replace(/^\uFEFF/, '');
2315
2365
  const catalog = JSON.parse(raw);
2316
- catalogKeys = new Set(Object.keys(catalog || {}).map((key)=>key.toLowerCase()));
2366
+ catalogKeys = new Set(Object.keys(catalog || {}));
2317
2367
  } catch {
2318
2368
  blockers.push(`default_locale: _locales/${defaultLocale}/messages.json is not valid JSON, Chrome refuses the whole extension.`);
2319
2369
  }
@@ -2321,11 +2371,7 @@ var __webpack_modules__ = {
2321
2371
  } catch {
2322
2372
  return blockers;
2323
2373
  }
2324
- if (catalogKeys) {
2325
- const refs = new Set();
2326
- collectMsgRefs(m, refs);
2327
- for (const ref of refs)if (!catalogKeys.has(ref.toLowerCase())) blockers.push(`__MSG_${ref}__: used in the manifest but not defined in _locales/${defaultLocale}/messages.json, Chrome refuses the whole extension.`);
2328
- }
2374
+ if (catalogKeys) for (const ref of findUndefinedMsgReferences(m, catalogKeys))blockers.push(`__MSG_${ref}__: used in the manifest but not defined in _locales/${defaultLocale}/messages.json, Chrome refuses the whole extension.`);
2329
2375
  } else try {
2330
2376
  if (external_node_fs_.existsSync(localesDir)) {
2331
2377
  const hasCatalog = external_node_fs_.readdirSync(localesDir).some((entry)=>external_node_fs_.existsSync(external_node_path_.join(localesDir, entry, 'messages.json')));
@@ -2346,13 +2392,6 @@ var __webpack_modules__ = {
2346
2392
  } catch {}
2347
2393
  return [];
2348
2394
  }
2349
- function collectMsgRefs(value, out) {
2350
- if ('string' == typeof value) {
2351
- const match = /^__MSG_(.+)__$/.exec(value.trim());
2352
- if (match && !match[1].startsWith('@@')) out.add(match[1]);
2353
- } else if (Array.isArray(value)) for (const item of value)collectMsgRefs(item, out);
2354
- else if (value && 'object' == typeof value) for (const item of Object.values(value))collectMsgRefs(item, out);
2355
- }
2356
2395
  function isValidDottedVersion(version) {
2357
2396
  if (!version) return false;
2358
2397
  const parts = version.split('.');
@@ -2533,7 +2572,19 @@ var __webpack_modules__ = {
2533
2572
  });
2534
2573
  external_node_fs_.writeFileSync(preferencesPath, JSON.stringify(mergedPreferences), 'utf8');
2535
2574
  }
2536
- function browserConfig(compilation, configOptions) {
2575
+ function chromiumLaunchPlan(binary, chromiumConfig, startingUrl) {
2576
+ return {
2577
+ binary,
2578
+ args: startingUrl ? [
2579
+ ...chromiumConfig,
2580
+ startingUrl
2581
+ ] : [
2582
+ ...chromiumConfig
2583
+ ]
2584
+ };
2585
+ }
2586
+ function browserConfig(compilation, configOptions, mode = {}) {
2587
+ const provision = false !== mode.provision;
2537
2588
  const extensionsToLoad = (0, runtime_options.fT)(configOptions.extension);
2538
2589
  const devWantsCDP = compilation?.options?.mode === 'development';
2539
2590
  const rawProfile = configOptions.profile;
@@ -2557,17 +2608,18 @@ var __webpack_modules__ = {
2557
2608
  persistProfile: configOptions.persistProfile,
2558
2609
  keepProfileChanges: configOptions.keepProfileChanges,
2559
2610
  copyFromProfile: configOptions.copyFromProfile,
2560
- resolveExplicit: (trimmedProfile)=>external_node_path_.isAbsolute(trimmedProfile) ? trimmedProfile : external_node_path_.resolve(contextDir, trimmedProfile)
2611
+ resolveExplicit: (trimmedProfile)=>external_node_path_.isAbsolute(trimmedProfile) ? trimmedProfile : external_node_path_.resolve(contextDir, trimmedProfile),
2612
+ provision
2561
2613
  });
2562
2614
  const userProfilePath = resolved.profilePath;
2563
- if ('managed' === resolved.kind) {
2615
+ if ('managed' === resolved.kind && provision) {
2564
2616
  if ((0, messaging._o)()) (0, messaging._w)(messages.sY(shownPath(userProfilePath)));
2565
2617
  if (!resolved.persisted) try {
2566
2618
  const maxAgeHours = parseInt(String(process.env.EXTENSION_TMP_PROFILE_MAX_AGE_HOURS || ''), 10);
2567
2619
  (0, shared_utils.CW)(managedBaseDir, external_node_path_.basename(userProfilePath), Number.isFinite(maxAgeHours) ? maxAgeHours : 12);
2568
2620
  } catch {}
2569
2621
  }
2570
- if (userProfilePath) {
2622
+ if (userProfilePath && provision) {
2571
2623
  external_node_fs_.mkdirSync(userProfilePath, {
2572
2624
  recursive: true
2573
2625
  });
@@ -2888,7 +2940,10 @@ var __webpack_modules__ = {
2888
2940
  process.exit(1);
2889
2941
  }
2890
2942
  }
2891
- if (this.options?.dryRun || process.env.VITEST || process.env.VITEST_WORKER_ID) return void logChromiumDryRun(this.options?.chromiumBinary ? (0, wsl_support.f7)(String(this.options.chromiumBinary)) : 'chromium-mock-binary', []);
2943
+ const inTestRunner = Boolean(process.env.VITEST || process.env.VITEST_WORKER_ID);
2944
+ const dryRun = Boolean(this.options?.dryRun);
2945
+ if (inTestRunner && !dryRun) return void logChromiumDryRun(this.options?.chromiumBinary ? (0, wsl_support.f7)(String(this.options.chromiumBinary)) : 'chromium-mock-binary', []);
2946
+ if (inTestRunner && dryRun && !this.options?.chromiumBinary) return void this.printDryRunPlan(compilation, 'chromium-mock-binary');
2892
2947
  const browser = this.options?.browser;
2893
2948
  let browserBinaryLocation = null;
2894
2949
  let printedGuidance = false;
@@ -3197,6 +3252,8 @@ var __webpack_modules__ = {
3197
3252
  instanceId: this.options.instanceId,
3198
3253
  extension: extensionsToLoad,
3199
3254
  logLevel: this.options.logLevel
3255
+ }, {
3256
+ provision: !dryRun
3200
3257
  });
3201
3258
  } catch (error) {
3202
3259
  if (shared_utils.ci(error)) (0, ready_stamp.iD)((0, extension_output_path.W)(compilation, void 0), {
@@ -3229,7 +3286,7 @@ var __webpack_modules__ = {
3229
3286
  enableCdp
3230
3287
  });
3231
3288
  } catch {}
3232
- if (this.options.dryRun) return void logChromiumDryRun(browserBinaryLocation, chromiumConfig);
3289
+ if (dryRun) return void this.printDryRunPlan(compilation, browserBinaryLocation, chromiumConfig);
3233
3290
  const usePipe = chromiumConfig.includes('--remote-debugging-pipe');
3234
3291
  this.closeHandlerContext = {
3235
3292
  isDevMode: 'development' === compilation.options.mode,
@@ -3299,14 +3356,18 @@ var __webpack_modules__ = {
3299
3356
  reportReady();
3300
3357
  }
3301
3358
  }
3359
+ printDryRunPlan(compilation, binary, chromiumConfig) {
3360
+ const flags = chromiumConfig ?? browserConfig(compilation, {
3361
+ ...this.options
3362
+ }, {
3363
+ provision: false
3364
+ });
3365
+ const plan = chromiumLaunchPlan(binary, flags, this.options?.startingUrl);
3366
+ logChromiumDryRun(plan.binary, plan.args);
3367
+ }
3302
3368
  async launchWithDirectSpawn(binary, chromeFlags, usePipe = false) {
3303
3369
  if ((0, messaging._o)()) this.logger.info(messages.xy());
3304
- const launchArgs = this.options?.startingUrl ? [
3305
- ...chromeFlags,
3306
- this.options.startingUrl
3307
- ] : [
3308
- ...chromeFlags
3309
- ];
3370
+ const { args: launchArgs } = chromiumLaunchPlan(binary, chromeFlags, this.options?.startingUrl);
3310
3371
  const stdio = usePipe ? [
3311
3372
  'ignore',
3312
3373
  'ignore',
@@ -3579,6 +3640,29 @@ var __webpack_modules__ = {
3579
3640
  return /^(1|true)$/i.test(String(env.MOZ_HEADLESS || '').trim()) || (0, shared_utils.ZO)(env);
3580
3641
  }
3581
3642
  class FirefoxBinaryDetector {
3643
+ static launchPlan(input) {
3644
+ if (input.profilePath) return FirefoxBinaryDetector.generateFirefoxArgs(input.binaryPath, input.profilePath, input.debugPort, input.binaryArgs, input.headless);
3645
+ const args = [
3646
+ ...input.headless ? [
3647
+ '-headless'
3648
+ ] : [],
3649
+ ...input.debugPort > 0 ? [
3650
+ '-start-debugger-server',
3651
+ String(input.debugPort)
3652
+ ] : [],
3653
+ ...'win32' === process.platform ? [
3654
+ '-wait-for-browser'
3655
+ ] : [],
3656
+ ...input.headless ? [] : [
3657
+ '--foreground'
3658
+ ],
3659
+ ...input.binaryArgs
3660
+ ];
3661
+ return {
3662
+ binary: input.binaryPath,
3663
+ args
3664
+ };
3665
+ }
3582
3666
  static generateFirefoxArgs(binaryPath, profilePath, debugPort, additionalArgs = [], headless = false) {
3583
3667
  const headlessArgs = headless ? [
3584
3668
  '-headless'
@@ -3708,7 +3792,8 @@ var __webpack_modules__ = {
3708
3792
  ...customPrefs
3709
3793
  };
3710
3794
  }
3711
- async function browserConfig(compilation, configOptions) {
3795
+ async function resolveFirefoxLaunchConfig(compilation, configOptions, mode = {}) {
3796
+ const provision = false !== mode.provision;
3712
3797
  const { browser, profile, browserFlags = [] } = configOptions;
3713
3798
  const binaryArgs = [];
3714
3799
  const excludeFlags = configOptions.excludeBrowserFlags || [];
@@ -3736,17 +3821,18 @@ var __webpack_modules__ = {
3736
3821
  persistProfile: configOptions.persistProfile,
3737
3822
  keepProfileChanges: configOptions.keepProfileChanges,
3738
3823
  copyFromProfile: configOptions.copyFromProfile,
3739
- resolveExplicit: (trimmedProfile)=>external_node_path_.isAbsolute(trimmedProfile) ? trimmedProfile : external_node_path_.resolve(contextDir, trimmedProfile)
3824
+ resolveExplicit: (trimmedProfile)=>external_node_path_.isAbsolute(trimmedProfile) ? trimmedProfile : external_node_path_.resolve(contextDir, trimmedProfile),
3825
+ provision
3740
3826
  });
3741
3827
  const profilePath = resolved.profilePath;
3742
- if ('managed' === resolved.kind) {
3828
+ if ('managed' === resolved.kind && provision) {
3743
3829
  if ((0, messaging._o)()) (0, messaging._w)(messages.sY(shownPath(profilePath)));
3744
3830
  if (!resolved.persisted) try {
3745
3831
  const maxAgeHours = parseInt(String(process.env.EXTENSION_TMP_PROFILE_MAX_AGE_HOURS || ''), 10);
3746
3832
  (0, shared_utils.CW)(managedBaseDir, external_node_path_.basename(profilePath), Number.isFinite(maxAgeHours) ? maxAgeHours : 12);
3747
3833
  } catch {}
3748
3834
  }
3749
- if (profilePath) {
3835
+ if (profilePath && provision) {
3750
3836
  try {
3751
3837
  external_node_fs_.mkdirSync(profilePath, {
3752
3838
  recursive: true
@@ -3759,7 +3845,7 @@ var __webpack_modules__ = {
3759
3845
  });
3760
3846
  } catch {}
3761
3847
  }
3762
- if (profilePath) try {
3848
+ if (profilePath && provision) try {
3763
3849
  const prefs = getPreferences(configOptions?.preferences || {});
3764
3850
  function serializeValue(value) {
3765
3851
  if ('string' == typeof value) return JSON.stringify(value);
@@ -3779,13 +3865,17 @@ var __webpack_modules__ = {
3779
3865
  ];
3780
3866
  if (binaryArgs.length > 0) parts.unshift(`--binary-args="${binaryArgs.join(' ')}"`);
3781
3867
  if (profilePath) parts.splice(1, 0, `--profile="${profilePath}"`);
3782
- return parts.join(' ');
3868
+ return {
3869
+ profilePath,
3870
+ binaryArgs,
3871
+ config: parts.join(' ')
3872
+ };
3783
3873
  }
3784
- function logFirefoxDryRun(browserBinaryLocation, firefoxConfig) {
3874
+ function logFirefoxDryRun(browserBinaryLocation, launchArgs) {
3785
3875
  if ((0, messaging._o)()) (0, messaging._w)(messages.A9());
3786
3876
  (0, messaging._w)(messages.qn());
3787
3877
  (0, messaging._w)(messages.LD(browserBinaryLocation));
3788
- (0, messaging._w)(messages.k6(firefoxConfig));
3878
+ (0, messaging._w)(messages.lO(launchArgs.join(' ')));
3789
3879
  }
3790
3880
  const activeInstances = new Set();
3791
3881
  let globalHandlersInstalled = false;
@@ -3850,6 +3940,7 @@ var __webpack_modules__ = {
3850
3940
  activeInstances.delete(instance);
3851
3941
  };
3852
3942
  }
3943
+ var newtab_override = __webpack_require__("./browsers/browsers-lib/newtab-override.ts");
3853
3944
  var constants = __webpack_require__("./browsers/browsers-lib/constants.ts");
3854
3945
  var manifest_readiness = __webpack_require__("./browsers/run-chromium/manifest-readiness.ts");
3855
3946
  function resolveAddonDirectory(baseDir, inputPath) {
@@ -4103,6 +4194,110 @@ var __webpack_modules__ = {
4103
4194
  } catch {}
4104
4195
  });
4105
4196
  }
4197
+ const MANAGER_ADDON_ID = 'devtools@extension.js';
4198
+ const OPEN_NEW_TAB_EXPRESSION = "(function () { var api = globalThis.browser || globalThis.chrome; api.tabs.create({active: true}); return true;})()";
4199
+ const TARGET_WAIT_MS = 2000;
4200
+ function reportStep(step, detail) {
4201
+ if (!(0, messaging._o)()) return;
4202
+ const reason = detail instanceof Error ? detail.message : void 0 === detail ? '' : ` ${JSON.stringify(detail).slice(0, 300)}`;
4203
+ (0, messaging.mR)(`[browser] Firefox new-tab courtesy: ${step}${reason}`);
4204
+ }
4205
+ async function findManagerAddon(client) {
4206
+ const reply = await client.request({
4207
+ to: 'root',
4208
+ type: 'listAddons'
4209
+ });
4210
+ return (reply?.addons || []).find((addon)=>addon?.id === MANAGER_ADDON_ID);
4211
+ }
4212
+ function manager_tab_unsubscribe(client, listener) {
4213
+ if ('function' == typeof client.off) client.off('message', listener);
4214
+ else client.removeListener?.('message', listener);
4215
+ }
4216
+ function isBackgroundPage(target) {
4217
+ return /_generated_background_page\.html|\/background/.test(String(target?.url || ''));
4218
+ }
4219
+ async function resolveConsoleActorViaWatcher(client, descriptorActor) {
4220
+ const watcher = await client.request({
4221
+ to: descriptorActor,
4222
+ type: 'getWatcher',
4223
+ isServerTargetSwitchingEnabled: true
4224
+ });
4225
+ const noop = ()=>{};
4226
+ if (!watcher?.actor) return {
4227
+ release: noop
4228
+ };
4229
+ const watcherActor = watcher.actor;
4230
+ const release = ()=>{
4231
+ client.request({
4232
+ to: watcherActor,
4233
+ type: 'unwatchTargets',
4234
+ targetType: 'frame'
4235
+ }).catch(()=>{});
4236
+ };
4237
+ const targets = [];
4238
+ const collect = (message)=>{
4239
+ const event = message;
4240
+ if (event?.type === 'target-available-form' && event.target) targets.push(event.target);
4241
+ };
4242
+ client.on('message', collect);
4243
+ try {
4244
+ collect(await client.request({
4245
+ to: watcherActor,
4246
+ type: 'watchTargets',
4247
+ targetType: 'frame'
4248
+ }));
4249
+ const deadline = Date.now() + TARGET_WAIT_MS;
4250
+ while(Date.now() < deadline){
4251
+ const background = targets.find((target)=>target.consoleActor && isBackgroundPage(target));
4252
+ if (background) return {
4253
+ consoleActor: background.consoleActor,
4254
+ release
4255
+ };
4256
+ await new Promise((resolve)=>setTimeout(resolve, 50));
4257
+ }
4258
+ return {
4259
+ consoleActor: targets.find((target)=>target.consoleActor)?.consoleActor,
4260
+ release
4261
+ };
4262
+ } finally{
4263
+ manager_tab_unsubscribe(client, collect);
4264
+ }
4265
+ }
4266
+ async function resolveConsoleActor(client, addon) {
4267
+ if (addon.consoleActor) return {
4268
+ consoleActor: addon.consoleActor,
4269
+ release: ()=>{}
4270
+ };
4271
+ if (!addon.actor) return {
4272
+ release: ()=>{}
4273
+ };
4274
+ return await resolveConsoleActorViaWatcher(client, addon.actor);
4275
+ }
4276
+ async function openManagerNewTab(client) {
4277
+ try {
4278
+ const addon = await findManagerAddon(client);
4279
+ if (!addon) {
4280
+ reportStep('manager add-on not listed');
4281
+ return false;
4282
+ }
4283
+ const { consoleActor, release } = await resolveConsoleActor(client, addon);
4284
+ if (!consoleActor) {
4285
+ release();
4286
+ reportStep('no console actor for the manager background page');
4287
+ return false;
4288
+ }
4289
+ try {
4290
+ const result = await client.evaluate(consoleActor, OPEN_NEW_TAB_EXPRESSION);
4291
+ reportStep('tabs.create evaluated', result);
4292
+ } finally{
4293
+ release();
4294
+ }
4295
+ return true;
4296
+ } catch (error) {
4297
+ reportStep('failed', error);
4298
+ return false;
4299
+ }
4300
+ }
4106
4301
  function requestErrorToMessage(error) {
4107
4302
  if (error instanceof Error) return String(error);
4108
4303
  try {
@@ -4291,21 +4486,33 @@ var __webpack_modules__ = {
4291
4486
  const raw = parseInt(String(process.env.EXTENSION_RDP_REQUEST_TIMEOUT_MS || ''), 10);
4292
4487
  return Number.isFinite(raw) && raw > 0 ? raw : 30000;
4293
4488
  }
4489
+ function surfaceTransportError(emitter, error) {
4490
+ if (emitter.listenerCount('error') > 0) return void emitter.emit('error', error);
4491
+ (0, messaging.Gg)(error instanceof Error ? error.message : String(error));
4492
+ }
4294
4493
  class RdpTransport extends external_node_events_default() {
4295
4494
  async connect(port, host = '127.0.0.1') {
4296
4495
  await new Promise((resolve, reject)=>{
4496
+ let connected = false;
4297
4497
  try {
4298
4498
  const c = external_node_net_default().createConnection({
4299
4499
  host,
4300
4500
  port
4301
4501
  }, ()=>{
4502
+ connected = true;
4302
4503
  if ((0, messaging._o)()) (0, messaging._w)(messages.EI(host, port));
4303
4504
  resolve();
4304
4505
  });
4305
4506
  this.conn = c;
4507
+ this.lost = false;
4306
4508
  c.on('data', this.onData.bind(this));
4307
- c.on('error', reject);
4308
- c.on('end', this.onEnd.bind(this));
4509
+ c.on('error', (err)=>{
4510
+ if (connected) return;
4511
+ this.conn = void 0;
4512
+ reject(err);
4513
+ });
4514
+ c.on('end', this.onConnectionLost.bind(this));
4515
+ c.on('close', this.onConnectionLost.bind(this));
4309
4516
  c.on('timeout', this.onTimeout.bind(this));
4310
4517
  } catch (err) {
4311
4518
  reject(err);
@@ -4313,11 +4520,15 @@ var __webpack_modules__ = {
4313
4520
  });
4314
4521
  }
4315
4522
  disconnect() {
4316
- if (!this.conn) return;
4317
- this.conn.removeAllListeners();
4318
- this.conn.end();
4319
- const err = new Error(messages.qN('firefox'));
4320
- this.rejectAll(err);
4523
+ const c = this.conn;
4524
+ if (!c) return;
4525
+ this.conn = void 0;
4526
+ this.lost = true;
4527
+ this.incoming = Buffer.alloc(0);
4528
+ c.removeAllListeners();
4529
+ c.on('error', ()=>{});
4530
+ c.end();
4531
+ this.rejectAll(new Error(messages.qN('firefox')));
4321
4532
  }
4322
4533
  rejectAll(error) {
4323
4534
  for (const entry of this.active.values()){
@@ -4389,8 +4600,8 @@ var __webpack_modules__ = {
4389
4600
  const { remainingData, parsedMessage, error, fatal } = parseRdpFrame(this.incoming);
4390
4601
  this.incoming = remainingData;
4391
4602
  if (error) {
4392
- this.emit('error', new Error(messages.l9('firefox', error)));
4393
- if (fatal) this.disconnect();
4603
+ surfaceTransportError(this, new Error(messages.l9('firefox', error)));
4604
+ if (fatal) this.onConnectionLost();
4394
4605
  return !fatal;
4395
4606
  }
4396
4607
  if (!parsedMessage) return false;
@@ -4398,10 +4609,11 @@ var __webpack_modules__ = {
4398
4609
  return true;
4399
4610
  }
4400
4611
  handleMessage(message) {
4401
- if (!message.from) return void this.emit('error', new Error(messages.HH('firefox', message)));
4402
- const entry = this.active.get(message.from);
4612
+ const from = message.from;
4613
+ if (!from) return void surfaceTransportError(this, new Error(messages.HH('firefox', message)));
4614
+ const entry = this.active.get(from);
4403
4615
  if (entry) {
4404
- this.active.delete(message.from);
4616
+ this.active.delete(from);
4405
4617
  if (entry.timer) clearTimeout(entry.timer);
4406
4618
  if (message.error) entry.deferred.reject(message);
4407
4619
  else entry.deferred.resolve(message);
@@ -4410,7 +4622,17 @@ var __webpack_modules__ = {
4410
4622
  }
4411
4623
  this.emit('message', message);
4412
4624
  }
4413
- onEnd() {
4625
+ onConnectionLost() {
4626
+ if (this.lost) return;
4627
+ this.lost = true;
4628
+ const c = this.conn;
4629
+ this.conn = void 0;
4630
+ this.incoming = Buffer.alloc(0);
4631
+ if (c) {
4632
+ c.removeAllListeners();
4633
+ c.on('error', ()=>{});
4634
+ c.destroy();
4635
+ }
4414
4636
  this.rejectAll(new Error(messages.qN('firefox')));
4415
4637
  this.emit('end');
4416
4638
  }
@@ -4418,7 +4640,7 @@ var __webpack_modules__ = {
4418
4640
  this.emit('timeout');
4419
4641
  }
4420
4642
  constructor(...args){
4421
- super(...args), _define_property(this, "conn", void 0), _define_property(this, "incoming", Buffer.alloc(0)), _define_property(this, "active", new Map()), _define_property(this, "pending", []);
4643
+ super(...args), _define_property(this, "conn", void 0), _define_property(this, "incoming", Buffer.alloc(0)), _define_property(this, "active", new Map()), _define_property(this, "pending", []), _define_property(this, "lost", false);
4422
4644
  }
4423
4645
  }
4424
4646
  function messaging_client_define_property(obj, key, value) {
@@ -4431,15 +4653,20 @@ var __webpack_modules__ = {
4431
4653
  else obj[key] = value;
4432
4654
  return obj;
4433
4655
  }
4656
+ const RECONNECT_MAX_ATTEMPTS = 5;
4657
+ const RECONNECT_RETRY_DELAY_MS = 1000;
4434
4658
  class MessagingClient extends external_node_events_default() {
4435
4659
  async connect(port) {
4436
- this.lastPort = port;
4437
4660
  this.disconnectedByUser = false;
4661
+ await this.openTransport(port);
4662
+ }
4663
+ async openTransport(port) {
4664
+ this.lastPort = port;
4438
4665
  await this.transport.connect(port);
4439
4666
  if (!this.forwardingSetup) {
4440
4667
  this.forwardingSetup = true;
4441
4668
  this.transport.on('message', (message)=>this.emit('message', message));
4442
- this.transport.on('error', (error)=>this.emit('error', error));
4669
+ this.transport.on('error', (error)=>surfaceTransportError(this, error));
4443
4670
  this.transport.on('end', ()=>{
4444
4671
  this.emit('end');
4445
4672
  this.attemptReconnect();
@@ -4454,20 +4681,21 @@ var __webpack_modules__ = {
4454
4681
  async attemptReconnect() {
4455
4682
  if (this.disconnectedByUser || this.reconnecting || !this.lastPort) return;
4456
4683
  this.reconnecting = true;
4457
- const maxAttempts = 5;
4458
- const retryDelay = 1000;
4459
- for(let i = 0; i < maxAttempts; i++){
4460
- await new Promise((r)=>setTimeout(r, retryDelay));
4461
- try {
4462
- this.transport = new RdpTransport();
4463
- this.forwardingSetup = false;
4464
- await this.connect(this.lastPort);
4465
- this.reconnecting = false;
4466
- this.emit('reconnected');
4467
- return;
4468
- } catch {}
4684
+ try {
4685
+ for(let i = 0; i < RECONNECT_MAX_ATTEMPTS; i++){
4686
+ await new Promise((r)=>setTimeout(r, RECONNECT_RETRY_DELAY_MS));
4687
+ if (this.disconnectedByUser) return;
4688
+ try {
4689
+ this.transport = new RdpTransport();
4690
+ this.forwardingSetup = false;
4691
+ await this.openTransport(this.lastPort);
4692
+ this.emit('reconnected');
4693
+ return;
4694
+ } catch {}
4695
+ }
4696
+ } finally{
4697
+ this.reconnecting = false;
4469
4698
  }
4470
- this.reconnecting = false;
4471
4699
  }
4472
4700
  async request(requestProps) {
4473
4701
  if ('string' == typeof requestProps) return await this.transport.request({
@@ -4656,6 +4884,10 @@ var __webpack_modules__ = {
4656
4884
  });
4657
4885
  if (!bannerPrinted) throw new Error(messages.WV(this.options.browser, 'Failed to print runningInDevelopment banner; add-on may not be installed.'));
4658
4886
  }
4887
+ async openNewTab() {
4888
+ if (!this.client) return false;
4889
+ return await openManagerNewTab(this.client);
4890
+ }
4659
4891
  async enableUnifiedLogging(opts) {
4660
4892
  try {
4661
4893
  if (this.loggingAttached) return;
@@ -4709,6 +4941,9 @@ var __webpack_modules__ = {
4709
4941
  getAddonInstallRefusalReason() {
4710
4942
  return this.remote.getAddonInstallRefusalReason();
4711
4943
  }
4944
+ async openNewTab() {
4945
+ return await this.remote.openNewTab();
4946
+ }
4712
4947
  getExtensionId() {
4713
4948
  return this.remote.getDerivedExtensionId();
4714
4949
  }
@@ -4771,6 +5006,14 @@ var __webpack_modules__ = {
4771
5006
  } catch (error) {
4772
5007
  throw withRefusalReason(error);
4773
5008
  }
5009
+ try {
5010
+ const outPath = String(compilation?.options?.output?.path || '');
5011
+ if (!plugin.startingUrl && !plugin.noOpen && (0, newtab_override.c)(outPath)) {
5012
+ const live = plugin.rdpController || controller;
5013
+ const opened = await live.openNewTab?.();
5014
+ if (!opened && (0, messaging._o)()) (0, messaging.mR)('[browser] Firefox: could not open the new-tab override page.');
5015
+ }
5016
+ } catch {}
4774
5017
  return controller;
4775
5018
  }
4776
5019
  var external_node_child_process_ = __webpack_require__("node:child_process");
@@ -4853,7 +5096,7 @@ var __webpack_modules__ = {
4853
5096
  debug: (...a)=>console?.debug?.(...a)
4854
5097
  };
4855
5098
  await this.launch(compilation, options);
4856
- if ('development' === options.mode && !this.host.extensionLoadRefused) this.ctx.logger?.info?.((0, ready_message.G)(options.mode, this.host.browser));
5099
+ if (options?.mode === 'development' && !this.host.extensionLoadRefused) this.ctx.logger?.info?.((0, ready_message.G)(options.mode, this.host.browser));
4857
5100
  this.ctx.didLaunch = true;
4858
5101
  }
4859
5102
  apply(compiler) {
@@ -4918,12 +5161,10 @@ var __webpack_modules__ = {
4918
5161
  if (process.env.VITEST || process.env.VITEST_WORKER_ID) throw new Error('Firefox not installed or binary path not found');
4919
5162
  process.exit(1);
4920
5163
  };
4921
- if (this.host.dryRun || process.env.VITEST || process.env.VITEST_WORKER_ID) {
4922
- try {
4923
- logFirefoxDryRun('firefox-mock-binary', '--binary-args=""');
4924
- } catch {}
4925
- return;
4926
- }
5164
+ const inTestRunner = Boolean(process.env.VITEST || process.env.VITEST_WORKER_ID);
5165
+ const dryRun = Boolean(this.host.dryRun);
5166
+ if (inTestRunner && !dryRun) return void logFirefoxDryRun('firefox-mock-binary', []);
5167
+ if (inTestRunner && dryRun && !this.host.geckoBinary) return void await this.printDryRunPlan(compilation, options, 'firefox-mock-binary');
4927
5168
  let browserBinaryLocation = resolveManagedBinary();
4928
5169
  let skipDetection = Boolean(browserBinaryLocation);
4929
5170
  const engineBased = 'gecko-based' === this.host.browser || 'firefox-based' === this.host.browser;
@@ -5017,25 +5258,25 @@ var __webpack_modules__ = {
5017
5258
  rdpPort: debugPort
5018
5259
  });
5019
5260
  const effectiveInstanceId = this.host.instanceId;
5020
- let firefoxCfg;
5021
- firefoxCfg = await browserConfig(compilation, {
5261
+ const launchConfig = await resolveFirefoxLaunchConfig(compilation, {
5022
5262
  ...options,
5023
5263
  profile: this.host.profile,
5024
5264
  preferences: this.host.preferences || {},
5025
5265
  instanceId: effectiveInstanceId
5266
+ }, {
5267
+ provision: !dryRun
5268
+ });
5269
+ const { profilePath, binaryArgs: firefoxArgs } = launchConfig;
5270
+ const plan = FirefoxBinaryDetector.launchPlan({
5271
+ binaryPath,
5272
+ profilePath,
5273
+ debugPort,
5274
+ binaryArgs: firefoxArgs,
5275
+ headless: isFirefoxHeadlessRequested()
5026
5276
  });
5027
- if (this.host.dryRun) return void logFirefoxDryRun(binaryPath, firefoxCfg);
5028
- const firefoxArgs = [];
5029
- const binaryArgsMatch = firefoxCfg.match(/--binary-args="([^"]*)"/);
5030
- if (binaryArgsMatch) {
5031
- const rawArgs = String(binaryArgsMatch[1] || '').trim();
5032
- if (rawArgs) firefoxArgs.push(...rawArgs.split(' ').filter((arg)=>arg.trim().length > 0));
5033
- if ((0, messaging._o)()) this.ctx.logger?.info?.(messages.iv(binaryArgsMatch[1]));
5034
- } else if ((0, messaging._o)()) this.ctx.logger?.info?.(messages.dN());
5035
- const profileMatch = firefoxCfg.match(/--profile="([^"]*)"/);
5036
- if (profileMatch) {
5037
- const profilePath = profileMatch[1];
5038
- const { binary, args } = FirefoxBinaryDetector.generateFirefoxArgs(binaryPath, profilePath, debugPort, firefoxArgs, isFirefoxHeadlessRequested());
5277
+ if (dryRun) return void logFirefoxDryRun(plan.binary, plan.args);
5278
+ if (profilePath) {
5279
+ const { binary, args } = plan;
5039
5280
  this.host.launchProfilePath = profilePath;
5040
5281
  this.child = await this.spawnFirefoxChild(binary, args, wslFallbackBinary);
5041
5282
  (0, ready_stamp.M)(this.extensionOutputPath, {
@@ -5075,23 +5316,7 @@ var __webpack_modules__ = {
5075
5316
  } catch {}
5076
5317
  } else {
5077
5318
  if ((0, messaging._o)()) this.ctx.logger?.warn?.('[browser] Firefox profile not set; skipping RDP add-on install.');
5078
- const args = [
5079
- ...isFirefoxHeadlessRequested() ? [
5080
- '-headless'
5081
- ] : [],
5082
- ...debugPort > 0 ? [
5083
- '-start-debugger-server',
5084
- String(debugPort)
5085
- ] : [],
5086
- ...'win32' === process.platform ? [
5087
- '-wait-for-browser'
5088
- ] : [],
5089
- ...isFirefoxHeadlessRequested() ? [] : [
5090
- '--foreground'
5091
- ],
5092
- ...firefoxArgs
5093
- ];
5094
- this.child = await this.spawnFirefoxChild(binaryPath, args, wslFallbackBinary);
5319
+ this.child = await this.spawnFirefoxChild(plan.binary, plan.args, wslFallbackBinary);
5095
5320
  (0, ready_stamp.M)(this.extensionOutputPath, {
5096
5321
  browserPid: this.child?.pid,
5097
5322
  extensionId: this.extensionOutputPath ? (0, banner.MT)(this.extensionOutputPath) : void 0
@@ -5101,6 +5326,24 @@ var __webpack_modules__ = {
5101
5326
  this.scheduleWatchTimeout();
5102
5327
  }
5103
5328
  }
5329
+ async printDryRunPlan(compilation, options, binaryPath) {
5330
+ const launchConfig = await resolveFirefoxLaunchConfig(compilation, {
5331
+ ...options,
5332
+ profile: this.host.profile,
5333
+ preferences: this.host.preferences || {},
5334
+ instanceId: this.host.instanceId
5335
+ }, {
5336
+ provision: false
5337
+ });
5338
+ const plan = FirefoxBinaryDetector.launchPlan({
5339
+ binaryPath,
5340
+ profilePath: launchConfig.profilePath,
5341
+ debugPort: (0, shared_utils.jl)(this.host.port, this.host.instanceId),
5342
+ binaryArgs: launchConfig.binaryArgs,
5343
+ headless: isFirefoxHeadlessRequested()
5344
+ });
5345
+ logFirefoxDryRun(plan.binary, plan.args);
5346
+ }
5104
5347
  resolveSpawnStdio() {
5105
5348
  if ('win32' !== process.platform) return [
5106
5349
  'pipe',
@@ -5314,6 +5557,7 @@ var __webpack_modules__ = {
5314
5557
  preferences: pluginOptions.preferences,
5315
5558
  browserFlags: pluginOptions.browserFlags,
5316
5559
  startingUrl: pluginOptions.startingUrl,
5560
+ noOpen: pluginOptions.noOpen,
5317
5561
  geckoBinary: pluginOptions.geckoBinary,
5318
5562
  instanceId: pluginOptions.instanceId,
5319
5563
  port: pluginOptions.port,