@hominis/fireforge 0.10.1 → 0.11.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.
- package/CHANGELOG.md +93 -1
- package/README.md +125 -238
- package/dist/bin/fireforge.js +26 -0
- package/dist/src/cli.d.ts +1 -1
- package/dist/src/cli.js +131 -52
- package/dist/src/commands/bootstrap.js +6 -2
- package/dist/src/commands/build.js +4 -2
- package/dist/src/commands/discard.js +16 -4
- package/dist/src/commands/doctor-furnace.d.ts +8 -0
- package/dist/src/commands/doctor-furnace.js +422 -0
- package/dist/src/commands/doctor.d.ts +115 -0
- package/dist/src/commands/doctor.js +327 -258
- package/dist/src/commands/download.js +16 -1
- package/dist/src/commands/export-all.js +15 -0
- package/dist/src/commands/export-flow.d.ts +91 -0
- package/dist/src/commands/export-flow.js +344 -0
- package/dist/src/commands/export.js +151 -5
- package/dist/src/commands/furnace/apply.d.ts +3 -2
- package/dist/src/commands/furnace/apply.js +169 -36
- package/dist/src/commands/furnace/create.js +162 -52
- package/dist/src/commands/furnace/deploy.js +156 -144
- package/dist/src/commands/furnace/diff.d.ts +8 -4
- package/dist/src/commands/furnace/diff.js +142 -73
- package/dist/src/commands/furnace/index.d.ts +6 -2
- package/dist/src/commands/furnace/index.js +76 -25
- package/dist/src/commands/furnace/init.d.ts +11 -0
- package/dist/src/commands/furnace/init.js +76 -0
- package/dist/src/commands/furnace/list.d.ts +4 -1
- package/dist/src/commands/furnace/list.js +35 -3
- package/dist/src/commands/furnace/override.d.ts +8 -0
- package/dist/src/commands/furnace/override.js +216 -26
- package/dist/src/commands/furnace/preview.js +184 -30
- package/dist/src/commands/furnace/refresh.d.ts +10 -0
- package/dist/src/commands/furnace/refresh.js +268 -0
- package/dist/src/commands/furnace/remove.js +285 -89
- package/dist/src/commands/furnace/rename.d.ts +5 -0
- package/dist/src/commands/furnace/rename.js +308 -0
- package/dist/src/commands/furnace/scan.d.ts +4 -1
- package/dist/src/commands/furnace/scan.js +72 -11
- package/dist/src/commands/furnace/status.js +85 -20
- package/dist/src/commands/furnace/sync.d.ts +12 -0
- package/dist/src/commands/furnace/sync.js +77 -0
- package/dist/src/commands/furnace/validate.d.ts +4 -1
- package/dist/src/commands/furnace/validate.js +99 -3
- package/dist/src/commands/furnace/validation-output.d.ts +24 -1
- package/dist/src/commands/furnace/validation-output.js +93 -1
- package/dist/src/commands/import.js +37 -4
- package/dist/src/commands/lint.js +11 -2
- package/dist/src/commands/manifest.d.ts +39 -0
- package/dist/src/commands/manifest.js +59 -0
- package/dist/src/commands/patch/delete.d.ts +28 -0
- package/dist/src/commands/patch/delete.js +209 -0
- package/dist/src/commands/patch/index.d.ts +17 -0
- package/dist/src/commands/patch/index.js +25 -0
- package/dist/src/commands/patch/reorder.d.ts +30 -0
- package/dist/src/commands/patch/reorder.js +377 -0
- package/dist/src/commands/re-export-files.d.ts +17 -0
- package/dist/src/commands/re-export-files.js +177 -0
- package/dist/src/commands/re-export.js +44 -0
- package/dist/src/commands/rebase/abort.d.ts +1 -1
- package/dist/src/commands/rebase/abort.js +12 -3
- package/dist/src/commands/rebase/confirm.d.ts +3 -3
- package/dist/src/commands/rebase/confirm.js +4 -4
- package/dist/src/commands/rebase/index.js +13 -4
- package/dist/src/commands/reset.js +20 -4
- package/dist/src/commands/run.js +46 -1
- package/dist/src/commands/setup-support.js +5 -5
- package/dist/src/commands/status.js +97 -6
- package/dist/src/commands/test.js +5 -37
- package/dist/src/commands/verify.d.ts +31 -0
- package/dist/src/commands/verify.js +126 -0
- package/dist/src/core/build-prepare.js +40 -16
- package/dist/src/core/destructive.d.ts +96 -0
- package/dist/src/core/destructive.js +137 -0
- package/dist/src/core/diff-hunks.d.ts +73 -0
- package/dist/src/core/diff-hunks.js +268 -0
- package/dist/src/core/firefox.d.ts +1 -1
- package/dist/src/core/firefox.js +1 -1
- package/dist/src/core/furnace-apply-helpers.d.ts +89 -6
- package/dist/src/core/furnace-apply-helpers.js +302 -57
- package/dist/src/core/furnace-apply-output.d.ts +16 -0
- package/dist/src/core/furnace-apply-output.js +57 -0
- package/dist/src/core/furnace-apply.d.ts +21 -3
- package/dist/src/core/furnace-apply.js +260 -29
- package/dist/src/core/furnace-checksum-utils.d.ts +4 -0
- package/dist/src/core/furnace-checksum-utils.js +24 -0
- package/dist/src/core/furnace-config.d.ts +28 -1
- package/dist/src/core/furnace-config.js +180 -17
- package/dist/src/core/furnace-constants.d.ts +22 -0
- package/dist/src/core/furnace-constants.js +36 -0
- package/dist/src/core/furnace-graph-utils.d.ts +11 -0
- package/dist/src/core/furnace-graph-utils.js +94 -0
- package/dist/src/core/furnace-operation.d.ts +108 -0
- package/dist/src/core/furnace-operation.js +220 -0
- package/dist/src/core/furnace-refresh.d.ts +20 -0
- package/dist/src/core/furnace-refresh.js +118 -0
- package/dist/src/core/furnace-registration-ast.d.ts +5 -0
- package/dist/src/core/furnace-registration-ast.js +134 -4
- package/dist/src/core/furnace-registration-remove.d.ts +25 -3
- package/dist/src/core/furnace-registration-remove.js +196 -62
- package/dist/src/core/furnace-registration-validate.d.ts +13 -1
- package/dist/src/core/furnace-registration-validate.js +15 -3
- package/dist/src/core/furnace-registration.d.ts +27 -4
- package/dist/src/core/furnace-registration.js +93 -11
- package/dist/src/core/furnace-rollback.d.ts +11 -0
- package/dist/src/core/furnace-rollback.js +78 -7
- package/dist/src/core/furnace-scanner.d.ts +8 -2
- package/dist/src/core/furnace-scanner.js +152 -55
- package/dist/src/core/furnace-stories.js +7 -5
- package/dist/src/core/furnace-validate-accessibility.js +7 -1
- package/dist/src/core/furnace-validate-compatibility.d.ts +1 -1
- package/dist/src/core/furnace-validate-compatibility.js +85 -1
- package/dist/src/core/furnace-validate-helpers.d.ts +4 -0
- package/dist/src/core/furnace-validate-helpers.js +31 -0
- package/dist/src/core/furnace-validate-registration.d.ts +17 -2
- package/dist/src/core/furnace-validate-registration.js +73 -3
- package/dist/src/core/furnace-validate-structure.d.ts +10 -2
- package/dist/src/core/furnace-validate-structure.js +45 -3
- package/dist/src/core/furnace-validate.d.ts +10 -1
- package/dist/src/core/furnace-validate.js +80 -6
- package/dist/src/core/furnace-version-drift.d.ts +55 -0
- package/dist/src/core/furnace-version-drift.js +101 -0
- package/dist/src/core/git-file-ops.d.ts +8 -0
- package/dist/src/core/git-file-ops.js +19 -6
- package/dist/src/core/lint-projection.d.ts +25 -0
- package/dist/src/core/lint-projection.js +44 -0
- package/dist/src/core/mach.d.ts +4 -2
- package/dist/src/core/mach.js +17 -2
- package/dist/src/core/markdown-table.d.ts +104 -0
- package/dist/src/core/markdown-table.js +266 -0
- package/dist/src/core/ownership-table.d.ts +53 -0
- package/dist/src/core/ownership-table.js +144 -0
- package/dist/src/core/patch-apply.d.ts +17 -3
- package/dist/src/core/patch-apply.js +86 -8
- package/dist/src/core/patch-export.d.ts +119 -5
- package/dist/src/core/patch-export.js +183 -25
- package/dist/src/core/patch-lint-cross.d.ts +195 -0
- package/dist/src/core/patch-lint-cross.js +428 -0
- package/dist/src/core/patch-lint-diff.d.ts +33 -0
- package/dist/src/core/patch-lint-diff.js +84 -0
- package/dist/src/core/patch-lint.d.ts +2 -4
- package/dist/src/core/patch-lint.js +12 -50
- package/dist/src/core/patch-lock.js +2 -1
- package/dist/src/core/patch-manifest-io.d.ts +102 -1
- package/dist/src/core/patch-manifest-io.js +270 -2
- package/dist/src/core/patch-manifest-query.d.ts +1 -1
- package/dist/src/core/patch-manifest-query.js +1 -1
- package/dist/src/core/patch-manifest.d.ts +1 -1
- package/dist/src/core/patch-manifest.js +1 -1
- package/dist/src/core/patch-transform.d.ts +12 -0
- package/dist/src/core/patch-transform.js +21 -7
- package/dist/src/core/token-manager.js +67 -69
- package/dist/src/core/wire-destroy.js +6 -3
- package/dist/src/core/wire-init.js +10 -4
- package/dist/src/core/wire-subscript.js +9 -3
- package/dist/src/core/wire-utils.d.ts +52 -5
- package/dist/src/core/wire-utils.js +69 -6
- package/dist/src/errors/base.d.ts +20 -0
- package/dist/src/errors/base.js +24 -0
- package/dist/src/errors/furnace.js +7 -1
- package/dist/src/errors/rebase.js +6 -1
- package/dist/src/types/commands/index.d.ts +1 -1
- package/dist/src/types/commands/options.d.ts +125 -4
- package/dist/src/types/commands/patches.d.ts +11 -1
- package/dist/src/types/config.d.ts +1 -1
- package/dist/src/types/furnace.d.ts +55 -1
- package/dist/src/utils/fs.d.ts +12 -0
- package/dist/src/utils/fs.js +30 -1
- package/dist/src/utils/package-root.d.ts +5 -0
- package/dist/src/utils/package-root.js +12 -0
- package/dist/src/utils/process.js +9 -4
- package/dist/src/utils/validation.d.ts +20 -2
- package/dist/src/utils/validation.js +26 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,97 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.11.0
|
|
4
|
+
|
|
5
|
+
### New commands
|
|
6
|
+
|
|
7
|
+
- **`fireforge verify`** — read-only integrity check for the patch queue. Reports duplicate file creations across patches, forward imports, orphaned patch files, and manifest inconsistencies. Exits non-zero on any error, making it usable as a CI pre-flight gate.
|
|
8
|
+
- **`fireforge patch delete <name>`** — removes a patch file and its manifest entry atomically. Refuses when a later patch imports from a file the deleted patch owns (bypassable with `--force-unsafe`).
|
|
9
|
+
- **`fireforge patch reorder <name> --to <N> | --before <anchor> | --after <anchor>`** — moves a patch to a new position, renumbers surrounding patches, and runs cross-patch lint against the projected order before writing.
|
|
10
|
+
|
|
11
|
+
### New flags and options
|
|
12
|
+
|
|
13
|
+
- `fireforge export --dry-run` previews the full export plan (filename, metadata, affected files) without writing. With `--supersede`, shows which existing patches would be absorbed and why.
|
|
14
|
+
- `fireforge export --order <N> | --before <anchor> | --after <anchor>` places a new patch at a specific position and shifts subsequent patches up.
|
|
15
|
+
- `fireforge re-export --files <paths> <patch>` restricts a re-export to an explicit file subset, useful for splitting or shrinking a patch's scope.
|
|
16
|
+
- `fireforge import --until <patch>` (alias `--stop-at`) applies patches only up to the named patch, useful for bisection.
|
|
17
|
+
- `fireforge status --ownership` prints a flat table mapping every managed path to its owning patch and flags ownership conflicts.
|
|
18
|
+
- `fireforge furnace apply --force` and `furnace deploy --force` proceed despite `baseVersion` drift between `furnace.json` and the Firefox version.
|
|
19
|
+
- `fireforge furnace deploy --skip-validate` skips the validation suite during deploy.
|
|
20
|
+
- `fireforge furnace override` now accepts multiple tag names in a single invocation for batch creation.
|
|
21
|
+
- `fireforge import --dry-run` previews which patches would be applied, in order, without modifying the engine.
|
|
22
|
+
- `fireforge status --json` outputs classified file status as machine-readable JSON for CI scripting.
|
|
23
|
+
|
|
24
|
+
### Furnace improvements
|
|
25
|
+
|
|
26
|
+
- **`furnace refresh <name>`** merges upstream Firefox changes into an override workspace via three-way merge. Clean merges update `baseVersion` automatically; conflicts leave standard markers for manual resolution. Supports `--dry-run` and `--reset-base` (skip merge, just update the baseline).
|
|
27
|
+
- **Full overrides now include shared Fluent files.** Localized widgets (those with a `.ftl` file) are now copied, applied, removed, and diffed end-to-end instead of silently dropping the locale payload.
|
|
28
|
+
- **`furnace diff` rewritten with proper multi-hunk output.** Scattered edits across a file now render as separate hunks with context lines instead of one giant block.
|
|
29
|
+
- **`furnace apply` detects and undeploys deleted workspace files.** If you remove a file from a component's workspace directory and re-run apply, the corresponding engine copy is cleaned up and registrations are adjusted.
|
|
30
|
+
- **`furnace status` now distinguishes workspace edits from engine drift.** These have different remediation paths and are reported separately instead of collapsed into one message.
|
|
31
|
+
- **`furnace scan` offers to override just-added stock components** in the same interactive session.
|
|
32
|
+
- **Preview stages workspace files into the engine** before launching Storybook so fresh edits actually appear, then rolls them back on teardown.
|
|
33
|
+
- **FTL base path is now configurable** via `ftlBasePath` in `furnace.json` for projects with non-standard locale paths.
|
|
34
|
+
- **`scanPaths` in `furnace.json`** lets `furnace scan` discover components outside the default `toolkit/content/widgets`.
|
|
35
|
+
- File copies during apply are now parallelized within each component.
|
|
36
|
+
|
|
37
|
+
### New lint rules
|
|
38
|
+
|
|
39
|
+
- **`duplicate-new-file-creation`** (error) — flags any path that appears as a new-file creation in more than one patch.
|
|
40
|
+
- **`forward-import`** (error) — flags imports that reference a file owned by a later-ordered patch. Supports an inline suppression marker (`// fireforge-ignore: forward-import`) for false positives from basename collisions.
|
|
41
|
+
|
|
42
|
+
### Doctor and diagnostics
|
|
43
|
+
|
|
44
|
+
- `fireforge doctor` now runs the full Furnace component validation suite (structure, accessibility, compatibility, registration) and reports issues without needing a separate `furnace validate` run.
|
|
45
|
+
- New `--repair-furnace` flag reconciles the engine when a furnace operation was interrupted or left inconsistent state.
|
|
46
|
+
- `fireforge doctor` checks that Firefox-internal paths Furnace depends on still exist and reports targeted warnings when they are missing.
|
|
47
|
+
- `furnace validate` now enforces `.ftl` presence for `localized: true` custom components and no longer false-warns about missing CSS jar entries when the component has no CSS file.
|
|
48
|
+
|
|
49
|
+
### Reliability
|
|
50
|
+
|
|
51
|
+
- All furnace mutations now serialize on a project-wide lock, preventing concurrent operations from racing on engine state.
|
|
52
|
+
- Ctrl+C and SIGTERM trigger clean rollback across all furnace commands. A `pendingRepair` marker is only written when rollback was actually incomplete, so normal interrupts do not leave false-positive repair flags.
|
|
53
|
+
- Override `baseVersion` drift now blocks `apply` and `deploy` by default instead of warning and continuing. Pass `--force` to override, or use `furnace refresh` to update the baseline.
|
|
54
|
+
- Post-apply consistency check verifies that `customElements.js` and `jar.mn` entries match what was deployed.
|
|
55
|
+
- Engine-side content hashes are cached in the furnace state file, making drift detection faster for the common no-change case.
|
|
56
|
+
- `build` and `test --build` now share the same preparation pipeline including Furnace apply, so incremental test builds no longer run against stale component state.
|
|
57
|
+
- `furnace remove` on an override now restores every overridden engine file to its Firefox baseline instead of leaving deployed files behind.
|
|
58
|
+
- Scanner results are cached by content hash within a process, avoiding redundant parsing during scan-status-apply sequences.
|
|
59
|
+
- `download` and `build` now check available disk space before starting and warn when free space is low (Firefox source ~5 GB, full build ~20 GB).
|
|
60
|
+
- `getProjectRoot()` now throws instead of silent fallback.
|
|
61
|
+
- `getPackageRoot()` caches its result after the first call, avoiding repeated filesystem walks.
|
|
62
|
+
- Process spawn timeout is now enforced via `AbortSignal.timeout()` instead of the unreliable `timeout` option on `child_process.spawn()`.
|
|
63
|
+
|
|
64
|
+
### Bug fixes
|
|
65
|
+
|
|
66
|
+
- `furnace refresh` now correctly advances the per-override `baseCommit` to the engine HEAD after a successful merge, preventing phantom conflicts on subsequent refreshes.
|
|
67
|
+
- `furnace rename` uses the correct file-removal function for FTL files.
|
|
68
|
+
- `furnace remove` now parses browser.toml sections properly, cleaning up metadata keys below the section header instead of leaving stale fragments.
|
|
69
|
+
- Registration duplicate detection now uses exact path matching so `moz-card` no longer collides with `moz-card-group`.
|
|
70
|
+
- The `customElements.js` parser now accepts `const` and `var` loop declarations alongside `let`.
|
|
71
|
+
- `re-export --files` refuses to write when a requested path would produce no hunks, preventing manifest/patch-body desynchronisation.
|
|
72
|
+
- `patch delete` now respects the `fireforge-ignore: forward-import` suppression marker, matching the behavior of `verify` and `lint`.
|
|
73
|
+
- Furnace apply no longer reports "up to date" after `reset --yes` or `download --force` wiped the engine. Both commands now clear the furnace state, and the skip logic checks engine-side drift before trusting cached checksums.
|
|
74
|
+
- `status` now classifies Furnace-managed engine paths as `furnace` instead of `unmanaged`, and `export-all` refuses to capture them.
|
|
75
|
+
- AST parser fallback in the scanner now emits a warning instead of failing silently.
|
|
76
|
+
- `stock` entries in `furnace.json` are validated against a safe character set, rejecting path-traversal strings.
|
|
77
|
+
|
|
78
|
+
### Internal
|
|
79
|
+
|
|
80
|
+
- CLI command registration is now driven by a declarative manifest instead of hand-listed calls.
|
|
81
|
+
- Doctor checks are a declarative registry with per-check `run`, `skipIf`, and `fix` fields.
|
|
82
|
+
- New shared destructive-op framework handles confirmation, `--dry-run`, `--yes`/`--force-unsafe`, and audit logging for the patch mutation commands.
|
|
83
|
+
- Export internals factored into `planExport` / `executeExportPlan` so dry-run and real writes share one code path.
|
|
84
|
+
- Ownership table builder extracted from `status.ts` into `src/core/ownership-table.ts`.
|
|
85
|
+
- Cross-patch lint regression calculator extracted from `re-export.ts` into `src/core/lint-projection.ts`.
|
|
86
|
+
- The `re-export --files` path extracted into `src/commands/re-export-files.ts` to keep `re-export.ts` under the line limit.
|
|
87
|
+
- `max-lines` and `max-lines-per-function` ESLint rules promoted from `warn` to `error`.
|
|
88
|
+
- Doctor check ordering dependencies documented in the registry comment.
|
|
89
|
+
- Default Firefox version bumped to ESR 146.
|
|
90
|
+
|
|
91
|
+
### Packaging
|
|
92
|
+
|
|
93
|
+
- Package metadata and lockfile updated to 0.11.0.
|
|
94
|
+
|
|
3
95
|
## 0.10.0
|
|
4
96
|
|
|
5
97
|
### Patch workflow validation
|
|
@@ -22,7 +114,7 @@
|
|
|
22
114
|
|
|
23
115
|
### Packaging
|
|
24
116
|
|
|
25
|
-
- Package metadata and smoke tests now use version
|
|
117
|
+
- Package metadata and smoke tests now use version 0.10.0.
|
|
26
118
|
- npm install instructions use the scoped `@hominis/fireforge` package name.
|
|
27
119
|
- Packaging and full Firefox integration helpers now handle platform-specific npm and mozconfig names more consistently.
|
|
28
120
|
|
package/README.md
CHANGED
|
@@ -6,16 +6,39 @@
|
|
|
6
6
|
[](https://www.npmjs.com/package/@hominis/fireforge)
|
|
7
7
|
[](https://www.npmjs.com/package/@hominis/fireforge)
|
|
8
8
|
|
|
9
|
-
**Build and maintain your own Firefox-based browser with a patch-first workflow
|
|
9
|
+
**Build and maintain your own Firefox-based browser with a patch-first workflow**
|
|
10
10
|
|
|
11
|
-
FireForge gives you a toolkit for forking Firefox: download a specific ESR release, manage your customisations as
|
|
11
|
+
FireForge gives you a toolkit for forking Firefox: download a specific ESR release, manage your customisations as a series of patches, survive version upgrades with semi-automated rebase, wire custom code into Mozilla's startup paths, and build the result. It also ships **Furnace**, a component system for creating and overriding Firefox custom elements under `toolkit/content/widgets`.
|
|
12
12
|
|
|
13
13
|
Inspired by [fern.js](https://github.com/ghostery/user-agent-desktop) and [Melon](https://github.com/dothq/melon).
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- **Patch-based fork management** Your customisations live as portable, ordered `.patch` files. Export single files, multiple paths, or everything at once. Contextual diffs mean upstream security fixes are not silently dropped when you rebase.
|
|
18
|
+
|
|
19
|
+
- **Semi-automated ESR rebase** `fireforge rebase` replays your patch stack onto new Firefox source with escalating fuzz matching. When a patch fails, you fix it manually and `--continue`. The full stack gets re-exported with updated version stamps.
|
|
20
|
+
|
|
21
|
+
- **Wiring and registration** `fireforge wire` and `fireforge register` inject your code into Mozilla's startup paths, build manifests, and JAR files with a single command. The injection is AST-based (via Acorn), so it survives formatting changes applied between versions.
|
|
22
|
+
|
|
23
|
+
- **Furnace component system** Override existing Firefox custom elements or create new ones under `toolkit/content/widgets` (CSS-only restyles, full behavioural forks, or entirely new widgets).
|
|
24
|
+
|
|
25
|
+
- **Design token management** Track CSS custom property coverage across your modified files.
|
|
26
|
+
|
|
27
|
+
- **Quality checks** `fireforge lint` catches fork-specific issues (raw colours, missing licence headers, relative imports, large patches, cross-patch ordering problems) before you export. `fireforge verify` runs a read-only integrity check over the whole patch queue. `fireforge doctor` diagnoses project health including Furnace component validation.
|
|
28
|
+
|
|
29
|
+
- **Built and validated against real Firefox code** Developed by editing a real Firefox ESR codebase, learning from existing patch tools, observing the breakages and edge cases that surfaced, and turning those findings into a realistic test suite. In-repo tests are thus grounded in actual development scenarios. Full end-to-end runs are currently only run locally, as they require about 30 GB of disk and significant compute for the full build.
|
|
16
30
|
|
|
17
31
|
## Quick Start
|
|
18
32
|
|
|
33
|
+
### Requirements
|
|
34
|
+
|
|
35
|
+
- **Node.js 20+**
|
|
36
|
+
- **Python 3** (required by Firefox's `mach` build system).
|
|
37
|
+
- **Git**
|
|
38
|
+
- Platform build tools: Xcode on macOS, `build-essential` on Linux, Visual Studio Build Tools on Windows.
|
|
39
|
+
|
|
40
|
+
### Setup
|
|
41
|
+
|
|
19
42
|
```bash
|
|
20
43
|
mkdir mybrowser && cd mybrowser
|
|
21
44
|
npm init -y
|
|
@@ -31,11 +54,7 @@ npx fireforge run # launch it
|
|
|
31
54
|
|
|
32
55
|
Your project now has `fireforge.json`, an `engine/` directory with Firefox source, and a `patches/` directory ready for your first customisation.
|
|
33
56
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
|
-
## Core Workflow
|
|
57
|
+
### Workflow Overview
|
|
39
58
|
|
|
40
59
|
```bash
|
|
41
60
|
# 1. Make changes inside engine/
|
|
@@ -49,45 +68,14 @@ npx fireforge export browser/base/content/browser.js \
|
|
|
49
68
|
# with metadata tracked in patches/patches.json
|
|
50
69
|
|
|
51
70
|
# 4. Later, reset and replay to verify everything applies cleanly
|
|
52
|
-
npx fireforge reset --
|
|
53
|
-
npx fireforge import
|
|
71
|
+
npx fireforge reset --yes
|
|
72
|
+
npx fireforge import # --dry-run to preview without applying
|
|
54
73
|
|
|
55
74
|
# 5. When Firefox releases a new ESR, update fireforge.json, re-download, and rebase
|
|
56
75
|
npx fireforge download --force
|
|
57
76
|
npx fireforge rebase
|
|
58
77
|
```
|
|
59
78
|
|
|
60
|
-
The reason your customisations live as patches rather than as a permanent fork branch is, in fairness, a trade-off. Branches are more familiar, but they make upstream merges progressively harder as your changes grow, and they obscure which modifications are intentional versus which are artefacts of merge resolution. Patches are explicit. Each one is a discrete, portable unit of intent. The cost is that you need tooling to manage the stack, which is what FireForge exists to provide.
|
|
61
|
-
|
|
62
|
-
---
|
|
63
|
-
|
|
64
|
-
## What You Get
|
|
65
|
-
|
|
66
|
-
- **Patch-based fork management.** Your customisations live as portable, ordered `.patch` files. Export single files, multiple paths, or everything at once. Contextual diffs mean upstream security fixes are not silently dropped when you rebase. This matters more then it might seem at first, because silent patch drift in a browser fork is the sort of bug that only surfaces when someone audits your security posture six months later.
|
|
67
|
-
|
|
68
|
-
- **Semi-automated ESR rebase.** `fireforge rebase` replays your patch stack onto new Firefox source with escalating fuzz matching. When a patch fails, you fix it manually and `--continue`. The full stack gets re-exported with updated version stamps. It would be cleaner to make this fully automatic, of course, but patches that touch the same code as upstream changes genuinely require human judgement about which intent should win. Pretending otherwise would be worse.
|
|
69
|
-
|
|
70
|
-
- **Wiring and registration.** `fireforge wire` and `fireforge register` inject your code into Mozilla's startup paths, build manifests, and JAR files with a single command. The injection is AST-based (via Acorn), not regex-based, which means it survives the formatting changes that Mozilla applies between versions. This is less about elegance then about not breaking on every minor release.
|
|
71
|
-
|
|
72
|
-
- **Furnace component system.** Override existing Firefox custom elements (CSS-only or full fork) or create new ones. Storybook preview included. The component types are `stock` (tracked for preview, no local files), `override` (CSS-only restyle or full behavioural fork), and `custom` (entirely new elements).
|
|
73
|
-
|
|
74
|
-
- **Design token management.** Track CSS custom property coverage across your modified files. This exists because raw colour values in a browser fork become a maintenance problem faster then you would expect, and catching them at export time is considerably cheaper then catching them during a visual regression review.
|
|
75
|
-
|
|
76
|
-
- **Quality checks.** `fireforge lint` catches fork-specific issues (raw colours, missing licence headers, relative imports, large patches) before you export. `fireforge doctor` diagnoses project health. These are not redundant with Mozilla's own `./mach lint`, which does not know about your fork-specific conventions.
|
|
77
|
-
|
|
78
|
-
- **Tested against real Firefox source.** We run end-to-end test passes against actual Firefox ESR 140 source code as part of development. The in-repo test suite is derived from those real-world runs, reflecting actual developer scenarios (multi-file patches, conflict resolution, manifest recovery, binary assets) without requiring 30 GB of Firefox source to execute. 1400+ tests run in under 15 seconds.
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
## Requirements
|
|
83
|
-
|
|
84
|
-
- **Node.js 20+.** Version 18 will appear to work initially, but the native fetch usage in the request layer will fail silently in certain edge cases, which is the sort of thing you would rather discover now.
|
|
85
|
-
- **Python 3** (required by Firefox's `mach` build system).
|
|
86
|
-
- **Git.**
|
|
87
|
-
- Platform build tools: Xcode on macOS, `build-essential` on Linux, Visual Studio on Windows. If you are on an M-series Mac and encounter native module compilation errors, this is almost certainly the `sharp` dependency in your broader toolchain, not FireForge itself.
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
79
|
## Patch Workflow
|
|
92
80
|
|
|
93
81
|
Patches live in `patches/`, applied by numeric filename prefix, and tracked in `patches/patches.json`:
|
|
@@ -102,7 +90,26 @@ patches/
|
|
|
102
90
|
|
|
103
91
|
**Categories:** `branding` | `ui` | `privacy` | `security` | `infra`
|
|
104
92
|
|
|
105
|
-
The category system is intentionally
|
|
93
|
+
The category system is intentionally broad. The numeric ordering provides sequencing.
|
|
94
|
+
|
|
95
|
+
### Importing patches
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Apply all patches from patches/ to the engine
|
|
99
|
+
fireforge import
|
|
100
|
+
|
|
101
|
+
# Preview what would be applied without modifying the engine
|
|
102
|
+
fireforge import --dry-run
|
|
103
|
+
|
|
104
|
+
# Apply patches up to (and including) a specific one
|
|
105
|
+
fireforge import --until 003-ui-sidebar-tweaks.patch
|
|
106
|
+
|
|
107
|
+
# Keep going if a patch fails instead of stopping
|
|
108
|
+
fireforge import --continue
|
|
109
|
+
|
|
110
|
+
# Force-apply even when the engine has drifted or has unmanaged changes
|
|
111
|
+
fireforge import --force
|
|
112
|
+
```
|
|
106
113
|
|
|
107
114
|
### Exporting changes
|
|
108
115
|
|
|
@@ -119,9 +126,19 @@ fireforge export-all --name "all-changes" --category ui
|
|
|
119
126
|
|
|
120
127
|
# Regenerate patches after further edits
|
|
121
128
|
fireforge re-export --all --scan
|
|
129
|
+
|
|
130
|
+
# Preview what an export would do without writing
|
|
131
|
+
fireforge export browser/base/content/browser.js --dry-run
|
|
132
|
+
|
|
133
|
+
# Insert a new patch at a specific position
|
|
134
|
+
fireforge export browser/base/content/browser.js --order 3 --name "inserted" --category ui
|
|
135
|
+
fireforge export browser/base/content/browser.js --before 005-ui-sidebar.patch --name "prelim"
|
|
136
|
+
|
|
137
|
+
# Restrict a re-export to a specific file subset
|
|
138
|
+
fireforge re-export --files browser/base/content/browser.js 002-ui-toolbar
|
|
122
139
|
```
|
|
123
140
|
|
|
124
|
-
### Rebasing
|
|
141
|
+
### Rebasing on top of a new Firefox version
|
|
125
142
|
|
|
126
143
|
1. Update `firefox.version` in `fireforge.json`
|
|
127
144
|
2. `fireforge download --force`
|
|
@@ -129,8 +146,6 @@ fireforge re-export --all --scan
|
|
|
129
146
|
4. Fix any rejects, then `fireforge rebase --continue`
|
|
130
147
|
5. If stuck, `fireforge rebase --abort` to restore the pre-rebase state
|
|
131
148
|
|
|
132
|
-
Mind you, the rebase process is deliberately conservative: it will stop at the first patch that cannot be applied cleanly rather then guessing at a resolution and potentially corrupting your intent. This is slower but considerably safer, especially for security-sensitive patches where a misapplied hunk could silently undo a fix.
|
|
133
|
-
|
|
134
149
|
### Resolving conflicts
|
|
135
150
|
|
|
136
151
|
When `fireforge import` fails on a patch, fix the `.rej` files in `engine/`, then:
|
|
@@ -157,40 +172,64 @@ This re-exports the fixed patch and continues applying the remaining stack.
|
|
|
157
172
|
"name": "custom-logo",
|
|
158
173
|
"description": "Replaces default Firefox branding with custom logo",
|
|
159
174
|
"createdAt": "2025-01-15T10:30:00Z",
|
|
160
|
-
"sourceEsrVersion": "
|
|
175
|
+
"sourceEsrVersion": "146.0esr",
|
|
161
176
|
"filesAffected": ["browser/branding/official/logo.png"]
|
|
162
177
|
}
|
|
163
178
|
]
|
|
164
179
|
}
|
|
165
180
|
```
|
|
166
181
|
|
|
167
|
-
If the manifest drifts after an interrupted export or manual edits, `fireforge import` will stop rather then silently applying a stale stack. Use `fireforge doctor --repair-patches-manifest` to rebuild it from disk.
|
|
182
|
+
If the manifest drifts after an interrupted export or manual edits, `fireforge import` will stop rather then silently applying a stale stack. Use `fireforge doctor --repair-patches-manifest` to rebuild it from disk. Because the rebuild is deterministic, the result will always be consistent with what is actually on the filesystem.
|
|
168
183
|
|
|
169
184
|
</details>
|
|
170
185
|
|
|
171
186
|
<details>
|
|
172
187
|
<summary>Patch lint checks</summary>
|
|
173
188
|
|
|
174
|
-
`fireforge lint` runs automatically during export, export-all, and re-export. Use `--skip-lint` to downgrade errors to warnings
|
|
189
|
+
`fireforge lint` runs automatically during export, export-all, and re-export. Use `--skip-lint` to downgrade errors to warnings. Errors block the export; warnings are printed but do not block.
|
|
190
|
+
|
|
191
|
+
| Check | Scope | Severity |
|
|
192
|
+
| ------------------------------ | ------------------------------------- | -------- |
|
|
193
|
+
| `missing-license-header` | New files (JS/CSS/FTL) | error |
|
|
194
|
+
| `relative-import` | JS/MJS files | error |
|
|
195
|
+
| `token-prefix-violation` | CSS files (with furnace) | error |
|
|
196
|
+
| `raw-color-value` | Introduced CSS color values | error |
|
|
197
|
+
| `duplicate-new-file-creation` | Same path created by multiple patches | error |
|
|
198
|
+
| `forward-import` | Patch imports from a later-patch file | error |
|
|
199
|
+
| `missing-modification-comment` | Modified upstream JS/MJS | warning |
|
|
200
|
+
| `file-too-large` | New files >650 lines | warning |
|
|
201
|
+
| `missing-jsdoc` | Exports in new `.sys.mjs` | warning |
|
|
202
|
+
| `observer-topic-naming` | Observer topics with binaryName | warning |
|
|
203
|
+
| `large-patch-files` | Patches affecting >5 files | warning |
|
|
204
|
+
| `large-patch-lines` | Patches >300 lines | warning |
|
|
205
|
+
|
|
206
|
+
The two cross-patch rules (`duplicate-new-file-creation` and `forward-import`) run over the whole patch queue rather than a single diff, catching ordering issues that only surface during `import`. Forward-import detection compares leaf filenames, so a false positive is theoretically possible when two patches create files with the same basename in different directories. Suppress with an inline `// fireforge-ignore: forward-import` comment on or above the import line. This is currently the only lint rule that supports inline suppression.
|
|
175
207
|
|
|
176
|
-
|
|
177
|
-
| ------------------------------ | ------------------------------- | -------- |
|
|
178
|
-
| `missing-license-header` | New files (JS/CSS/FTL) | error |
|
|
179
|
-
| `relative-import` | JS/MJS files | error |
|
|
180
|
-
| `token-prefix-violation` | CSS files (with furnace) | error |
|
|
181
|
-
| `raw-color-value` | Introduced CSS color values | error |
|
|
182
|
-
| `missing-modification-comment` | Modified upstream JS/MJS | warning |
|
|
183
|
-
| `file-too-large` | New files >650 lines | warning |
|
|
184
|
-
| `missing-jsdoc` | Exports in new `.sys.mjs` | warning |
|
|
185
|
-
| `observer-topic-naming` | Observer topics with binaryName | warning |
|
|
186
|
-
| `large-patch-files` | Patches affecting >5 files | warning |
|
|
187
|
-
| `large-patch-lines` | Patches >300 lines | warning |
|
|
208
|
+
</details>
|
|
188
209
|
|
|
189
|
-
|
|
210
|
+
### Repairing a broken patch queue
|
|
190
211
|
|
|
191
|
-
|
|
212
|
+
When a patch queue drifts — overlapping new-file creations, forward imports, manifest desync — start with diagnosis:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
fireforge verify # fsck: manifest + cross-patch lint
|
|
216
|
+
fireforge lint # includes the same cross-patch rules
|
|
217
|
+
fireforge status --ownership # flat path → owning patch table
|
|
218
|
+
fireforge status --json # machine-readable classified output
|
|
219
|
+
```
|
|
192
220
|
|
|
193
|
-
|
|
221
|
+
Then fix with the appropriate primitive:
|
|
222
|
+
|
|
223
|
+
| Problem | Fix |
|
|
224
|
+
| ---------------------------------------------- | --------------------------------------------------------------------- |
|
|
225
|
+
| Two patches each creating the same file | `fireforge patch delete <duplicate>` or `fireforge re-export --files` |
|
|
226
|
+
| A patch imports from a module in a later patch | `fireforge patch reorder <later> --before <importer>` |
|
|
227
|
+
| Wrong patch ordering | `fireforge patch reorder <patch> --to <N>` |
|
|
228
|
+
| A patch claims files that belong elsewhere | `fireforge re-export --files <subset> <patch>` |
|
|
229
|
+
| Manifest references a missing patch file | `fireforge doctor --repair-patches-manifest` |
|
|
230
|
+
| Unmanaged changes you want to discard | `fireforge discard <file>` or `fireforge reset` |
|
|
231
|
+
|
|
232
|
+
Every destructive command defaults to an interactive confirmation with a change summary. `--dry-run` previews without writing; `--yes` skips the prompt for CI; `--force-unsafe` bypasses structural refusals when you have context the linter cannot see. Do not hand-edit `patches.json` — it is owned by FireForge.
|
|
194
233
|
|
|
195
234
|
## Wiring Custom Code
|
|
196
235
|
|
|
@@ -229,81 +268,28 @@ fireforge register browser/modules/mybrowser/MyStore.sys.mjs
|
|
|
229
268
|
|
|
230
269
|
</details>
|
|
231
270
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
## Furnace (Component System)
|
|
235
|
-
|
|
236
|
-
```bash
|
|
237
|
-
fireforge furnace scan # discover available components
|
|
238
|
-
fireforge furnace override moz-button -t css-only # fork an existing one
|
|
239
|
-
fireforge furnace create moz-my-widget # create a new one
|
|
240
|
-
fireforge furnace deploy --dry-run # preview
|
|
241
|
-
fireforge furnace deploy # apply + validate
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
Furnace manages Firefox custom elements (`MozLitElement`). Override stock components with CSS-only restyles or full forks, or scaffold entirely new ones. Changes are applied to `engine/` and then captured by the patch system, which means Furnace is not a separate persistence layer; it feeds into the same patch workflow as everything else.
|
|
245
|
-
|
|
246
|
-
<details>
|
|
247
|
-
<summary>Component types</summary>
|
|
248
|
-
|
|
249
|
-
| Type | Description | Local files |
|
|
250
|
-
| ------------ | ----------------------------------------------------------------- | ------------------------------ |
|
|
251
|
-
| **Stock** | Engine components tracked for Storybook preview | None |
|
|
252
|
-
| **Override** | Forked copies: `css-only` (restyle) or `full` (behaviour + style) | `components/overrides/<name>/` |
|
|
253
|
-
| **Custom** | New elements that do not exist in Firefox | `components/custom/<name>/` |
|
|
271
|
+
## Furnace (UI Component System)
|
|
254
272
|
|
|
255
|
-
|
|
273
|
+
Furnace manages Firefox custom elements (`MozLitElement`) under `toolkit/content/widgets`. You can override existing components or create new ones. Changes feed into the same patch workflow as everything else — Furnace is not a separate persistence layer.
|
|
256
274
|
|
|
257
|
-
|
|
258
|
-
<summary>Validation checks</summary>
|
|
259
|
-
|
|
260
|
-
Furnace validates components on deploy. Errors block apply; warnings are advisory. The distinction is not about severity in the abstract but about whether a violation will cause a runtime failure versus a maintenance headache.
|
|
261
|
-
|
|
262
|
-
| Check | Severity | Description |
|
|
263
|
-
| ------------------------ | -------- | ------------------------------------------- |
|
|
264
|
-
| `missing-mjs` | error | Custom component missing `.mjs` file |
|
|
265
|
-
| `missing-css` | warning | No `.css` file |
|
|
266
|
-
| `filename-mismatch` | error | File name does not match tag name |
|
|
267
|
-
| `missing-override-json` | error | Override missing `override.json` |
|
|
268
|
-
| `no-aria-role` | warning | Generic interactive markup lacks semantics |
|
|
269
|
-
| `no-keyboard-handler` | warning | Has `@click` but no keyboard handler |
|
|
270
|
-
| `relative-import` | error | Imports must use `chrome://` URIs |
|
|
271
|
-
| `raw-color-value` | error | Raw hex/rgb/hsl (use CSS custom properties) |
|
|
272
|
-
| `token-prefix-violation` | error | CSS variable does not match `tokenPrefix` |
|
|
275
|
+
There are three component types:
|
|
273
276
|
|
|
274
|
-
|
|
277
|
+
| Type | What it is | Local files |
|
|
278
|
+
| ------------ | ------------------------------------------------------ | ------------------------------ |
|
|
279
|
+
| **Stock** | Engine components tracked for Storybook preview | None |
|
|
280
|
+
| **Override** | Forked copy: `css-only` (restyle) or `full` (JS + CSS) | `components/overrides/<name>/` |
|
|
281
|
+
| **Custom** | New element that does not exist in Firefox | `components/custom/<name>/` |
|
|
275
282
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
"stock": ["moz-button", "moz-toggle"],
|
|
284
|
-
"overrides": {
|
|
285
|
-
"moz-button": {
|
|
286
|
-
"type": "css-only",
|
|
287
|
-
"description": "Custom button styles",
|
|
288
|
-
"basePath": "toolkit/content/widgets/moz-button",
|
|
289
|
-
"baseVersion": "134.0",
|
|
290
|
-
},
|
|
291
|
-
},
|
|
292
|
-
"custom": {
|
|
293
|
-
"moz-my-widget": {
|
|
294
|
-
"description": "A new widget",
|
|
295
|
-
"targetPath": "toolkit/content/widgets/moz-my-widget",
|
|
296
|
-
"register": true,
|
|
297
|
-
"localized": false,
|
|
298
|
-
"composes": ["moz-button"],
|
|
299
|
-
},
|
|
300
|
-
},
|
|
301
|
-
}
|
|
283
|
+
```bash
|
|
284
|
+
fireforge furnace scan # discover components in the engine
|
|
285
|
+
fireforge furnace override moz-button -t css-only # fork with CSS-only restyle
|
|
286
|
+
fireforge furnace create moz-my-widget # scaffold a new component
|
|
287
|
+
fireforge furnace deploy # apply to engine/ + validate
|
|
288
|
+
fireforge furnace status # workspace vs engine drift
|
|
289
|
+
fireforge furnace diff moz-button # unified diff against baseline
|
|
302
290
|
```
|
|
303
291
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
---
|
|
292
|
+
`furnace deploy` validates components before applying — errors block, warnings are advisory. `fireforge build` and `fireforge test --build` run apply automatically. Use `fireforge doctor --repair-furnace` if the engine gets out of sync.
|
|
307
293
|
|
|
308
294
|
## Configuration
|
|
309
295
|
|
|
@@ -317,7 +303,7 @@ Furnace validates components on deploy. Errors block apply; warnings are advisor
|
|
|
317
303
|
"binaryName": "mybrowser",
|
|
318
304
|
"license": "EUPL-1.2",
|
|
319
305
|
"firefox": {
|
|
320
|
-
"version": "
|
|
306
|
+
"version": "146.0esr",
|
|
321
307
|
"product": "firefox-esr"
|
|
322
308
|
},
|
|
323
309
|
"build": { "jobs": 8 },
|
|
@@ -325,114 +311,15 @@ Furnace validates components on deploy. Errors block apply; warnings are advisor
|
|
|
325
311
|
}
|
|
326
312
|
```
|
|
327
313
|
|
|
328
|
-
Use `fireforge config <key> [value]` to read or update values. Run `fireforge --help` and `fireforge <command> --help` for the full option reference. The `jobs` value defaults to your CPU core count, which is usually reasonable but not always optimal; Firefox's build system has enough sequential bottlenecks that doubling your core count does not halve your build time, for what it is worth.
|
|
329
|
-
|
|
330
|
-
---
|
|
331
|
-
|
|
332
|
-
## Testing Methodology
|
|
333
|
-
|
|
334
|
-
FireForge's test suite is designed around a constraint that, at least in my experience, does not get enough attention: realistic tests do not have to be slow.
|
|
335
|
-
|
|
336
|
-
### Real Firefox validation
|
|
337
|
-
|
|
338
|
-
We run full end-to-end test passes against real Firefox ESR 140 source code in a production fork setup. These validate the entire workflow: setup, download, bootstrap, build, export, import, discard, and recovery.
|
|
339
|
-
|
|
340
|
-
### Derived in-repo tests
|
|
341
|
-
|
|
342
|
-
The 1400+ in-repo tests are not idealised mocks. They are derived from those real Firefox runs. Every fixture, edge case, and scenario was first observed against actual Firefox source, then distilled into a deterministic test that runs in seconds. Examples:
|
|
343
|
-
|
|
344
|
-
- CSS design tokens with `light-dark(#hex)` from a real 348-line tokens file
|
|
345
|
-
- BrowserGlue lazy import with `// BRAND:` markers from a real 2-hunk modification
|
|
346
|
-
- Multi-file theme patches spanning CSS + manifest + build system from real patches
|
|
347
|
-
- Observer topic regex edge cases from a real `notifyObservers` call
|
|
348
|
-
|
|
349
|
-
This means the fast test suite covers the same behavioural surface as the full-tree runs, without requiring 30 GB of Firefox source. It would be fair to call the fixtures "synthetic" in the sense that they are not the original files, but the scenarios they encode are not invented; they are reproductions of real behaviour we observed during development.
|
|
350
|
-
|
|
351
|
-
<details>
|
|
352
|
-
<summary>Running the full-tree suite</summary>
|
|
353
|
-
|
|
354
|
-
The opt-in full-tree suite exercises a connected workflow against a prepared Firefox project:
|
|
355
|
-
|
|
356
|
-
```bash
|
|
357
|
-
FIREFORGE_FULL_PROJECT_ROOT=/path/to/project npm run test:firefox-full
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
Optional environment variables:
|
|
361
|
-
|
|
362
|
-
- `FIREFORGE_FULL_BUILD_MODE=ui|full` (defaults to `ui`)
|
|
363
|
-
- `FIREFORGE_FULL_TARGET_FILE=browser/base/content/browser.js` (override the target file for export/import)
|
|
364
|
-
- `FIREFORGE_FULL_KEEP_PATCH=1` (keep the temporary patch instead of cleaning up)
|
|
365
|
-
- `FIREFORGE_FULL_SKIP_SETUP=1` (skip `setup --force` for an already-prepared project)
|
|
366
|
-
|
|
367
|
-
Each run writes artefacts under `.fireforge/full-integration-artifacts/<timestamp>/` in the target project.
|
|
368
|
-
|
|
369
|
-
</details>
|
|
370
|
-
|
|
371
|
-
---
|
|
372
|
-
|
|
373
|
-
<details>
|
|
374
|
-
<summary>Programmatic API</summary>
|
|
375
|
-
|
|
376
|
-
> **Pre-1.0 stability notice.** FireForge is at v0.9.x. The programmatic API
|
|
377
|
-
> exported from the main package entry point is functional and tested, but
|
|
378
|
-
> may change between minor versions until 1.0. Pin your dependency to an
|
|
379
|
-
> exact version if you rely on it. I would rather be honest about this then
|
|
380
|
-
> pretend the API surface is frozen when it is not.
|
|
381
|
-
|
|
382
|
-
FireForge can be used as a library in addition to the CLI:
|
|
383
|
-
|
|
384
|
-
```typescript
|
|
385
|
-
import { loadConfig, validateConfig, applyAllComponents, loadFurnaceConfig } from 'fireforge';
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
### Exported functions
|
|
389
|
-
|
|
390
|
-
| Function | Module | Purpose |
|
|
391
|
-
| ----------------------- | ---------------- | ------------------------------------------ |
|
|
392
|
-
| `loadConfig` | config | Load and parse `fireforge.json` |
|
|
393
|
-
| `validateConfig` | config | Validate a config object |
|
|
394
|
-
| `applyAllComponents` | furnace-apply | Apply all Furnace components to the engine |
|
|
395
|
-
| `ensureFurnaceConfig` | furnace-config | Create `furnace.json` if missing |
|
|
396
|
-
| `loadFurnaceConfig` | furnace-config | Load and parse `furnace.json` |
|
|
397
|
-
| `loadFurnaceState` | furnace-config | Load Furnace runtime state |
|
|
398
|
-
| `saveFurnaceState` | furnace-config | Persist Furnace runtime state |
|
|
399
|
-
| `validateFurnaceConfig` | furnace-config | Validate a Furnace config |
|
|
400
|
-
| `validateAllComponents` | furnace-validate | Validate all registered components |
|
|
401
|
-
| `validateComponent` | furnace-validate | Validate a single component |
|
|
402
|
-
| `addToken` | token-manager | Add a design token |
|
|
403
|
-
| `getTokensCssPath` | token-manager | Get the path to the tokens CSS file |
|
|
404
|
-
| `validateTokenAdd` | token-manager | Validate a token before adding |
|
|
405
|
-
|
|
406
|
-
### Exported types
|
|
407
|
-
|
|
408
|
-
All configuration and result types are exported (`FireForgeConfig`, `FurnaceConfig`, `BuildConfig`, `ApplyResult`, `PatchInfo`, etc.). See `src/types/index.ts` for the full list.
|
|
409
|
-
|
|
410
|
-
### Error classes
|
|
411
|
-
|
|
412
|
-
All error classes extend `FireForgeError`:
|
|
413
|
-
|
|
414
|
-
- `CancellationError` (user-initiated cancellation)
|
|
415
|
-
- `CommandError` (CLI command failure)
|
|
416
|
-
- `GeneralError` (catch-all for unexpected failures)
|
|
417
|
-
- `InvalidArgumentError` (bad input)
|
|
418
|
-
- `ResolutionError` (dependency resolution failure)
|
|
419
|
-
|
|
420
|
-
Use `ExitCode` for programmatic exit code handling.
|
|
421
|
-
|
|
422
|
-
</details>
|
|
423
|
-
|
|
424
|
-
---
|
|
425
|
-
|
|
426
314
|
## Roadmap
|
|
427
315
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
- **Docker builds.** Reproducible builds using Docker containers. The main challenge is keeping the image size reasonable given Firefox's build dependency tree.
|
|
431
|
-
- **CI mode.** Automated setup for continuous integration pipelines.
|
|
432
|
-
- **Update manifests.** Generate update server manifests for auto-updates.
|
|
433
|
-
- **Nightly support.** This requires `hg clone` from mozilla-central rather then the archive download path, which is a meaningfully different code path.
|
|
316
|
+
Planned but not yet implemented:
|
|
434
317
|
|
|
435
|
-
|
|
318
|
+
- **Docker builds** Reproducible builds using Docker containers.
|
|
319
|
+
- **CI mode** Automated setup for continuous integration pipelines.
|
|
320
|
+
- **Update manifests** Generate update server manifests for auto-updates.
|
|
321
|
+
- **Nightly support** Requires implementing `hg clone` support via mozilla-central. Currently fireforge only downloads from the archive.
|
|
322
|
+
- **E2E Github Actions** Requires either a higher tier of Github offering, an external VPS or similar, or another provider entirely. In either case, full end-to-end testing is currently run solely locally.
|
|
436
323
|
|
|
437
324
|
## Licence
|
|
438
325
|
|
package/dist/bin/fireforge.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
*/
|
|
11
11
|
import { installBrokenPipeHandler, main } from '../src/cli.js';
|
|
12
|
+
import { isSignalRollbackInFlight, rollbackActiveOperationsForSignal, } from '../src/core/furnace-operation.js';
|
|
12
13
|
import { CommandError } from '../src/errors/base.js';
|
|
13
14
|
installBrokenPipeHandler();
|
|
14
15
|
process.on('unhandledRejection', (reason) => {
|
|
@@ -18,6 +19,31 @@ process.on('unhandledRejection', (reason) => {
|
|
|
18
19
|
}
|
|
19
20
|
process.exit(1);
|
|
20
21
|
});
|
|
22
|
+
// SIGINT / SIGTERM handlers run any in-flight furnace rollback before
|
|
23
|
+
// terminating. The library cannot call process.exit itself (the
|
|
24
|
+
// process-boundary test enforces that invariant), so the bin entry point owns
|
|
25
|
+
// both the rollback dispatch and the exit. The handler is a no-op when no
|
|
26
|
+
// furnace mutation is currently registered with the lifecycle wrapper, so
|
|
27
|
+
// patch-only commands behave exactly as before.
|
|
28
|
+
function installFurnaceSignalHandler(signal, exitCode) {
|
|
29
|
+
process.on(signal, () => {
|
|
30
|
+
if (isSignalRollbackInFlight()) {
|
|
31
|
+
// A second Ctrl+C while we're already rolling back is a noisy "I want
|
|
32
|
+
// out now" — let the second signal terminate the process forcefully
|
|
33
|
+
// rather than queueing another rollback that will race the first.
|
|
34
|
+
process.exit(exitCode);
|
|
35
|
+
}
|
|
36
|
+
rollbackActiveOperationsForSignal(signal)
|
|
37
|
+
.catch((error) => {
|
|
38
|
+
console.error(`Furnace rollback after ${signal} failed:`, error instanceof Error ? error.message : error);
|
|
39
|
+
})
|
|
40
|
+
.finally(() => {
|
|
41
|
+
process.exit(exitCode);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
installFurnaceSignalHandler('SIGINT', 130);
|
|
46
|
+
installFurnaceSignalHandler('SIGTERM', 143);
|
|
21
47
|
main().catch((error) => {
|
|
22
48
|
if (error instanceof CommandError) {
|
|
23
49
|
process.exit(error.exitCode);
|
package/dist/src/cli.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export declare function resetBrokenPipeHandlerForTests(): void;
|
|
|
11
11
|
/**
|
|
12
12
|
* Gets the project root directory.
|
|
13
13
|
* Walks up from the current working directory until a fireforge.json is found.
|
|
14
|
-
*
|
|
14
|
+
* Throws when no fireforge.json is found within the walk depth limit.
|
|
15
15
|
*/
|
|
16
16
|
export declare function getProjectRoot(): string;
|
|
17
17
|
/**
|