@hominis/fireforge 0.37.0 → 0.38.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 (58) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +1 -1
  3. package/dist/src/commands/build.js +5 -5
  4. package/dist/src/commands/config.js +1 -0
  5. package/dist/src/commands/download.js +5 -2
  6. package/dist/src/commands/export-flow.d.ts +5 -1
  7. package/dist/src/commands/export-flow.js +10 -7
  8. package/dist/src/commands/export-placement-gate.js +3 -5
  9. package/dist/src/commands/export-placement-policy.d.ts +11 -3
  10. package/dist/src/commands/export-placement-policy.js +32 -29
  11. package/dist/src/commands/export.js +5 -5
  12. package/dist/src/commands/furnace/index.js +23 -18
  13. package/dist/src/commands/patch/move-files-create.d.ts +19 -0
  14. package/dist/src/commands/patch/move-files-create.js +116 -0
  15. package/dist/src/commands/patch/move-files.d.ts +3 -1
  16. package/dist/src/commands/patch/move-files.js +49 -4
  17. package/dist/src/commands/patch/split.d.ts +11 -1
  18. package/dist/src/commands/patch/split.js +6 -5
  19. package/dist/src/commands/re-export-scan.d.ts +17 -0
  20. package/dist/src/commands/re-export-scan.js +51 -0
  21. package/dist/src/commands/re-export.js +17 -6
  22. package/dist/src/commands/source.js +28 -3
  23. package/dist/src/commands/test-register.js +6 -5
  24. package/dist/src/commands/test-stale-gate.d.ts +44 -0
  25. package/dist/src/commands/test-stale-gate.js +81 -0
  26. package/dist/src/commands/test.js +15 -50
  27. package/dist/src/core/build-audit.d.ts +12 -0
  28. package/dist/src/core/build-audit.js +14 -0
  29. package/dist/src/core/build-baseline-types.d.ts +34 -0
  30. package/dist/src/core/build-baseline.d.ts +6 -1
  31. package/dist/src/core/build-baseline.js +47 -7
  32. package/dist/src/core/config-paths.d.ts +1 -1
  33. package/dist/src/core/config-paths.js +1 -0
  34. package/dist/src/core/config-validate.js +6 -1
  35. package/dist/src/core/engine-session-lock.d.ts +10 -1
  36. package/dist/src/core/engine-session-lock.js +28 -2
  37. package/dist/src/core/file-lock.d.ts +33 -0
  38. package/dist/src/core/file-lock.js +32 -6
  39. package/dist/src/core/firefox-archive.d.ts +2 -1
  40. package/dist/src/core/firefox-archive.js +32 -8
  41. package/dist/src/core/firefox.d.ts +8 -3
  42. package/dist/src/core/firefox.js +11 -6
  43. package/dist/src/core/furnace-validate-helpers.js +28 -1
  44. package/dist/src/core/license-headers.d.ts +12 -0
  45. package/dist/src/core/license-headers.js +76 -1
  46. package/dist/src/core/patch-lint.d.ts +3 -0
  47. package/dist/src/core/patch-lint.js +25 -7
  48. package/dist/src/core/status-classify.d.ts +11 -2
  49. package/dist/src/core/status-classify.js +49 -25
  50. package/dist/src/core/test-stale-check.d.ts +41 -1
  51. package/dist/src/core/test-stale-check.js +77 -3
  52. package/dist/src/types/commands/options.d.ts +57 -3
  53. package/dist/src/types/config.d.ts +7 -0
  54. package/dist/src/utils/options.d.ts +20 -0
  55. package/dist/src/utils/options.js +39 -0
  56. package/dist/src/utils/validation.d.ts +5 -0
  57. package/dist/src/utils/validation.js +7 -0
  58. package/package.json +3 -3
@@ -43,6 +43,10 @@ export interface SourceSetOptions {
43
43
  sha256?: string;
44
44
  /** Clear any existing pinned SHA-256 */
45
45
  clearSha256?: boolean;
46
+ /** Optional release-candidate build directory (e.g. "build2") */
47
+ candidate?: string;
48
+ /** Clear any existing release-candidate build directory */
49
+ clearCandidate?: boolean;
46
50
  }
47
51
  /**
48
52
  * Options for the build command.
@@ -62,6 +66,12 @@ export interface BuildOptions {
62
66
  * for any mismatch the rewriter cannot prove safe.
63
67
  */
64
68
  rewriteMozinfo?: boolean;
69
+ /**
70
+ * Parsed `--wait-lock [seconds]` value (`true` for the bare flag, meaning
71
+ * 60). Consumed at the CLI layer to bound the engine-session-lock wait;
72
+ * the command implementation ignores it.
73
+ */
74
+ waitLock?: number | boolean;
65
75
  }
66
76
  /**
67
77
  * Options for the export command.
@@ -112,6 +122,12 @@ export interface ExportOptions {
112
122
  * another patch, because the resulting queue fails `verify` immediately.
113
123
  */
114
124
  allowOverlap?: boolean;
125
+ /**
126
+ * Parsed `--wait-lock [seconds]` value (`true` for the bare flag, meaning
127
+ * 60). Consumed at the CLI layer to bound the engine-session-lock wait;
128
+ * the command implementation ignores it.
129
+ */
130
+ waitLock?: number | boolean;
115
131
  /**
116
132
  * Force a tier override on the new patch's `PatchMetadata.tier`. Only
117
133
  * `"branding"` is currently recognised — Commander rejects other values
@@ -251,6 +267,12 @@ export interface ReExportOptions {
251
267
  * patch to also suppress X").
252
268
  */
253
269
  lintIgnore?: string[];
270
+ /**
271
+ * Parsed `--wait-lock [seconds]` value (`true` for the bare flag, meaning
272
+ * 60). Consumed at the CLI layer to bound the engine-session-lock wait;
273
+ * the command implementation ignores it.
274
+ */
275
+ waitLock?: number | boolean;
254
276
  }
255
277
  /**
256
278
  * Options for the `fireforge patch tier` subcommand. Sets or clears the
@@ -350,13 +372,31 @@ export interface PatchSplitOptions {
350
372
  skipLint?: boolean;
351
373
  }
352
374
  /**
353
- * Options for the preview-only `fireforge patch move-files` subcommand.
354
- * It validates an ownership transfer and prints the explicit
355
- * `re-export --files` commands needed to perform it.
375
+ * Options for the `fireforge patch move-files` subcommand. Without
376
+ * `--create` it is preview-only: it validates an ownership transfer and
377
+ * prints the explicit `re-export --files` commands needed to perform it.
378
+ * With `--create --order <n>` the target patch is created at that order
379
+ * and the files move into it as one split-style transaction.
356
380
  */
357
381
  export interface PatchMoveFilesOptions {
358
382
  /** File paths relative to engine/ to move from the source patch to the target patch. */
359
383
  file?: string[];
384
+ /** Create the target patch (transactional bootstrap of a split). Requires `order`. */
385
+ create?: boolean;
386
+ /** Exact sparse order for the created patch. Only valid with `create`. */
387
+ order?: number;
388
+ /** Category for the created patch; defaults to the source patch's. */
389
+ category?: string;
390
+ /** Description for the created patch. */
391
+ description?: string;
392
+ /** Preview the create+move without writing. */
393
+ dryRun?: boolean;
394
+ /** Skip interactive confirmation (required for non-TTY). */
395
+ yes?: boolean;
396
+ /** Bypass projected-lint refusals. */
397
+ forceUnsafe?: boolean;
398
+ /** Skip per-patch lint of the projected bodies. */
399
+ skipLint?: boolean;
360
400
  }
361
401
  /**
362
402
  * Options for the rebase command.
@@ -457,6 +497,14 @@ export interface TestOptions {
457
497
  killStaleMarionette?: boolean;
458
498
  /** Permit tests against packageable engine edits newer than the last successful build. */
459
499
  allowStaleBuild?: boolean;
500
+ /**
501
+ * Permit tests despite `components.conf` changes that only a full
502
+ * `fireforge build` compiles into the StaticComponents table — the
503
+ * packaged child process will resolve the OLD table. For operators who
504
+ * rebuilt out-of-band and accept the risk; distinct from
505
+ * `allowStaleBuild`, which only accepts stale packaged content.
506
+ */
507
+ allowStaleComponents?: boolean;
460
508
  /** Run the configured short harness canary. `true` means use `fireforge.json`'s test.canaryPath. */
461
509
  canary?: string | boolean;
462
510
  /**
@@ -487,6 +535,12 @@ export interface TestOptions {
487
535
  * checkers that consume a sample artifact after the run.
488
536
  */
489
537
  perfSamples?: string;
538
+ /**
539
+ * Parsed `--wait-lock [seconds]` value (`true` for the bare flag, meaning
540
+ * 60). Consumed at the CLI layer to bound the engine-session-lock wait;
541
+ * the command implementation ignores it.
542
+ */
543
+ waitLock?: number | boolean;
490
544
  }
491
545
  /**
492
546
  * Options for the furnace apply command.
@@ -12,6 +12,13 @@ export interface FirefoxConfig {
12
12
  product: FirefoxProduct;
13
13
  /** Optional pinned SHA-256 for the resolved source archive */
14
14
  sha256?: string;
15
+ /**
16
+ * Optional release-candidate build directory (e.g. "build2"). When set,
17
+ * the source archive resolves under
18
+ * `pub/<product>/candidates/<version>-candidates/<candidate>/` instead of
19
+ * `pub/<product>/releases/<version>/`, for pre-release verification.
20
+ */
21
+ candidate?: string;
15
22
  }
16
23
  /**
17
24
  * Supported project license SPDX identifiers.
@@ -6,6 +6,7 @@
6
6
  export declare function pickDefined<T extends Record<string, unknown>>(obj: T): {
7
7
  [K in keyof T]+?: Exclude<T[K], undefined>;
8
8
  };
9
+ import type { Command } from 'commander';
9
10
  /**
10
11
  * Wraps an option-argument parser so its failures surface through
11
12
  * commander's own invalid-argument channel.
@@ -21,3 +22,22 @@ export declare function pickDefined<T extends Record<string, unknown>>(obj: T):
21
22
  * helper (or throw commander's InvalidArgumentError directly).
22
23
  */
23
24
  export declare function commanderArgParser<T>(parse: (raw: string) => T): (raw: string) => T;
25
+ /**
26
+ * Resolves the parsed `--wait-lock [seconds]` option value into a wait budget
27
+ * in seconds for `withEngineSessionLock`:
28
+ * - absent (`undefined`) → `undefined` (legacy ~1 s fail-fast),
29
+ * - bare flag (`true`) → {@link DEFAULT_WAIT_LOCK_SECONDS},
30
+ * - explicit value → integer validated into 1..3600.
31
+ *
32
+ * Accepts the raw string too, so it doubles as the option's arg parser (wrap
33
+ * with {@link commanderArgParser} so failures surface through commander's
34
+ * invalid-argument channel).
35
+ */
36
+ export declare function resolveWaitLockSeconds(value: string | number | boolean | undefined): number | undefined;
37
+ /**
38
+ * Registers the shared `--wait-lock [seconds]` flag on an engine-mutating
39
+ * command. The parsed option value is `true` for the bare flag or a validated
40
+ * integer; feed it through {@link resolveWaitLockSeconds} at the call site to
41
+ * obtain the `waitLockSeconds` for `withEngineSessionLock`.
42
+ */
43
+ export declare function addWaitLockOption(command: Command): Command;
@@ -14,6 +14,7 @@ export function pickDefined(obj) {
14
14
  return result;
15
15
  }
16
16
  import { InvalidArgumentError as CommanderInvalidArgumentError } from 'commander';
17
+ import { GeneralError } from '../errors/base.js';
17
18
  /**
18
19
  * Wraps an option-argument parser so its failures surface through
19
20
  * commander's own invalid-argument channel.
@@ -38,3 +39,41 @@ export function commanderArgParser(parse) {
38
39
  }
39
40
  };
40
41
  }
42
+ /** Wait budget applied when `--wait-lock` is passed without a value. */
43
+ const DEFAULT_WAIT_LOCK_SECONDS = 60;
44
+ /**
45
+ * Resolves the parsed `--wait-lock [seconds]` option value into a wait budget
46
+ * in seconds for `withEngineSessionLock`:
47
+ * - absent (`undefined`) → `undefined` (legacy ~1 s fail-fast),
48
+ * - bare flag (`true`) → {@link DEFAULT_WAIT_LOCK_SECONDS},
49
+ * - explicit value → integer validated into 1..3600.
50
+ *
51
+ * Accepts the raw string too, so it doubles as the option's arg parser (wrap
52
+ * with {@link commanderArgParser} so failures surface through commander's
53
+ * invalid-argument channel).
54
+ */
55
+ export function resolveWaitLockSeconds(value) {
56
+ if (value === undefined || value === false) {
57
+ return undefined;
58
+ }
59
+ if (value === true) {
60
+ return DEFAULT_WAIT_LOCK_SECONDS;
61
+ }
62
+ if (typeof value === 'number') {
63
+ return value;
64
+ }
65
+ const n = Number.parseInt(value, 10);
66
+ if (!Number.isFinite(n) || n < 1 || n > 3600) {
67
+ throw new GeneralError(`--wait-lock must be an integer in 1..3600 (got "${value}")`);
68
+ }
69
+ return n;
70
+ }
71
+ /**
72
+ * Registers the shared `--wait-lock [seconds]` flag on an engine-mutating
73
+ * command. The parsed option value is `true` for the bare flag or a validated
74
+ * integer; feed it through {@link resolveWaitLockSeconds} at the call site to
75
+ * obtain the `waitLockSeconds` for `withEngineSessionLock`.
76
+ */
77
+ export function addWaitLockOption(command) {
78
+ return command.option('--wait-lock [seconds]', 'Wait up to this many seconds (default 60) for another FireForge engine-mutating command to release the engine lock, instead of failing immediately', commanderArgParser((raw) => resolveWaitLockSeconds(raw)));
79
+ }
@@ -57,6 +57,11 @@ export declare function isArray(value: unknown): value is unknown[];
57
57
  * Accepts formats like "140.9.0", "140.9.1", "140.9.0esr", "147.0b1"
58
58
  */
59
59
  export declare function isValidFirefoxVersion(version: string): boolean;
60
+ /**
61
+ * Validates a release-candidate build directory name.
62
+ * Accepts formats like "build1", "build2", "build12" (no leading zero).
63
+ */
64
+ export declare function isValidFirefoxCandidate(candidate: string): boolean;
60
65
  /**
61
66
  * Validates a Firefox product string.
62
67
  * Accepts: firefox, firefox-esr, firefox-beta, firefox-devedition
@@ -87,6 +87,13 @@ export function isValidFirefoxVersion(version) {
87
87
  // Beta: 147.0b1, 147.0b2
88
88
  return /^[1-9]\d{0,2}\.\d+(?:b[1-9]\d*|\.\d+(?:esr)?|esr)?$/.test(version);
89
89
  }
90
+ /**
91
+ * Validates a release-candidate build directory name.
92
+ * Accepts formats like "build1", "build2", "build12" (no leading zero).
93
+ */
94
+ export function isValidFirefoxCandidate(candidate) {
95
+ return /^build[1-9]\d{0,3}$/.test(candidate);
96
+ }
90
97
  /**
91
98
  * Validates a Firefox product string.
92
99
  * Accepts: firefox, firefox-esr, firefox-beta, firefox-devedition
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hominis/fireforge",
3
- "version": "0.37.0",
3
+ "version": "0.38.0",
4
4
  "description": "FireForge — a build tool for customizing Firefox",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -73,9 +73,9 @@
73
73
  "eslint-plugin-simple-import-sort": "^13.0.0",
74
74
  "fast-check": "^4.6.0",
75
75
  "husky": "^9.1.7",
76
- "knip": "6.25.0",
76
+ "knip": "6.26.0",
77
77
  "lint-staged": "^17.0.4",
78
- "prettier": "3.9.4",
78
+ "prettier": "3.9.5",
79
79
  "tsx": "^4.7.0",
80
80
  "typescript": "~6.0.0",
81
81
  "typescript-eslint": "^8.0.0",