extension 4.1.35 → 4.1.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -120,7 +120,7 @@ Useful flags:
120
120
  - `--zip` packages the build into a ZIP ready for store upload
121
121
  - `--zip-source` includes source files for store source-code review
122
122
  - `--zip-filename <name>` controls the output filename, written as `dist/<name>-<browser>.zip`
123
- - `--out-dir <path>` writes the build to `<path>/<browser>` instead of `dist/<browser>`, so a build can run beside a dev session
123
+ - `--out-dir <path>` writes the build to `<path>/<browser>` instead of `dist/<browser>`. A build into the folder a live dev session serves is refused, so this is how a build runs beside a dev session
124
124
  - `--polyfill` enables the cross-browser webextension polyfill
125
125
 
126
126
  ## Manage browser binaries
package/dist/browsers.cjs CHANGED
@@ -364,7 +364,8 @@ var __webpack_modules__ = {
364
364
  function stageCompanionForSession(input) {
365
365
  const { extensionPaths } = input;
366
366
  const cdpOnly = (0, _browser_family__rspack_import_3.v$)(input.browser || '');
367
- if (!input.noOpen && !cdpOnly || !input.stageRoot) return extensionPaths;
367
+ const plain = !input.noOpen && !input.startingUrl && !cdpOnly;
368
+ if (plain || !input.stageRoot) return extensionPaths;
368
369
  const index = extensionPaths.findIndex((p)=>isDevtoolsCompanionPath(p));
369
370
  if (-1 === index) return extensionPaths;
370
371
  const source = extensionPaths[index];
@@ -379,7 +380,8 @@ var __webpack_modules__ = {
379
380
  recursive: true
380
381
  });
381
382
  const flags = {
382
- noOpen: Boolean(input.noOpen)
383
+ noOpen: Boolean(input.noOpen),
384
+ startingUrl: Boolean(input.startingUrl)
383
385
  };
384
386
  node_fs__rspack_import_0.writeFileSync(node_path__rspack_import_1.join(staged, COMPANION_SESSION_FLAGS_FILE), `${JSON.stringify(flags)}\n`, 'utf8');
385
387
  if (cdpOnly) dropNewTabOverride(staged);
@@ -809,6 +811,13 @@ var __webpack_modules__ = {
809
811
  function browserGoneBeforeReady(browser) {
810
812
  return `${getLoggingPrefix('error')} ${capitalizedBrowserName(browser)} exited before the extension loaded, so nothing is running.\nThe dev server keeps watching, but nothing will load until the browser is relaunched. Restart "extension dev".`;
811
813
  }
814
+ function browserUpNotAttached(opts) {
815
+ const name = capitalizedBrowserName(opts.browser);
816
+ const pid = opts.browserPid ? ` (pid ${opts.browserPid})` : '';
817
+ const seconds = Math.round(opts.waitedMs / 1000);
818
+ const profile = opts.profilePath ? opts.profileReused ? `Profile ${pintor__rspack_import_8_default().underline(opts.profilePath)} had been run before: a profile picker, a restore prompt or a stale copy of the extension in it can keep the extension from connecting.` : `Profile ${pintor__rspack_import_8_default().underline(opts.profilePath)} is fresh, so look at the browser window for a dialog or an extensions page error.` : "Look at the browser window for a dialog or an extensions page error.";
819
+ return `${getLoggingPrefix('warn')} ${name}${pid} is up, but the extension has not connected after ${seconds} s.\n${profile}\nDismiss any dialog there, or stop this session and run again on a fresh profile (delete that folder, or pass ${pintor__rspack_import_8_default().yellow('--profile <new path>')}). The session keeps waiting and says "ready" once the extension connects.`;
820
+ }
812
821
  function chromeProcessError(error) {
813
822
  return `${getLoggingPrefix('error')} The Chrome process reported an error.\n${pintor__rspack_import_8_default().red(errorDetail(error))}`;
814
823
  }
@@ -929,10 +938,24 @@ var __webpack_modules__ = {
929
938
  function safariOpening(target) {
930
939
  return `${getLoggingPrefix('info')} Opening ${pintor__rspack_import_8_default().underline(target)}`;
931
940
  }
932
- function safariToolFailed(tool, exitCode, outputTail) {
941
+ function safariToolFailed(tool, exitCode, outputTail, cause) {
933
942
  const code = null === exitCode ? 'no exit code' : `exit ${exitCode}`;
934
943
  const tail = outputTail.trim().length ? `\n${pintor__rspack_import_8_default().gray('── last output ──')}\n${outputTail}` : `\n${pintor__rspack_import_8_default().gray('(no output captured)')}`;
935
- return `${getLoggingPrefix('error')} Safari packaging tool ${pintor__rspack_import_8_default().underline(tool)} failed (${pintor__rspack_import_8_default().red(code)}).${tail}`;
944
+ return `${getLoggingPrefix('error')} Safari packaging tool ${pintor__rspack_import_8_default().underline(tool)} failed (${pintor__rspack_import_8_default().red(code)}).${cause ? `\n${cause}` : ''}${tail}`;
945
+ }
946
+ function safariKnownTeamsList(teams) {
947
+ return teams.map((team)=>team.name ? `${pintor__rspack_import_8_default().yellow(team.id)} (${team.name})` : pintor__rspack_import_8_default().yellow(team.id)).join(', ');
948
+ }
949
+ function safariTeamRemedyLines(team, knownTeams = []) {
950
+ const known = knownTeams.length ? `Set ${pintor__rspack_import_8_default().blue('developmentTeam')} to a team Xcode knows: ${safariKnownTeamsList(knownTeams)}.` : `Set ${pintor__rspack_import_8_default().blue('developmentTeam')} to a team Xcode is signed into.`;
951
+ return [
952
+ `Sign in to Xcode (Settings, Accounts) with the Apple ID that owns team ${pintor__rspack_import_8_default().yellow(team)}.`,
953
+ known,
954
+ `Drop ${pintor__rspack_import_8_default().blue('developmentTeam')} for an ad-hoc build.`
955
+ ];
956
+ }
957
+ function safariNoAccountForTeam(team, knownTeams = []) {
958
+ return `Xcode has no account for team ${pintor__rspack_import_8_default().yellow(team)}, so it couldn't sign the app with it.\n` + safariTeamRemedyLines(team, knownTeams).map((line)=>`- ${line}`).join('\n');
936
959
  }
937
960
  const SAFARI_KEPT_ON_PURPOSE = {
938
961
  world: 'Safari has honored the MAIN world since Safari 18, so the key stays'
@@ -957,14 +980,26 @@ var __webpack_modules__ = {
957
980
  function safariDryRunXcodebuild(cmd) {
958
981
  return `${getLoggingPrefix('info')} xcodebuild: ${pintor__rspack_import_8_default().gray(cmd)}.`;
959
982
  }
960
- function safariNextSteps(appName, signed) {
983
+ const SAFARI_AD_HOC_LOADING = 'Safari runs an ad-hoc build only while unsigned extensions are allowed, and Safari turns that off at quit';
984
+ const SAFARI_TEAM_SIGNED_LOADING = 'A team-signed build needs no toggle, and the Apple Development certificate of an Xcode account signed in on this Mac is enough for local runs, no Developer ID needed';
985
+ function safariNextSteps(appName, signed, signing = {}) {
961
986
  const name = pintor__rspack_import_8_default().yellow(appName);
962
- const unsignedStep = signed ? '' : ` ${pintor__rspack_import_8_default().gray('1.')} Safari ▸ Settings ▸ Developer ▸ Allow unsigned extensions (Safari forgets it on quit)\n`;
987
+ const unsignedStep = signed ? '' : ` ${pintor__rspack_import_8_default().gray('1.')} Safari ▸ Settings ▸ Developer ▸ Allow unsigned extensions (Safari turns it off at quit, so turn it on after each relaunch)\n`;
963
988
  const enableStep = ` ${pintor__rspack_import_8_default().gray(signed ? '1.' : '2.')} Safari ▸ Settings ▸ Extensions ▸ turn on ${name}\n`;
964
989
  const websitesStep = ` ${pintor__rspack_import_8_default().gray(signed ? '2.' : '3.')} Safari ▸ Settings ▸ Websites ▸ ${name} ▸ For other websites ▸ Allow\n`;
965
990
  const steps = `${getLoggingPrefix('info')} One-time setup to load ${name} in Safari, or pass ${pintor__rspack_import_8_default().blue('--enable-extension')} to let Extension.js do it:\n` + unsignedStep + enableStep + websitesStep + ` ${pintor__rspack_import_8_default().gray('→')} Use a regular Safari window for this, a trip to Settings from the automation window ends the WebDriver session.\n`;
966
- if (signed) return steps + ` ${pintor__rspack_import_8_default().gray('→')} Signed with your team id, so the identity is stable for distribution.`;
967
- return steps + ` ${pintor__rspack_import_8_default().gray('→')} Ad-hoc signed, so Safari lists it only while unsigned extensions are allowed.`;
991
+ if (signed) {
992
+ const team = signing.team ? `team ${pintor__rspack_import_8_default().yellow(signing.team)}` : 'your team id';
993
+ return steps + ` ${pintor__rspack_import_8_default().gray('→')} Signed with ${team}, so Safari loads it with no developer toggle and the identity is stable for distribution.`;
994
+ }
995
+ const adHoc = ` ${pintor__rspack_import_8_default().gray('→')} Ad-hoc signed. ${SAFARI_AD_HOC_LOADING}. With the toggle off after a relaunch, the toolbar button stays but does nothing.\n ${pintor__rspack_import_8_default().gray('→')} Pass ${pintor__rspack_import_8_default().blue('--development-team')} to sign with your team. ${SAFARI_TEAM_SIGNED_LOADING}.\n ${pintor__rspack_import_8_default().gray('→')} Safari keys stored data on the appex id, so ${pintor__rspack_import_8_default().yellow('storage.local')} survives rebuilds.`;
996
+ const requested = String(signing.requestedTeam || '').trim();
997
+ if (!requested) return steps + adHoc;
998
+ const why = signing.noAccount ? 'Xcode has no account for that team' : 'Xcode did not sign with it';
999
+ return steps + ` ${pintor__rspack_import_8_default().gray('→')} Ad-hoc signed although ${pintor__rspack_import_8_default().blue('developmentTeam')} ${pintor__rspack_import_8_default().yellow(requested)} was set: ${why}.\n` + safariTeamRemedyLines(requested, signing.knownTeams).map((line)=>` ${pintor__rspack_import_8_default().gray('→')} ${line}`).join('\n');
1000
+ }
1001
+ function safariSigningChanged(appName, before, after) {
1002
+ return `${getLoggingPrefix('info')} ${pintor__rspack_import_8_default().yellow(appName)} is now ${after} signed and the last build was ${before} signed, so Safari treats it as a new extension and the setup steps run again.`;
968
1003
  }
969
1004
  function safariEnableStep(step, before, after, detail) {
970
1005
  const reading = null === before ? `${pintor__rspack_import_8_default().gray('read back')} ${pintor__rspack_import_8_default().yellow(after ?? 'nothing')}` : `${pintor__rspack_import_8_default().gray('read')} ${pintor__rspack_import_8_default().yellow(before)} ${pintor__rspack_import_8_default().gray('→')} ${pintor__rspack_import_8_default().yellow(after ?? 'nothing')}`;
@@ -1012,9 +1047,6 @@ var __webpack_modules__ = {
1012
1047
  function safariBuildUpToDate() {
1013
1048
  return `${getLoggingPrefix('info')} Skipping xcodebuild, the Safari app is up to date with the build.`;
1014
1049
  }
1015
- function safariStorageReset(appName) {
1016
- return `${getLoggingPrefix('warn')} Safari reset the extension's storage: ${pintor__rspack_import_8_default().yellow(appName)} is signed ad hoc, and Safari keeps an extension's storage only for a build signed by a team, so each rebuild starts with an empty ${pintor__rspack_import_8_default().yellow('storage.local')}.\nPass ${pintor__rspack_import_8_default().blue('--development-team <TEAM_ID>')} to keep it across rebuilds.`;
1017
- }
1018
1050
  function safariSkippingConversion() {
1019
1051
  return `${getLoggingPrefix('info')} Skipping the conversion, the Xcode project is up to date with manifest.json.`;
1020
1052
  }
@@ -1205,6 +1237,7 @@ var __webpack_modules__ = {
1205
1237
  Cd: ()=>safariEnabled,
1206
1238
  Cn: ()=>chromeProcessError,
1207
1239
  Cs: ()=>safariToolchainMissing,
1240
+ D$: ()=>safariNoAccountForTeam,
1208
1241
  Dh: ()=>invalidGeckoBinaryPath,
1209
1242
  E8: ()=>chromiumDryRunFlags,
1210
1243
  EE: ()=>geckoAddonLoadRefused,
@@ -1228,6 +1261,7 @@ var __webpack_modules__ = {
1228
1261
  KP: ()=>safariBuildCalled,
1229
1262
  L: ()=>chromiumManifestLoadBlockers,
1230
1263
  LD: ()=>firefoxDryRunBinary,
1264
+ LE: ()=>browserUpNotAttached,
1231
1265
  LT: ()=>browserStderrTail,
1232
1266
  M3: ()=>cdpClientConnected,
1233
1267
  M6: ()=>chromiumExtensionLoadRefused,
@@ -1275,11 +1309,11 @@ var __webpack_modules__ = {
1275
1309
  dw: ()=>devFirefoxProfilePath,
1276
1310
  eK: ()=>copyFromProfileSourceMissing,
1277
1311
  e_: ()=>runningInDevelopment,
1312
+ ei: ()=>safariSigningChanged,
1278
1313
  fL: ()=>safariDryRunConverter,
1279
1314
  fO: ()=>safariNextSteps,
1280
1315
  fR: ()=>cdpClientConnectionError,
1281
1316
  fd: ()=>safariRegistered,
1282
- fl: ()=>safariStorageReset,
1283
1317
  fw: ()=>safariOpening,
1284
1318
  gE: ()=>firefoxProfileRemoteDebuggingOn,
1285
1319
  gX: ()=>firstRunInstallFailed,
@@ -1800,10 +1834,12 @@ var __webpack_modules__ = {
1800
1834
  Jk: ()=>claimReadyPath,
1801
1835
  dT: ()=>describeLaunchFailure,
1802
1836
  NE: ()=>launchFailureCode,
1837
+ Lb: ()=>readReadyExecutorAttached,
1803
1838
  Uf: ()=>readReadyRunId,
1804
1839
  Wi: ()=>stampReadyBrowserExited,
1805
1840
  M: ()=>stampReadyBrowserLaunch,
1806
1841
  dz: ()=>stampReadyBrowserLaunchFailed,
1842
+ xG: ()=>stampReadyBrowserUpNotAttached,
1807
1843
  QP: ()=>stampReadyCdpFault,
1808
1844
  HI: ()=>stampReadyCdpPort,
1809
1845
  hg: ()=>stampReadyExtensionId,
@@ -1909,6 +1945,7 @@ var __webpack_modules__ = {
1909
1945
  if (isForeignRun(ready, runId)) return;
1910
1946
  const profilePath = String(details?.profilePath || '').trim();
1911
1947
  if (profilePath) ready.profilePath = profilePath;
1948
+ if ('boolean' == typeof details?.profileReused) ready.profileReused = details.profileReused;
1912
1949
  if ('number' == typeof details?.browserPid && Number.isFinite(details.browserPid)) ready.browserPid = details.browserPid;
1913
1950
  if ('number' == typeof details?.launcherPid && Number.isFinite(details.launcherPid)) ready.launcherPid = details.launcherPid;
1914
1951
  const extensionId = String(details?.extensionId || '').trim();
@@ -1932,6 +1969,31 @@ var __webpack_modules__ = {
1932
1969
  writeJsonAtomic(readyPath, ready);
1933
1970
  } catch {}
1934
1971
  }
1972
+ function readReadyExecutorAttached(extensionOutputPath, runId) {
1973
+ try {
1974
+ if (!extensionOutputPath) return false;
1975
+ const readyPath = readyPathFor(extensionOutputPath);
1976
+ if (!external_node_fs_.existsSync(readyPath)) return false;
1977
+ const ready = JSON.parse(external_node_fs_.readFileSync(readyPath, 'utf-8'));
1978
+ if (isForeignRun(ready, runId)) return false;
1979
+ return 'string' == typeof ready.executorAttachedAt || 'attached' === ready.runtime;
1980
+ } catch {
1981
+ return false;
1982
+ }
1983
+ }
1984
+ function stampReadyBrowserUpNotAttached(extensionOutputPath, details, runId) {
1985
+ try {
1986
+ if (!extensionOutputPath) return;
1987
+ const readyPath = readyPathFor(extensionOutputPath);
1988
+ if (!external_node_fs_.existsSync(readyPath)) return;
1989
+ const ready = JSON.parse(external_node_fs_.readFileSync(readyPath, 'utf-8'));
1990
+ if (isForeignRun(ready, runId)) return;
1991
+ ready.browserUpNotAttachedAt = new Date().toISOString();
1992
+ ready.browserUpNotAttachedWaitMs = details.waitedMs;
1993
+ ready.browserUpNotAttachedHint = String(details.hint || '').trim() || 'the browser is up, but the extension has not connected';
1994
+ writeJsonAtomic(readyPath, ready);
1995
+ } catch {}
1996
+ }
1935
1997
  function describeLaunchFailure(error) {
1936
1998
  const message = error instanceof Error ? error.message : 'string' == typeof error ? error : String(error?.message ?? error ?? '');
1937
1999
  return (0, messaging.UT)(message).replace(/\s+/g, ' ').trim();
@@ -3744,7 +3806,6 @@ var __webpack_modules__ = {
3744
3806
  '--disable-features=InterestFeedContentSuggestions',
3745
3807
  '--disable-features=Translate',
3746
3808
  '--hide-scrollbars',
3747
- '--mute-audio',
3748
3809
  '--no-default-browser-check',
3749
3810
  '--ash-no-nudges',
3750
3811
  '--disable-search-engine-choice-screen',
@@ -3762,6 +3823,48 @@ var __webpack_modules__ = {
3762
3823
  '--enable-unsafe-extension-debugging',
3763
3824
  '--silent-debugger-extension-api'
3764
3825
  ];
3826
+ const HEADLESS_ONLY_BROWSER_FLAGS = [
3827
+ '--mute-audio'
3828
+ ];
3829
+ const AUTOMATION_CONTROLLED = 'AutomationControlled';
3830
+ const DISABLE_BLINK_FEATURES = '--disable-blink-features=';
3831
+ function asksForAutomation(flags) {
3832
+ return flags.some((flag)=>'--enable-automation' === flag || flag.startsWith('--enable-blink-features=') && flag.slice(24).split(',').some((name)=>name.trim() === AUTOMATION_CONTROLLED));
3833
+ }
3834
+ function withBlinkFeatureDisabled(flags, feature) {
3835
+ const values = [];
3836
+ let at = -1;
3837
+ const rest = [];
3838
+ for (const flag of flags){
3839
+ if (!flag.startsWith(DISABLE_BLINK_FEATURES)) {
3840
+ rest.push(flag);
3841
+ continue;
3842
+ }
3843
+ if (at < 0) at = rest.length;
3844
+ for (const value of flag.slice(DISABLE_BLINK_FEATURES.length).split(',')){
3845
+ const trimmed = value.trim();
3846
+ if (trimmed && !values.includes(trimmed)) values.push(trimmed);
3847
+ }
3848
+ }
3849
+ if (!values.includes(feature)) values.push(feature);
3850
+ rest.splice(at < 0 ? rest.length : at, 0, DISABLE_BLINK_FEATURES + values.join(','));
3851
+ return rest;
3852
+ }
3853
+ function applyLaunchModeFlags(flags, excludeFlags = []) {
3854
+ if ((0, shared_utils.P1)(flags)) {
3855
+ const muted = (0, shared_utils.ov)(HEADLESS_ONLY_BROWSER_FLAGS, excludeFlags);
3856
+ return [
3857
+ ...flags,
3858
+ ...muted.filter((flag)=>!flags.includes(flag))
3859
+ ];
3860
+ }
3861
+ if (asksForAutomation(flags)) return flags;
3862
+ const clearWebdriver = `${DISABLE_BLINK_FEATURES}${AUTOMATION_CONTROLLED}`;
3863
+ if (!(0, shared_utils.ov)([
3864
+ clearWebdriver
3865
+ ], excludeFlags).length) return flags;
3866
+ return withBlinkFeatureDisabled(flags, AUTOMATION_CONTROLLED);
3867
+ }
3765
3868
  function isPlainObject(value) {
3766
3869
  return !!value && 'object' == typeof value && !Array.isArray(value);
3767
3870
  }
@@ -3914,7 +4017,7 @@ var __webpack_modules__ = {
3914
4017
  ...(0, shared_utils.W0)(process.env.EXTENSION_BROWSER_FLAGS)
3915
4018
  ];
3916
4019
  if ((0, shared_utils.ZO)() && !baseFlags.some((flag)=>flag.startsWith('--headless'))) baseFlags.push('--headless=new');
3917
- return (0, shared_utils.Py)(baseFlags);
4020
+ return (0, shared_utils.Py)(applyLaunchModeFlags(baseFlags, excludeFlags));
3918
4021
  }
3919
4022
  function logChromiumDryRun(browser, browserBinaryLocation, chromiumConfig) {
3920
4023
  if ((0, messaging._o)()) (0, messaging._w)(messages.xy(browser));
@@ -4173,6 +4276,24 @@ var __webpack_modules__ = {
4173
4276
  });
4174
4277
  }
4175
4278
  const STDERR_TAIL_LINES = 8;
4279
+ const ATTACH_GRACE_MS = 15000;
4280
+ const ATTACH_POLL_MS = 250;
4281
+ function profileWasRunBefore(profilePath) {
4282
+ if (!profilePath) return false;
4283
+ try {
4284
+ return external_node_fs_.existsSync(external_node_path_.join(profilePath, 'Local State'));
4285
+ } catch {
4286
+ return false;
4287
+ }
4288
+ }
4289
+ function hostsNoDevRuntime(extensionOutputPath) {
4290
+ try {
4291
+ const manifest = JSON.parse(external_node_fs_.readFileSync(external_node_path_.join(extensionOutputPath, 'manifest.json'), 'utf-8'));
4292
+ return Boolean(manifest.theme) && !manifest.background;
4293
+ } catch {
4294
+ return false;
4295
+ }
4296
+ }
4176
4297
  class ChromiumLaunchPlugin {
4177
4298
  getExtensionLoadRefusal() {
4178
4299
  return this.extensionLoadRefused || null;
@@ -4225,7 +4346,7 @@ var __webpack_modules__ = {
4225
4346
  if (hasErrors) return void this.logger.info(messages.y7());
4226
4347
  await this.launchChromium(stats.compilation);
4227
4348
  this.didLaunch = true;
4228
- if (!this.didReportReady && !this.extensionLoadRefused && !this.browserGone) (0, messaging._w)((0, ready_message.G)(stats.compilation.options.mode, this.options.browser));
4349
+ if (!this.didReportReady && !this.readyDeferred && !this.extensionLoadRefused && !this.browserGone) (0, messaging._w)((0, ready_message.G)(stats.compilation.options.mode, this.options.browser));
4229
4350
  } catch (error) {
4230
4351
  this.stampLaunchFailed(stats.compilation, error);
4231
4352
  try {
@@ -4629,8 +4750,11 @@ var __webpack_modules__ = {
4629
4750
  const child = await this.launchWithDirectSpawn(browserBinaryLocation, chromiumConfig, usePipe);
4630
4751
  this.didSpawn = true;
4631
4752
  const launchOutputPath = this.closeHandlerContext?.extensionOutputPath;
4753
+ const launchProfilePath = chromiumConfig.find((flag)=>flag.startsWith('--user-data-dir='))?.slice('--user-data-dir='.length).replace(/^"|"$/g, '');
4754
+ this.profileReused = profileWasRunBefore(launchProfilePath);
4632
4755
  (0, ready_stamp.M)(launchOutputPath, {
4633
- profilePath: chromiumConfig.find((flag)=>flag.startsWith('--user-data-dir='))?.slice('--user-data-dir='.length).replace(/^"|"$/g, ''),
4756
+ profilePath: launchProfilePath,
4757
+ profileReused: this.profileReused,
4634
4758
  browserPid: child?.pid,
4635
4759
  binary: browserBinaryLocation ?? void 0,
4636
4760
  binaryProvenance,
@@ -4696,7 +4820,13 @@ var __webpack_modules__ = {
4696
4820
  if (cdpConfig.extensionLoadRefused) this.extensionLoadRefused = cdpConfig.extensionLoadRefused;
4697
4821
  if (cdpConfig.cdpController) this.ctx.setController(cdpConfig.cdpController);
4698
4822
  }
4699
- reportReady();
4823
+ await this.reportReadyWhenAttached({
4824
+ compilation,
4825
+ enableCdp,
4826
+ reportReady,
4827
+ browserPid: child?.pid,
4828
+ profilePath: launchProfilePath
4829
+ });
4700
4830
  } catch (error) {
4701
4831
  const message = String(error && error.message);
4702
4832
  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." : '';
@@ -4707,9 +4837,49 @@ var __webpack_modules__ = {
4707
4837
  return;
4708
4838
  }
4709
4839
  this.stampCdpFault(compilation, error);
4710
- reportReady();
4840
+ await this.reportReadyWhenAttached({
4841
+ compilation,
4842
+ enableCdp,
4843
+ reportReady,
4844
+ browserPid: child?.pid,
4845
+ profilePath: launchProfilePath
4846
+ });
4711
4847
  }
4712
4848
  }
4849
+ async reportReadyWhenAttached(opts) {
4850
+ const outputPath = this.closeHandlerContext?.extensionOutputPath;
4851
+ const runId = this.closeHandlerContext?.runId;
4852
+ if ('development' !== opts.compilation.options.mode || !opts.enableCdp || !outputPath || this.extensionLoadRefused || hostsNoDevRuntime(outputPath)) return void opts.reportReady();
4853
+ const graceMs = opts.graceMs ?? ATTACH_GRACE_MS;
4854
+ const pollMs = opts.pollMs ?? ATTACH_POLL_MS;
4855
+ const attached = ()=>(0, ready_stamp.Lb)(outputPath, runId);
4856
+ const deadline = Date.now() + graceMs;
4857
+ while(!this.browserGone && !attached() && Date.now() < deadline)await new Promise((resolve)=>setTimeout(resolve, pollMs));
4858
+ if (this.browserGone) return;
4859
+ if (attached()) return void opts.reportReady();
4860
+ const waitedMs = graceMs;
4861
+ const message = messages.LE({
4862
+ browser: this.options.browser,
4863
+ browserPid: opts.browserPid,
4864
+ profilePath: opts.profilePath,
4865
+ profileReused: this.profileReused,
4866
+ waitedMs
4867
+ });
4868
+ (0, messaging.mR)(message);
4869
+ (0, ready_stamp.xG)(outputPath, {
4870
+ waitedMs,
4871
+ hint: (0, messaging.UT)(message)
4872
+ }, runId);
4873
+ this.readyDeferred = true;
4874
+ const watcher = setInterval(()=>{
4875
+ if (this.browserGone || this.didReportReady) return void clearInterval(watcher);
4876
+ if (attached()) {
4877
+ clearInterval(watcher);
4878
+ opts.reportReady();
4879
+ }
4880
+ }, pollMs);
4881
+ watcher.unref?.();
4882
+ }
4713
4883
  async waitForBrowserGone(child, graceMs) {
4714
4884
  if (!child) return;
4715
4885
  const deadline = Date.now() + graceMs;
@@ -4819,6 +4989,8 @@ var __webpack_modules__ = {
4819
4989
  _define_property(this, "ctx", void 0);
4820
4990
  _define_property(this, "didLaunch", void 0);
4821
4991
  _define_property(this, "didReportReady", void 0);
4992
+ _define_property(this, "readyDeferred", void 0);
4993
+ _define_property(this, "profileReused", void 0);
4822
4994
  _define_property(this, "browserGone", void 0);
4823
4995
  _define_property(this, "didSpawn", void 0);
4824
4996
  _define_property(this, "extensionLoadRefused", void 0);
@@ -4829,6 +5001,8 @@ var __webpack_modules__ = {
4829
5001
  this.ctx = ctx;
4830
5002
  this.didLaunch = false;
4831
5003
  this.didReportReady = false;
5004
+ this.readyDeferred = false;
5005
+ this.profileReused = false;
4832
5006
  this.browserGone = false;
4833
5007
  this.didSpawn = false;
4834
5008
  this.closeHandlerContext = null;
@@ -5340,6 +5514,7 @@ var __webpack_modules__ = {
5340
5514
  const extensionsToLoad = (0, companion_session.mO)({
5341
5515
  extensionPaths: configOptions.extension ? (0, runtime_options.fT)(configOptions.extension) : [],
5342
5516
  noOpen: configOptions.noOpen,
5517
+ startingUrl: Boolean((0, runtime_options.cP)(configOptions)),
5343
5518
  stageRoot: profilePath || void 0,
5344
5519
  provision
5345
5520
  });
@@ -7883,6 +8058,67 @@ var __webpack_modules__ = {
7883
8058
  (0, messaging._w)(messages.Aj(xcodebuildCmd));
7884
8059
  }
7885
8060
  var safari_config = __webpack_require__("./browsers/run-safari/safari-launch/safari-config.ts");
8061
+ var external_node_path_ = __webpack_require__("node:path");
8062
+ const ADHOC_SIGNATURE = 'adhoc';
8063
+ function parseCodeSignature(output) {
8064
+ const rows = new Map();
8065
+ for (const line of output.split(/\r?\n/)){
8066
+ const at = line.indexOf('=');
8067
+ if (!(at <= 0)) rows.set(line.slice(0, at).trim(), line.slice(at + 1).trim());
8068
+ }
8069
+ const team = rows.get('TeamIdentifier') || '';
8070
+ const adhoc = 'adhoc' === rows.get('Signature') || !team || /^not set$/i.test(team);
8071
+ if (adhoc) return {
8072
+ signed: false,
8073
+ team: null
8074
+ };
8075
+ return {
8076
+ signed: true,
8077
+ team
8078
+ };
8079
+ }
8080
+ function signatureKey(signature) {
8081
+ return signature.signed && signature.team ? signature.team : ADHOC_SIGNATURE;
8082
+ }
8083
+ function describeSignature(key) {
8084
+ return key && key !== ADHOC_SIGNATURE ? `team ${key}` : 'ad-hoc';
8085
+ }
8086
+ function noAccountForTeam(output) {
8087
+ const hit = /No Account for Team\s+"?([A-Za-z0-9]+)"?/i.exec(output);
8088
+ return hit ? hit[1] : null;
8089
+ }
8090
+ function parseXcodeTeams(output) {
8091
+ const teams = new Map();
8092
+ for (const block of output.split('{')){
8093
+ const id = /teamID\s*=\s*"?([A-Za-z0-9]+)"?\s*;/.exec(block);
8094
+ if (!id || teams.has(id[1])) continue;
8095
+ const name = /teamName\s*=\s*"?([^";]*)"?\s*;/.exec(block);
8096
+ teams.set(id[1], {
8097
+ id: id[1],
8098
+ name: name?.[1].trim() || null
8099
+ });
8100
+ }
8101
+ return [
8102
+ ...teams.values()
8103
+ ];
8104
+ }
8105
+ function signatureRecordPath(config) {
8106
+ return external_node_path_.join(config.projectLocation, '.signature');
8107
+ }
8108
+ function readSignatureRecord(config) {
8109
+ try {
8110
+ const stored = external_node_fs_.readFileSync(signatureRecordPath(config), 'utf8').trim();
8111
+ return stored || null;
8112
+ } catch {
8113
+ return null;
8114
+ }
8115
+ }
8116
+ function saveSignatureRecord(config, signature) {
8117
+ external_node_fs_.mkdirSync(external_node_path_.dirname(signatureRecordPath(config)), {
8118
+ recursive: true
8119
+ });
8120
+ external_node_fs_.writeFileSync(signatureRecordPath(config), signatureKey(signature), 'utf8');
8121
+ }
7886
8122
  var external_node_child_process_ = __webpack_require__("node:child_process");
7887
8123
  function isMacOS() {
7888
8124
  return 'darwin' === process.platform;
@@ -8087,7 +8323,24 @@ var __webpack_modules__ = {
8087
8323
  String(port)
8088
8324
  ]),
8089
8325
  listAutomationPids: ()=>listPidsWhere(isAutomationSafariArgs),
8090
- listAppPids: (appPath)=>listPidsWhere((args)=>isContainerAppArgs(appPath, args))
8326
+ listAppPids: (appPath)=>listPidsWhere((args)=>isContainerAppArgs(appPath, args)),
8327
+ readCodeSignature: (appPath)=>runTool('codesign', [
8328
+ '-dv',
8329
+ '--verbose=2',
8330
+ appPath
8331
+ ], {
8332
+ quiet: true
8333
+ }),
8334
+ readXcodeTeams: async ()=>{
8335
+ const { ok, output } = await runTool('defaults', [
8336
+ 'read',
8337
+ 'com.apple.dt.Xcode',
8338
+ 'IDEProvisioningTeams'
8339
+ ], {
8340
+ quiet: true
8341
+ });
8342
+ return ok ? output : '';
8343
+ }
8091
8344
  };
8092
8345
  }
8093
8346
  var external_node_http_ = __webpack_require__("node:http");
@@ -8097,6 +8350,8 @@ var __webpack_modules__ = {
8097
8350
  const SESSION_CREATE_MS = 30000;
8098
8351
  const SESSION_CLOSE_MS = 5000;
8099
8352
  const AUTOMATION_QUIT_MS = 3000;
8353
+ const WEBDRIVER_NOT_ASKED_YET = 'the launcher has not asked safaridriver for a session yet: it opens the app and enables the extension first, then asks, and this line is replaced by the session or by the reason it got none';
8354
+ const WEBDRIVER_SESSION_PENDING = `the launcher is asking safaridriver for a session now: the request alone waits up to ${SESSION_CREATE_MS / 1000} s, and this line is replaced by the session or by the reason it got none`;
8100
8355
  const activeSessions = new Set();
8101
8356
  const activeDrivers = new Set();
8102
8357
  let webdriver_handlersInstalled = false;
@@ -8330,7 +8585,7 @@ var __webpack_modules__ = {
8330
8585
  if ('0' === value) return 'off';
8331
8586
  return value;
8332
8587
  }
8333
- async function enableThroughSafariUi(host, config, appPath, logger) {
8588
+ async function enableThroughSafariUi(host, config, appPath, logger, signedTeam) {
8334
8589
  const uiTools = host.uiTools || (0, safari_ui.Uw)();
8335
8590
  const access = await (0, safari_ui.d8)(uiTools);
8336
8591
  if (!access.granted) {
@@ -8341,7 +8596,7 @@ var __webpack_modules__ = {
8341
8596
  const report = await (0, safari_ui.Hm)({
8342
8597
  target: {
8343
8598
  bundleId: config.bundleIdentifier,
8344
- developmentTeam: config.developmentTeam
8599
+ developmentTeam: signedTeam ?? void 0
8345
8600
  },
8346
8601
  appPath,
8347
8602
  tools: uiTools,
@@ -8359,6 +8614,24 @@ var __webpack_modules__ = {
8359
8614
  return false;
8360
8615
  }
8361
8616
  }
8617
+ async function readAppSignature(tools, appPath) {
8618
+ try {
8619
+ const { output } = await tools.readCodeSignature(appPath);
8620
+ return parseCodeSignature(output);
8621
+ } catch {
8622
+ return {
8623
+ signed: false,
8624
+ team: null
8625
+ };
8626
+ }
8627
+ }
8628
+ async function listXcodeTeams(tools) {
8629
+ try {
8630
+ return parseXcodeTeams(await tools.readXcodeTeams());
8631
+ } catch {
8632
+ return [];
8633
+ }
8634
+ }
8362
8635
  function describePackage(config) {
8363
8636
  return {
8364
8637
  appName: config.appName,
@@ -8411,8 +8684,11 @@ var __webpack_modules__ = {
8411
8684
  } catch {}
8412
8685
  }
8413
8686
  async function holdWebDriverSession(tools, config, logger) {
8414
- await closeSafariWebDriverSessions();
8415
8687
  const runId = (0, ready_stamp.Uf)(config.extensionDir);
8688
+ (0, ready_stamp.ZC)(config.extensionDir, {
8689
+ unavailableReason: WEBDRIVER_SESSION_PENDING
8690
+ }, runId);
8691
+ await closeSafariWebDriverSessions();
8416
8692
  const outcome = await openSafariWebDriverSession(tools);
8417
8693
  if (outcome.session) {
8418
8694
  const { port, sessionId } = outcome.session;
@@ -8433,7 +8709,6 @@ var __webpack_modules__ = {
8433
8709
  const config = (0, safari_config.F7)(compilation, host);
8434
8710
  const converterArgs = (0, safari_config.w7)(config);
8435
8711
  const xcodebuildArgs = (0, safari_config.vx)(config);
8436
- const isSigned = Boolean(config.developmentTeam);
8437
8712
  if (host.dryRun) {
8438
8713
  logSafariDryRun(`xcrun ${converterArgs.join(' ')}`, `xcodebuild ${xcodebuildArgs.join(' ')}`);
8439
8714
  return completePackage(config, logger, mode);
@@ -8480,6 +8755,7 @@ var __webpack_modules__ = {
8480
8755
  } else if ('full' === mode) logger.info?.(messages.oM());
8481
8756
  const buildFingerprint = (0, safari_config.XE)(config, xcodebuildArgs);
8482
8757
  const reuseBuild = !needsConversion && (0, safari_config.uO)(config, buildFingerprint);
8758
+ let buildOutput = '';
8483
8759
  if (reuseBuild) {
8484
8760
  if ('full' === mode) logger.info?.(messages.xx());
8485
8761
  } else {
@@ -8487,13 +8763,30 @@ var __webpack_modules__ = {
8487
8763
  const built = await tools.runXcodebuild(xcodebuildArgs);
8488
8764
  if (!built.ok) {
8489
8765
  const tail = toolOutputTail(built.output);
8490
- logger.error?.(messages.A('xcodebuild', built.code, tail));
8491
- throw new Error(`xcodebuild failed (exit ${built.code})\n${tail}`);
8766
+ const missingTeam = noAccountForTeam(built.output);
8767
+ const cause = missingTeam ? messages.D$(missingTeam, await listXcodeTeams(tools)) : void 0;
8768
+ logger.error?.(messages.A('xcodebuild', built.code, tail, cause));
8769
+ throw new Error(`xcodebuild failed (exit ${built.code})\n${cause ? `${cause}\n` : ''}${tail}`);
8492
8770
  }
8771
+ buildOutput = built.output;
8493
8772
  (0, safari_config.q_)(config, buildFingerprint);
8494
- if (host.announceDevReady && !isSigned) logger.warn?.(messages.fl(config.appName));
8495
8773
  }
8496
8774
  const appPath = (0, safari_config.fd)(config);
8775
+ const signature = await readAppSignature(tools, appPath);
8776
+ const isSigned = signature.signed;
8777
+ const previousSignature = readSignatureRecord(config);
8778
+ const requestedTeam = String(config.developmentTeam || '').trim();
8779
+ const noAccount = Boolean(noAccountForTeam(buildOutput));
8780
+ const signingNote = {
8781
+ team: signature.team,
8782
+ requestedTeam: requestedTeam || void 0,
8783
+ noAccount,
8784
+ knownTeams: !isSigned && requestedTeam ? await listXcodeTeams(tools) : []
8785
+ };
8786
+ if (!reuseBuild) {
8787
+ saveSignatureRecord(config, signature);
8788
+ if (null !== previousSignature && previousSignature !== signatureKey(signature)) logger.info?.(messages.ei(config.appName, describeSignature(previousSignature), describeSignature(signatureKey(signature))));
8789
+ }
8497
8790
  if ('resync' === mode) {
8498
8791
  if (!reuseBuild) logger.info?.(messages.cF(config.appName));
8499
8792
  return describePackage(config);
@@ -8518,13 +8811,16 @@ var __webpack_modules__ = {
8518
8811
  binaryProvenance: config.safariBinary ? 'pinned' : 'system',
8519
8812
  extensionId: `${config.bundleIdentifier}.Extension`
8520
8813
  }, (0, ready_stamp.Uf)(config.extensionDir));
8814
+ if (host.announceDevReady) (0, ready_stamp.ZC)(config.extensionDir, {
8815
+ unavailableReason: WEBDRIVER_NOT_ASKED_YET
8816
+ }, (0, ready_stamp.Uf)(config.extensionDir));
8521
8817
  if (!browserPid) logger.warn?.(messages.jn(config.appName));
8522
- if (!host.enableExtension) logger.info?.(messages.fO(config.appName, isSigned));
8818
+ if (!host.enableExtension) logger.info?.(messages.fO(config.appName, isSigned, signingNote));
8523
8819
  if (await confirmRegisteredWithSafari(tools, config.bundleIdentifier)) logger.info?.(messages.fd(config.appName));
8524
8820
  else logger.info?.(messages.qY(config.appName));
8525
8821
  if (host.enableExtension) {
8526
- const enabled = await enableThroughSafariUi(host, config, appPath, logger);
8527
- if (!enabled) logger.info?.(messages.fO(config.appName, isSigned));
8822
+ const enabled = await enableThroughSafariUi(host, config, appPath, logger, signature.team);
8823
+ if (!enabled) logger.info?.(messages.fO(config.appName, isSigned, signingNote));
8528
8824
  }
8529
8825
  if (host.announceDevReady) {
8530
8826
  await holdWebDriverSession(tools, config, logger);
@@ -9833,6 +10129,7 @@ function describeButton(b) {
9833
10129
  E_LOCALES_LAYOUT: 'E_LOCALES_LAYOUT',
9834
10130
  E_WAR_INVALID: 'E_WAR_INVALID',
9835
10131
  E_DEV_SESSION_DIST_SHARED: 'E_DEV_SESSION_DIST_SHARED',
10132
+ E_PROD_LOOPBACK_ORIGIN: 'E_PROD_LOOPBACK_ORIGIN',
9836
10133
  E_BACKGROUND_REQUIRED: 'E_BACKGROUND_REQUIRED',
9837
10134
  E_CONTENT_SCRIPT_SYNTAX: 'E_CONTENT_SCRIPT_SYNTAX',
9838
10135
  E_NO_ENTRYPOINTS: 'E_NO_ENTRYPOINTS',