extension 4.1.1 → 4.1.3
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 +6 -6
- package/dist/browsers.cjs +53 -8
- package/dist/cli.cjs +67 -11
- package/dist/extension/browsers/browsers-lib/messages.d.ts +2 -2
- package/dist/extension/browsers/run-safari/safari-types.d.ts +2 -0
- package/dist/extension/helpers/template-catalog.d.ts +1 -1
- package/dist/extension/helpers/template-corpus.generated.d.ts +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
[npm-version-image]: https://img.shields.io/npm/v/extension.svg?color=0971fe
|
|
2
2
|
[npm-version-url]: https://www.npmjs.com/package/extension
|
|
3
|
-
[npm-downloads-image]: https://img.shields.io/npm/dm/extension.svg?color=0971fe
|
|
4
|
-
[npm-downloads-url]: https://www.npmjs.com/package/extension
|
|
5
3
|
[stars-image]: https://img.shields.io/github/stars/extension-js/extension.js?style=flat&color=0971fe
|
|
6
4
|
[stars-url]: https://github.com/extension-js/extension.js/stargazers
|
|
7
5
|
[action-image]: https://github.com/extension-js/extension.js/actions/workflows/ci.yml/badge.svg?branch=main&color=0971fe
|
|
@@ -11,7 +9,7 @@
|
|
|
11
9
|
[snyk-image]: https://snyk.io/test/github/extension-js/extension.js/badge.svg?color=0971fe
|
|
12
10
|
[snyk-url]: https://snyk.io/test/github/extension-js/extension.js
|
|
13
11
|
|
|
14
|
-
# Extension.js [![Version][npm-version-image]][npm-version-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]
|
|
15
13
|
|
|
16
14
|
> The cross-browser extension framework. Build for Chrome, Edge, Firefox, and Safari with no build config required.
|
|
17
15
|
|
|
@@ -41,7 +39,7 @@ Browser extensions ship with the worst dev experience in modern web. Manifest V3
|
|
|
41
39
|
|
|
42
40
|
## Watch it work
|
|
43
41
|
|
|
44
|
-
[](https://extension.js.org/docs)
|
|
45
43
|
|
|
46
44
|
Or skip the install and try a [live template](https://templates.extension.dev) in your browser.
|
|
47
45
|
|
|
@@ -96,7 +94,7 @@ npx extension@latest dev --gecko-binary "/Applications/Firefox.app/Contents/MacO
|
|
|
96
94
|
|
|
97
95
|
| <img alt="Chrome" src="https://media.extension.land/logos/browsers/chrome.svg" width="70"> | <img alt="Edge" src="https://media.extension.land/logos/browsers/edge.svg" width="70"> | <img alt="Firefox" src="https://media.extension.land/logos/browsers/firefox.svg" width="70"> | <img alt="Safari" src="https://media.extension.land/logos/browsers/safari.svg" width="70"> | <img alt="Chromium" src="https://media.extension.land/logos/browsers/chromium.svg" width="70"> | <img alt="Gecko" src="https://media.extension.land/logos/browsers/firefox.svg" width="70"> |
|
|
98
96
|
| :-: | :-: | :-: | :-: | :-: | :-: |
|
|
99
|
-
| Google Chrome<br>✅ Supported | Microsoft Edge<br>✅ Supported | Mozilla Firefox<br>✅ Supported | Apple Safari<br>✅ Supported | Chromium-based<br>✅ Supported | Gecko-based<br>✅ Supported |
|
|
97
|
+
| <sup>Google Chrome<br>✅ Supported</sup> | <sup>Microsoft Edge<br>✅ Supported</sup> | <sup>Mozilla Firefox<br>✅ Supported</sup> | <sup>Apple Safari<br>✅ Supported</sup> | <sup>Chromium-based<br>✅ Supported</sup> | <sup>Gecko-based<br>✅ Supported</sup> |
|
|
100
98
|
|
|
101
99
|
</div>
|
|
102
100
|
|
|
@@ -155,10 +153,12 @@ npm install extension@latest --save-dev
|
|
|
155
153
|
}
|
|
156
154
|
```
|
|
157
155
|
|
|
158
|
-
Run `npm run dev` to develop,
|
|
156
|
+
Run `npm run dev` to develop, and watch the browser open with your extension already loaded:
|
|
159
157
|
|
|
160
158
|
[](https://extension.js.org/docs/commands/dev)
|
|
161
159
|
|
|
160
|
+
Use `npm run build` for production, and `npm run preview` to inspect the production output.
|
|
161
|
+
|
|
162
162
|
## Start from a Chrome sample
|
|
163
163
|
|
|
164
164
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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',
|
|
@@ -6824,7 +6869,7 @@ var __webpack_modules__ = {
|
|
|
6824
6869
|
}
|
|
6825
6870
|
var messaging = __webpack_require__("./helpers/messaging.ts");
|
|
6826
6871
|
const TEMPLATE_CORPUS_REPO = 'extension-js/examples';
|
|
6827
|
-
const TEMPLATE_CORPUS_REF = '
|
|
6872
|
+
const TEMPLATE_CORPUS_REF = '36cd41466038e3d1045e3eca368f44f40b0a024b';
|
|
6828
6873
|
const TEMPLATE_CORPUS_SLUGS = [
|
|
6829
6874
|
'action',
|
|
6830
6875
|
'action-locales',
|
|
@@ -6870,6 +6915,7 @@ var __webpack_modules__ = {
|
|
|
6870
6915
|
'react',
|
|
6871
6916
|
'sidebar',
|
|
6872
6917
|
'sidebar-antd',
|
|
6918
|
+
'sidebar-monorepo-nx',
|
|
6873
6919
|
'sidebar-monorepo-turborepo',
|
|
6874
6920
|
'sidebar-shadcn',
|
|
6875
6921
|
'special-folders-pages',
|
|
@@ -6906,6 +6952,7 @@ var __webpack_modules__ = {
|
|
|
6906
6952
|
'sidebar-antd',
|
|
6907
6953
|
'sidebar-shadcn',
|
|
6908
6954
|
'sidebar-monorepo-turborepo',
|
|
6955
|
+
'sidebar-monorepo-nx',
|
|
6909
6956
|
'ai-chatgpt',
|
|
6910
6957
|
'ai-claude',
|
|
6911
6958
|
'ai-gemini',
|
|
@@ -8353,7 +8400,7 @@ Cross-browser compatibility
|
|
|
8353
8400
|
return null;
|
|
8354
8401
|
}
|
|
8355
8402
|
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 })=>{
|
|
8403
|
+
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
8404
|
if (buildOptions.debug || buildOptions.author || buildOptions.authorMode) {
|
|
8358
8405
|
process.env.EXTENSION_DEBUG = '1';
|
|
8359
8406
|
process.env.EXTENSION_AUTHOR_MODE = 'true';
|
|
@@ -8386,6 +8433,10 @@ Cross-browser compatibility
|
|
|
8386
8433
|
'--bundle-id',
|
|
8387
8434
|
buildOptions.bundleId
|
|
8388
8435
|
],
|
|
8436
|
+
[
|
|
8437
|
+
'--development-team',
|
|
8438
|
+
buildOptions.developmentTeam
|
|
8439
|
+
],
|
|
8389
8440
|
[
|
|
8390
8441
|
'--force-regenerate',
|
|
8391
8442
|
buildOptions.forceRegenerate
|
|
@@ -8431,6 +8482,7 @@ Cross-browser compatibility
|
|
|
8431
8482
|
mode,
|
|
8432
8483
|
appName: buildOptions.appName,
|
|
8433
8484
|
bundleId: buildOptions.bundleId,
|
|
8485
|
+
developmentTeam: buildOptions.developmentTeam,
|
|
8434
8486
|
macOsOnly: buildOptions.macosOnly,
|
|
8435
8487
|
forceRegenerate: buildOptions.forceRegenerate,
|
|
8436
8488
|
safariPackager: safariPackagingEnabled ? (0, safari_packager.P)({
|
|
@@ -8940,7 +8992,7 @@ Cross-browser compatibility
|
|
|
8940
8992
|
return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : 8080;
|
|
8941
8993
|
}
|
|
8942
8994
|
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)=>{
|
|
8995
|
+
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
8996
|
const { browser = 'chromium', ...devOptions } = options;
|
|
8945
8997
|
if (devOptions.debug || devOptions.author || devOptions.authorMode) {
|
|
8946
8998
|
process.env.EXTENSION_DEBUG = '1';
|
|
@@ -8984,6 +9036,10 @@ Cross-browser compatibility
|
|
|
8984
9036
|
'--bundle-id',
|
|
8985
9037
|
opts.bundleId
|
|
8986
9038
|
],
|
|
9039
|
+
[
|
|
9040
|
+
'--development-team',
|
|
9041
|
+
opts.developmentTeam
|
|
9042
|
+
],
|
|
8987
9043
|
[
|
|
8988
9044
|
'--force-regenerate',
|
|
8989
9045
|
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
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const DEFAULT_TEMPLATE = "javascript";
|
|
2
2
|
export declare const BUNDLED_TEMPLATES: readonly string[];
|
|
3
|
-
export declare const TEMPLATE_CATALOG_URL = "https://github.com/extension-js/examples/tree/
|
|
3
|
+
export declare const TEMPLATE_CATALOG_URL = "https://github.com/extension-js/examples/tree/36cd41466038e3d1045e3eca368f44f40b0a024b/examples";
|
|
4
4
|
export interface TemplateGroup {
|
|
5
5
|
title: string;
|
|
6
6
|
summary: string;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export declare const TEMPLATE_CORPUS_REPO = "extension-js/examples";
|
|
2
|
-
export declare const TEMPLATE_CORPUS_REF = "
|
|
2
|
+
export declare const TEMPLATE_CORPUS_REF = "36cd41466038e3d1045e3eca368f44f40b0a024b";
|
|
3
3
|
export declare const TEMPLATE_CORPUS_SLUGS: readonly string[];
|
package/package.json
CHANGED
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"extension": "./bin/extension.cjs"
|
|
39
39
|
},
|
|
40
40
|
"name": "extension",
|
|
41
|
-
"version": "4.1.
|
|
41
|
+
"version": "4.1.3",
|
|
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.
|
|
110
|
-
"extension-develop": "4.1.
|
|
111
|
-
"extension-install": "4.1.
|
|
109
|
+
"extension-create": "4.1.3",
|
|
110
|
+
"extension-develop": "4.1.3",
|
|
111
|
+
"extension-install": "4.1.3",
|
|
112
112
|
"commander": "^15.0.0",
|
|
113
113
|
"pintor": "0.3.0",
|
|
114
114
|
"semver": "^7.7.3",
|