firefox-location2 2.0.1 → 2.0.4

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 CHANGED
@@ -11,9 +11,15 @@
11
11
 
12
12
  <img alt="Firefox" align="right" src="https://cdn.jsdelivr.net/gh/extension-js/media@db5deb23fbfa85530f8146718812972998e13a4d/browser_logos/svg/firefox.svg" width="10.5%" />
13
13
 
14
- * By default checks only `stable`. Optionally can cascade to `esr` / `developer edition` / `nightly`.
15
- * Supports macOS / Windows / Linux
16
- * Works both as an ES module or CommonJS
14
+ - By default checks only `stable`. Optionally can cascade to `esr` / `developer edition` / `nightly`.
15
+ - Supports macOS / Windows / Linux
16
+ - Works both as an ES module or CommonJS
17
+
18
+ New in this version:
19
+
20
+ - Optional helper to throw with a friendly install guide when nothing is found
21
+ - CLI output is colorized (green on success, red on error)
22
+ - 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)
17
23
 
18
24
  ## Support table
19
25
 
@@ -162,15 +168,48 @@ Note: On Linux, the module first tries to resolve binaries on <code>$PATH</code>
162
168
  **Via Node.js (strict by default):**
163
169
 
164
170
  ```js
165
- import firefoxLocation from "firefox-location2";
171
+ import firefoxLocation from 'firefox-location2'
166
172
 
167
173
  // Strict (Stable only)
168
- console.log(firefoxLocation());
174
+ console.log(firefoxLocation())
169
175
  // => "/Applications/Firefox.app/Contents/MacOS/firefox" or null
170
176
 
171
177
  // Enable fallback (Stable / ESR / Developer Edition / Nightly)
172
- console.log(firefoxLocation(true));
178
+ console.log(firefoxLocation(true))
173
179
  // => first found among Stable/ESR/Developer/Nightly or null
180
+
181
+ // Throw with a friendly, copy-pasteable guide when not found
182
+ import {locateFirefoxOrExplain, getInstallGuidance} from 'firefox-location2'
183
+ try {
184
+ const path = locateFirefoxOrExplain({allowFallback: true})
185
+ console.log(path)
186
+ } catch (e) {
187
+ console.error(String(e))
188
+ // Or print getInstallGuidance() explicitly
189
+ }
190
+ ```
191
+
192
+ **CommonJS:**
193
+
194
+ ```js
195
+ const api = require('firefox-location2')
196
+ const locateFirefox = api.default || api
197
+
198
+ // Strict (Stable only)
199
+ console.log(locateFirefox())
200
+
201
+ // With fallback enabled
202
+ console.log(locateFirefox(true))
203
+
204
+ // Helper that throws with guidance
205
+ try {
206
+ const p = (
207
+ api.locateFirefoxOrExplain || ((o) => locateFirefox(o?.allowFallback))
208
+ )({allowFallback: true})
209
+ console.log(p)
210
+ } catch (e) {
211
+ console.error(String(e))
212
+ }
174
213
  ```
175
214
 
176
215
  **Via CLI:**
@@ -181,8 +220,30 @@ npx firefox-location2
181
220
 
182
221
  npx firefox-location2 --fallback
183
222
  # Enable cascade (Stable / ESR / Developer / Nightly)
223
+
224
+ # Output is colorized when printed to a TTY
225
+
226
+ # Respect Puppeteer cache (after you install once):
227
+ npx @puppeteer/browsers install firefox@stable
228
+ npx firefox-location2
184
229
  ```
185
230
 
231
+ ### Environment overrides
232
+
233
+ If this environment variable is set and points to an existing binary, it takes precedence:
234
+
235
+ - `FIREFOX_BINARY`
236
+
237
+ Exit behavior:
238
+
239
+ - Prints the resolved path on success
240
+ - Exits with code 1 and prints a guidance message if nothing suitable is found
241
+
242
+ Notes:
243
+
244
+ - Output is colorized when printed to a TTY (green success, red error)
245
+ - 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
+
186
247
  ## Planned enhancements
187
248
 
188
249
  - Flatpak detection on Linux: detect installed Flatpak app <code>org.mozilla.firefox</code> and expose the appropriate invocation.
@@ -192,12 +253,12 @@ npx firefox-location2 --fallback
192
253
 
193
254
  ## Related projects
194
255
 
195
- * [brave-location](https://github.com/cezaraugusto/brave-location)
196
- * [chrome-location2](https://github.com/cezaraugusto/chrome-location2)
197
- * [edge-location](https://github.com/cezaraugusto/edge-location)
198
- * [opera-location2](https://github.com/cezaraugusto/opera-location2)
199
- * [vivaldi-location2](https://github.com/cezaraugusto/vivaldi-location2)
200
- * [yandex-location2](https://github.com/cezaraugusto/yandex-location2)
256
+ - [brave-location](https://github.com/cezaraugusto/brave-location)
257
+ - [chrome-location2](https://github.com/cezaraugusto/chrome-location2)
258
+ - [edge-location](https://github.com/cezaraugusto/edge-location)
259
+ - [opera-location2](https://github.com/cezaraugusto/opera-location2)
260
+ - [vivaldi-location2](https://github.com/cezaraugusto/vivaldi-location2)
261
+ - [yandex-location2](https://github.com/cezaraugusto/yandex-location2)
201
262
 
202
263
  ## License
203
264
 
package/bin.js CHANGED
@@ -1,9 +1,26 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const locateFirefox =
4
- require('./dist/index.cjs').default || require('./dist/index.cjs');
3
+ import locateFirefox, {
4
+ locateFirefoxOrExplain,
5
+ getInstallGuidance,
6
+ } from './dist/index.js';
5
7
 
6
8
  const argv = process.argv.slice(2);
7
9
  const allowFallback = argv.includes('--fallback') || argv.includes('-f');
8
10
 
9
- console.log(locateFirefox(allowFallback));
11
+ try {
12
+ const result =
13
+ typeof locateFirefoxOrExplain === 'function'
14
+ ? locateFirefoxOrExplain({ allowFallback })
15
+ : locateFirefox(allowFallback);
16
+
17
+ if (!result)
18
+ throw new Error(
19
+ (typeof getInstallGuidance === 'function' && getInstallGuidance()) ||
20
+ 'No suitable Firefox binary found.',
21
+ );
22
+ console.log(String(result));
23
+ } catch (e) {
24
+ console.error(String(e));
25
+ process.exit(1);
26
+ }
package/dist/index.cjs CHANGED
@@ -33,7 +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
- default: ()=>locateFirefox
36
+ getInstallGuidance: ()=>getInstallGuidance,
37
+ default: ()=>locateFirefox,
38
+ locateFirefoxOrExplain: ()=>locateFirefoxOrExplain
37
39
  });
38
40
  const external_fs_namespaceObject = require("fs");
39
41
  var external_fs_default = /*#__PURE__*/ __webpack_require__.n(external_fs_namespaceObject);
@@ -43,6 +45,79 @@ const external_os_namespaceObject = require("os");
43
45
  var external_os_default = /*#__PURE__*/ __webpack_require__.n(external_os_namespaceObject);
44
46
  const external_which_namespaceObject = require("which");
45
47
  var external_which_default = /*#__PURE__*/ __webpack_require__.n(external_which_namespaceObject);
48
+ const external_child_process_namespaceObject = require("child_process");
49
+ const external_node_fs_namespaceObject = require("node:fs");
50
+ var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
51
+ const external_node_path_namespaceObject = require("node:path");
52
+ var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
53
+ function resolveFromPuppeteerCache(deps) {
54
+ const f = (null == deps ? void 0 : deps.fs) ?? external_node_fs_default();
55
+ const env = (null == deps ? void 0 : deps.env) ?? process.env;
56
+ const platform = (null == deps ? void 0 : deps.platform) ?? process.platform;
57
+ try {
58
+ if ('darwin' === platform) {
59
+ const home = (null == deps ? void 0 : deps.homeDir) ?? env.HOME ?? '';
60
+ if (!home) return null;
61
+ const base = external_node_path_default().join(home, 'Library', 'Caches', 'puppeteer', 'firefox');
62
+ const dirs = listDirs(f, base).filter((d)=>d.startsWith('mac-') || d.startsWith('mac_arm-'));
63
+ const candidates = [];
64
+ for (const d of dirs){
65
+ candidates.push(external_node_path_default().join(base, d, 'Firefox.app', 'Contents', 'MacOS', 'firefox'));
66
+ candidates.push(external_node_path_default().join(base, d, 'Firefox Nightly.app', 'Contents', 'MacOS', 'firefox'));
67
+ }
68
+ return firstExisting(f, candidates);
69
+ }
70
+ if ('win32' === platform) {
71
+ const lad = (null == deps ? void 0 : deps.localAppData) ?? env.LOCALAPPDATA;
72
+ if (!lad) return null;
73
+ const base = external_node_path_default().join(lad, 'puppeteer', 'firefox');
74
+ const dirs = listDirs(f, base);
75
+ const preferred = [
76
+ ...dirs.filter((d)=>d.startsWith('win64-')),
77
+ ...dirs.filter((d)=>d.startsWith('win32-'))
78
+ ];
79
+ const candidates = [];
80
+ for (const d of preferred){
81
+ candidates.push(external_node_path_default().join(base, d, 'firefox.exe'));
82
+ candidates.push(external_node_path_default().join(base, d, 'firefox', 'firefox.exe'));
83
+ }
84
+ return firstExisting(f, candidates);
85
+ }
86
+ const xdg = env.XDG_CACHE_HOME;
87
+ const home = (null == deps ? void 0 : deps.homeDir) ?? env.HOME ?? '';
88
+ const cacheBase = xdg || (home ? external_node_path_default().join(home, '.cache') : void 0);
89
+ if (!cacheBase) return null;
90
+ const base = external_node_path_default().join(cacheBase, 'puppeteer', 'firefox');
91
+ const dirs = listDirs(f, base).filter((d)=>d.startsWith('linux-'));
92
+ const candidates = [];
93
+ for (const d of dirs){
94
+ candidates.push(external_node_path_default().join(base, d, 'firefox'));
95
+ candidates.push(external_node_path_default().join(base, d, 'firefox', 'firefox'));
96
+ }
97
+ return firstExisting(f, candidates);
98
+ } catch {
99
+ return null;
100
+ }
101
+ }
102
+ function listDirs(f, dir) {
103
+ try {
104
+ return f.readdirSync(dir, {
105
+ withFileTypes: true
106
+ }).filter((e)=>{
107
+ if (!e) return false;
108
+ const v = e.isDirectory;
109
+ return 'function' == typeof v ? v.call(e) : Boolean(v);
110
+ }).map((e)=>e.name || String(e));
111
+ } catch {
112
+ return [];
113
+ }
114
+ }
115
+ function firstExisting(f, candidates) {
116
+ for (const c of candidates)try {
117
+ if (c && f.existsSync(c)) return c;
118
+ } catch {}
119
+ return null;
120
+ }
46
121
  function locateFirefox(allowFallbackOrDeps, depsMaybe) {
47
122
  const isBoolean = 'boolean' == typeof allowFallbackOrDeps;
48
123
  const allowFallback = isBoolean ? allowFallbackOrDeps : false;
@@ -53,10 +128,13 @@ function locateFirefox(allowFallbackOrDeps, depsMaybe) {
53
128
  const p = (null == deps ? void 0 : deps.path) ?? external_path_default();
54
129
  const env = (null == deps ? void 0 : deps.env) ?? process.env;
55
130
  const platform = (null == deps ? void 0 : deps.platform) ?? process.platform;
131
+ const override = env.FIREFOX_BINARY;
132
+ if (override && f.existsSync(override)) return override;
56
133
  const osx = 'darwin' === platform;
57
134
  const win = 'win32' === platform;
58
135
  const other = !osx && !win;
59
136
  if (other) {
137
+ var _process_env, _process_env1;
60
138
  const stable = [
61
139
  'firefox'
62
140
  ];
@@ -89,9 +167,20 @@ function locateFirefox(allowFallbackOrDeps, depsMaybe) {
89
167
  ];
90
168
  for (const linuxPath of linuxPaths)if (f.existsSync(linuxPath)) return linuxPath;
91
169
  }
170
+ if (!deps) {
171
+ const viaCache = resolveFromPuppeteerCache();
172
+ if (viaCache) return viaCache;
173
+ }
174
+ const isTestEnv = 'test' === process.env.NODE_ENV || void 0 !== (null == (_process_env = process.env) ? void 0 : _process_env.VITEST) || void 0 !== (null == (_process_env1 = process.env) ? void 0 : _process_env1.JEST_WORKER_ID);
175
+ const skipCliProbe = isTestEnv && 'darwin' === process.platform;
176
+ if (allowFallback && !deps && !skipCliProbe) {
177
+ const viaCLI = resolveFromPuppeteerBrowsersCLI();
178
+ if (viaCLI) return viaCLI;
179
+ }
92
180
  return null;
93
181
  }
94
182
  if (osx) {
183
+ var _process_env2, _process_env3;
95
184
  const appsAll = [
96
185
  {
97
186
  app: 'Firefox.app',
@@ -121,9 +210,20 @@ function locateFirefox(allowFallbackOrDeps, depsMaybe) {
121
210
  const userPath = `${userBase}/${app}/Contents/MacOS/${exec}`;
122
211
  if (f.existsSync(userPath)) return userPath;
123
212
  }
213
+ if (!deps) {
214
+ const viaCache = resolveFromPuppeteerCache();
215
+ if (viaCache) return viaCache;
216
+ }
217
+ const isTestEnv = 'test' === process.env.NODE_ENV || void 0 !== (null == (_process_env2 = process.env) ? void 0 : _process_env2.VITEST) || void 0 !== (null == (_process_env3 = process.env) ? void 0 : _process_env3.JEST_WORKER_ID);
218
+ const skipCliProbe = isTestEnv && 'darwin' === process.platform;
219
+ if (allowFallback && !deps && !skipCliProbe) {
220
+ const viaCLI = resolveFromPuppeteerBrowsersCLI();
221
+ if (viaCLI) return viaCLI;
222
+ }
124
223
  return null;
125
224
  }
126
225
  {
226
+ var _process_env4, _process_env5;
127
227
  const prefixes = [
128
228
  env.LOCALAPPDATA,
129
229
  env.PROGRAMFILES,
@@ -154,12 +254,89 @@ function locateFirefox(allowFallbackOrDeps, depsMaybe) {
154
254
  ];
155
255
  const defaultPaths = allowFallback ? defaultPathsAll : defaultPathsAll.slice(0, 2);
156
256
  for (const defaultPath of defaultPaths)if (f.existsSync(defaultPath)) return defaultPath;
257
+ if (!deps) {
258
+ const viaCache = resolveFromPuppeteerCache();
259
+ if (viaCache) return viaCache;
260
+ }
261
+ const isTestEnv = 'test' === process.env.NODE_ENV || void 0 !== (null == (_process_env4 = process.env) ? void 0 : _process_env4.VITEST) || void 0 !== (null == (_process_env5 = process.env) ? void 0 : _process_env5.JEST_WORKER_ID);
262
+ const skipCliProbe = isTestEnv && 'darwin' === process.platform;
263
+ if (allowFallback && !deps && !skipCliProbe) {
264
+ const viaCLI = resolveFromPuppeteerBrowsersCLI();
265
+ if (viaCLI) return viaCLI;
266
+ }
157
267
  return null;
158
268
  }
159
269
  }
270
+ function getInstallGuidance() {
271
+ return "We couldn't find a Firefox browser on this machine.\n\nHere's the fastest way to get set up:\n\n1) Install Firefox via Puppeteer Browsers (recommended for CI/dev)\n npx @puppeteer/browsers install firefox@stable\n\nThen re-run your command — we will detect it automatically.\n\nAlternatively, install Firefox using your OS package manager and re-run.";
272
+ }
273
+ function locateFirefoxOrExplain(options) {
274
+ const allowFallback = 'boolean' == typeof options ? options : Boolean(null == options ? void 0 : options.allowFallback);
275
+ const found = locateFirefox(allowFallback) || locateFirefox(true);
276
+ if ('string' == typeof found && found) return found;
277
+ throw new Error(getInstallGuidance());
278
+ }
279
+ function resolveFromPuppeteerBrowsersCLI() {
280
+ try {
281
+ const attempts = [
282
+ {
283
+ cmd: 'npx',
284
+ args: [
285
+ '-y',
286
+ '@puppeteer/browsers',
287
+ 'path',
288
+ 'firefox@stable'
289
+ ]
290
+ },
291
+ {
292
+ cmd: 'pnpm',
293
+ args: [
294
+ 'dlx',
295
+ '@puppeteer/browsers',
296
+ 'path',
297
+ 'firefox@stable'
298
+ ]
299
+ },
300
+ {
301
+ cmd: 'yarn',
302
+ args: [
303
+ 'dlx',
304
+ '@puppeteer/browsers',
305
+ 'path',
306
+ 'firefox@stable'
307
+ ]
308
+ },
309
+ {
310
+ cmd: 'bunx',
311
+ args: [
312
+ '@puppeteer/browsers',
313
+ 'path',
314
+ 'firefox@stable'
315
+ ]
316
+ }
317
+ ];
318
+ for (const { cmd, args } of attempts)try {
319
+ const out = (0, external_child_process_namespaceObject.execFileSync)(cmd, args, {
320
+ encoding: 'utf8',
321
+ stdio: [
322
+ 'ignore',
323
+ 'pipe',
324
+ 'ignore'
325
+ ],
326
+ timeout: 2000
327
+ }).trim();
328
+ if (out && external_fs_default().existsSync(out)) return out;
329
+ } catch {}
330
+ } catch {}
331
+ return null;
332
+ }
160
333
  exports["default"] = __webpack_exports__["default"];
334
+ exports.getInstallGuidance = __webpack_exports__.getInstallGuidance;
335
+ exports.locateFirefoxOrExplain = __webpack_exports__.locateFirefoxOrExplain;
161
336
  for(var __webpack_i__ in __webpack_exports__)if (-1 === [
162
- "default"
337
+ "default",
338
+ "getInstallGuidance",
339
+ "locateFirefoxOrExplain"
163
340
  ].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
164
341
  Object.defineProperty(exports, '__esModule', {
165
342
  value: true
package/dist/index.d.ts CHANGED
@@ -17,3 +17,7 @@ export type Deps = {
17
17
  platform?: NodeJS.Platform;
18
18
  };
19
19
  export default function locateFirefox(allowFallbackOrDeps?: boolean | Deps, depsMaybe?: Deps): string | null;
20
+ export declare function getInstallGuidance(): string;
21
+ export declare function locateFirefoxOrExplain(options?: boolean | {
22
+ allowFallback?: boolean;
23
+ }): string;
package/dist/index.js CHANGED
@@ -2,6 +2,77 @@ import * as __WEBPACK_EXTERNAL_MODULE_fs__ from "fs";
2
2
  import * as __WEBPACK_EXTERNAL_MODULE_path__ from "path";
3
3
  import * as __WEBPACK_EXTERNAL_MODULE_os__ from "os";
4
4
  import * as __WEBPACK_EXTERNAL_MODULE_which__ from "which";
5
+ import * as __WEBPACK_EXTERNAL_MODULE_child_process__ from "child_process";
6
+ import * as __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__ from "node:fs";
7
+ import * as __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__ from "node:path";
8
+ function resolveFromPuppeteerCache(deps) {
9
+ const f = (null == deps ? void 0 : deps.fs) ?? __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"];
10
+ const env = (null == deps ? void 0 : deps.env) ?? process.env;
11
+ const platform = (null == deps ? void 0 : deps.platform) ?? process.platform;
12
+ try {
13
+ if ('darwin' === platform) {
14
+ const home = (null == deps ? void 0 : deps.homeDir) ?? env.HOME ?? '';
15
+ if (!home) return null;
16
+ const base = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(home, 'Library', 'Caches', 'puppeteer', 'firefox');
17
+ const dirs = listDirs(f, base).filter((d)=>d.startsWith('mac-') || d.startsWith('mac_arm-'));
18
+ const candidates = [];
19
+ for (const d of dirs){
20
+ candidates.push(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(base, d, 'Firefox.app', 'Contents', 'MacOS', 'firefox'));
21
+ candidates.push(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(base, d, 'Firefox Nightly.app', 'Contents', 'MacOS', 'firefox'));
22
+ }
23
+ return firstExisting(f, candidates);
24
+ }
25
+ if ('win32' === platform) {
26
+ const lad = (null == deps ? void 0 : deps.localAppData) ?? env.LOCALAPPDATA;
27
+ if (!lad) return null;
28
+ const base = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(lad, 'puppeteer', 'firefox');
29
+ const dirs = listDirs(f, base);
30
+ const preferred = [
31
+ ...dirs.filter((d)=>d.startsWith('win64-')),
32
+ ...dirs.filter((d)=>d.startsWith('win32-'))
33
+ ];
34
+ const candidates = [];
35
+ for (const d of preferred){
36
+ candidates.push(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(base, d, 'firefox.exe'));
37
+ candidates.push(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(base, d, 'firefox', 'firefox.exe'));
38
+ }
39
+ return firstExisting(f, candidates);
40
+ }
41
+ const xdg = env.XDG_CACHE_HOME;
42
+ const home = (null == deps ? void 0 : deps.homeDir) ?? env.HOME ?? '';
43
+ const cacheBase = xdg || (home ? __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(home, '.cache') : void 0);
44
+ if (!cacheBase) return null;
45
+ const base = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(cacheBase, 'puppeteer', 'firefox');
46
+ const dirs = listDirs(f, base).filter((d)=>d.startsWith('linux-'));
47
+ const candidates = [];
48
+ for (const d of dirs){
49
+ candidates.push(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(base, d, 'firefox'));
50
+ candidates.push(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(base, d, 'firefox', 'firefox'));
51
+ }
52
+ return firstExisting(f, candidates);
53
+ } catch {
54
+ return null;
55
+ }
56
+ }
57
+ function listDirs(f, dir) {
58
+ try {
59
+ return f.readdirSync(dir, {
60
+ withFileTypes: true
61
+ }).filter((e)=>{
62
+ if (!e) return false;
63
+ const v = e.isDirectory;
64
+ return 'function' == typeof v ? v.call(e) : Boolean(v);
65
+ }).map((e)=>e.name || String(e));
66
+ } catch {
67
+ return [];
68
+ }
69
+ }
70
+ function firstExisting(f, candidates) {
71
+ for (const c of candidates)try {
72
+ if (c && f.existsSync(c)) return c;
73
+ } catch {}
74
+ return null;
75
+ }
5
76
  function locateFirefox(allowFallbackOrDeps, depsMaybe) {
6
77
  const isBoolean = 'boolean' == typeof allowFallbackOrDeps;
7
78
  const allowFallback = isBoolean ? allowFallbackOrDeps : false;
@@ -12,10 +83,13 @@ function locateFirefox(allowFallbackOrDeps, depsMaybe) {
12
83
  const p = (null == deps ? void 0 : deps.path) ?? __WEBPACK_EXTERNAL_MODULE_path__["default"];
13
84
  const env = (null == deps ? void 0 : deps.env) ?? process.env;
14
85
  const platform = (null == deps ? void 0 : deps.platform) ?? process.platform;
86
+ const override = env.FIREFOX_BINARY;
87
+ if (override && f.existsSync(override)) return override;
15
88
  const osx = 'darwin' === platform;
16
89
  const win = 'win32' === platform;
17
90
  const other = !osx && !win;
18
91
  if (other) {
92
+ var _process_env, _process_env1;
19
93
  const stable = [
20
94
  'firefox'
21
95
  ];
@@ -48,9 +122,20 @@ function locateFirefox(allowFallbackOrDeps, depsMaybe) {
48
122
  ];
49
123
  for (const linuxPath of linuxPaths)if (f.existsSync(linuxPath)) return linuxPath;
50
124
  }
125
+ if (!deps) {
126
+ const viaCache = resolveFromPuppeteerCache();
127
+ if (viaCache) return viaCache;
128
+ }
129
+ const isTestEnv = 'test' === process.env.NODE_ENV || void 0 !== (null == (_process_env = process.env) ? void 0 : _process_env.VITEST) || void 0 !== (null == (_process_env1 = process.env) ? void 0 : _process_env1.JEST_WORKER_ID);
130
+ const skipCliProbe = isTestEnv && 'darwin' === process.platform;
131
+ if (allowFallback && !deps && !skipCliProbe) {
132
+ const viaCLI = resolveFromPuppeteerBrowsersCLI();
133
+ if (viaCLI) return viaCLI;
134
+ }
51
135
  return null;
52
136
  }
53
137
  if (osx) {
138
+ var _process_env2, _process_env3;
54
139
  const appsAll = [
55
140
  {
56
141
  app: 'Firefox.app',
@@ -80,9 +165,20 @@ function locateFirefox(allowFallbackOrDeps, depsMaybe) {
80
165
  const userPath = `${userBase}/${app}/Contents/MacOS/${exec}`;
81
166
  if (f.existsSync(userPath)) return userPath;
82
167
  }
168
+ if (!deps) {
169
+ const viaCache = resolveFromPuppeteerCache();
170
+ if (viaCache) return viaCache;
171
+ }
172
+ const isTestEnv = 'test' === process.env.NODE_ENV || void 0 !== (null == (_process_env2 = process.env) ? void 0 : _process_env2.VITEST) || void 0 !== (null == (_process_env3 = process.env) ? void 0 : _process_env3.JEST_WORKER_ID);
173
+ const skipCliProbe = isTestEnv && 'darwin' === process.platform;
174
+ if (allowFallback && !deps && !skipCliProbe) {
175
+ const viaCLI = resolveFromPuppeteerBrowsersCLI();
176
+ if (viaCLI) return viaCLI;
177
+ }
83
178
  return null;
84
179
  }
85
180
  {
181
+ var _process_env4, _process_env5;
86
182
  const prefixes = [
87
183
  env.LOCALAPPDATA,
88
184
  env.PROGRAMFILES,
@@ -113,7 +209,80 @@ function locateFirefox(allowFallbackOrDeps, depsMaybe) {
113
209
  ];
114
210
  const defaultPaths = allowFallback ? defaultPathsAll : defaultPathsAll.slice(0, 2);
115
211
  for (const defaultPath of defaultPaths)if (f.existsSync(defaultPath)) return defaultPath;
212
+ if (!deps) {
213
+ const viaCache = resolveFromPuppeteerCache();
214
+ if (viaCache) return viaCache;
215
+ }
216
+ const isTestEnv = 'test' === process.env.NODE_ENV || void 0 !== (null == (_process_env4 = process.env) ? void 0 : _process_env4.VITEST) || void 0 !== (null == (_process_env5 = process.env) ? void 0 : _process_env5.JEST_WORKER_ID);
217
+ const skipCliProbe = isTestEnv && 'darwin' === process.platform;
218
+ if (allowFallback && !deps && !skipCliProbe) {
219
+ const viaCLI = resolveFromPuppeteerBrowsersCLI();
220
+ if (viaCLI) return viaCLI;
221
+ }
116
222
  return null;
117
223
  }
118
224
  }
119
- export { locateFirefox as default };
225
+ function getInstallGuidance() {
226
+ return "We couldn't find a Firefox browser on this machine.\n\nHere's the fastest way to get set up:\n\n1) Install Firefox via Puppeteer Browsers (recommended for CI/dev)\n npx @puppeteer/browsers install firefox@stable\n\nThen re-run your command — we will detect it automatically.\n\nAlternatively, install Firefox using your OS package manager and re-run.";
227
+ }
228
+ function locateFirefoxOrExplain(options) {
229
+ const allowFallback = 'boolean' == typeof options ? options : Boolean(null == options ? void 0 : options.allowFallback);
230
+ const found = locateFirefox(allowFallback) || locateFirefox(true);
231
+ if ('string' == typeof found && found) return found;
232
+ throw new Error(getInstallGuidance());
233
+ }
234
+ function resolveFromPuppeteerBrowsersCLI() {
235
+ try {
236
+ const attempts = [
237
+ {
238
+ cmd: 'npx',
239
+ args: [
240
+ '-y',
241
+ '@puppeteer/browsers',
242
+ 'path',
243
+ 'firefox@stable'
244
+ ]
245
+ },
246
+ {
247
+ cmd: 'pnpm',
248
+ args: [
249
+ 'dlx',
250
+ '@puppeteer/browsers',
251
+ 'path',
252
+ 'firefox@stable'
253
+ ]
254
+ },
255
+ {
256
+ cmd: 'yarn',
257
+ args: [
258
+ 'dlx',
259
+ '@puppeteer/browsers',
260
+ 'path',
261
+ 'firefox@stable'
262
+ ]
263
+ },
264
+ {
265
+ cmd: 'bunx',
266
+ args: [
267
+ '@puppeteer/browsers',
268
+ 'path',
269
+ 'firefox@stable'
270
+ ]
271
+ }
272
+ ];
273
+ for (const { cmd, args } of attempts)try {
274
+ const out = (0, __WEBPACK_EXTERNAL_MODULE_child_process__.execFileSync)(cmd, args, {
275
+ encoding: 'utf8',
276
+ stdio: [
277
+ 'ignore',
278
+ 'pipe',
279
+ 'ignore'
280
+ ],
281
+ timeout: 2000
282
+ }).trim();
283
+ if (out && __WEBPACK_EXTERNAL_MODULE_fs__["default"].existsSync(out)) return out;
284
+ } catch {}
285
+ } catch {}
286
+ return null;
287
+ }
288
+ export { locateFirefox as default, getInstallGuidance, locateFirefoxOrExplain };
@@ -0,0 +1,11 @@
1
+ import fs from 'node:fs';
2
+ type FsLike = Pick<typeof fs, 'existsSync' | 'readdirSync'>;
3
+ type EnvLike = NodeJS.ProcessEnv;
4
+ export declare function resolveFromPuppeteerCache(deps?: {
5
+ fs?: FsLike;
6
+ env?: EnvLike;
7
+ platform?: NodeJS.Platform;
8
+ homeDir?: string;
9
+ localAppData?: string;
10
+ }): string | null;
11
+ export {};
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.0.1",
8
+ "version": "2.0.4",
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",
@@ -26,13 +26,17 @@
26
26
  },
27
27
  "scripts": {
28
28
  "build": "rslib build",
29
- "check": "biome check --write",
29
+ "check": "pnpm dlx @biomejs/biome@1.9.4 check --write",
30
30
  "dev": "rslib build --watch",
31
- "format": "biome format --write",
32
- "test": "vitest run",
31
+ "format": "pnpm dlx @biomejs/biome@1.9.4 format --write",
32
+ "test": "vitest run --pool vmForks --poolOptions.vmForks.singleFork",
33
33
  "prepublishOnly": "npm run build",
34
34
  "publish:provenance": "np patch --no-tests --any-branch --yolo --message 'release: %s' --provenance"
35
35
  },
36
+ "engines": {
37
+ "node": ">=18 <23"
38
+ },
39
+ "engineStrict": true,
36
40
  "publishConfig": {
37
41
  "provenance": true
38
42
  },