extension 4.1.20 → 4.1.21

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
@@ -6,10 +6,10 @@
6
6
  [action-url]: https://github.com/extension-js/extension.js/actions
7
7
  [discord-image]: https://img.shields.io/discord/1253608412890271755?label=Discord&logo=discord&style=flat&color=0971fe
8
8
  [discord-url]: https://discord.gg/v9h2RgeTSN
9
- [bestpractices-image]: https://img.shields.io/cii/level/14662?label=OpenSSF%20Best%20Practices&style=flat&color=0971fe
9
+ [bestpractices-image]: https://img.shields.io/cii/level/14662?label=Best%20Practices&style=flat&color=0971fe
10
10
  [bestpractices-url]: https://www.bestpractices.dev/projects/14662
11
11
 
12
- # Extension.js [![Version][npm-version-image]][npm-version-url] [![Stars][stars-image]][stars-url] [![CI][action-image]][action-url] [![Discord][discord-image]][discord-url] [![OpenSSF Best Practices][bestpractices-image]][bestpractices-url]
12
+ # Extension.js [![Version][npm-version-image]][npm-version-url] [![Stars][stars-image]][stars-url] [![CI][action-image]][action-url] [![Discord][discord-image]][discord-url] [![Best Practices][bestpractices-image]][bestpractices-url]
13
13
 
14
14
  > The cross-browser extension framework. Build for Chrome, Edge, Firefox, and Safari with no build config required.
15
15
 
@@ -23,9 +23,9 @@ npm run dev
23
23
 
24
24
  Works with `npm`, `pnpm`, `yarn`, `bun`, and `deno`.
25
25
 
26
- The CLI itself runs on Node.js 22.12+ and Deno 2.5+. Bun installs and launches it, and it runs on Node.js from there.
26
+ The CLI itself runs on Node.js 22.12+, Deno 2.5+, and Bun 1.2+.
27
27
 
28
- [Documentation](https://extension.js.org/docs) · [Templates](https://templates.extension.dev/?utm_source=readme&utm_campaign=nav-templates) · [Showcase](https://extension.js.org/showcase) · [Blog](https://extension.js.org/blog)
28
+ [Documentation](https://extension.js.org/docs) · [Templates](https://templates.extension.dev/?utm_source=readme&utm_campaign=nav-templates) · [YouTube](https://www.youtube.com/@BrowserExtension) · [Showcase](https://extension.js.org/showcase) · [Blog](https://extension.js.org/blog)
29
29
 
30
30
  ## Why Extension.js
31
31
 
@@ -173,23 +173,25 @@ npx extension@latest dev https://github.com/GoogleChrome/chrome-extensions-sampl
173
173
 
174
174
  ## Package managers
175
175
 
176
- <div align="center">
177
-
178
- | <img alt="npm" src="https://media.extension.land/logos/package-managers/npm.svg" width="70"> | <img alt="pnpm" src="https://media.extension.land/logos/package-managers/pnpm.svg" width="70"> | <img alt="Yarn" src="https://media.extension.land/logos/package-managers/yarn.svg" width="70"> | <img alt="Bun" src="https://media.extension.land/logos/package-managers/bun.svg" width="70"> | <picture><source media="(prefers-color-scheme: dark)" srcset="https://media.extension.land/logos/package-managers/deno-dark.svg"><img alt="Deno" src="https://media.extension.land/logos/package-managers/deno.svg" width="70"></picture> |
179
- | :-: | :-: | :-: | :-: | :-: |
180
- | npm<br>✅ Supported | pnpm<br>✅ Supported | Yarn<br>✅ Supported | Bun<br>✅ Supported | Deno<br>✅ Supported |
176
+ Add Extension.js to a project, or run it once without installing, with the package manager you already use.
181
177
 
182
- </div>
178
+ | Package manager | Add to a project | Run without installing |
179
+ | :-- | :-- | :-- |
180
+ | npm | `npm install extension@latest --save-dev` | `npx extension@latest create my-extension` |
181
+ | pnpm | `pnpm add extension@latest --save-dev` | `pnpm dlx extension@latest create my-extension` |
182
+ | Yarn | `yarn add extension@latest --dev` | `yarn dlx extension@latest create my-extension` |
183
+ | Bun | `bun add --dev extension@latest` | `bunx extension@latest create my-extension` |
184
+ | Deno | `deno add npm:extension@latest` | `deno run -A npm:extension@latest create my-extension` |
183
185
 
184
- Each of these installs Extension.js, launches it, and runs its scripts. Which runtime the CLI then executes on is a separate question.
186
+ Which runtime the CLI then executes on is a separate question, answered below.
185
187
 
186
188
  ## Runtimes
187
189
 
188
- | Runtime | Status | Notes |
189
- | :-- | :-- | :-- |
190
- | Node.js | ✅ 22.12 and newer | The default. `npx`, `pnpm dlx`, `yarn dlx` and `bunx` all land here through the published bin |
191
- | Deno | ✅ 2.5 and newer | `deno run -A npm:extension@latest`. Deno 2.8.0 is refused because it cannot load `node:querystring`, fixed in 2.8.1 |
192
- | Bun | Not a runtime for the CLI | Bun installs and launches Extension.js, which then runs on Node.js. `bunx --bun` and `bun run --bun` are refused |
190
+ | | Runtime | Status | Notes |
191
+ | :-: | :-- | :-- | :-- |
192
+ | <img alt="Node.js" src="https://media.extension.land/logos/package-managers/node.svg" width="28"> | Node.js | ✅ 22.12 and newer | The default. `npx`, `pnpm dlx`, `yarn dlx` and `bunx` all land here through the published bin |
193
+ | <picture><source media="(prefers-color-scheme: dark)" srcset="https://media.extension.land/logos/package-managers/deno-dark.svg"><img alt="Deno" src="https://media.extension.land/logos/package-managers/deno.svg" width="28"></picture> | Deno | ✅ 2.5 and newer | `deno run -A npm:extension@latest`. Deno 2.8.0 is refused because it cannot load `node:querystring`, fixed in 2.8.1 |
194
+ | <img alt="Bun" src="https://media.extension.land/logos/package-managers/bun.svg" width="28"> | Bun | 1.2 and newer | `bunx --bun extension` and `bun run --bun`. Plain `bunx` runs the CLI on Node.js instead, through the published bin |
193
195
 
194
196
  ## Community
195
197
 
package/dist/84.cjs CHANGED
@@ -197,6 +197,7 @@ exports.modules = {
197
197
  var newtab_override = __webpack_require__("./browsers/browsers-lib/newtab-override.ts");
198
198
  var ready_stamp = __webpack_require__("./browsers/browsers-lib/ready-stamp.ts");
199
199
  var shared_utils = __webpack_require__("./browsers/browsers-lib/shared-utils.ts");
200
+ var write_json_atomic = __webpack_require__("./browsers/browsers-lib/write-json-atomic.ts");
200
201
  var external_ws_ = __webpack_require__("ws");
201
202
  var external_ws_default = /*#__PURE__*/ __webpack_require__.n(external_ws_);
202
203
  var constants = __webpack_require__("./browsers/browsers-lib/constants.ts");
@@ -1116,7 +1117,7 @@ exports.modules = {
1116
1117
  const ready = JSON.parse(external_node_fs_.readFileSync(readyPath, 'utf-8'));
1117
1118
  if (ready.cdpPort !== chromeRemoteDebugPort) {
1118
1119
  ready.cdpPort = chromeRemoteDebugPort;
1119
- external_node_fs_.writeFileSync(readyPath, JSON.stringify(ready, null, 2));
1120
+ (0, write_json_atomic.Z)(readyPath, ready);
1120
1121
  }
1121
1122
  }
1122
1123
  }
package/dist/browsers.cjs CHANGED
@@ -749,7 +749,7 @@ var __webpack_modules__ = {
749
749
  return `${getLoggingPrefix('warn')} safari-web-extension-converter reported ${pintor__rspack_import_8_default().yellow(String(warnings.length))} ${1 === warnings.length ? 'warning' : 'warnings'}, some manifest keys/APIs may not be supported by Safari:\n` + warnings.map((line)=>` ${pintor__rspack_import_8_default().gray('•')} ${line}`).join('\n') + (kept.length ? `\nExtension.js kept ${1 === kept.length ? 'one of these keys' : 'some of these keys'} on purpose:\n${keptLines}` : '');
750
750
  }
751
751
  function safariDefaultBundleIdNote(bundleId) {
752
- return `${getLoggingPrefix('warn')} The bundle id ${pintor__rspack_import_8_default().gray(bundleId)} is generated from the app name.\nEvery project built from the same source shares this id, and the first team to register it takes it.\nSet your own with ${pintor__rspack_import_8_default().blue('--bundle-id')} before your first submission.\nAfter a submission, a new id is a new extension with none of your users.`;
752
+ return `${getLoggingPrefix('info')} Bundle id ${pintor__rspack_import_8_default().gray(bundleId)} (generated, set ${pintor__rspack_import_8_default().blue('--bundle-id')} to own it).`;
753
753
  }
754
754
  function safariOpenHint(appPath, appName) {
755
755
  return `${getLoggingPrefix('info')} Launch it once to register with Safari: ${pintor__rspack_import_8_default().blue('open')} ${pintor__rspack_import_8_default().underline(`"${appPath}"`)}\nThen turn on ${pintor__rspack_import_8_default().yellow(appName)} in Safari ▸ Settings ▸ Extensions.`;
@@ -771,6 +771,9 @@ var __webpack_modules__ = {
771
771
  function safariRegistered(appName) {
772
772
  return `${getLoggingPrefix('success')} Safari recognizes ${pintor__rspack_import_8_default().yellow(appName)}, finish enabling it with the steps above.`;
773
773
  }
774
+ function safariPidUnresolved(appName) {
775
+ return `${getLoggingPrefix('warn')} Opened ${pintor__rspack_import_8_default().yellow(appName)} but could not find its process id.\nThe session's ready.json names the app and the extension without a ${pintor__rspack_import_8_default().gray('browserPid')}.`;
776
+ }
774
777
  function safariNotYetRegistered(appName) {
775
778
  return `${getLoggingPrefix('info')} Safari hasn't picked up ${pintor__rspack_import_8_default().yellow(appName)} yet.\nOpen the app once, then check Safari ▸ Settings ▸ Extensions.`;
776
779
  }
@@ -1032,6 +1035,7 @@ var __webpack_modules__ = {
1032
1035
  jR: ()=>safariBuilding,
1033
1036
  jc: ()=>safariProjectStale,
1034
1037
  jk: ()=>requireGeckoBinaryForGeckoBased,
1038
+ jn: ()=>safariPidUnresolved,
1035
1039
  kK: ()=>preferringSystemBrowserOverSnapshot,
1036
1040
  l9: ()=>parsingPacketError,
1037
1041
  lO: ()=>firefoxDryRunArgs,
@@ -1404,6 +1408,7 @@ var __webpack_modules__ = {
1404
1408
  "./browsers/browsers-lib/ready-stamp.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1405
1409
  var node_fs__rspack_import_0 = __webpack_require__("node:fs");
1406
1410
  var node_path__rspack_import_1 = __webpack_require__("node:path");
1411
+ var _write_json_atomic__rspack_import_2 = __webpack_require__("./browsers/browsers-lib/write-json-atomic.ts");
1407
1412
  function readyPathFor(extensionOutputPath) {
1408
1413
  return node_path__rspack_import_1.join(node_path__rspack_import_1.dirname(extensionOutputPath), 'extension-js', node_path__rspack_import_1.basename(extensionOutputPath), 'ready.json');
1409
1414
  }
@@ -1415,7 +1420,7 @@ var __webpack_modules__ = {
1415
1420
  const ready = JSON.parse(node_fs__rspack_import_0.readFileSync(readyPath, 'utf-8'));
1416
1421
  if (ready.rdpPort === rdpPort) return;
1417
1422
  ready.rdpPort = rdpPort;
1418
- node_fs__rspack_import_0.writeFileSync(readyPath, JSON.stringify(ready, null, 2));
1423
+ (0, _write_json_atomic__rspack_import_2.Z)(readyPath, ready);
1419
1424
  } catch {}
1420
1425
  }
1421
1426
  function stampReadyBrowserLaunch(extensionOutputPath, details) {
@@ -1433,7 +1438,7 @@ var __webpack_modules__ = {
1433
1438
  if (binary) ready.binary = binary;
1434
1439
  const provenance = String(details?.binaryProvenance || '').trim();
1435
1440
  if (provenance) ready.binaryProvenance = provenance;
1436
- node_fs__rspack_import_0.writeFileSync(readyPath, JSON.stringify(ready, null, 2));
1441
+ (0, _write_json_atomic__rspack_import_2.Z)(readyPath, ready);
1437
1442
  } catch {}
1438
1443
  }
1439
1444
  function stampReadyExtensionId(extensionOutputPath, extensionId) {
@@ -1445,7 +1450,7 @@ var __webpack_modules__ = {
1445
1450
  const ready = JSON.parse(node_fs__rspack_import_0.readFileSync(readyPath, 'utf-8'));
1446
1451
  if (ready.extensionId === id) return;
1447
1452
  ready.extensionId = id;
1448
- node_fs__rspack_import_0.writeFileSync(readyPath, JSON.stringify(ready, null, 2));
1453
+ (0, _write_json_atomic__rspack_import_2.Z)(readyPath, ready);
1449
1454
  } catch {}
1450
1455
  }
1451
1456
  function stampReadyExtensionLoadRefused(extensionOutputPath, reason) {
@@ -1460,7 +1465,7 @@ var __webpack_modules__ = {
1460
1465
  ready.message = `${browserLabel.charAt(0).toUpperCase() + browserLabel.slice(1)} refused to load the extension at ${extensionOutputPath}${reason ? `: ${reason}` : ''}`;
1461
1466
  ready.extensionLoadRefusedAt = new Date().toISOString();
1462
1467
  if (reason) ready.extensionLoadRefusedReason = reason;
1463
- node_fs__rspack_import_0.writeFileSync(readyPath, JSON.stringify(ready, null, 2));
1468
+ (0, _write_json_atomic__rspack_import_2.Z)(readyPath, ready);
1464
1469
  } catch {}
1465
1470
  }
1466
1471
  function stampReadyProfileLocked(extensionOutputPath, details) {
@@ -1474,7 +1479,7 @@ var __webpack_modules__ = {
1474
1479
  ready.message = String(details?.message || '').trim() || 'the browser profile is already in use by another session';
1475
1480
  ready.profileLockedAt = new Date().toISOString();
1476
1481
  if (details?.owner) ready.profileLockOwner = details.owner;
1477
- node_fs__rspack_import_0.writeFileSync(readyPath, JSON.stringify(ready, null, 2));
1482
+ (0, _write_json_atomic__rspack_import_2.Z)(readyPath, ready);
1478
1483
  } catch {}
1479
1484
  }
1480
1485
  function stampReadyBrowserExited(extensionOutputPath, code) {
@@ -1490,7 +1495,7 @@ var __webpack_modules__ = {
1490
1495
  ready.code = 'browser_exited';
1491
1496
  ready.message = `the ${ready.browser || 'browser'} process exited (code ${code ?? 'unknown'}); nothing is running`;
1492
1497
  }
1493
- node_fs__rspack_import_0.writeFileSync(readyPath, JSON.stringify(ready, null, 2));
1498
+ (0, _write_json_atomic__rspack_import_2.Z)(readyPath, ready);
1494
1499
  } catch {}
1495
1500
  }
1496
1501
  __webpack_require__.d(__webpack_exports__, {
@@ -1953,6 +1958,27 @@ var __webpack_modules__ = {
1953
1958
  yO: ()=>probeChromiumBinaryVersion
1954
1959
  });
1955
1960
  },
1961
+ "./browsers/browsers-lib/write-json-atomic.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1962
+ var node_fs__rspack_import_0 = __webpack_require__("node:fs");
1963
+ function writeJsonAtomic(filePath, value) {
1964
+ const tmpPath = `${filePath}.tmp-${process.pid}`;
1965
+ try {
1966
+ node_fs__rspack_import_0.writeFileSync(tmpPath, JSON.stringify(value, null, 2), 'utf-8');
1967
+ node_fs__rspack_import_0.renameSync(tmpPath, filePath);
1968
+ return true;
1969
+ } catch {
1970
+ try {
1971
+ node_fs__rspack_import_0.rmSync(tmpPath, {
1972
+ force: true
1973
+ });
1974
+ } catch {}
1975
+ return false;
1976
+ }
1977
+ }
1978
+ __webpack_require__.d(__webpack_exports__, {
1979
+ Z: ()=>writeJsonAtomic
1980
+ });
1981
+ },
1956
1982
  "./browsers/browsers-lib/wsl-support.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1957
1983
  __webpack_require__.d(__webpack_exports__, {
1958
1984
  qc: ()=>external_wsl_support_namespaceObject.hasGuiDisplay,
@@ -5816,7 +5842,6 @@ var __webpack_modules__ = {
5816
5842
  QW: ()=>safariBuildPreflight,
5817
5843
  iF: ()=>safariPreflightError
5818
5844
  });
5819
- var external_node_child_process_ = __webpack_require__("node:child_process");
5820
5845
  var external_node_fs_ = __webpack_require__("node:fs");
5821
5846
  var messaging = __webpack_require__("./helpers/messaging.ts");
5822
5847
  var banner = __webpack_require__("./browsers/browsers-lib/banner.ts");
@@ -5830,6 +5855,7 @@ var __webpack_modules__ = {
5830
5855
  (0, messaging._w)(messages.Aj(xcodebuildCmd));
5831
5856
  }
5832
5857
  var safari_config = __webpack_require__("./browsers/run-safari/safari-launch/safari-config.ts");
5858
+ var external_node_child_process_ = __webpack_require__("node:child_process");
5833
5859
  function isMacOS() {
5834
5860
  return 'darwin' === process.platform;
5835
5861
  }
@@ -5887,20 +5913,6 @@ var __webpack_modules__ = {
5887
5913
  ok: Boolean(converter && xcodebuild)
5888
5914
  };
5889
5915
  }
5890
- function fallbackLogger() {
5891
- return {
5892
- info: (...a)=>(0, messaging._w)(...a),
5893
- warn: (...a)=>(0, messaging.mR)(...a),
5894
- error: (...a)=>(0, messaging.Gg)(...a),
5895
- debug: (...a)=>console?.debug?.(...a)
5896
- };
5897
- }
5898
- function isTestEnv() {
5899
- return Boolean(process.env.VITEST || process.env.VITEST_WORKER_ID);
5900
- }
5901
- function delay(ms) {
5902
- return new Promise((resolve)=>setTimeout(resolve, ms));
5903
- }
5904
5916
  const TOOL_TAIL_LINES = 50;
5905
5917
  const TOOL_TAIL_BYTES = 8192;
5906
5918
  function toolOutputTail(output) {
@@ -5939,6 +5951,60 @@ var __webpack_modules__ = {
5939
5951
  }));
5940
5952
  });
5941
5953
  }
5954
+ async function resolvePidForBundle(bundleId) {
5955
+ for(let attempt = 0; attempt < 10; attempt += 1){
5956
+ const pid = await new Promise((resolve)=>{
5957
+ const child = (0, external_node_child_process_.spawn)("osascript", [
5958
+ '-e',
5959
+ `tell application "System Events" to get unix id of first process whose bundle identifier is "${bundleId}"`
5960
+ ]);
5961
+ let out = '';
5962
+ child.stdout.on('data', (d)=>out += String(d));
5963
+ child.on('error', ()=>resolve(null));
5964
+ child.on('close', ()=>{
5965
+ const n = Number(String(out).trim());
5966
+ resolve(Number.isFinite(n) && n > 0 ? n : null);
5967
+ });
5968
+ });
5969
+ if (pid) return pid;
5970
+ await new Promise((r)=>setTimeout(r, 500));
5971
+ }
5972
+ return null;
5973
+ }
5974
+ function createSafariTools() {
5975
+ return {
5976
+ detectToolchain: ()=>detectSafariToolchain(),
5977
+ runConverter: (args)=>runTool('xcrun', args),
5978
+ runXcodebuild: (args)=>runTool('xcodebuild', args),
5979
+ openApp: (target)=>runTool('open', [
5980
+ target
5981
+ ]),
5982
+ openSafari: (binary)=>runTool('open', [
5983
+ '-a',
5984
+ binary
5985
+ ]),
5986
+ resolvePid: (bundleId)=>resolvePidForBundle(bundleId),
5987
+ pluginkitList: async ()=>{
5988
+ const { ok, output } = await runTool('pluginkit', [
5989
+ '-m'
5990
+ ], {
5991
+ quiet: true
5992
+ });
5993
+ return ok ? output : '';
5994
+ }
5995
+ };
5996
+ }
5997
+ function fallbackLogger() {
5998
+ return {
5999
+ info: (...a)=>(0, messaging._w)(...a),
6000
+ warn: (...a)=>(0, messaging.mR)(...a),
6001
+ error: (...a)=>(0, messaging.Gg)(...a),
6002
+ debug: (...a)=>console?.debug?.(...a)
6003
+ };
6004
+ }
6005
+ function delay(ms) {
6006
+ return new Promise((resolve)=>setTimeout(resolve, ms));
6007
+ }
5942
6008
  function converterWarnings(output) {
5943
6009
  const lines = output.split(/\r?\n/);
5944
6010
  const collected = [];
@@ -5959,15 +6025,11 @@ var __webpack_modules__ = {
5959
6025
  }
5960
6026
  return collected;
5961
6027
  }
5962
- async function confirmRegisteredWithSafari(bundleIdentifier) {
6028
+ async function confirmRegisteredWithSafari(tools, bundleIdentifier) {
5963
6029
  const needle = `${bundleIdentifier}.Extension`;
5964
6030
  for(let attempt = 0; attempt < 6; attempt += 1){
5965
- const { ok, output } = await runTool('pluginkit', [
5966
- '-m'
5967
- ], {
5968
- quiet: true
5969
- });
5970
- if (ok && output.includes(needle)) return true;
6031
+ const listing = await tools.pluginkitList();
6032
+ if (listing.includes(needle)) return true;
5971
6033
  await delay(800);
5972
6034
  }
5973
6035
  return false;
@@ -5982,6 +6044,10 @@ var __webpack_modules__ = {
5982
6044
  macOsOnly: config.macOsOnly
5983
6045
  };
5984
6046
  }
6047
+ function completePackage(config, logger, mode) {
6048
+ if ('full' === mode && config.bundleIdDerived) logger.info?.(messages.$q(config.bundleIdentifier));
6049
+ return describePackage(config);
6050
+ }
5985
6051
  function safariPreflightError() {
5986
6052
  const tc = detectSafariToolchain();
5987
6053
  if (!tc.platformOk) return messages.G3(process.platform);
@@ -6005,26 +6071,6 @@ var __webpack_modules__ = {
6005
6071
  severity: 'ok'
6006
6072
  };
6007
6073
  }
6008
- async function resolvePidForBundle(bundleId) {
6009
- for(let attempt = 0; attempt < 10; attempt += 1){
6010
- const pid = await new Promise((resolve)=>{
6011
- const child = (0, external_node_child_process_.spawn)("osascript", [
6012
- '-e',
6013
- `tell application "System Events" to get unix id of first process whose bundle identifier is "${bundleId}"`
6014
- ]);
6015
- let out = '';
6016
- child.stdout.on('data', (d)=>out += String(d));
6017
- child.on('error', ()=>resolve(null));
6018
- child.on('close', ()=>{
6019
- const n = Number(String(out).trim());
6020
- resolve(Number.isFinite(n) && n > 0 ? n : null);
6021
- });
6022
- });
6023
- if (pid) return pid;
6024
- await new Promise((r)=>setTimeout(r, 500));
6025
- }
6026
- return null;
6027
- }
6028
6074
  async function announceSafariDevSession(host, config, appPath) {
6029
6075
  try {
6030
6076
  await (0, banner.ai)({
@@ -6040,16 +6086,16 @@ var __webpack_modules__ = {
6040
6086
  } catch {}
6041
6087
  }
6042
6088
  async function runSafariPipeline(compilation, host, logger, mode) {
6089
+ const tools = host.tools || createSafariTools();
6043
6090
  const config = (0, safari_config.F7)(compilation, host);
6044
6091
  const converterArgs = (0, safari_config.w7)(config);
6045
6092
  const xcodebuildArgs = (0, safari_config.vx)(config);
6046
6093
  const isSigned = Boolean(config.developmentTeam);
6047
- if ('full' === mode && config.bundleIdDerived) logger.warn?.(messages.$q(config.bundleIdentifier));
6048
- if (host.dryRun || isTestEnv()) {
6094
+ if (host.dryRun) {
6049
6095
  logSafariDryRun(`xcrun ${converterArgs.join(' ')}`, `xcodebuild ${xcodebuildArgs.join(' ')}`);
6050
- return describePackage(config);
6096
+ return completePackage(config, logger, mode);
6051
6097
  }
6052
- const toolchain = detectSafariToolchain();
6098
+ const toolchain = tools.detectToolchain();
6053
6099
  if (!toolchain.platformOk) {
6054
6100
  logger.warn?.(messages.G3(process.platform));
6055
6101
  return describePackage(config);
@@ -6073,7 +6119,7 @@ var __webpack_modules__ = {
6073
6119
  }
6074
6120
  const { saved, restore } = (0, safari_config._D)(config);
6075
6121
  logger.info?.(messages.uK(config.extensionDir));
6076
- const converted = await runTool('xcrun', converterArgs);
6122
+ const converted = await tools.runConverter(converterArgs);
6077
6123
  if (!converted.ok) {
6078
6124
  const tail = toolOutputTail(converted.output);
6079
6125
  logger.error?.(messages.A('safari-web-extension-converter', converted.code, tail));
@@ -6090,7 +6136,7 @@ var __webpack_modules__ = {
6090
6136
  logger.info?.(messages.l_(config.projectLocation));
6091
6137
  } else if ('full' === mode) logger.info?.(messages.oM());
6092
6138
  if ('full' === mode) logger.info?.(messages.jR((0, safari_config.aD)(config)));
6093
- const built = await runTool('xcodebuild', xcodebuildArgs);
6139
+ const built = await tools.runXcodebuild(xcodebuildArgs);
6094
6140
  if (!built.ok) {
6095
6141
  const tail = toolOutputTail(built.output);
6096
6142
  logger.error?.(messages.A('xcodebuild', built.code, tail));
@@ -6105,30 +6151,26 @@ var __webpack_modules__ = {
6105
6151
  if (!config.open) {
6106
6152
  logger.info?.(messages.aO(appPath, config.appName));
6107
6153
  if (host.announceDevReady) await announceSafariDevSession(host, config, appPath);
6108
- return describePackage(config);
6154
+ return completePackage(config, logger, mode);
6109
6155
  }
6110
6156
  const target = external_node_fs_.existsSync(appPath) ? appPath : (0, safari_config.Gi)(config);
6111
6157
  logger.info?.(messages.fw(target));
6112
- await runTool('open', [
6113
- target
6114
- ]);
6115
- if (config.safariBinary) await runTool('open', [
6116
- '-a',
6117
- config.safariBinary
6118
- ]);
6158
+ await tools.openApp(target);
6159
+ if (config.safariBinary) await tools.openSafari(config.safariBinary);
6119
6160
  const raisedBundleId = config.safariBinary ? 'com.apple.Safari' : config.bundleIdentifier;
6120
- const browserPid = await resolvePidForBundle(raisedBundleId);
6121
- if (browserPid) (0, ready_stamp.M)(config.extensionDir, {
6122
- browserPid,
6161
+ const browserPid = await tools.resolvePid(raisedBundleId);
6162
+ (0, ready_stamp.M)(config.extensionDir, {
6163
+ browserPid: browserPid || void 0,
6123
6164
  binary: config.safariBinary || appPath,
6124
6165
  binaryProvenance: config.safariBinary ? 'pinned' : 'system',
6125
6166
  extensionId: `${config.bundleIdentifier}.Extension`
6126
6167
  });
6168
+ if (!browserPid) logger.warn?.(messages.jn(config.appName));
6127
6169
  logger.info?.(messages.fO(config.appName, isSigned));
6128
- if (await confirmRegisteredWithSafari(config.bundleIdentifier)) logger.info?.(messages.fd(config.appName));
6170
+ if (await confirmRegisteredWithSafari(tools, config.bundleIdentifier)) logger.info?.(messages.fd(config.appName));
6129
6171
  else logger.info?.(messages.qY(config.appName));
6130
6172
  if (host.announceDevReady) await announceSafariDevSession(host, config, appPath);
6131
- return describePackage(config);
6173
+ return completePackage(config, logger, mode);
6132
6174
  }
6133
6175
  async function packageSafariExtension(host, outputPath, logger, mode = 'full') {
6134
6176
  const compilation = {
@@ -6248,9 +6290,10 @@ var __webpack_modules__ = {
6248
6290
  function manifestFingerprintPath(config) {
6249
6291
  return node_path__rspack_import_1.join(config.projectLocation, '.manifest-fingerprint');
6250
6292
  }
6293
+ const HOT_UPDATE_DIR = 'hot';
6251
6294
  function topLevelEntries(extensionDir) {
6252
6295
  try {
6253
- return node_fs__rspack_import_0.readdirSync(extensionDir).sort();
6296
+ return node_fs__rspack_import_0.readdirSync(extensionDir).filter((entry)=>entry !== HOT_UPDATE_DIR).sort();
6254
6297
  } catch {
6255
6298
  return [];
6256
6299
  }
@@ -6379,7 +6422,7 @@ var __webpack_modules__ = {
6379
6422
  return Object.fromEntries(Object.entries(input).filter(([, value])=>void 0 !== value));
6380
6423
  }
6381
6424
  function createSafariPackager(options = {}) {
6382
- const { browser = 'safari', noOpen = true, dryRun = false, logger, ...identity } = options;
6425
+ const { browser = 'safari', noOpen = true, dryRun = false, logger, tools, ...identity } = options;
6383
6426
  return async (distPath, mode = 'full', overrides)=>await (0, _safari_launch__rspack_import_0.Ah)({
6384
6427
  extension: [
6385
6428
  distPath
@@ -6387,6 +6430,7 @@ var __webpack_modules__ = {
6387
6430
  browser,
6388
6431
  noOpen,
6389
6432
  dryRun,
6433
+ tools,
6390
6434
  ...withoutUndefined(identity),
6391
6435
  ...withoutUndefined(overrides)
6392
6436
  }, distPath, logger, mode);