extension 4.1.1 → 4.1.2

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
@@ -41,7 +41,7 @@ Browser extensions ship with the worst dev experience in modern web. Manifest V3
41
41
 
42
42
  ## Watch it work
43
43
 
44
- [![Extension.js in 60 seconds: one command, a running extension](https://media.extension.land/video/extension-js/sixty-second-demo.gif)](https://extension.js.org/docs)
44
+ [![One command, and the extension is running in a real browser](https://media.extension.land/video/extension-js/sixty-second-demo.gif)](https://extension.js.org/docs)
45
45
 
46
46
  Or skip the install and try a [live template](https://templates.extension.dev) in your browser.
47
47
 
@@ -155,10 +155,12 @@ npm install extension@latest --save-dev
155
155
  }
156
156
  ```
157
157
 
158
- Run `npm run dev` to develop, `npm run build` for production, and `npm run preview` to inspect the production output.
158
+ Run `npm run dev` to develop, and watch the browser open with your extension already loaded:
159
159
 
160
160
  [![extension dev: the browser opens with the extension loaded](https://media.extension.land/video/extension-js/dev-build-preview.gif)](https://extension.js.org/docs/commands/dev)
161
161
 
162
+ Use `npm run build` for production, and `npm run preview` to inspect the production output.
163
+
162
164
  ## Start from a Chrome sample
163
165
 
164
166
  Pull any sample from [Chrome Extension Samples](https://github.com/GoogleChrome/chrome-extensions-samples) and run it directly:
package/dist/browsers.cjs CHANGED
@@ -706,8 +706,10 @@ var __webpack_modules__ = {
706
706
  function safariDefaultBundleIdNote(bundleId) {
707
707
  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.`;
708
708
  }
709
- function safariOpenHint(appPath, appName) {
710
- 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 enable ${pintor__rspack_import_8_default().yellow(appName)} via Safari ▸ Develop ▸ ${pintor__rspack_import_8_default().yellow('Allow Unsigned Extensions')} and Safari ▸ Settings ▸ Extensions.`;
709
+ function safariOpenHint(appPath, appName, signed) {
710
+ const launch = `${getLoggingPrefix('info')} Launch it once to register with Safari: ${pintor__rspack_import_8_default().blue('open')} ${pintor__rspack_import_8_default().underline(`"${appPath}"`)}\n`;
711
+ if (signed) return launch + `Then turn on ${pintor__rspack_import_8_default().yellow(appName)} in Safari ▸ Settings ▸ Extensions.`;
712
+ return launch + `Then enable ${pintor__rspack_import_8_default().yellow(appName)} via Safari ▸ Develop ▸ ` + `${pintor__rspack_import_8_default().yellow('Allow Unsigned Extensions')} and Safari ▸ Settings ▸ Extensions.`;
711
713
  }
712
714
  function safariDryRunNotBuilding() {
713
715
  return `${getLoggingPrefix('info')} Dry run: skip the Safari app build.`;
@@ -718,7 +720,8 @@ var __webpack_modules__ = {
718
720
  function safariDryRunXcodebuild(cmd) {
719
721
  return `${getLoggingPrefix('info')} xcodebuild: ${pintor__rspack_import_8_default().gray(cmd)}.`;
720
722
  }
721
- function safariNextSteps(appName) {
723
+ function safariNextSteps(appName, signed) {
724
+ if (signed) return `${getLoggingPrefix('info')} One-time setup to load ${pintor__rspack_import_8_default().yellow(appName)} in Safari:\n ${pintor__rspack_import_8_default().gray('1.')} Safari ▸ Settings ▸ Extensions ▸ turn on ${pintor__rspack_import_8_default().yellow(appName)}\n ${pintor__rspack_import_8_default().gray('→')} Signed with your team id, so this survives a restart.`;
722
725
  return `${getLoggingPrefix('info')} One-time setup to load ${pintor__rspack_import_8_default().yellow(appName)} in Safari:\n ${pintor__rspack_import_8_default().gray('1.')} Safari ▸ Settings ▸ Advanced ▸ check ${pintor__rspack_import_8_default().yellow('“Show features for web developers”')}\n ${pintor__rspack_import_8_default().gray('2.')} Safari ▸ Develop ▸ ${pintor__rspack_import_8_default().yellow('Allow Unsigned Extensions')} ${pintor__rspack_import_8_default().gray('(resets each launch)')}\n ${pintor__rspack_import_8_default().gray('3.')} Safari ▸ Settings ▸ Extensions ▸ turn on ${pintor__rspack_import_8_default().yellow(appName)}\n ${pintor__rspack_import_8_default().gray('→')} The app window that just opened can also take you there.`;
723
726
  }
724
727
  function safariRegistered(appName) {
@@ -5402,6 +5405,7 @@ var __webpack_modules__ = {
5402
5405
  var banner = __webpack_require__("./browsers/browsers-lib/banner.ts");
5403
5406
  var messages = __webpack_require__("./browsers/browsers-lib/messages.ts");
5404
5407
  var ready_message = __webpack_require__("./browsers/browsers-lib/ready-message.ts");
5408
+ var ready_stamp = __webpack_require__("./browsers/browsers-lib/ready-stamp.ts");
5405
5409
  function logSafariDryRun(converterCmd, xcodebuildCmd) {
5406
5410
  if ((0, messaging._o)()) (0, messaging._w)(messages.KP());
5407
5411
  (0, messaging._w)(messages.yc());
@@ -5567,6 +5571,26 @@ var __webpack_modules__ = {
5567
5571
  severity: 'ok'
5568
5572
  };
5569
5573
  }
5574
+ async function resolvePidForBundle(bundleId) {
5575
+ for(let attempt = 0; attempt < 10; attempt += 1){
5576
+ const pid = await new Promise((resolve)=>{
5577
+ const child = (0, external_node_child_process_.spawn)("osascript", [
5578
+ '-e',
5579
+ `tell application "System Events" to get unix id of first process whose bundle identifier is "${bundleId}"`
5580
+ ]);
5581
+ let out = '';
5582
+ child.stdout.on('data', (d)=>out += String(d));
5583
+ child.on('error', ()=>resolve(null));
5584
+ child.on('close', ()=>{
5585
+ const n = Number(String(out).trim());
5586
+ resolve(Number.isFinite(n) && n > 0 ? n : null);
5587
+ });
5588
+ });
5589
+ if (pid) return pid;
5590
+ await new Promise((r)=>setTimeout(r, 500));
5591
+ }
5592
+ return null;
5593
+ }
5570
5594
  async function announceSafariDevSession(host, config, appPath) {
5571
5595
  try {
5572
5596
  await (0, banner.ai)({
@@ -5585,6 +5609,7 @@ var __webpack_modules__ = {
5585
5609
  const config = (0, safari_config.F7)(compilation, host);
5586
5610
  const converterArgs = (0, safari_config.w7)(config);
5587
5611
  const xcodebuildArgs = (0, safari_config.vx)(config);
5612
+ const isSigned = Boolean(config.developmentTeam);
5588
5613
  if ('full' === mode && config.bundleIdDerived) logger.warn?.(messages.$q(config.bundleIdentifier));
5589
5614
  if (host.dryRun || isTestEnv()) {
5590
5615
  logSafariDryRun(`xcrun ${converterArgs.join(' ')}`, `xcodebuild ${xcodebuildArgs.join(' ')}`);
@@ -5644,7 +5669,7 @@ var __webpack_modules__ = {
5644
5669
  }
5645
5670
  logger.info?.(messages.Rl(appPath));
5646
5671
  if (!config.open) {
5647
- logger.info?.(messages.aO(appPath, config.appName));
5672
+ logger.info?.(messages.aO(appPath, config.appName, isSigned));
5648
5673
  if (host.announceDevReady) await announceSafariDevSession(host, config, appPath);
5649
5674
  return describePackage(config);
5650
5675
  }
@@ -5657,7 +5682,15 @@ var __webpack_modules__ = {
5657
5682
  '-a',
5658
5683
  config.safariBinary
5659
5684
  ]);
5660
- logger.info?.(messages.fO(config.appName));
5685
+ const raisedBundleId = config.safariBinary ? 'com.apple.Safari' : config.bundleIdentifier;
5686
+ const browserPid = await resolvePidForBundle(raisedBundleId);
5687
+ if (browserPid) (0, ready_stamp.M)(config.extensionDir, {
5688
+ browserPid,
5689
+ binary: config.safariBinary || appPath,
5690
+ binaryProvenance: config.safariBinary ? 'pinned' : 'system',
5691
+ extensionId: `${config.bundleIdentifier}.Extension`
5692
+ });
5693
+ logger.info?.(messages.fO(config.appName, isSigned));
5661
5694
  if (await confirmRegisteredWithSafari(config.bundleIdentifier)) logger.info?.(messages.fd(config.appName));
5662
5695
  else logger.info?.(messages.qY(config.appName));
5663
5696
  if (host.announceDevReady) await announceSafariDevSession(host, config, appPath);
@@ -5717,7 +5750,8 @@ var __webpack_modules__ = {
5717
5750
  macOsOnly: false !== host.macOsOnly,
5718
5751
  language: 'swift',
5719
5752
  open: !host.noOpen,
5720
- safariBinary: host.safariBinary
5753
+ safariBinary: host.safariBinary,
5754
+ developmentTeam: String(host.developmentTeam || '').trim() || void 0
5721
5755
  };
5722
5756
  }
5723
5757
  function composeConverterArgs(config) {
@@ -5751,7 +5785,7 @@ var __webpack_modules__ = {
5751
5785
  return node_path__rspack_import_1.join(derivedDataPath(config), 'Build', 'Products', 'Release', `${config.appName}.app`);
5752
5786
  }
5753
5787
  function composeXcodebuildArgs(config) {
5754
- return [
5788
+ const base = [
5755
5789
  '-project',
5756
5790
  xcodeProjectPath(config),
5757
5791
  '-scheme',
@@ -5759,7 +5793,18 @@ var __webpack_modules__ = {
5759
5793
  '-configuration',
5760
5794
  'Release',
5761
5795
  '-derivedDataPath',
5762
- derivedDataPath(config),
5796
+ derivedDataPath(config)
5797
+ ];
5798
+ const team = String(config.developmentTeam || '').trim();
5799
+ if (team) return [
5800
+ ...base,
5801
+ `DEVELOPMENT_TEAM=${team}`,
5802
+ 'CODE_SIGN_STYLE=Automatic',
5803
+ '-allowProvisioningUpdates',
5804
+ 'build'
5805
+ ];
5806
+ return [
5807
+ ...base,
5763
5808
  'CODE_SIGN_IDENTITY=-',
5764
5809
  'CODE_SIGNING_REQUIRED=NO',
5765
5810
  'CODE_SIGNING_ALLOWED=YES',
package/dist/cli.cjs CHANGED
@@ -707,8 +707,10 @@ var __webpack_modules__ = {
707
707
  function safariDefaultBundleIdNote(bundleId) {
708
708
  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.`;
709
709
  }
710
- function safariOpenHint(appPath, appName) {
711
- 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 enable ${pintor__rspack_import_8_default().yellow(appName)} via Safari ▸ Develop ▸ ${pintor__rspack_import_8_default().yellow('Allow Unsigned Extensions')} and Safari ▸ Settings ▸ Extensions.`;
710
+ function safariOpenHint(appPath, appName, signed) {
711
+ const launch = `${getLoggingPrefix('info')} Launch it once to register with Safari: ${pintor__rspack_import_8_default().blue('open')} ${pintor__rspack_import_8_default().underline(`"${appPath}"`)}\n`;
712
+ if (signed) return launch + `Then turn on ${pintor__rspack_import_8_default().yellow(appName)} in Safari ▸ Settings ▸ Extensions.`;
713
+ return launch + `Then enable ${pintor__rspack_import_8_default().yellow(appName)} via Safari ▸ Develop ▸ ` + `${pintor__rspack_import_8_default().yellow('Allow Unsigned Extensions')} and Safari ▸ Settings ▸ Extensions.`;
712
714
  }
713
715
  function safariDryRunNotBuilding() {
714
716
  return `${getLoggingPrefix('info')} Dry run: skip the Safari app build.`;
@@ -719,7 +721,8 @@ var __webpack_modules__ = {
719
721
  function safariDryRunXcodebuild(cmd) {
720
722
  return `${getLoggingPrefix('info')} xcodebuild: ${pintor__rspack_import_8_default().gray(cmd)}.`;
721
723
  }
722
- function safariNextSteps(appName) {
724
+ function safariNextSteps(appName, signed) {
725
+ if (signed) return `${getLoggingPrefix('info')} One-time setup to load ${pintor__rspack_import_8_default().yellow(appName)} in Safari:\n ${pintor__rspack_import_8_default().gray('1.')} Safari ▸ Settings ▸ Extensions ▸ turn on ${pintor__rspack_import_8_default().yellow(appName)}\n ${pintor__rspack_import_8_default().gray('→')} Signed with your team id, so this survives a restart.`;
723
726
  return `${getLoggingPrefix('info')} One-time setup to load ${pintor__rspack_import_8_default().yellow(appName)} in Safari:\n ${pintor__rspack_import_8_default().gray('1.')} Safari ▸ Settings ▸ Advanced ▸ check ${pintor__rspack_import_8_default().yellow('“Show features for web developers”')}\n ${pintor__rspack_import_8_default().gray('2.')} Safari ▸ Develop ▸ ${pintor__rspack_import_8_default().yellow('Allow Unsigned Extensions')} ${pintor__rspack_import_8_default().gray('(resets each launch)')}\n ${pintor__rspack_import_8_default().gray('3.')} Safari ▸ Settings ▸ Extensions ▸ turn on ${pintor__rspack_import_8_default().yellow(appName)}\n ${pintor__rspack_import_8_default().gray('→')} The app window that just opened can also take you there.`;
724
727
  }
725
728
  function safariRegistered(appName) {
@@ -5393,6 +5396,7 @@ var __webpack_modules__ = {
5393
5396
  var banner = __webpack_require__("./browsers/browsers-lib/banner.ts");
5394
5397
  var messages = __webpack_require__("./browsers/browsers-lib/messages.ts");
5395
5398
  var ready_message = __webpack_require__("./browsers/browsers-lib/ready-message.ts");
5399
+ var ready_stamp = __webpack_require__("./browsers/browsers-lib/ready-stamp.ts");
5396
5400
  function logSafariDryRun(converterCmd, xcodebuildCmd) {
5397
5401
  if ((0, messaging._o)()) (0, messaging._w)(messages.KP());
5398
5402
  (0, messaging._w)(messages.yc());
@@ -5558,6 +5562,26 @@ var __webpack_modules__ = {
5558
5562
  severity: 'ok'
5559
5563
  };
5560
5564
  }
5565
+ async function resolvePidForBundle(bundleId) {
5566
+ for(let attempt = 0; attempt < 10; attempt += 1){
5567
+ const pid = await new Promise((resolve)=>{
5568
+ const child = (0, external_node_child_process_.spawn)("osascript", [
5569
+ '-e',
5570
+ `tell application "System Events" to get unix id of first process whose bundle identifier is "${bundleId}"`
5571
+ ]);
5572
+ let out = '';
5573
+ child.stdout.on('data', (d)=>out += String(d));
5574
+ child.on('error', ()=>resolve(null));
5575
+ child.on('close', ()=>{
5576
+ const n = Number(String(out).trim());
5577
+ resolve(Number.isFinite(n) && n > 0 ? n : null);
5578
+ });
5579
+ });
5580
+ if (pid) return pid;
5581
+ await new Promise((r)=>setTimeout(r, 500));
5582
+ }
5583
+ return null;
5584
+ }
5561
5585
  async function announceSafariDevSession(host, config, appPath) {
5562
5586
  try {
5563
5587
  await (0, banner.ai)({
@@ -5576,6 +5600,7 @@ var __webpack_modules__ = {
5576
5600
  const config = (0, safari_config.F7)(compilation, host);
5577
5601
  const converterArgs = (0, safari_config.w7)(config);
5578
5602
  const xcodebuildArgs = (0, safari_config.vx)(config);
5603
+ const isSigned = Boolean(config.developmentTeam);
5579
5604
  if ('full' === mode && config.bundleIdDerived) logger.warn?.(messages.$q(config.bundleIdentifier));
5580
5605
  if (host.dryRun || isTestEnv()) {
5581
5606
  logSafariDryRun(`xcrun ${converterArgs.join(' ')}`, `xcodebuild ${xcodebuildArgs.join(' ')}`);
@@ -5635,7 +5660,7 @@ var __webpack_modules__ = {
5635
5660
  }
5636
5661
  logger.info?.(messages.Rl(appPath));
5637
5662
  if (!config.open) {
5638
- logger.info?.(messages.aO(appPath, config.appName));
5663
+ logger.info?.(messages.aO(appPath, config.appName, isSigned));
5639
5664
  if (host.announceDevReady) await announceSafariDevSession(host, config, appPath);
5640
5665
  return describePackage(config);
5641
5666
  }
@@ -5648,7 +5673,15 @@ var __webpack_modules__ = {
5648
5673
  '-a',
5649
5674
  config.safariBinary
5650
5675
  ]);
5651
- logger.info?.(messages.fO(config.appName));
5676
+ const raisedBundleId = config.safariBinary ? 'com.apple.Safari' : config.bundleIdentifier;
5677
+ const browserPid = await resolvePidForBundle(raisedBundleId);
5678
+ if (browserPid) (0, ready_stamp.M)(config.extensionDir, {
5679
+ browserPid,
5680
+ binary: config.safariBinary || appPath,
5681
+ binaryProvenance: config.safariBinary ? 'pinned' : 'system',
5682
+ extensionId: `${config.bundleIdentifier}.Extension`
5683
+ });
5684
+ logger.info?.(messages.fO(config.appName, isSigned));
5652
5685
  if (await confirmRegisteredWithSafari(config.bundleIdentifier)) logger.info?.(messages.fd(config.appName));
5653
5686
  else logger.info?.(messages.qY(config.appName));
5654
5687
  if (host.announceDevReady) await announceSafariDevSession(host, config, appPath);
@@ -5708,7 +5741,8 @@ var __webpack_modules__ = {
5708
5741
  macOsOnly: false !== host.macOsOnly,
5709
5742
  language: 'swift',
5710
5743
  open: !host.noOpen,
5711
- safariBinary: host.safariBinary
5744
+ safariBinary: host.safariBinary,
5745
+ developmentTeam: String(host.developmentTeam || '').trim() || void 0
5712
5746
  };
5713
5747
  }
5714
5748
  function composeConverterArgs(config) {
@@ -5742,7 +5776,7 @@ var __webpack_modules__ = {
5742
5776
  return node_path__rspack_import_1.join(derivedDataPath(config), 'Build', 'Products', 'Release', `${config.appName}.app`);
5743
5777
  }
5744
5778
  function composeXcodebuildArgs(config) {
5745
- return [
5779
+ const base = [
5746
5780
  '-project',
5747
5781
  xcodeProjectPath(config),
5748
5782
  '-scheme',
@@ -5750,7 +5784,18 @@ var __webpack_modules__ = {
5750
5784
  '-configuration',
5751
5785
  'Release',
5752
5786
  '-derivedDataPath',
5753
- derivedDataPath(config),
5787
+ derivedDataPath(config)
5788
+ ];
5789
+ const team = String(config.developmentTeam || '').trim();
5790
+ if (team) return [
5791
+ ...base,
5792
+ `DEVELOPMENT_TEAM=${team}`,
5793
+ 'CODE_SIGN_STYLE=Automatic',
5794
+ '-allowProvisioningUpdates',
5795
+ 'build'
5796
+ ];
5797
+ return [
5798
+ ...base,
5754
5799
  'CODE_SIGN_IDENTITY=-',
5755
5800
  'CODE_SIGNING_REQUIRED=NO',
5756
5801
  'CODE_SIGNING_ALLOWED=YES',
@@ -8353,7 +8398,7 @@ Cross-browser compatibility
8353
8398
  return null;
8354
8399
  }
8355
8400
  function registerBuildCommand(program) {
8356
- program.command('build').arguments('[project-name]').usage('[path-to-remote-extension] [options]').description(commandDescriptions.build).option(`--browser <${BROWSER_TARGETS_HELP}>`, 'specify a browser/engine to run. Defaults to `chromium`. `safari` builds a Safari app via Xcode (macOS only)').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `false`', parseOptionalBoolean).option('--no-polyfill', 'disable the cross-browser polyfill').option('--zip [boolean]', 'whether or not to compress the extension into a ZIP file. Defaults to `false`', parseOptionalBoolean).option('--zip-source [boolean]', 'whether or not to include the source files in the ZIP file. Defaults to `false`', parseOptionalBoolean).option('--zip-filename <string>', 'specify the name of the ZIP file. Defaults to the extension name and version').option('--silent [boolean]', 'suppress the build summary output. Defaults to `false`', parseOptionalBoolean).option('--install [boolean]', '[internal] install project dependencies when missing', parseOptionalBoolean).option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--mode <development|production|none>', 'bundler mode override (also sets NODE_ENV). Defaults to `production`').option('--open [boolean]', 'open the built Safari app after packaging (safari targets only). Defaults to `false`', parseOptionalBoolean).option('--app-name <name>', 'override the Safari app name (safari targets only). Defaults to the manifest `name`').option('--bundle-id <reverse.dns>', 'set a user-owned Safari bundle identifier (safari targets only). Defaults to a generated dev.extensionjs.* id').option('--macos-only [boolean]', 'generate a macOS-only Safari Xcode project (safari targets only). Pass `false` for a universal macOS + iOS project. Defaults to `true`', parseOptionalBoolean).option('--force-regenerate', 'regenerate the Safari Xcode project even when up to date (safari targets only)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addOption(new external_commander_namespaceObject.Option('--debug', 'print maintainer diagnostics alongside normal output')).addOption(new external_commander_namespaceObject.Option('--author, --author-mode', 'deprecated alias for --debug').hideHelp()).action(async (pathOrRemoteUrl, { browser = 'chromium', ...buildOptions })=>{
8401
+ program.command('build').arguments('[project-name]').usage('[path-to-remote-extension] [options]').description(commandDescriptions.build).option(`--browser <${BROWSER_TARGETS_HELP}>`, 'specify a browser/engine to run. Defaults to `chromium`. `safari` builds a Safari app via Xcode (macOS only)').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `false`', parseOptionalBoolean).option('--no-polyfill', 'disable the cross-browser polyfill').option('--zip [boolean]', 'whether or not to compress the extension into a ZIP file. Defaults to `false`', parseOptionalBoolean).option('--zip-source [boolean]', 'whether or not to include the source files in the ZIP file. Defaults to `false`', parseOptionalBoolean).option('--zip-filename <string>', 'specify the name of the ZIP file. Defaults to the extension name and version').option('--silent [boolean]', 'suppress the build summary output. Defaults to `false`', parseOptionalBoolean).option('--install [boolean]', '[internal] install project dependencies when missing', parseOptionalBoolean).option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--mode <development|production|none>', 'bundler mode override (also sets NODE_ENV). Defaults to `production`').option('--open [boolean]', 'open the built Safari app after packaging (safari targets only). Defaults to `false`', parseOptionalBoolean).option('--app-name <name>', 'override the Safari app name (safari targets only). Defaults to the manifest `name`').option('--bundle-id <reverse.dns>', 'set a user-owned Safari bundle identifier (safari targets only). Defaults to a generated dev.extensionjs.* id').option('--development-team <id>', 'sign the Safari app with an Apple Developer team id (safari targets only). Without it the build is ad-hoc signed, which Safari treats as unsigned: the extension then needs Develop \u25b8 Allow Unsigned Extensions re-ticked on every launch. A signed build is listed and stays enabled across restarts').option('--macos-only [boolean]', 'generate a macOS-only Safari Xcode project (safari targets only). Pass `false` for a universal macOS + iOS project. Defaults to `true`', parseOptionalBoolean).option('--force-regenerate', 'regenerate the Safari Xcode project even when up to date (safari targets only)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addOption(new external_commander_namespaceObject.Option('--debug', 'print maintainer diagnostics alongside normal output')).addOption(new external_commander_namespaceObject.Option('--author, --author-mode', 'deprecated alias for --debug').hideHelp()).action(async (pathOrRemoteUrl, { browser = 'chromium', ...buildOptions })=>{
8357
8402
  if (buildOptions.debug || buildOptions.author || buildOptions.authorMode) {
8358
8403
  process.env.EXTENSION_DEBUG = '1';
8359
8404
  process.env.EXTENSION_AUTHOR_MODE = 'true';
@@ -8386,6 +8431,10 @@ Cross-browser compatibility
8386
8431
  '--bundle-id',
8387
8432
  buildOptions.bundleId
8388
8433
  ],
8434
+ [
8435
+ '--development-team',
8436
+ buildOptions.developmentTeam
8437
+ ],
8389
8438
  [
8390
8439
  '--force-regenerate',
8391
8440
  buildOptions.forceRegenerate
@@ -8431,6 +8480,7 @@ Cross-browser compatibility
8431
8480
  mode,
8432
8481
  appName: buildOptions.appName,
8433
8482
  bundleId: buildOptions.bundleId,
8483
+ developmentTeam: buildOptions.developmentTeam,
8434
8484
  macOsOnly: buildOptions.macosOnly,
8435
8485
  forceRegenerate: buildOptions.forceRegenerate,
8436
8486
  safariPackager: safariPackagingEnabled ? (0, safari_packager.P)({
@@ -8940,7 +8990,7 @@ Cross-browser compatibility
8940
8990
  return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : 8080;
8941
8991
  }
8942
8992
  function registerDevCommand(program) {
8943
- program.command('dev').arguments('[project-path|remote-url]').usage('[project-path|remote-url] [options]').description(commandDescriptions.dev).addHelpText('after', "\nAdditional options:\n --no-browser do not launch the browser (dev server still starts)\n --no-reload emit a dev-mode dist without the content-script reload runtime; tabs need manual reload to see changes\n --wait wait for ready contract and exit; pair with --output json for machine output\n").option('--profile <path-to-file | boolean>', 'what path to use for the browser profile. A boolean value of false sets the profile to the default user profile. Defaults to a fresh profile').option(`-b, --browser <${BROWSER_TARGETS_HELP}>`, 'specify a browser/engine to run. Defaults to `chromium`. `safari` builds and opens a Safari app via Xcode (macOS only; no live reload)').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').option('--gecko-binary, --firefox-binary <path-to-binary>', 'specify a path to the Gecko binary. This option overrides the --browser setting. Defaults to the system default').option('--safari-binary <path-to-binary>', 'specify the Safari binary to open after packaging (safari targets only)').option('--app-name <name>', 'override the Safari app name (safari targets only). Defaults to the manifest `name`').option('--bundle-id <reverse.dns>', 'set a user-owned Safari bundle identifier (safari targets only). Defaults to a generated dev.extensionjs.* id').option('--macos-only [boolean]', 'generate a macOS-only Safari Xcode project (safari targets only). Pass `false` for a universal macOS + iOS project. Defaults to `true`', parseOptionalBoolean).option('--force-regenerate', 'regenerate the Safari Xcode project even when up to date (safari targets only)').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `true`', parseOptionalBoolean).option('--no-polyfill', 'disable the cross-browser polyfill').option('--no-open', 'do not open the browser automatically (default: open)').option('--starting-url <url>', 'specify the starting URL for the browser. Defaults to `undefined`').option('--port <port>', 'specify the port to use for the development server. Defaults to `8080`').option('--host <host>', 'specify the host to bind the dev server to. Use 0.0.0.0 for Docker/devcontainers. Defaults to `127.0.0.1`').option('--public-host <host>', 'connectable host the browser (HMR + reload bridge) dials when it differs from the bind host (e.g. a remote/devcontainer). Defaults to the bind host, or 127.0.0.1 when bound to 0.0.0.0').option('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). Use `all` to include all contexts (default)').option('--logs <off|error|warn|info|debug|trace|all>', '[experimental] minimum centralized logger level to display in terminal (default: off)').option('--log-format <pretty|json|ndjson>', '[experimental] output format for logger events. Defaults to `pretty`').option('--no-log-timestamps', 'disable ISO timestamps in pretty output').option('--no-log-color', 'disable color in pretty output').option('--log-url <pattern>', '[experimental] only show logs where event.url matches this substring or regex (/re/i)').option('--log-tab <id>', 'only show logs for a specific tabId (number)').option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--install [boolean]', '[internal] install project dependencies when missing', parseOptionalBoolean).option('--wait [boolean]', 'wait for dist/extension-js/<browser>/ready.json and exit', parseOptionalBoolean).option('--wait-timeout <ms>', 'timeout in milliseconds when using --wait (default: 60000)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addOption(new external_commander_namespaceObject.Option('--wait-format <pretty|json>').hideHelp()).addOption(new external_commander_namespaceObject.Option('--debug', 'print maintainer diagnostics alongside normal output')).addOption(new external_commander_namespaceObject.Option('--author, --author-mode', 'deprecated alias for --debug').hideHelp()).option('--allow-control', 'enable the agent-bridge control channel for bounded act (storage/reload/open): see `extension reload|storage|open`').option('--allow-eval', 'additionally enable `extension eval` (implies --allow-control, runs arbitrary code in a context, writes a 0600 session token)').option('--parent-pid <pid>', 'exit when the given process dies. For wrappers that spawn `extension dev`, so a leaked dev server can never outlive its owner').action(async (pathOrRemoteUrl, options, command)=>{
8993
+ program.command('dev').arguments('[project-path|remote-url]').usage('[project-path|remote-url] [options]').description(commandDescriptions.dev).addHelpText('after', "\nAdditional options:\n --no-browser do not launch the browser (dev server still starts)\n --no-reload emit a dev-mode dist without the content-script reload runtime; tabs need manual reload to see changes\n --wait wait for ready contract and exit; pair with --output json for machine output\n").option('--profile <path-to-file | boolean>', 'what path to use for the browser profile. A boolean value of false sets the profile to the default user profile. Defaults to a fresh profile').option(`-b, --browser <${BROWSER_TARGETS_HELP}>`, 'specify a browser/engine to run. Defaults to `chromium`. `safari` builds and opens a Safari app via Xcode (macOS only; no live reload)').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').option('--gecko-binary, --firefox-binary <path-to-binary>', 'specify a path to the Gecko binary. This option overrides the --browser setting. Defaults to the system default').option('--safari-binary <path-to-binary>', 'specify the Safari binary to open after packaging (safari targets only)').option('--app-name <name>', 'override the Safari app name (safari targets only). Defaults to the manifest `name`').option('--bundle-id <reverse.dns>', 'set a user-owned Safari bundle identifier (safari targets only). Defaults to a generated dev.extensionjs.* id').option('--development-team <id>', 'sign the Safari app with an Apple Developer team id (safari targets only). Without it the build is ad-hoc signed, which Safari treats as unsigned: the extension then needs Develop \u25b8 Allow Unsigned Extensions re-ticked on every launch. A signed build is listed and stays enabled across restarts').option('--macos-only [boolean]', 'generate a macOS-only Safari Xcode project (safari targets only). Pass `false` for a universal macOS + iOS project. Defaults to `true`', parseOptionalBoolean).option('--force-regenerate', 'regenerate the Safari Xcode project even when up to date (safari targets only)').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `true`', parseOptionalBoolean).option('--no-polyfill', 'disable the cross-browser polyfill').option('--no-open', 'do not open the browser automatically (default: open)').option('--starting-url <url>', 'specify the starting URL for the browser. Defaults to `undefined`').option('--port <port>', 'specify the port to use for the development server. Defaults to `8080`').option('--host <host>', 'specify the host to bind the dev server to. Use 0.0.0.0 for Docker/devcontainers. Defaults to `127.0.0.1`').option('--public-host <host>', 'connectable host the browser (HMR + reload bridge) dials when it differs from the bind host (e.g. a remote/devcontainer). Defaults to the bind host, or 127.0.0.1 when bound to 0.0.0.0').option('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). Use `all` to include all contexts (default)').option('--logs <off|error|warn|info|debug|trace|all>', '[experimental] minimum centralized logger level to display in terminal (default: off)').option('--log-format <pretty|json|ndjson>', '[experimental] output format for logger events. Defaults to `pretty`').option('--no-log-timestamps', 'disable ISO timestamps in pretty output').option('--no-log-color', 'disable color in pretty output').option('--log-url <pattern>', '[experimental] only show logs where event.url matches this substring or regex (/re/i)').option('--log-tab <id>', 'only show logs for a specific tabId (number)').option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--install [boolean]', '[internal] install project dependencies when missing', parseOptionalBoolean).option('--wait [boolean]', 'wait for dist/extension-js/<browser>/ready.json and exit', parseOptionalBoolean).option('--wait-timeout <ms>', 'timeout in milliseconds when using --wait (default: 60000)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addOption(new external_commander_namespaceObject.Option('--wait-format <pretty|json>').hideHelp()).addOption(new external_commander_namespaceObject.Option('--debug', 'print maintainer diagnostics alongside normal output')).addOption(new external_commander_namespaceObject.Option('--author, --author-mode', 'deprecated alias for --debug').hideHelp()).option('--allow-control', 'enable the agent-bridge control channel for bounded act (storage/reload/open): see `extension reload|storage|open`').option('--allow-eval', 'additionally enable `extension eval` (implies --allow-control, runs arbitrary code in a context, writes a 0600 session token)').option('--parent-pid <pid>', 'exit when the given process dies. For wrappers that spawn `extension dev`, so a leaked dev server can never outlive its owner').action(async (pathOrRemoteUrl, options, command)=>{
8944
8994
  const { browser = 'chromium', ...devOptions } = options;
8945
8995
  if (devOptions.debug || devOptions.author || devOptions.authorMode) {
8946
8996
  process.env.EXTENSION_DEBUG = '1';
@@ -8984,6 +9034,10 @@ Cross-browser compatibility
8984
9034
  '--bundle-id',
8985
9035
  opts.bundleId
8986
9036
  ],
9037
+ [
9038
+ '--development-team',
9039
+ opts.developmentTeam
9040
+ ],
8987
9041
  [
8988
9042
  '--force-regenerate',
8989
9043
  opts.forceRegenerate
@@ -72,11 +72,11 @@ export declare function safariOpening(target: string): string;
72
72
  export declare function safariToolFailed(tool: string, exitCode: number | null, outputTail: string): string;
73
73
  export declare function safariConverterWarnings(warnings: string[]): string;
74
74
  export declare function safariDefaultBundleIdNote(bundleId: string): string;
75
- export declare function safariOpenHint(appPath: string, appName: string): string;
75
+ export declare function safariOpenHint(appPath: string, appName: string, signed?: boolean): string;
76
76
  export declare function safariDryRunNotBuilding(): string;
77
77
  export declare function safariDryRunConverter(cmd: string): string;
78
78
  export declare function safariDryRunXcodebuild(cmd: string): string;
79
- export declare function safariNextSteps(appName: string): string;
79
+ export declare function safariNextSteps(appName: string, signed?: boolean): string;
80
80
  export declare function safariRegistered(appName: string): string;
81
81
  export declare function safariNotYetRegistered(appName: string): string;
82
82
  export declare function safariRebuilt(appName: string): string;
@@ -2,6 +2,7 @@ import type { PluginInterface } from '../browsers-types';
2
2
  export type SafariPluginLike = Pick<PluginInterface, 'extension' | 'noOpen' | 'instanceId' | 'dryRun'> & {
3
3
  browser: PluginInterface['browser'];
4
4
  safariBinary?: string;
5
+ developmentTeam?: string;
5
6
  appName?: string;
6
7
  bundleId?: string;
7
8
  macOsOnly?: boolean;
@@ -19,4 +20,5 @@ export interface SafariBuildConfig {
19
20
  language: 'swift' | 'objc';
20
21
  open: boolean;
21
22
  safariBinary?: string;
23
+ developmentTeam?: string;
22
24
  }
package/package.json CHANGED
@@ -38,7 +38,7 @@
38
38
  "extension": "./bin/extension.cjs"
39
39
  },
40
40
  "name": "extension",
41
- "version": "4.1.1",
41
+ "version": "4.1.2",
42
42
  "description": "The cross-browser extension framework. Build Chrome, Edge, Firefox, and Safari extensions with no build configuration.",
43
43
  "homepage": "https://extension.js.org/",
44
44
  "bugs": {
@@ -106,9 +106,9 @@
106
106
  "vivaldi-location2": "2.1.1",
107
107
  "waterfox-location": "2.1.1",
108
108
  "yandex-location": "2.1.1",
109
- "extension-create": "4.1.1",
110
- "extension-develop": "4.1.1",
111
- "extension-install": "4.1.1",
109
+ "extension-create": "4.1.2",
110
+ "extension-develop": "4.1.2",
111
+ "extension-install": "4.1.2",
112
112
  "commander": "^15.0.0",
113
113
  "pintor": "0.3.0",
114
114
  "semver": "^7.7.3",