extension 4.1.20 → 4.1.22
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 +18 -16
- package/dist/{84.cjs → 597.cjs} +80 -2
- package/dist/browsers.cjs +408 -103
- package/dist/cli.cjs +558 -148
- package/dist/extension/browsers/__spec__/safari-fake-tools.d.ts +27 -0
- package/dist/extension/browsers/browsers-lib/messages.d.ts +2 -1
- package/dist/extension/browsers/browsers-lib/process-teardown.d.ts +3 -0
- package/dist/extension/browsers/browsers-lib/ready-stamp.d.ts +1 -0
- package/dist/extension/browsers/browsers-lib/resolve-live-pid.d.ts +25 -0
- package/dist/extension/browsers/browsers-lib/write-json-atomic.d.ts +1 -0
- package/dist/extension/browsers/browsers-types.d.ts +1 -1
- package/dist/extension/browsers/index.d.ts +1 -1
- package/dist/extension/browsers/run-chromium/cdp/cdp-extension-controller/index.d.ts +2 -0
- package/dist/extension/browsers/run-chromium/cdp/ensure-developer-mode.d.ts +12 -0
- package/dist/extension/browsers/run-firefox/firefox-launch/index.d.ts +9 -0
- package/dist/extension/browsers/run-firefox/firefox-launch/process-handlers.d.ts +1 -1
- package/dist/extension/browsers/run-safari/safari-launch/index.d.ts +1 -1
- package/dist/extension/browsers/run-safari/safari-launch/tools.d.ts +17 -0
- package/dist/extension/browsers/run-safari/safari-packager.d.ts +2 -1
- package/dist/extension/browsers/run-safari/safari-types.d.ts +2 -0
- package/dist/extension/config-types.d.ts +5 -2
- package/dist/extension/helpers/messages.d.ts +7 -0
- package/dist/extension/helpers/messaging.d.ts +1 -0
- package/dist/extension/helpers/node-version-guard.d.ts +3 -1
- package/dist/extension/helpers/template-catalog.d.ts +1 -1
- package/dist/extension/helpers/template-corpus.generated.d.ts +1 -1
- package/package.json +5 -7
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=
|
|
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] [![
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 → 597.cjs}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
exports.ids = [
|
|
3
|
-
|
|
3
|
+
597
|
|
4
4
|
];
|
|
5
5
|
exports.modules = {
|
|
6
6
|
"./browsers/run-chromium/cdp/cdp-extension-controller/ensure.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
@@ -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");
|
|
@@ -482,6 +483,73 @@ exports.modules = {
|
|
|
482
483
|
this.host = host;
|
|
483
484
|
}
|
|
484
485
|
}
|
|
486
|
+
const EXTENSIONS_PAGE = 'chrome://extensions';
|
|
487
|
+
const READ_DEVELOPER_MODE = "new Promise((resolve) => chrome.developerPrivate.getProfileConfiguration((config) => resolve(!!config.inDeveloperMode)))";
|
|
488
|
+
const ENABLE_DEVELOPER_MODE = "new Promise((resolve) => chrome.developerPrivate.updateProfileConfiguration({inDeveloperMode: true}, () => resolve(!chrome.runtime.lastError)))";
|
|
489
|
+
function developerModeFromProfile(profilePath) {
|
|
490
|
+
try {
|
|
491
|
+
const securePath = external_node_path_.join(profilePath, 'Default', 'Secure Preferences');
|
|
492
|
+
const parsed = JSON.parse(external_node_fs_.readFileSync(securePath, 'utf-8'));
|
|
493
|
+
return parsed?.extensions?.ui?.developer_mode === true;
|
|
494
|
+
} catch {
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
function developerModeFlipIsSafe(browserArgs) {
|
|
499
|
+
return !browserArgs.some((arg)=>arg.startsWith('--no-startup-window'));
|
|
500
|
+
}
|
|
501
|
+
async function evaluateBoolean(transport, sessionId, expression) {
|
|
502
|
+
try {
|
|
503
|
+
const response = await transport.sendCommand('Runtime.evaluate', {
|
|
504
|
+
expression,
|
|
505
|
+
awaitPromise: true,
|
|
506
|
+
returnByValue: true
|
|
507
|
+
}, sessionId);
|
|
508
|
+
const value = response?.result?.value;
|
|
509
|
+
return 'boolean' == typeof value ? value : void 0;
|
|
510
|
+
} catch {
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
async function ensureDeveloperMode(options) {
|
|
515
|
+
const { transport } = options;
|
|
516
|
+
const attempts = options.attempts ?? 10;
|
|
517
|
+
const delayMs = options.delayMs ?? 200;
|
|
518
|
+
const sleep = options.sleep ?? ((ms)=>new Promise((r)=>setTimeout(r, ms)));
|
|
519
|
+
let targetId = '';
|
|
520
|
+
try {
|
|
521
|
+
const created = await transport.sendCommand('Target.createTarget', {
|
|
522
|
+
url: EXTENSIONS_PAGE,
|
|
523
|
+
background: true
|
|
524
|
+
});
|
|
525
|
+
targetId = created?.targetId ?? '';
|
|
526
|
+
if (!targetId) return 'unavailable';
|
|
527
|
+
const attached = await transport.sendCommand('Target.attachToTarget', {
|
|
528
|
+
targetId,
|
|
529
|
+
flatten: true
|
|
530
|
+
});
|
|
531
|
+
const sessionId = attached?.sessionId ?? '';
|
|
532
|
+
if (!sessionId) return 'unavailable';
|
|
533
|
+
for(let attempt = 0; attempt < attempts; attempt++){
|
|
534
|
+
const current = await evaluateBoolean(transport, sessionId, READ_DEVELOPER_MODE);
|
|
535
|
+
if (true === current) return 'already-on';
|
|
536
|
+
if (false === current) {
|
|
537
|
+
const enabled = await evaluateBoolean(transport, sessionId, ENABLE_DEVELOPER_MODE);
|
|
538
|
+
return true === enabled ? 'enabled' : 'unavailable';
|
|
539
|
+
}
|
|
540
|
+
await sleep(delayMs);
|
|
541
|
+
}
|
|
542
|
+
return 'unavailable';
|
|
543
|
+
} catch {
|
|
544
|
+
return 'unavailable';
|
|
545
|
+
} finally{
|
|
546
|
+
if (targetId) try {
|
|
547
|
+
await transport.sendCommand('Target.closeTarget', {
|
|
548
|
+
targetId
|
|
549
|
+
});
|
|
550
|
+
} catch {}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
485
553
|
function isRecoverableBootstrapError(error) {
|
|
486
554
|
const msg = String(error?.message || error || '').toLowerCase();
|
|
487
555
|
return msg.includes('econnreset') || msg.includes('websocket is not open') || msg.includes('cdp transport is not open') || msg.includes('cdp connection closed') || msg.includes('cdp pipe closed') || msg.includes('socket hang up') || msg.includes('timed out') || msg.includes('no cdp websocket url');
|
|
@@ -783,6 +851,12 @@ exports.modules = {
|
|
|
783
851
|
if (this.cdp) return;
|
|
784
852
|
await this.connectFreshClient();
|
|
785
853
|
}
|
|
854
|
+
async ensureDeveloperMode() {
|
|
855
|
+
if (!this.cdp) return 'unavailable';
|
|
856
|
+
return ensureDeveloperMode({
|
|
857
|
+
transport: this.cdp
|
|
858
|
+
});
|
|
859
|
+
}
|
|
786
860
|
async openTab(url) {
|
|
787
861
|
if (!this.cdp) return;
|
|
788
862
|
await this.cdp.sendCommand('Target.createTarget', {
|
|
@@ -1109,6 +1183,10 @@ exports.modules = {
|
|
|
1109
1183
|
});
|
|
1110
1184
|
await cdpExtensionController.connect();
|
|
1111
1185
|
if ((0, messaging._o)()) (0, messaging._w)(messages.M3('127.0.0.1', chromeRemoteDebugPort));
|
|
1186
|
+
if (userDataDir && developerModeFlipIsSafe(chromiumArgs) && !developerModeFromProfile(userDataDir)) {
|
|
1187
|
+
const developerMode = await cdpExtensionController.ensureDeveloperMode();
|
|
1188
|
+
if ((0, messaging._o)()) (0, messaging._w)(`[CDP] developer mode: ${developerMode}`);
|
|
1189
|
+
}
|
|
1112
1190
|
try {
|
|
1113
1191
|
if (extensionOutputPath && Number.isFinite(chromeRemoteDebugPort)) {
|
|
1114
1192
|
const readyPath = external_node_path_.join(external_node_path_.dirname(extensionOutputPath), 'extension-js', external_node_path_.basename(extensionOutputPath), 'ready.json');
|
|
@@ -1116,7 +1194,7 @@ exports.modules = {
|
|
|
1116
1194
|
const ready = JSON.parse(external_node_fs_.readFileSync(readyPath, 'utf-8'));
|
|
1117
1195
|
if (ready.cdpPort !== chromeRemoteDebugPort) {
|
|
1118
1196
|
ready.cdpPort = chromeRemoteDebugPort;
|
|
1119
|
-
|
|
1197
|
+
(0, write_json_atomic.Z)(readyPath, ready);
|
|
1120
1198
|
}
|
|
1121
1199
|
}
|
|
1122
1200
|
}
|