firefox-location2 2.0.4 → 2.1.1
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 +25 -0
- package/bin.js +22 -6
- package/dist/index.cjs +80 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +77 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -169,6 +169,7 @@ Note: On Linux, the module first tries to resolve binaries on <code>$PATH</code>
|
|
|
169
169
|
|
|
170
170
|
```js
|
|
171
171
|
import firefoxLocation from 'firefox-location2'
|
|
172
|
+
import {getFirefoxVersion} from 'firefox-location2'
|
|
172
173
|
|
|
173
174
|
// Strict (Stable only)
|
|
174
175
|
console.log(firefoxLocation())
|
|
@@ -183,6 +184,14 @@ import {locateFirefoxOrExplain, getInstallGuidance} from 'firefox-location2'
|
|
|
183
184
|
try {
|
|
184
185
|
const path = locateFirefoxOrExplain({allowFallback: true})
|
|
185
186
|
console.log(path)
|
|
187
|
+
|
|
188
|
+
// Cross-platform version (no exec by default)
|
|
189
|
+
const v = getFirefoxVersion(path)
|
|
190
|
+
console.log(v) // e.g. "130.0.1" or null
|
|
191
|
+
|
|
192
|
+
// Opt-in: allow executing the binary to fetch version on platforms without metadata (e.g. Linux)
|
|
193
|
+
const v2 = getFirefoxVersion(path, {allowExec: true})
|
|
194
|
+
console.log(v2)
|
|
186
195
|
} catch (e) {
|
|
187
196
|
console.error(String(e))
|
|
188
197
|
// Or print getInstallGuidance() explicitly
|
|
@@ -244,6 +253,22 @@ Notes:
|
|
|
244
253
|
- Output is colorized when printed to a TTY (green success, red error)
|
|
245
254
|
- After you run `npx @puppeteer/browsers install firefox@stable` once, we auto-detect Firefox from Puppeteer's cache on all platforms. No env vars needed.
|
|
246
255
|
|
|
256
|
+
## API
|
|
257
|
+
|
|
258
|
+
- `default export locateFirefox(allowFallback?: boolean): string | null`
|
|
259
|
+
- Returns the first existing path among the selected channels or `null`.
|
|
260
|
+
- When `allowFallback` is `true`, checks Stable → ESR → Developer → Nightly.
|
|
261
|
+
|
|
262
|
+
- `locateFirefoxOrExplain(options?: boolean | { allowFallback?: boolean }): string`
|
|
263
|
+
- Returns a path if found, otherwise throws an `Error` with a friendly installation guide.
|
|
264
|
+
- Path resolution never executes the browser.
|
|
265
|
+
|
|
266
|
+
- `getFirefoxVersion(bin: string, opts?: { allowExec?: boolean }): string | null`
|
|
267
|
+
- Cross-platform version resolver that does not execute the browser by default.
|
|
268
|
+
- Windows: reads PE file metadata via PowerShell (no GUI spawn).
|
|
269
|
+
- macOS: reads `Info.plist` (no GUI spawn).
|
|
270
|
+
- Linux/other: returns `null` unless `allowExec` is `true`, then tries `--version`.
|
|
271
|
+
|
|
247
272
|
## Planned enhancements
|
|
248
273
|
|
|
249
274
|
- Flatpak detection on Linux: detect installed Flatpak app <code>org.mozilla.firefox</code> and expose the appropriate invocation.
|
package/bin.js
CHANGED
|
@@ -3,23 +3,39 @@
|
|
|
3
3
|
import locateFirefox, {
|
|
4
4
|
locateFirefoxOrExplain,
|
|
5
5
|
getInstallGuidance,
|
|
6
|
+
getFirefoxVersion,
|
|
6
7
|
} from './dist/index.js';
|
|
7
8
|
|
|
8
9
|
const argv = process.argv.slice(2);
|
|
9
10
|
const allowFallback = argv.includes('--fallback') || argv.includes('-f');
|
|
11
|
+
const printBrowserVersion =
|
|
12
|
+
argv.includes('--firefox-version') || argv.includes('--browser-version');
|
|
13
|
+
const allowExec = argv.includes('--allow-exec');
|
|
10
14
|
|
|
11
15
|
try {
|
|
12
|
-
const
|
|
13
|
-
typeof locateFirefoxOrExplain === 'function'
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
const location =
|
|
17
|
+
(typeof locateFirefoxOrExplain === 'function' &&
|
|
18
|
+
locateFirefoxOrExplain({ allowFallback })) ||
|
|
19
|
+
(typeof locateFirefox === 'function' && locateFirefox(allowFallback)) ||
|
|
20
|
+
null;
|
|
16
21
|
|
|
17
|
-
if (!
|
|
22
|
+
if (!location)
|
|
18
23
|
throw new Error(
|
|
19
24
|
(typeof getInstallGuidance === 'function' && getInstallGuidance()) ||
|
|
20
25
|
'No suitable Firefox binary found.',
|
|
21
26
|
);
|
|
22
|
-
|
|
27
|
+
|
|
28
|
+
if (printBrowserVersion && typeof getFirefoxVersion === 'function') {
|
|
29
|
+
const v = getFirefoxVersion(location, { allowExec });
|
|
30
|
+
if (!v) {
|
|
31
|
+
console.log('');
|
|
32
|
+
process.exit(2);
|
|
33
|
+
}
|
|
34
|
+
console.log(String(v));
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
console.log(String(location));
|
|
23
39
|
} catch (e) {
|
|
24
40
|
console.error(String(e));
|
|
25
41
|
process.exit(1);
|
package/dist/index.cjs
CHANGED
|
@@ -33,8 +33,9 @@ var __webpack_require__ = {};
|
|
|
33
33
|
var __webpack_exports__ = {};
|
|
34
34
|
__webpack_require__.r(__webpack_exports__);
|
|
35
35
|
__webpack_require__.d(__webpack_exports__, {
|
|
36
|
-
getInstallGuidance: ()=>getInstallGuidance,
|
|
37
36
|
default: ()=>locateFirefox,
|
|
37
|
+
getFirefoxVersion: ()=>getFirefoxVersion,
|
|
38
|
+
getInstallGuidance: ()=>getInstallGuidance,
|
|
38
39
|
locateFirefoxOrExplain: ()=>locateFirefoxOrExplain
|
|
39
40
|
});
|
|
40
41
|
const external_fs_namespaceObject = require("fs");
|
|
@@ -276,6 +277,82 @@ function locateFirefoxOrExplain(options) {
|
|
|
276
277
|
if ('string' == typeof found && found) return found;
|
|
277
278
|
throw new Error(getInstallGuidance());
|
|
278
279
|
}
|
|
280
|
+
function getFirefoxVersion(bin, opts) {
|
|
281
|
+
if ('win32' === process.platform) {
|
|
282
|
+
try {
|
|
283
|
+
const psPath = bin.replace(/'/g, "''");
|
|
284
|
+
const pv = (0, external_child_process_namespaceObject.execFileSync)('powershell.exe', [
|
|
285
|
+
'-NoProfile',
|
|
286
|
+
'-Command',
|
|
287
|
+
`(Get-Item -LiteralPath '${psPath}').VersionInfo.ProductVersion`
|
|
288
|
+
], {
|
|
289
|
+
encoding: 'utf8',
|
|
290
|
+
stdio: [
|
|
291
|
+
'ignore',
|
|
292
|
+
'pipe',
|
|
293
|
+
'ignore'
|
|
294
|
+
]
|
|
295
|
+
}).trim();
|
|
296
|
+
return normalizeVersion(pv);
|
|
297
|
+
} catch {}
|
|
298
|
+
if (null == opts ? void 0 : opts.allowExec) {
|
|
299
|
+
const v = tryExec(bin, [
|
|
300
|
+
'--version'
|
|
301
|
+
]);
|
|
302
|
+
return normalizeVersion(v);
|
|
303
|
+
}
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
if ('darwin' === process.platform) {
|
|
307
|
+
try {
|
|
308
|
+
const contentsDir = external_path_default().dirname(external_path_default().dirname(bin));
|
|
309
|
+
const infoPlist = external_path_default().join(contentsDir, 'Info.plist');
|
|
310
|
+
if (external_fs_default().existsSync(infoPlist)) {
|
|
311
|
+
const xml = external_fs_default().readFileSync(infoPlist, 'utf8');
|
|
312
|
+
const v = parsePlistString(xml, 'CFBundleShortVersionString') || parsePlistString(xml, 'CFBundleVersion') || '';
|
|
313
|
+
return normalizeVersion(v);
|
|
314
|
+
}
|
|
315
|
+
} catch {}
|
|
316
|
+
if (null == opts ? void 0 : opts.allowExec) {
|
|
317
|
+
const v = tryExec(bin, [
|
|
318
|
+
'--version'
|
|
319
|
+
]);
|
|
320
|
+
return normalizeVersion(v);
|
|
321
|
+
}
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
if (null == opts ? void 0 : opts.allowExec) {
|
|
325
|
+
const v = tryExec(bin, [
|
|
326
|
+
'--version'
|
|
327
|
+
]);
|
|
328
|
+
return normalizeVersion(v);
|
|
329
|
+
}
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
function normalizeVersion(s) {
|
|
333
|
+
if (!s) return null;
|
|
334
|
+
const m = String(s).match(/(\d+(?:\.\d+){1,3})/);
|
|
335
|
+
return m ? m[1] : null;
|
|
336
|
+
}
|
|
337
|
+
function parsePlistString(xml, key) {
|
|
338
|
+
const re = new RegExp(`<key>${key}<\\/key>\\s*<string>([^<]+)<\\/string>`);
|
|
339
|
+
const m = xml.match(re);
|
|
340
|
+
return m ? m[1].trim() : null;
|
|
341
|
+
}
|
|
342
|
+
function tryExec(bin, args) {
|
|
343
|
+
try {
|
|
344
|
+
return (0, external_child_process_namespaceObject.execFileSync)(bin, args, {
|
|
345
|
+
encoding: 'utf8',
|
|
346
|
+
stdio: [
|
|
347
|
+
'ignore',
|
|
348
|
+
'pipe',
|
|
349
|
+
'ignore'
|
|
350
|
+
]
|
|
351
|
+
}).trim();
|
|
352
|
+
} catch {
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
279
356
|
function resolveFromPuppeteerBrowsersCLI() {
|
|
280
357
|
try {
|
|
281
358
|
const attempts = [
|
|
@@ -331,10 +408,12 @@ function resolveFromPuppeteerBrowsersCLI() {
|
|
|
331
408
|
return null;
|
|
332
409
|
}
|
|
333
410
|
exports["default"] = __webpack_exports__["default"];
|
|
411
|
+
exports.getFirefoxVersion = __webpack_exports__.getFirefoxVersion;
|
|
334
412
|
exports.getInstallGuidance = __webpack_exports__.getInstallGuidance;
|
|
335
413
|
exports.locateFirefoxOrExplain = __webpack_exports__.locateFirefoxOrExplain;
|
|
336
414
|
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
337
415
|
"default",
|
|
416
|
+
"getFirefoxVersion",
|
|
338
417
|
"getInstallGuidance",
|
|
339
418
|
"locateFirefoxOrExplain"
|
|
340
419
|
].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
|
package/dist/index.d.ts
CHANGED
|
@@ -21,3 +21,13 @@ export declare function getInstallGuidance(): string;
|
|
|
21
21
|
export declare function locateFirefoxOrExplain(options?: boolean | {
|
|
22
22
|
allowFallback?: boolean;
|
|
23
23
|
}): string;
|
|
24
|
+
/**
|
|
25
|
+
* Cross-platform Firefox version resolver.
|
|
26
|
+
* - Never executes the browser by default.
|
|
27
|
+
* - On Windows: reads PE metadata via PowerShell.
|
|
28
|
+
* - On macOS: reads Info.plist next to the binary.
|
|
29
|
+
* - On Linux/others: returns null unless opts.allowExec is true, then tries --version.
|
|
30
|
+
*/
|
|
31
|
+
export declare function getFirefoxVersion(bin: string, opts?: {
|
|
32
|
+
allowExec?: boolean;
|
|
33
|
+
}): string | null;
|
package/dist/index.js
CHANGED
|
@@ -231,6 +231,82 @@ function locateFirefoxOrExplain(options) {
|
|
|
231
231
|
if ('string' == typeof found && found) return found;
|
|
232
232
|
throw new Error(getInstallGuidance());
|
|
233
233
|
}
|
|
234
|
+
function getFirefoxVersion(bin, opts) {
|
|
235
|
+
if ('win32' === process.platform) {
|
|
236
|
+
try {
|
|
237
|
+
const psPath = bin.replace(/'/g, "''");
|
|
238
|
+
const pv = (0, __WEBPACK_EXTERNAL_MODULE_child_process__.execFileSync)('powershell.exe', [
|
|
239
|
+
'-NoProfile',
|
|
240
|
+
'-Command',
|
|
241
|
+
`(Get-Item -LiteralPath '${psPath}').VersionInfo.ProductVersion`
|
|
242
|
+
], {
|
|
243
|
+
encoding: 'utf8',
|
|
244
|
+
stdio: [
|
|
245
|
+
'ignore',
|
|
246
|
+
'pipe',
|
|
247
|
+
'ignore'
|
|
248
|
+
]
|
|
249
|
+
}).trim();
|
|
250
|
+
return normalizeVersion(pv);
|
|
251
|
+
} catch {}
|
|
252
|
+
if (null == opts ? void 0 : opts.allowExec) {
|
|
253
|
+
const v = tryExec(bin, [
|
|
254
|
+
'--version'
|
|
255
|
+
]);
|
|
256
|
+
return normalizeVersion(v);
|
|
257
|
+
}
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
if ('darwin' === process.platform) {
|
|
261
|
+
try {
|
|
262
|
+
const contentsDir = __WEBPACK_EXTERNAL_MODULE_path__["default"].dirname(__WEBPACK_EXTERNAL_MODULE_path__["default"].dirname(bin));
|
|
263
|
+
const infoPlist = __WEBPACK_EXTERNAL_MODULE_path__["default"].join(contentsDir, 'Info.plist');
|
|
264
|
+
if (__WEBPACK_EXTERNAL_MODULE_fs__["default"].existsSync(infoPlist)) {
|
|
265
|
+
const xml = __WEBPACK_EXTERNAL_MODULE_fs__["default"].readFileSync(infoPlist, 'utf8');
|
|
266
|
+
const v = parsePlistString(xml, 'CFBundleShortVersionString') || parsePlistString(xml, 'CFBundleVersion') || '';
|
|
267
|
+
return normalizeVersion(v);
|
|
268
|
+
}
|
|
269
|
+
} catch {}
|
|
270
|
+
if (null == opts ? void 0 : opts.allowExec) {
|
|
271
|
+
const v = tryExec(bin, [
|
|
272
|
+
'--version'
|
|
273
|
+
]);
|
|
274
|
+
return normalizeVersion(v);
|
|
275
|
+
}
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
if (null == opts ? void 0 : opts.allowExec) {
|
|
279
|
+
const v = tryExec(bin, [
|
|
280
|
+
'--version'
|
|
281
|
+
]);
|
|
282
|
+
return normalizeVersion(v);
|
|
283
|
+
}
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
function normalizeVersion(s) {
|
|
287
|
+
if (!s) return null;
|
|
288
|
+
const m = String(s).match(/(\d+(?:\.\d+){1,3})/);
|
|
289
|
+
return m ? m[1] : null;
|
|
290
|
+
}
|
|
291
|
+
function parsePlistString(xml, key) {
|
|
292
|
+
const re = new RegExp(`<key>${key}<\\/key>\\s*<string>([^<]+)<\\/string>`);
|
|
293
|
+
const m = xml.match(re);
|
|
294
|
+
return m ? m[1].trim() : null;
|
|
295
|
+
}
|
|
296
|
+
function tryExec(bin, args) {
|
|
297
|
+
try {
|
|
298
|
+
return (0, __WEBPACK_EXTERNAL_MODULE_child_process__.execFileSync)(bin, args, {
|
|
299
|
+
encoding: 'utf8',
|
|
300
|
+
stdio: [
|
|
301
|
+
'ignore',
|
|
302
|
+
'pipe',
|
|
303
|
+
'ignore'
|
|
304
|
+
]
|
|
305
|
+
}).trim();
|
|
306
|
+
} catch {
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
234
310
|
function resolveFromPuppeteerBrowsersCLI() {
|
|
235
311
|
try {
|
|
236
312
|
const attempts = [
|
|
@@ -285,4 +361,4 @@ function resolveFromPuppeteerBrowsersCLI() {
|
|
|
285
361
|
} catch {}
|
|
286
362
|
return null;
|
|
287
363
|
}
|
|
288
|
-
export { locateFirefox as default, getInstallGuidance, locateFirefoxOrExplain };
|
|
364
|
+
export { locateFirefox as default, getFirefoxVersion, getInstallGuidance, locateFirefoxOrExplain };
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"url": "https://github.com/cezaraugusto/firefox-location2.git"
|
|
6
6
|
},
|
|
7
7
|
"name": "firefox-location2",
|
|
8
|
-
"version": "2.
|
|
8
|
+
"version": "2.1.1",
|
|
9
9
|
"description": "Approximates the current location of the Firefox browser across platforms.",
|
|
10
10
|
"homepage": "https://www.npmjs.com/package/firefox-location2",
|
|
11
11
|
"type": "module",
|
|
@@ -29,14 +29,15 @@
|
|
|
29
29
|
"check": "pnpm dlx @biomejs/biome@1.9.4 check --write",
|
|
30
30
|
"dev": "rslib build --watch",
|
|
31
31
|
"format": "pnpm dlx @biomejs/biome@1.9.4 format --write",
|
|
32
|
+
"pretest": "npm run build",
|
|
32
33
|
"test": "vitest run --pool vmForks --poolOptions.vmForks.singleFork",
|
|
33
34
|
"prepublishOnly": "npm run build",
|
|
34
35
|
"publish:provenance": "np patch --no-tests --any-branch --yolo --message 'release: %s' --provenance"
|
|
35
36
|
},
|
|
36
37
|
"engines": {
|
|
37
|
-
"node": ">=
|
|
38
|
+
"node": ">=16"
|
|
38
39
|
},
|
|
39
|
-
"engineStrict":
|
|
40
|
+
"engineStrict": false,
|
|
40
41
|
"publishConfig": {
|
|
41
42
|
"provenance": true
|
|
42
43
|
},
|