extension 3.7.0 → 3.8.0
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 +39 -0
- package/dist/cli-lib/messages.d.ts +3 -1
- package/dist/cli.cjs +153 -3
- package/dist/commands/install.d.ts +2 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -137,6 +137,45 @@ npx extension@latest dev --chromium-binary "/Applications/Google Chrome.app/Cont
|
|
|
137
137
|
npx extension@latest dev --gecko-binary "/Applications/Firefox.app/Contents/MacOS/firefox"
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
+
### Managed browser binaries
|
|
141
|
+
|
|
142
|
+
Use Extension.js commands to install/remove managed browser binaries:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# Install into Extension.js managed cache
|
|
146
|
+
npx extension@latest install --browser=chromium
|
|
147
|
+
npx extension@latest install --browser=firefox
|
|
148
|
+
|
|
149
|
+
# Show managed cache root
|
|
150
|
+
npx extension@latest install --where
|
|
151
|
+
|
|
152
|
+
# Show managed path for a specific browser
|
|
153
|
+
npx extension@latest install --where --browser=firefox
|
|
154
|
+
|
|
155
|
+
# Remove one browser binary
|
|
156
|
+
npx extension@latest uninstall chromium
|
|
157
|
+
|
|
158
|
+
# Remove all managed browser binaries
|
|
159
|
+
npx extension@latest uninstall --all
|
|
160
|
+
|
|
161
|
+
# Show managed cache root
|
|
162
|
+
npx extension@latest uninstall --where
|
|
163
|
+
|
|
164
|
+
# Show managed path(s) for target browser(s)
|
|
165
|
+
npx extension@latest uninstall --where --browser=chromium
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`uninstall` only removes binaries from the Extension.js managed cache root (or `EXT_BROWSERS_CACHE_DIR` when set). It does not remove browser installations that were installed elsewhere (for example, system browsers or custom paths outside the managed cache).
|
|
169
|
+
|
|
170
|
+
`edge` note for Linux: Playwright channel installs may require a privileged interactive session (`sudo` prompt). If channel install cannot proceed but a system Edge binary is already present, Extension.js will use that existing binary. Otherwise, install Edge system-wide first and then run Extension.js with `--browser=edge` (or use `chromium`).
|
|
171
|
+
|
|
172
|
+
Default managed cache locations are stable and human-readable:
|
|
173
|
+
- macOS: `~/Library/Caches/extension.js/browsers`
|
|
174
|
+
- Linux: `~/.cache/extension.js/browsers` (or `$XDG_CACHE_HOME/extension.js/browsers`)
|
|
175
|
+
- Windows: `%LOCALAPPDATA%\\extension.js\\browsers`
|
|
176
|
+
|
|
177
|
+
If you want a custom path, set `EXT_BROWSERS_CACHE_DIR` to a clean location (for example, `EXT_BROWSERS_CACHE_DIR=/tmp/extension.js/browsers-dev`).
|
|
178
|
+
|
|
140
179
|
## Sponsors
|
|
141
180
|
|
|
142
181
|
<div align="center">
|
|
@@ -13,6 +13,8 @@ export declare const commandDescriptions: {
|
|
|
13
13
|
readonly start: "Builds and starts the extension in production mode";
|
|
14
14
|
readonly preview: "Previews the extension in production mode without building";
|
|
15
15
|
readonly build: "Builds the extension for packaging/distribution";
|
|
16
|
+
readonly install: "Installs a managed browser binary into Extension.js cache";
|
|
17
|
+
readonly uninstall: "Removes managed browser binaries from Extension.js cache";
|
|
16
18
|
};
|
|
17
19
|
export declare function unhandledError(err: unknown): string;
|
|
18
20
|
export declare function updateFailed(err: any): string;
|
|
@@ -33,7 +35,7 @@ export declare function programAIHelp(): string;
|
|
|
33
35
|
export type ProgramAIHelpJSON = {
|
|
34
36
|
version: string;
|
|
35
37
|
commands: Array<{
|
|
36
|
-
name: 'create' | 'dev' | 'start' | 'preview' | 'build';
|
|
38
|
+
name: 'create' | 'dev' | 'start' | 'preview' | 'build' | 'install' | 'uninstall';
|
|
37
39
|
summary: string;
|
|
38
40
|
supportsSourceInspection: boolean;
|
|
39
41
|
}>;
|
package/dist/cli.cjs
CHANGED
|
@@ -85,7 +85,9 @@ var __webpack_exports__ = {};
|
|
|
85
85
|
dev: 'Starts the development server with hot reloading',
|
|
86
86
|
start: 'Builds and starts the extension in production mode',
|
|
87
87
|
preview: 'Previews the extension in production mode without building',
|
|
88
|
-
build: 'Builds the extension for packaging/distribution'
|
|
88
|
+
build: 'Builds the extension for packaging/distribution',
|
|
89
|
+
install: 'Installs a managed browser binary into Extension.js cache',
|
|
90
|
+
uninstall: 'Removes managed browser binaries from Extension.js cache'
|
|
89
91
|
};
|
|
90
92
|
function unhandledError(err) {
|
|
91
93
|
const message = err instanceof Error ? err.stack || err.message : 'string' == typeof err ? err : fmt.truncate(err);
|
|
@@ -129,6 +131,18 @@ Available Commands
|
|
|
129
131
|
- ${code('extension build ' + messages_arg('[project-path|remote-url]'))}
|
|
130
132
|
${commandDescriptions.build}
|
|
131
133
|
|
|
134
|
+
- ${code('extension install ' + messages_arg('--browser <chrome|chromium|edge|firefox|chromium-based|gecko-based|firefox-based|all>'))}
|
|
135
|
+
${commandDescriptions.install}
|
|
136
|
+
|
|
137
|
+
- ${code('extension install --where')}
|
|
138
|
+
Prints the managed browser cache root (or browser install path(s) when --browser is provided)
|
|
139
|
+
|
|
140
|
+
- ${code('extension uninstall ' + messages_arg('<chrome|chromium|edge|firefox> | --all'))}
|
|
141
|
+
${commandDescriptions.uninstall}
|
|
142
|
+
|
|
143
|
+
- ${code('extension uninstall --where')}
|
|
144
|
+
Prints the managed browser cache root (or browser install path(s) when --browser/--all is provided)
|
|
145
|
+
|
|
132
146
|
Common Options
|
|
133
147
|
- ${code('--browser')} ${messages_arg('<chrome|edge|firefox|chromium|chromium-based|gecko-based|firefox-based>')} Target browser/engine (default: chromium)
|
|
134
148
|
- ${code('--profile')} ${messages_arg('<path|boolean>')} Browser profile configuration
|
|
@@ -376,6 +390,16 @@ Cross-Browser Compatibility
|
|
|
376
390
|
name: 'build',
|
|
377
391
|
summary: commandDescriptions.build,
|
|
378
392
|
supportsSourceInspection: false
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
name: 'install',
|
|
396
|
+
summary: commandDescriptions.install,
|
|
397
|
+
supportsSourceInspection: false
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
name: 'uninstall',
|
|
401
|
+
summary: commandDescriptions.uninstall,
|
|
402
|
+
supportsSourceInspection: false
|
|
379
403
|
}
|
|
380
404
|
],
|
|
381
405
|
globalOptions: [
|
|
@@ -406,7 +430,9 @@ Cross-Browser Compatibility
|
|
|
406
430
|
'start',
|
|
407
431
|
'preview',
|
|
408
432
|
'build',
|
|
409
|
-
'create'
|
|
433
|
+
'create',
|
|
434
|
+
'install',
|
|
435
|
+
'uninstall'
|
|
410
436
|
],
|
|
411
437
|
notes: [
|
|
412
438
|
'--source supports URL fallback to --starting-url or https://example.com',
|
|
@@ -443,7 +469,11 @@ Cross-Browser Compatibility
|
|
|
443
469
|
'extension --ai-help',
|
|
444
470
|
'extension --ai-help --format json',
|
|
445
471
|
'extension dev ./my-ext --source https://example.com --source-format json',
|
|
446
|
-
'extension dev ./my-ext --logs=info --log-format=json'
|
|
472
|
+
'extension dev ./my-ext --logs=info --log-format=json',
|
|
473
|
+
'extension install chromium',
|
|
474
|
+
'extension install --where',
|
|
475
|
+
'extension uninstall --where',
|
|
476
|
+
'extension uninstall --all'
|
|
447
477
|
]
|
|
448
478
|
};
|
|
449
479
|
}
|
|
@@ -1316,6 +1346,125 @@ Cross-Browser Compatibility
|
|
|
1316
1346
|
});
|
|
1317
1347
|
});
|
|
1318
1348
|
}
|
|
1349
|
+
function resolveManagedBrowsersCacheRoot() {
|
|
1350
|
+
const explicit = String(process.env.EXT_BROWSERS_CACHE_DIR || '').trim();
|
|
1351
|
+
if (explicit) return external_node_path_default().resolve(explicit);
|
|
1352
|
+
const isWin = 'win32' === process.platform;
|
|
1353
|
+
const isMac = 'darwin' === process.platform;
|
|
1354
|
+
if (isWin) {
|
|
1355
|
+
const local = String(process.env.LOCALAPPDATA || '').trim();
|
|
1356
|
+
if (local) return external_node_path_default().join(local, 'extension.js', 'browsers');
|
|
1357
|
+
const userProfile = String(process.env.USERPROFILE || '').trim();
|
|
1358
|
+
if (userProfile) return external_node_path_default().join(userProfile, 'AppData', 'Local', 'extension.js', 'browsers');
|
|
1359
|
+
return external_node_path_default().resolve(process.cwd(), '.cache', 'extension.js', 'browsers');
|
|
1360
|
+
}
|
|
1361
|
+
if (isMac) {
|
|
1362
|
+
const home = String(process.env.HOME || '').trim();
|
|
1363
|
+
if (home) return external_node_path_default().join(home, 'Library', 'Caches', 'extension.js', 'browsers');
|
|
1364
|
+
return external_node_path_default().resolve(process.cwd(), '.cache', 'extension.js', 'browsers');
|
|
1365
|
+
}
|
|
1366
|
+
const xdg = String(process.env.XDG_CACHE_HOME || '').trim();
|
|
1367
|
+
if (xdg) return external_node_path_default().join(xdg, 'extension.js', 'browsers');
|
|
1368
|
+
const home = String(process.env.HOME || '').trim();
|
|
1369
|
+
if (home) return external_node_path_default().join(home, '.cache', 'extension.js', 'browsers');
|
|
1370
|
+
return external_node_path_default().resolve(process.cwd(), '.cache', 'extension.js', 'browsers');
|
|
1371
|
+
}
|
|
1372
|
+
function normalizeInstallVendor(vendor) {
|
|
1373
|
+
const value = String(vendor).trim().toLowerCase();
|
|
1374
|
+
if ('chromium-based' === value) return 'chromium';
|
|
1375
|
+
if ('gecko-based' === value || 'firefox-based' === value) return 'firefox';
|
|
1376
|
+
if ('chrome' === value || 'chromium' === value || 'edge' === value || 'firefox' === value) return value;
|
|
1377
|
+
return 'chromium';
|
|
1378
|
+
}
|
|
1379
|
+
function registerInstallCommand(program, telemetry) {
|
|
1380
|
+
program.command('install').arguments('[browser-name]').usage('install [browser-name] [--browser <name>] [--where]').description(commandDescriptions.install).option('--browser <chrome | chromium | edge | firefox | chromium-based | gecko-based | firefox-based | all>', 'specify browser(s) to install. Supports comma-separated values and `all`.').option('--where', 'print the resolved managed browser cache root').action(async function(browserArg, options) {
|
|
1381
|
+
const startedAt = Date.now();
|
|
1382
|
+
const selectedBrowser = options.browser || browserArg || 'chromium';
|
|
1383
|
+
const browserList = vendors(selectedBrowser);
|
|
1384
|
+
validateVendorsOrExit(browserList, (invalid, supported)=>{
|
|
1385
|
+
console.error(unsupportedBrowserFlag(invalid, supported));
|
|
1386
|
+
});
|
|
1387
|
+
telemetry.track('cli_command_start', {
|
|
1388
|
+
command: 'install',
|
|
1389
|
+
vendors: browserList,
|
|
1390
|
+
where: Boolean(options.where)
|
|
1391
|
+
});
|
|
1392
|
+
try {
|
|
1393
|
+
if (options.where) {
|
|
1394
|
+
const root = resolveManagedBrowsersCacheRoot();
|
|
1395
|
+
if (options.browser || browserArg) for (const browser of browserList)console.log(external_node_path_default().join(root, normalizeInstallVendor(browser)));
|
|
1396
|
+
else console.log(root);
|
|
1397
|
+
} else {
|
|
1398
|
+
const { extensionInstall } = await import("extension-install");
|
|
1399
|
+
for (const browser of browserList)await extensionInstall({
|
|
1400
|
+
browser
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1403
|
+
telemetry.track('cli_command_finish', {
|
|
1404
|
+
command: 'install',
|
|
1405
|
+
duration_ms: Date.now() - startedAt,
|
|
1406
|
+
success: true,
|
|
1407
|
+
exit_code: 0
|
|
1408
|
+
});
|
|
1409
|
+
} catch (err) {
|
|
1410
|
+
telemetry.track('cli_command_finish', {
|
|
1411
|
+
command: 'install',
|
|
1412
|
+
duration_ms: Date.now() - startedAt,
|
|
1413
|
+
success: false,
|
|
1414
|
+
exit_code: 1
|
|
1415
|
+
});
|
|
1416
|
+
throw err;
|
|
1417
|
+
}
|
|
1418
|
+
});
|
|
1419
|
+
program.command('uninstall').usage('uninstall <browser-name> | uninstall --all | uninstall --where').description(commandDescriptions.uninstall).option('--browser <browser-name>', 'browser to uninstall').option('--all', 'remove all managed browser binaries').option('--where', 'print the resolved managed browser cache root').argument('[browser-name]').action(async function(browserArg, { browser, all, where }) {
|
|
1420
|
+
const startedAt = Date.now();
|
|
1421
|
+
const target = browserArg || browser;
|
|
1422
|
+
telemetry.track('cli_command_start', {
|
|
1423
|
+
command: 'uninstall',
|
|
1424
|
+
browser: target,
|
|
1425
|
+
all: Boolean(all),
|
|
1426
|
+
where: Boolean(where)
|
|
1427
|
+
});
|
|
1428
|
+
try {
|
|
1429
|
+
if (where) {
|
|
1430
|
+
const root = resolveManagedBrowsersCacheRoot();
|
|
1431
|
+
if (all) for (const browser of [
|
|
1432
|
+
'chrome',
|
|
1433
|
+
'chromium',
|
|
1434
|
+
'edge',
|
|
1435
|
+
'firefox'
|
|
1436
|
+
])console.log(external_node_path_default().join(root, browser));
|
|
1437
|
+
else if (target) {
|
|
1438
|
+
const list = vendors(target);
|
|
1439
|
+
validateVendorsOrExit(list, (invalid, supported)=>{
|
|
1440
|
+
console.error(unsupportedBrowserFlag(invalid, supported));
|
|
1441
|
+
});
|
|
1442
|
+
for (const browser of list)console.log(external_node_path_default().join(root, normalizeInstallVendor(browser)));
|
|
1443
|
+
} else console.log(root);
|
|
1444
|
+
} else {
|
|
1445
|
+
const { extensionUninstall } = await import("extension-install");
|
|
1446
|
+
await extensionUninstall({
|
|
1447
|
+
browser: target,
|
|
1448
|
+
all
|
|
1449
|
+
});
|
|
1450
|
+
}
|
|
1451
|
+
telemetry.track('cli_command_finish', {
|
|
1452
|
+
command: 'uninstall',
|
|
1453
|
+
duration_ms: Date.now() - startedAt,
|
|
1454
|
+
success: true,
|
|
1455
|
+
exit_code: 0
|
|
1456
|
+
});
|
|
1457
|
+
} catch (err) {
|
|
1458
|
+
telemetry.track('cli_command_finish', {
|
|
1459
|
+
command: 'uninstall',
|
|
1460
|
+
duration_ms: Date.now() - startedAt,
|
|
1461
|
+
success: false,
|
|
1462
|
+
exit_code: 1
|
|
1463
|
+
});
|
|
1464
|
+
throw err;
|
|
1465
|
+
}
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1319
1468
|
const cliPackageJson = getCliPackageJson();
|
|
1320
1469
|
function developVersion() {
|
|
1321
1470
|
try {
|
|
@@ -1345,6 +1494,7 @@ Cross-Browser Compatibility
|
|
|
1345
1494
|
registerStartCommand(extensionJs, telemetry_cli_telemetry);
|
|
1346
1495
|
registerPreviewCommand(extensionJs, telemetry_cli_telemetry);
|
|
1347
1496
|
registerBuildCommand(extensionJs, telemetry_cli_telemetry);
|
|
1497
|
+
registerInstallCommand(extensionJs, telemetry_cli_telemetry);
|
|
1348
1498
|
extensionJs.on('option:ai-help', function() {
|
|
1349
1499
|
const format = resolveAIHelpFormatFromArgv(process.argv).trim().toLowerCase();
|
|
1350
1500
|
if ('json' === format) {
|
package/package.json
CHANGED
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"extension": "./bin/extension.cjs"
|
|
34
34
|
},
|
|
35
35
|
"name": "extension",
|
|
36
|
-
"version": "3.
|
|
36
|
+
"version": "3.8.0",
|
|
37
37
|
"description": "Create cross-browser extensions with no build configuration.",
|
|
38
38
|
"homepage": "https://extension.js.org/",
|
|
39
39
|
"bugs": {
|
|
@@ -90,8 +90,9 @@
|
|
|
90
90
|
"@types/chrome": "^0.1.33",
|
|
91
91
|
"@types/node": "^25.2.0",
|
|
92
92
|
"@types/webextension-polyfill": "0.12.4",
|
|
93
|
-
"extension-create": "
|
|
94
|
-
"extension-develop": "
|
|
93
|
+
"extension-create": "3.8.0",
|
|
94
|
+
"extension-develop": "3.8.0",
|
|
95
|
+
"extension-install": "3.8.0",
|
|
95
96
|
"commander": "^14.0.3",
|
|
96
97
|
"pintor": "0.3.0",
|
|
97
98
|
"semver": "^7.7.3",
|