@hominis/fireforge 0.19.5 → 0.20.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.
Files changed (37) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +21 -8
  3. package/dist/src/commands/config.js +1 -0
  4. package/dist/src/commands/download.js +188 -185
  5. package/dist/src/commands/export-flow.js +2 -13
  6. package/dist/src/commands/furnace/create-validation.d.ts +6 -0
  7. package/dist/src/commands/furnace/create-validation.js +59 -0
  8. package/dist/src/commands/furnace/create.d.ts +7 -7
  9. package/dist/src/commands/furnace/create.js +21 -96
  10. package/dist/src/commands/furnace/index.js +2 -2
  11. package/dist/src/commands/furnace/refresh.js +11 -2
  12. package/dist/src/commands/furnace/remove-state.d.ts +5 -0
  13. package/dist/src/commands/furnace/remove-state.js +14 -0
  14. package/dist/src/commands/furnace/remove.js +30 -45
  15. package/dist/src/commands/furnace/rename-helpers.d.ts +13 -0
  16. package/dist/src/commands/furnace/rename-helpers.js +42 -0
  17. package/dist/src/commands/furnace/rename.js +27 -47
  18. package/dist/src/core/config-paths.d.ts +1 -1
  19. package/dist/src/core/config-paths.js +1 -0
  20. package/dist/src/core/config-validate.js +5 -0
  21. package/dist/src/core/config.js +11 -7
  22. package/dist/src/core/file-lock.js +2 -2
  23. package/dist/src/core/firefox-cache.d.ts +1 -1
  24. package/dist/src/core/firefox-cache.js +43 -17
  25. package/dist/src/core/firefox-download.js +12 -4
  26. package/dist/src/core/firefox.d.ts +1 -1
  27. package/dist/src/core/firefox.js +2 -2
  28. package/dist/src/core/furnace-refresh.js +16 -5
  29. package/dist/src/core/patch-lint-imports.d.ts +5 -0
  30. package/dist/src/core/patch-lint-imports.js +68 -0
  31. package/dist/src/core/patch-lint.js +2 -3
  32. package/dist/src/types/commands/options.d.ts +9 -9
  33. package/dist/src/types/config.d.ts +2 -0
  34. package/dist/src/utils/fs.d.ts +5 -0
  35. package/dist/src/utils/fs.js +54 -1
  36. package/dist/src/utils/process.js +4 -1
  37. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  import { randomUUID } from 'node:crypto';
3
- import { access, copyFile as fsCopyFile, mkdir, open, readdir, readFile, rename, rm, statfs, } from 'node:fs/promises';
3
+ import { access, chmod, copyFile as fsCopyFile, mkdir, open, readdir, readFile, rename, rm, stat, statfs, } from 'node:fs/promises';
4
4
  import { dirname, join } from 'node:path';
5
5
  const RETRIABLE_REMOVE_ERRORS = new Set(['ENOTEMPTY', 'EBUSY', 'EPERM']);
6
6
  function sleep(ms) {
@@ -22,6 +22,25 @@ export async function pathExists(path) {
22
22
  return false;
23
23
  }
24
24
  }
25
+ /**
26
+ * Checks if a path exists while surfacing permission errors.
27
+ * @param path - Path to check
28
+ */
29
+ export async function pathExistsStrict(path) {
30
+ try {
31
+ await access(path);
32
+ return true;
33
+ }
34
+ catch (error) {
35
+ const code = error instanceof Error && 'code' in error && typeof error.code === 'string'
36
+ ? error.code
37
+ : undefined;
38
+ if (code === 'ENOENT') {
39
+ return false;
40
+ }
41
+ throw error;
42
+ }
43
+ }
25
44
  /**
26
45
  * Ensures a directory exists, creating it recursively if needed.
27
46
  * @param path - Directory path to ensure
@@ -137,6 +156,18 @@ export async function writeTextIfChanged(path, content) {
137
156
  */
138
157
  export async function writeFileAtomic(path, content) {
139
158
  await ensureParentDir(path);
159
+ let existingMode;
160
+ try {
161
+ existingMode = (await stat(path)).mode;
162
+ }
163
+ catch (error) {
164
+ const code = error instanceof Error && 'code' in error && typeof error.code === 'string'
165
+ ? error.code
166
+ : undefined;
167
+ if (code !== 'ENOENT') {
168
+ throw error;
169
+ }
170
+ }
140
171
  const tempPath = createAtomicTempPath(path);
141
172
  const handle = await open(tempPath, 'w');
142
173
  try {
@@ -150,13 +181,35 @@ export async function writeFileAtomic(path, content) {
150
181
  }
151
182
  await handle.close();
152
183
  try {
184
+ if (existingMode !== undefined) {
185
+ await chmod(tempPath, existingMode);
186
+ }
153
187
  await rename(tempPath, path);
188
+ await syncParentDir(path);
154
189
  }
155
190
  catch (error) {
156
191
  await rm(tempPath, { force: true });
157
192
  throw error;
158
193
  }
159
194
  }
195
+ async function syncParentDir(path) {
196
+ let directoryHandle;
197
+ try {
198
+ directoryHandle = await open(dirname(path), 'r');
199
+ await directoryHandle.sync();
200
+ }
201
+ catch (error) {
202
+ void error;
203
+ }
204
+ finally {
205
+ try {
206
+ await directoryHandle?.close();
207
+ }
208
+ catch (error) {
209
+ void error;
210
+ }
211
+ }
212
+ }
160
213
  /**
161
214
  * Copies a directory recursively.
162
215
  * @param src - Source directory path
@@ -367,7 +367,10 @@ export async function findExecutable(name) {
367
367
  const result = await exec(command, [name]);
368
368
  if (result.exitCode === 0 && result.stdout.trim()) {
369
369
  // Return the first line (first match)
370
- return result.stdout.trim().split('\n')[0];
370
+ return result.stdout
371
+ .split(/\r?\n/)
372
+ .map((line) => line.trim())
373
+ .find((line) => line.length > 0);
371
374
  }
372
375
  return undefined;
373
376
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hominis/fireforge",
3
- "version": "0.19.5",
3
+ "version": "0.20.0",
4
4
  "description": "FireForge — a build tool for customizing Firefox",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",