extension-install 3.7.0-canary.172.1e95d6a

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 ADDED
@@ -0,0 +1,25 @@
1
+ # extension-install
2
+
3
+ Managed browser installer/uninstaller runtime for Extension.js CLI.
4
+
5
+ This package powers:
6
+
7
+ - `extension install --browser <browser>`
8
+ - `extension install --where`
9
+ - `extension uninstall <browser>`
10
+ - `extension uninstall --all`
11
+ - `extension uninstall --where`
12
+
13
+ When `--where` is used together with `--browser` (or `--all` on uninstall), Extension.js prints the resolved managed install path(s) for those target browsers. Without a target, it prints the managed cache root.
14
+
15
+ Uninstall scope is limited to the Extension.js managed cache root (or `EXT_BROWSERS_CACHE_DIR` when set). It does not remove browser installations outside that managed location.
16
+
17
+ Linux note for `edge`: 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`).
18
+
19
+ Default managed cache locations are stable and human-readable:
20
+ - macOS: `~/Library/Caches/extension.js/browsers`
21
+ - Linux: `~/.cache/extension.js/browsers` (or `$XDG_CACHE_HOME/extension.js/browsers`)
22
+ - Windows: `%LOCALAPPDATA%\\extension.js\\browsers`
23
+
24
+ Custom path override example:
25
+ - `EXT_BROWSERS_CACHE_DIR=/tmp/extension.js/browsers-dev`
@@ -0,0 +1,2 @@
1
+ export type InstallBrowserTarget = 'chrome' | 'chromium' | 'edge' | 'firefox';
2
+ export declare function normalizeBrowserName(input: string): InstallBrowserTarget;
@@ -0,0 +1,7 @@
1
+ import { InstallBrowserTarget } from './browser-target';
2
+ export declare function resolveBrowsersCacheRoot(): string;
3
+ export declare function resolveBrowserInstallDir(browser: InstallBrowserTarget): string;
4
+ export declare function removeBrowserDir(browser: InstallBrowserTarget): {
5
+ path: string;
6
+ removed: boolean;
7
+ };
@@ -0,0 +1,10 @@
1
+ import { InstallBrowserTarget } from './browser-target';
2
+ export declare function installingBrowser(browser: InstallBrowserTarget, destination: string): string;
3
+ export declare function installSucceeded(browser: InstallBrowserTarget, destination: string): string;
4
+ export declare function installFailed(browser: InstallBrowserTarget, command: string, args: string[], code: number | null, stderr: string): string;
5
+ export declare function edgeInstallNeedsInteractivePrivilegedSession(): string;
6
+ export declare function edgeInstallUsingSystemBinary(path: string): string;
7
+ export declare function uninstallRequiresTarget(): string;
8
+ export declare function uninstallingBrowsers(cacheRoot: string, browsers: InstallBrowserTarget[]): string;
9
+ export declare function uninstallSucceeded(browser: InstallBrowserTarget, removedPath: string): string;
10
+ export declare function uninstallNoop(browser: InstallBrowserTarget, checkedPath: string): string;
@@ -0,0 +1,15 @@
1
+ import { InstallBrowserTarget } from './browser-target';
2
+ export declare function browserInstallCommand(_target: InstallBrowserTarget): string;
3
+ export declare function browserInstallArgs(target: InstallBrowserTarget, destination: string): string[];
4
+ export declare function browserInstallEnv(target: InstallBrowserTarget, destination: string): NodeJS.ProcessEnv;
5
+ export declare function runCommand(command: string, args: string[], opts: {
6
+ cwd: string;
7
+ env: NodeJS.ProcessEnv;
8
+ }): Promise<{
9
+ code: number | null;
10
+ stdout: string;
11
+ stderr: string;
12
+ }>;
13
+ export declare function edgeInstallNeedsInteractivePrivilegedSession(): boolean;
14
+ export declare function isEdgePrivilegeEscalationFailure(stderr: string): boolean;
15
+ export declare function detectSystemEdgeBinary(): string | null;
@@ -0,0 +1,302 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.n = (module)=>{
5
+ var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
6
+ __webpack_require__.d(getter, {
7
+ a: getter
8
+ });
9
+ return getter;
10
+ };
11
+ })();
12
+ (()=>{
13
+ __webpack_require__.d = (exports1, definition)=>{
14
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
15
+ enumerable: true,
16
+ get: definition[key]
17
+ });
18
+ };
19
+ })();
20
+ (()=>{
21
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
22
+ })();
23
+ (()=>{
24
+ __webpack_require__.r = (exports1)=>{
25
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
26
+ value: 'Module'
27
+ });
28
+ Object.defineProperty(exports1, '__esModule', {
29
+ value: true
30
+ });
31
+ };
32
+ })();
33
+ var __webpack_exports__ = {};
34
+ __webpack_require__.r(__webpack_exports__);
35
+ __webpack_require__.d(__webpack_exports__, {
36
+ getManagedBrowserInstallDir: ()=>getManagedBrowserInstallDir,
37
+ extensionInstall: ()=>extensionInstall,
38
+ extensionUninstall: ()=>extensionUninstall,
39
+ getManagedBrowsersCacheRoot: ()=>getManagedBrowsersCacheRoot
40
+ });
41
+ const external_pintor_namespaceObject = require("pintor");
42
+ var external_pintor_default = /*#__PURE__*/ __webpack_require__.n(external_pintor_namespaceObject);
43
+ const statusPrefix = external_pintor_default().brightBlue('►►►');
44
+ function titleCase(value) {
45
+ return value.length ? value[0].toUpperCase() + value.slice(1) : value;
46
+ }
47
+ function installingBrowser(browser, destination) {
48
+ return `${statusPrefix} Installing ${external_pintor_default().blue(titleCase(browser))} into ${external_pintor_default().underline(destination)}...`;
49
+ }
50
+ function installSucceeded(browser, destination) {
51
+ return `${statusPrefix} ${external_pintor_default().green('Installed')} ${external_pintor_default().blue(titleCase(browser))} in ${external_pintor_default().underline(destination)}`;
52
+ }
53
+ function installFailed(browser, command, args, code, stderr) {
54
+ const details = String(stderr || '').trim();
55
+ const detailSuffix = details ? `\n${external_pintor_default().red(details)}` : '';
56
+ return `${external_pintor_default().red('Error')} Failed to install ${external_pintor_default().blue(titleCase(browser))}.\nCommand: ${external_pintor_default().yellow(command)} ${external_pintor_default().yellow(args.join(' '))}\nExit code: ${external_pintor_default().yellow(String(code))}` + detailSuffix;
57
+ }
58
+ function edgeInstallNeedsInteractivePrivilegedSession() {
59
+ return `${external_pintor_default().red('Error')} Edge installation on Linux requires a privileged interactive session.\nRun this command in a terminal session where sudo can prompt for credentials, or install Edge system-wide with your package manager.\nExamples:\n- Ubuntu/Debian: ${external_pintor_default().blue('sudo apt install microsoft-edge-stable')}\n- Fedora: ${external_pintor_default().blue('sudo dnf install microsoft-edge-stable')}\nThen run Extension.js with ${external_pintor_default().blue('--browser=edge')} (or use ${external_pintor_default().blue('chromium')} when privileged install is unavailable).`;
60
+ }
61
+ function edgeInstallUsingSystemBinary(path) {
62
+ return `${statusPrefix} ${external_pintor_default().yellow('Edge channel install was skipped due privilege requirements.')}\n${statusPrefix} Using existing system Edge binary at ${external_pintor_default().underline(path)}.`;
63
+ }
64
+ function uninstallRequiresTarget() {
65
+ return `${external_pintor_default().red('Error')} Missing browser target. Use --browser <name> or --all.`;
66
+ }
67
+ function uninstallingBrowsers(cacheRoot, browsers) {
68
+ return `${statusPrefix} Removing browser binaries (${browsers.join(', ')}) from ${external_pintor_default().underline(cacheRoot)}...`;
69
+ }
70
+ function uninstallSucceeded(browser, removedPath) {
71
+ return `${statusPrefix} ${external_pintor_default().green('Removed')} ${external_pintor_default().blue(titleCase(browser))} from ${external_pintor_default().underline(removedPath)}`;
72
+ }
73
+ function uninstallNoop(browser, checkedPath) {
74
+ return `${statusPrefix} ${external_pintor_default().gray(`${titleCase(browser)} is already absent`)} (${external_pintor_default().underline(checkedPath)})`;
75
+ }
76
+ const BROWSER_ALIASES = {
77
+ chrome: 'chrome',
78
+ chromium: 'chromium',
79
+ edge: 'edge',
80
+ firefox: 'firefox',
81
+ 'chromium-based': 'chromium',
82
+ 'gecko-based': 'firefox',
83
+ 'firefox-based': 'firefox'
84
+ };
85
+ function normalizeBrowserName(input) {
86
+ const value = String(input || '').trim().toLowerCase();
87
+ const resolved = BROWSER_ALIASES[value];
88
+ if (resolved) return resolved;
89
+ throw new Error(`Unsupported browser "${value}". Supported values: ${Object.keys(BROWSER_ALIASES).join(', ')}`);
90
+ }
91
+ const external_node_path_namespaceObject = require("node:path");
92
+ var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
93
+ const external_node_fs_namespaceObject = require("node:fs");
94
+ var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
95
+ const external_node_child_process_namespaceObject = require("node:child_process");
96
+ const external_cross_spawn_namespaceObject = require("cross-spawn");
97
+ function buildExecEnv(base) {
98
+ if ('win32' !== process.platform) return base;
99
+ const nodeDir = external_node_path_default().dirname(process.execPath);
100
+ const pathSep = external_node_path_default().delimiter;
101
+ const existing = base.PATH || base.Path || '';
102
+ if (existing.includes(nodeDir)) return base;
103
+ const updated = `${nodeDir}${pathSep}${existing}`.trim();
104
+ return {
105
+ ...base,
106
+ PATH: updated,
107
+ Path: updated
108
+ };
109
+ }
110
+ function browserInstallCommand(_target) {
111
+ return 'win32' === process.platform ? 'npx.cmd' : 'npx';
112
+ }
113
+ function browserInstallArgs(target, destination) {
114
+ if ('edge' === target) return [
115
+ '-y',
116
+ 'playwright@latest',
117
+ 'install',
118
+ 'msedge'
119
+ ];
120
+ const browserRef = 'chrome' === target ? 'chrome@stable' : target;
121
+ return [
122
+ '-y',
123
+ '@puppeteer/browsers@latest',
124
+ 'install',
125
+ browserRef,
126
+ '--path',
127
+ destination
128
+ ];
129
+ }
130
+ function browserInstallEnv(target, destination) {
131
+ if ('edge' === target) return {
132
+ ...process.env,
133
+ PLAYWRIGHT_BROWSERS_PATH: destination
134
+ };
135
+ return {
136
+ ...process.env
137
+ };
138
+ }
139
+ async function runCommand(command, args, opts) {
140
+ const child = (0, external_cross_spawn_namespaceObject.spawn)(command, args, {
141
+ cwd: opts.cwd,
142
+ env: buildExecEnv(opts.env),
143
+ stdio: 'pipe'
144
+ });
145
+ let stdout = '';
146
+ let stderr = '';
147
+ if (child.stdout) child.stdout.on('data', (chunk)=>{
148
+ stdout += chunk.toString();
149
+ process.stdout.write(chunk);
150
+ });
151
+ if (child.stderr) child.stderr.on('data', (chunk)=>{
152
+ stderr += chunk.toString();
153
+ process.stderr.write(chunk);
154
+ });
155
+ return new Promise((resolve, reject)=>{
156
+ child.on('close', (code)=>resolve({
157
+ code,
158
+ stdout,
159
+ stderr
160
+ }));
161
+ child.on('error', (error)=>reject(error));
162
+ });
163
+ }
164
+ function runner_edgeInstallNeedsInteractivePrivilegedSession() {
165
+ return 'linux' === process.platform && !Boolean(process.stdin?.isTTY);
166
+ }
167
+ function isEdgePrivilegeEscalationFailure(stderr) {
168
+ const text = String(stderr || '');
169
+ return /switching to root user to install dependencies/i.test(text) || /sudo:\s+a password is required/i.test(text) || /sudo:\s+a terminal is required/i.test(text);
170
+ }
171
+ function detectSystemEdgeBinary() {
172
+ if ('darwin' === process.platform) {
173
+ const macPath = '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge';
174
+ return external_node_fs_default().existsSync(macPath) ? macPath : null;
175
+ }
176
+ if ('win32' === process.platform) {
177
+ const result = (0, external_node_child_process_namespaceObject.spawnSync)('where', [
178
+ 'msedge'
179
+ ], {
180
+ stdio: 'pipe',
181
+ encoding: 'utf8'
182
+ });
183
+ result.status;
184
+ return null;
185
+ }
186
+ const candidates = [
187
+ 'microsoft-edge-stable',
188
+ 'microsoft-edge',
189
+ 'msedge'
190
+ ];
191
+ for (const cmd of candidates){
192
+ const result = (0, external_node_child_process_namespaceObject.spawnSync)('which', [
193
+ cmd
194
+ ], {
195
+ stdio: 'pipe',
196
+ encoding: 'utf8'
197
+ });
198
+ result.status;
199
+ }
200
+ return null;
201
+ }
202
+ function resolveBrowsersCacheRoot() {
203
+ const explicit = String(process.env.EXT_BROWSERS_CACHE_DIR || '').trim();
204
+ if (explicit) return external_node_path_default().resolve(explicit);
205
+ const isWin = 'win32' === process.platform;
206
+ const isMac = 'darwin' === process.platform;
207
+ if (isWin) {
208
+ const local = String(process.env.LOCALAPPDATA || '').trim();
209
+ if (local) return external_node_path_default().join(local, 'extension.js', 'browsers');
210
+ const userProfile = String(process.env.USERPROFILE || '').trim();
211
+ if (userProfile) return external_node_path_default().join(userProfile, 'AppData', 'Local', 'extension.js', 'browsers');
212
+ return external_node_path_default().resolve(process.cwd(), '.cache', 'extension.js', 'browsers');
213
+ }
214
+ if (isMac) {
215
+ const home = String(process.env.HOME || '').trim();
216
+ if (home) return external_node_path_default().join(home, 'Library', 'Caches', 'extension.js', 'browsers');
217
+ return external_node_path_default().resolve(process.cwd(), '.cache', 'extension.js', 'browsers');
218
+ }
219
+ const xdg = String(process.env.XDG_CACHE_HOME || '').trim();
220
+ if (xdg) return external_node_path_default().join(xdg, 'extension.js', 'browsers');
221
+ const home = String(process.env.HOME || '').trim();
222
+ if (home) return external_node_path_default().join(home, '.cache', 'extension.js', 'browsers');
223
+ return external_node_path_default().resolve(process.cwd(), '.cache', 'extension.js', 'browsers');
224
+ }
225
+ function resolveBrowserInstallDir(browser) {
226
+ return external_node_path_default().join(resolveBrowsersCacheRoot(), browser);
227
+ }
228
+ function removeBrowserDir(browser) {
229
+ const installDir = resolveBrowserInstallDir(browser);
230
+ if (!external_node_fs_default().existsSync(installDir)) return {
231
+ path: installDir,
232
+ removed: false
233
+ };
234
+ external_node_fs_default().rmSync(installDir, {
235
+ recursive: true,
236
+ force: true
237
+ });
238
+ return {
239
+ path: installDir,
240
+ removed: true
241
+ };
242
+ }
243
+ function getManagedBrowsersCacheRoot() {
244
+ return resolveBrowsersCacheRoot();
245
+ }
246
+ function getManagedBrowserInstallDir(browser) {
247
+ const target = normalizeBrowserName(browser);
248
+ return resolveBrowserInstallDir(target);
249
+ }
250
+ async function extensionInstall({ browser }) {
251
+ const target = normalizeBrowserName(browser);
252
+ const destination = resolveBrowserInstallDir(target);
253
+ if ('edge' === target && runner_edgeInstallNeedsInteractivePrivilegedSession()) throw new Error(edgeInstallNeedsInteractivePrivilegedSession());
254
+ console.log(installingBrowser(target, destination));
255
+ const cmd = browserInstallCommand(target);
256
+ const args = browserInstallArgs(target, destination);
257
+ const env = browserInstallEnv(target, destination);
258
+ const result = await runCommand(cmd, args, {
259
+ cwd: process.cwd(),
260
+ env
261
+ });
262
+ if (0 !== result.code) {
263
+ if ('edge' === target && isEdgePrivilegeEscalationFailure(result.stderr)) {
264
+ const systemEdge = detectSystemEdgeBinary();
265
+ if (systemEdge) return void console.log(edgeInstallUsingSystemBinary(systemEdge));
266
+ throw new Error(edgeInstallNeedsInteractivePrivilegedSession());
267
+ }
268
+ throw new Error(installFailed(target, cmd, args, result.code, result.stderr));
269
+ }
270
+ console.log(installSucceeded(target, destination));
271
+ }
272
+ async function extensionUninstall({ browser, all }) {
273
+ const cacheRoot = resolveBrowsersCacheRoot();
274
+ if (!all && !browser) throw new Error(uninstallRequiresTarget());
275
+ const targets = all ? [
276
+ 'chrome',
277
+ 'chromium',
278
+ 'edge',
279
+ 'firefox'
280
+ ] : [
281
+ normalizeBrowserName(String(browser || ''))
282
+ ];
283
+ console.log(uninstallingBrowsers(cacheRoot, targets));
284
+ for (const target of targets){
285
+ const result = removeBrowserDir(target);
286
+ if (result.removed) console.log(uninstallSucceeded(target, result.path));
287
+ else console.log(uninstallNoop(target, result.path));
288
+ }
289
+ }
290
+ exports.extensionInstall = __webpack_exports__.extensionInstall;
291
+ exports.extensionUninstall = __webpack_exports__.extensionUninstall;
292
+ exports.getManagedBrowserInstallDir = __webpack_exports__.getManagedBrowserInstallDir;
293
+ exports.getManagedBrowsersCacheRoot = __webpack_exports__.getManagedBrowsersCacheRoot;
294
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
295
+ "extensionInstall",
296
+ "extensionUninstall",
297
+ "getManagedBrowserInstallDir",
298
+ "getManagedBrowsersCacheRoot"
299
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
300
+ Object.defineProperty(exports, '__esModule', {
301
+ value: true
302
+ });
@@ -0,0 +1,11 @@
1
+ export interface InstallOptions {
2
+ browser: string;
3
+ }
4
+ export interface UninstallOptions {
5
+ browser?: string;
6
+ all?: boolean;
7
+ }
8
+ export declare function getManagedBrowsersCacheRoot(): string;
9
+ export declare function getManagedBrowserInstallDir(browser: string): string;
10
+ export declare function extensionInstall({ browser }: InstallOptions): Promise<void>;
11
+ export declare function extensionUninstall({ browser, all }: UninstallOptions): Promise<void>;
@@ -0,0 +1,2 @@
1
+ declare const _default: import("@rslib/core").RslibConfig;
2
+ export default _default;
@@ -0,0 +1,2 @@
1
+ declare const _default: import("vite").UserConfig;
2
+ export default _default;
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "type": "module",
3
+ "license": "MIT",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/extension-js/extension.js.git",
7
+ "directory": "programs/install"
8
+ },
9
+ "engines": {
10
+ "node": ">=18"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "development": "./module.ts",
15
+ "types": "./dist/module.d.ts",
16
+ "import": "./dist/module.cjs",
17
+ "require": "./dist/module.cjs"
18
+ }
19
+ },
20
+ "main": "./dist/module.cjs",
21
+ "types": "./dist/module.d.ts",
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "name": "extension-install",
26
+ "version": "3.7.0-canary.172.1e95d6a",
27
+ "description": "Managed browser installer/uninstaller for Extension.js",
28
+ "author": {
29
+ "name": "Cezar Augusto",
30
+ "email": "boss@cezaraugusto.net",
31
+ "url": "https://cezaraugusto.com"
32
+ },
33
+ "homepage": "https://github.com/extension-js/extension.js/tree/main/programs/install#readme",
34
+ "bugs": {
35
+ "url": "https://github.com/extension-js/extension.js/issues"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public",
39
+ "registry": "https://registry.npmjs.org"
40
+ },
41
+ "scripts": {
42
+ "watch": "rslib build --watch",
43
+ "compile": "rslib build",
44
+ "test": "vitest run"
45
+ },
46
+ "keywords": [
47
+ "webextension",
48
+ "browser-extension",
49
+ "extensionjs",
50
+ "browser-installer",
51
+ "chrome",
52
+ "chromium",
53
+ "edge",
54
+ "firefox"
55
+ ],
56
+ "dependencies": {
57
+ "cross-spawn": "^7.0.6",
58
+ "pintor": "0.3.0"
59
+ },
60
+ "devDependencies": {
61
+ "@rslib/core": "^0.19.4",
62
+ "@types/node": "^25.2.0",
63
+ "tsconfig": "*",
64
+ "typescript": "5.9.3",
65
+ "vitest": "^4.0.17"
66
+ }
67
+ }