@hominis/fireforge 0.11.0 → 0.11.2
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 +9 -1
- package/README.md +4 -4
- package/dist/src/commands/setup-support.js +11 -5
- package/dist/src/core/branding.js +5 -5
- package/dist/src/core/firefox.d.ts +1 -1
- package/dist/src/core/firefox.js +1 -1
- package/dist/src/core/furnace-version-drift.d.ts +2 -2
- package/dist/src/core/furnace-version-drift.js +2 -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/types/commands/patches.d.ts +1 -1
- package/dist/src/types/config.d.ts +1 -1
- package/dist/src/utils/fs.d.ts +8 -0
- package/dist/src/utils/fs.js +17 -0
- package/dist/src/utils/validation.d.ts +2 -2
- package/dist/src/utils/validation.js +3 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -53,6 +53,7 @@
|
|
|
53
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
54
|
- Post-apply consistency check verifies that `customElements.js` and `jar.mn` entries match what was deployed.
|
|
55
55
|
- Engine-side content hashes are cached in the furnace state file, making drift detection faster for the common no-change case.
|
|
56
|
+
- Branding file writes are now content-aware: re-running setup with the same configuration no longer bumps file timestamps, avoiding unnecessary `config.status` reconfiguration during incremental builds.
|
|
56
57
|
- `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
58
|
- `furnace remove` on an override now restores every overridden engine file to its Firefox baseline instead of leaving deployed files behind.
|
|
58
59
|
- Scanner results are cached by content hash within a process, avoiding redundant parsing during scan-status-apply sequences.
|
|
@@ -63,6 +64,9 @@
|
|
|
63
64
|
|
|
64
65
|
### Bug fixes
|
|
65
66
|
|
|
67
|
+
- `fireforge setup` now writes an initial `patches/patches.json` (with `version: 1`) when creating a new project. Previously, setup created the `patches/` directory but not the manifest, causing `fireforge doctor` to fail the "Patch manifest consistency" check on a fresh project. Re-running `setup --force` on an existing project preserves the current manifest.
|
|
68
|
+
- The full Firefox integration test script (`scripts/run-full-firefox-integration.mjs`) now uses `--yes` instead of `--force` when invoking `fireforge discard`, matching the actual CLI flag. This was the sole cause of integration test failures in the discard and recovery workflow steps.
|
|
69
|
+
- The integration test's cleanup loop now uses direct git operations (`git checkout` for tracked files, `git clean` for untracked) instead of routing through `fireforge discard`, which could not handle untracked branding files introduced by the build.
|
|
66
70
|
- `furnace refresh` now correctly advances the per-override `baseCommit` to the engine HEAD after a successful merge, preventing phantom conflicts on subsequent refreshes.
|
|
67
71
|
- `furnace rename` uses the correct file-removal function for FTL files.
|
|
68
72
|
- `furnace remove` now parses browser.toml sections properly, cleaning up metadata keys below the section header instead of leaving stale fragments.
|
|
@@ -77,6 +81,10 @@
|
|
|
77
81
|
|
|
78
82
|
### Internal
|
|
79
83
|
|
|
84
|
+
- The full Firefox integration script now accepts `FIREFORGE_FULL_FIREFOX_VERSION` to override the Firefox version used during the test run, decoupling the test from the version baked into `fireforge.json`.
|
|
85
|
+
- The integration test now verifies that `obj-*/dist/bin/` exists after a build reports success, detecting cases where mach masks a build failure with exit code 0.
|
|
86
|
+
- The integration test cleanup loop now uses direct git operations (`checkout` / `clean`) instead of routing through `fireforge discard`, correctly handling untracked branding files introduced by the build.
|
|
87
|
+
- New unit tests from a full local Firefox integration run: Python version resolution skips candidates above mach's `MAX_PYTHON_VERSION_TO_CONSIDER` and falls through to a compatible version; fresh-project manifest consistency returns zero issues for the empty manifest that `setup` now writes; bootstrap soft-failure detection catches the `urllib.error.HTTPError: HTTP Error 403` pattern observed in real `mach bootstrap` output.
|
|
80
88
|
- CLI command registration is now driven by a declarative manifest instead of hand-listed calls.
|
|
81
89
|
- Doctor checks are a declarative registry with per-check `run`, `skipIf`, and `fix` fields.
|
|
82
90
|
- New shared destructive-op framework handles confirmation, `--dry-run`, `--yes`/`--force-unsafe`, and audit logging for the patch mutation commands.
|
|
@@ -86,7 +94,7 @@
|
|
|
86
94
|
- The `re-export --files` path extracted into `src/commands/re-export-files.ts` to keep `re-export.ts` under the line limit.
|
|
87
95
|
- `max-lines` and `max-lines-per-function` ESLint rules promoted from `warn` to `error`.
|
|
88
96
|
- Doctor check ordering dependencies documented in the registry comment.
|
|
89
|
-
- Default Firefox version bumped to ESR
|
|
97
|
+
- Default Firefox version bumped to ESR 140.9.0.
|
|
90
98
|
|
|
91
99
|
### Packaging
|
|
92
100
|
|
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ Inspired by [fern.js](https://github.com/ghostery/user-agent-desktop) and [Melon
|
|
|
26
26
|
|
|
27
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
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
|
|
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. Yes, we mock quite a bit, but when building a tool that modifies a separate code base, I think it's a solid compromise for the time being. Full end-to-end runs are currently run locally, as they require about 30 GB of disk and significant compute for multiple full builds. Full end-to-end via Github Actions will be added soonishlyTM.
|
|
30
30
|
|
|
31
31
|
## Quick Start
|
|
32
32
|
|
|
@@ -52,7 +52,7 @@ npx fireforge build # build the browser
|
|
|
52
52
|
npx fireforge run # launch it
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
Your project now has `fireforge.json`, an `engine/` directory with Firefox source, and a `patches/` directory ready for your first customisation.
|
|
55
|
+
Your project now has `fireforge.json`, an `engine/` directory with Firefox source, and a `patches/` directory with an empty `patches.json` manifest ready for your first customisation.
|
|
56
56
|
|
|
57
57
|
### Workflow Overview
|
|
58
58
|
|
|
@@ -172,7 +172,7 @@ This re-exports the fixed patch and continues applying the remaining stack.
|
|
|
172
172
|
"name": "custom-logo",
|
|
173
173
|
"description": "Replaces default Firefox branding with custom logo",
|
|
174
174
|
"createdAt": "2025-01-15T10:30:00Z",
|
|
175
|
-
"sourceEsrVersion": "
|
|
175
|
+
"sourceEsrVersion": "140.9.0esr",
|
|
176
176
|
"filesAffected": ["browser/branding/official/logo.png"]
|
|
177
177
|
}
|
|
178
178
|
]
|
|
@@ -303,7 +303,7 @@ fireforge furnace diff moz-button # unified diff against baseli
|
|
|
303
303
|
"binaryName": "mybrowser",
|
|
304
304
|
"license": "EUPL-1.2",
|
|
305
305
|
"firefox": {
|
|
306
|
-
"version": "
|
|
306
|
+
"version": "140.9.0esr",
|
|
307
307
|
"product": "firefox-esr"
|
|
308
308
|
},
|
|
309
309
|
"build": { "jobs": 8 },
|
|
@@ -3,6 +3,7 @@ import { cpus } from 'node:os';
|
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { group, select, text } from '@clack/prompts';
|
|
5
5
|
import { getProjectPaths, writeConfig } from '../core/config.js';
|
|
6
|
+
import { PATCHES_MANIFEST, savePatchesManifest } from '../core/patch-manifest-io.js';
|
|
6
7
|
import { CancellationError, InvalidArgumentError } from '../errors/base.js';
|
|
7
8
|
import { ensureDir, pathExists, readText, writeText } from '../utils/fs.js';
|
|
8
9
|
import { cancel } from '../utils/logger.js';
|
|
@@ -63,7 +64,7 @@ export function validateSetupOptions(options) {
|
|
|
63
64
|
throw new InvalidArgumentError('Binary name must start with a letter and contain only lowercase letters, numbers, and hyphens', '--binary-name');
|
|
64
65
|
}
|
|
65
66
|
if (options.firefoxVersion !== undefined && !isValidFirefoxVersion(options.firefoxVersion)) {
|
|
66
|
-
throw new InvalidArgumentError('Invalid Firefox version format (e.g.,
|
|
67
|
+
throw new InvalidArgumentError('Invalid Firefox version format (e.g., 140.9.0, 140.9.0esr, or 147.0b1)', '--firefox-version');
|
|
67
68
|
}
|
|
68
69
|
if (options.product !== undefined) {
|
|
69
70
|
resolveFirefoxProduct(options.product, '--product');
|
|
@@ -127,10 +128,10 @@ async function promptSetupInputs(options) {
|
|
|
127
128
|
? Promise.resolve(options.firefoxVersion)
|
|
128
129
|
: text({
|
|
129
130
|
message: 'Firefox version to base on',
|
|
130
|
-
placeholder: '
|
|
131
|
+
placeholder: '140.9.0esr',
|
|
131
132
|
validate: (value) => {
|
|
132
133
|
if (value && !isValidFirefoxVersion(value)) {
|
|
133
|
-
return 'Invalid Firefox version format (e.g.,
|
|
134
|
+
return 'Invalid Firefox version format (e.g., 140.9.0, 140.9.0esr, or 147.0b1)';
|
|
134
135
|
}
|
|
135
136
|
return undefined;
|
|
136
137
|
},
|
|
@@ -141,7 +142,7 @@ async function promptSetupInputs(options) {
|
|
|
141
142
|
}
|
|
142
143
|
const effectiveVersion = (typeof results.firefoxVersion === 'string' && results.firefoxVersion.trim()) ||
|
|
143
144
|
options.firefoxVersion ||
|
|
144
|
-
'
|
|
145
|
+
'140.9.0esr';
|
|
145
146
|
const inferredProduct = inferProductFromVersion(effectiveVersion);
|
|
146
147
|
if (inferredProduct) {
|
|
147
148
|
return Promise.resolve(inferredProduct);
|
|
@@ -183,7 +184,8 @@ async function promptSetupInputs(options) {
|
|
|
183
184
|
const finalAppId = (typeof project.appId === 'string' ? project.appId.trim() : '') ||
|
|
184
185
|
`org.${sanitizedName}.browser`;
|
|
185
186
|
const finalBinaryName = (typeof project.binaryName === 'string' ? project.binaryName.trim() : '') || sanitizedName;
|
|
186
|
-
const finalFirefoxVersion = (typeof project.firefoxVersion === 'string' ? project.firefoxVersion.trim() : '') ||
|
|
187
|
+
const finalFirefoxVersion = (typeof project.firefoxVersion === 'string' ? project.firefoxVersion.trim() : '') ||
|
|
188
|
+
'140.9.0esr';
|
|
187
189
|
if (!isValidAppId(finalAppId)) {
|
|
188
190
|
throw new InvalidArgumentError(`Derived appId "${finalAppId}" is invalid.`, 'appId');
|
|
189
191
|
}
|
|
@@ -250,6 +252,10 @@ export async function writeSetupProjectFiles(projectRoot, config) {
|
|
|
250
252
|
await ensureDir(paths.configs);
|
|
251
253
|
await ensureDir(paths.fireforgeDir);
|
|
252
254
|
await writeConfig(projectRoot, config);
|
|
255
|
+
const manifestPath = join(paths.patches, PATCHES_MANIFEST);
|
|
256
|
+
if (!(await pathExists(manifestPath))) {
|
|
257
|
+
await savePatchesManifest(paths.patches, { version: 1, patches: [] });
|
|
258
|
+
}
|
|
253
259
|
const gitignorePath = join(projectRoot, '.gitignore');
|
|
254
260
|
const requiredIgnores = ['node_modules/', 'dist/', 'engine/', '.fireforge/'];
|
|
255
261
|
if (await pathExists(gitignorePath)) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { FireForgeError } from '../errors/base.js';
|
|
4
4
|
import { ExitCode } from '../errors/codes.js';
|
|
5
|
-
import { copyDir, pathExists, readText,
|
|
5
|
+
import { copyDir, pathExists, readText, writeTextIfChanged } from '../utils/fs.js';
|
|
6
6
|
import { warn } from '../utils/logger.js';
|
|
7
7
|
/**
|
|
8
8
|
* Error thrown when branding operations fail.
|
|
@@ -49,7 +49,7 @@ export async function setupBranding(engineDir, config) {
|
|
|
49
49
|
*/
|
|
50
50
|
async function createConfigureScript(brandingDir, config) {
|
|
51
51
|
const configureShPath = join(brandingDir, 'configure.sh');
|
|
52
|
-
await
|
|
52
|
+
await writeTextIfChanged(configureShPath, buildConfigureScriptContent(config));
|
|
53
53
|
}
|
|
54
54
|
function buildConfigureScriptContent(config) {
|
|
55
55
|
return `# This Source Code Form is subject to the terms of the Mozilla Public
|
|
@@ -69,7 +69,7 @@ async function updateBrandProperties(brandingDir, config) {
|
|
|
69
69
|
warn('brand.properties not found in branding directory — browser will use default strings');
|
|
70
70
|
return;
|
|
71
71
|
}
|
|
72
|
-
await
|
|
72
|
+
await writeTextIfChanged(propsPath, buildBrandPropertiesContent(config));
|
|
73
73
|
}
|
|
74
74
|
function buildBrandPropertiesContent(config) {
|
|
75
75
|
return `# This Source Code Form is subject to the terms of the Mozilla Public
|
|
@@ -90,7 +90,7 @@ async function updateBrandFtl(brandingDir, config) {
|
|
|
90
90
|
warn('brand.ftl not found in branding directory — browser will use default strings');
|
|
91
91
|
return;
|
|
92
92
|
}
|
|
93
|
-
await
|
|
93
|
+
await writeTextIfChanged(ftlPath, buildBrandFtlContent(config));
|
|
94
94
|
}
|
|
95
95
|
function buildBrandFtlContent(config) {
|
|
96
96
|
return `# This Source Code Form is subject to the terms of the Mozilla Public
|
|
@@ -128,7 +128,7 @@ async function patchMozConfigure(engineDir, config) {
|
|
|
128
128
|
throw new BrandingError('Could not find MOZ_APP_VENDOR imply_option in browser/moz.configure');
|
|
129
129
|
}
|
|
130
130
|
content = content.replace(vendorRegex, buildMozConfigureVendorLine(config));
|
|
131
|
-
await
|
|
131
|
+
await writeTextIfChanged(mozConfigurePath, content);
|
|
132
132
|
}
|
|
133
133
|
function buildMozConfigureVendorLine(config) {
|
|
134
134
|
return `imply_option("MOZ_APP_VENDOR", "${escapeString(config.vendor)}")`;
|
|
@@ -11,7 +11,7 @@ export type { ProgressCallback } from './firefox-download.js';
|
|
|
11
11
|
export { formatBytes, getFirefoxVersion } from './firefox-extract.js';
|
|
12
12
|
/**
|
|
13
13
|
* Gets the download URL for a Firefox source tarball.
|
|
14
|
-
* @param version - Firefox version (e.g., "
|
|
14
|
+
* @param version - Firefox version (e.g., "140.9.0esr")
|
|
15
15
|
* @param product - Firefox product type
|
|
16
16
|
* @returns Full URL to the source tarball
|
|
17
17
|
*/
|
package/dist/src/core/firefox.js
CHANGED
|
@@ -17,7 +17,7 @@ export { resolveArchive } from './firefox-archive.js';
|
|
|
17
17
|
export { formatBytes, getFirefoxVersion } from './firefox-extract.js';
|
|
18
18
|
/**
|
|
19
19
|
* Gets the download URL for a Firefox source tarball.
|
|
20
|
-
* @param version - Firefox version (e.g., "
|
|
20
|
+
* @param version - Firefox version (e.g., "140.9.0esr")
|
|
21
21
|
* @param product - Firefox product type
|
|
22
22
|
* @returns Full URL to the source tarball
|
|
23
23
|
*/
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
* This module is deliberately pure and string-only: it does no I/O and does
|
|
11
11
|
* not parse Firefox version components. Comparing by string equality is
|
|
12
12
|
* sufficient because `fireforge.json` stores a canonical version string
|
|
13
|
-
* (e.g. `"
|
|
13
|
+
* (e.g. `"140.9.0esr"`) and overrides are created with exactly that string
|
|
14
14
|
* copied from `forgeConfig.firefox.version`. Any string mismatch is worth
|
|
15
|
-
* surfacing — even "140.0" vs "
|
|
15
|
+
* surfacing — even "140.0" vs "140.9.0esr" is a real drift signal.
|
|
16
16
|
*
|
|
17
17
|
* The result is advisory: apply/deploy emit warnings but do not fail, and
|
|
18
18
|
* status reports drift alongside the component overview. Nothing here
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
* This module is deliberately pure and string-only: it does no I/O and does
|
|
12
12
|
* not parse Firefox version components. Comparing by string equality is
|
|
13
13
|
* sufficient because `fireforge.json` stores a canonical version string
|
|
14
|
-
* (e.g. `"
|
|
14
|
+
* (e.g. `"140.9.0esr"`) and overrides are created with exactly that string
|
|
15
15
|
* copied from `forgeConfig.firefox.version`. Any string mismatch is worth
|
|
16
|
-
* surfacing — even "140.0" vs "
|
|
16
|
+
* surfacing — even "140.0" vs "140.9.0esr" is a real drift signal.
|
|
17
17
|
*
|
|
18
18
|
* The result is advisory: apply/deploy emit warnings but do not fail, and
|
|
19
19
|
* status reports drift alongside the component overview. Nothing here
|
|
@@ -43,6 +43,6 @@ export declare function validatePatchIntegrity(patchesDir: string, engineDir: st
|
|
|
43
43
|
* manifest read-modify-write cycle.
|
|
44
44
|
* @param patchesDir - Path to the patches directory
|
|
45
45
|
* @param filenames - Patch filenames to update
|
|
46
|
-
* @param newVersion - Version string to set (e.g. "
|
|
46
|
+
* @param newVersion - Version string to set (e.g. "140.9.0esr")
|
|
47
47
|
*/
|
|
48
48
|
export declare function stampPatchVersions(patchesDir: string, filenames: string[], newVersion: string): Promise<void>;
|
|
@@ -103,7 +103,7 @@ export async function validatePatchIntegrity(patchesDir, engineDir) {
|
|
|
103
103
|
* manifest read-modify-write cycle.
|
|
104
104
|
* @param patchesDir - Path to the patches directory
|
|
105
105
|
* @param filenames - Patch filenames to update
|
|
106
|
-
* @param newVersion - Version string to set (e.g. "
|
|
106
|
+
* @param newVersion - Version string to set (e.g. "140.9.0esr")
|
|
107
107
|
*/
|
|
108
108
|
export async function stampPatchVersions(patchesDir, filenames, newVersion) {
|
|
109
109
|
const manifest = await loadPatchesManifest(patchesDir);
|
|
@@ -47,7 +47,7 @@ export interface PatchMetadata {
|
|
|
47
47
|
description: string;
|
|
48
48
|
/** ISO timestamp of when the patch was created */
|
|
49
49
|
createdAt: string;
|
|
50
|
-
/** ESR version the patch was created against (e.g., "
|
|
50
|
+
/** ESR version the patch was created against (e.g., "140.9.0esr") */
|
|
51
51
|
sourceEsrVersion: string;
|
|
52
52
|
/** Array of file paths affected by this patch */
|
|
53
53
|
filesAffected: string[];
|
|
@@ -6,7 +6,7 @@ export type FirefoxProduct = 'firefox' | 'firefox-esr' | 'firefox-beta';
|
|
|
6
6
|
* Firefox version configuration.
|
|
7
7
|
*/
|
|
8
8
|
export interface FirefoxConfig {
|
|
9
|
-
/** Firefox release version (e.g., "
|
|
9
|
+
/** Firefox release version (e.g., "140.9.0esr") */
|
|
10
10
|
version: string;
|
|
11
11
|
/** Firefox product type */
|
|
12
12
|
product: FirefoxProduct;
|
package/dist/src/utils/fs.d.ts
CHANGED
|
@@ -57,6 +57,14 @@ export declare function readText(path: string): Promise<string>;
|
|
|
57
57
|
* @param content - Content to write
|
|
58
58
|
*/
|
|
59
59
|
export declare function writeText(path: string, content: string): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Writes text to a file only when the content has actually changed.
|
|
62
|
+
* Prevents unnecessary mtime bumps that can trigger downstream rebuilds.
|
|
63
|
+
* @param path - Path to text file
|
|
64
|
+
* @param content - Content to write
|
|
65
|
+
* @returns true if the file was written, false if content was already up to date
|
|
66
|
+
*/
|
|
67
|
+
export declare function writeTextIfChanged(path: string, content: string): Promise<boolean>;
|
|
60
68
|
/**
|
|
61
69
|
* Writes content atomically using a temp-file-and-rename strategy.
|
|
62
70
|
* Temp files are created in the destination directory so rename stays atomic.
|
package/dist/src/utils/fs.js
CHANGED
|
@@ -112,6 +112,23 @@ export async function readText(path) {
|
|
|
112
112
|
export async function writeText(path, content) {
|
|
113
113
|
await writeFileAtomic(path, content);
|
|
114
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Writes text to a file only when the content has actually changed.
|
|
117
|
+
* Prevents unnecessary mtime bumps that can trigger downstream rebuilds.
|
|
118
|
+
* @param path - Path to text file
|
|
119
|
+
* @param content - Content to write
|
|
120
|
+
* @returns true if the file was written, false if content was already up to date
|
|
121
|
+
*/
|
|
122
|
+
export async function writeTextIfChanged(path, content) {
|
|
123
|
+
if (await pathExists(path)) {
|
|
124
|
+
const existing = await readText(path);
|
|
125
|
+
if (existing === content) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
await writeText(path, content);
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
115
132
|
/**
|
|
116
133
|
* Writes content atomically using a temp-file-and-rename strategy.
|
|
117
134
|
* Temp files are created in the destination directory so rename stays atomic.
|
|
@@ -66,7 +66,7 @@ export declare function assertString(value: unknown, name: string): asserts valu
|
|
|
66
66
|
export declare function assertObject(value: unknown, name: string): asserts value is Record<string, unknown>;
|
|
67
67
|
/**
|
|
68
68
|
* Validates a Firefox version string.
|
|
69
|
-
* Accepts formats like "
|
|
69
|
+
* Accepts formats like "140.9.0", "140.9.1", "140.9.0esr", "147.0b1"
|
|
70
70
|
*/
|
|
71
71
|
export declare function isValidFirefoxVersion(version: string): boolean;
|
|
72
72
|
/**
|
|
@@ -107,7 +107,7 @@ export declare function inferProductFromVersion(version: string): 'firefox' | 'f
|
|
|
107
107
|
* Validates that a Firefox product and version are compatible.
|
|
108
108
|
*
|
|
109
109
|
* Rules:
|
|
110
|
-
* - `firefox-esr` requires an ESR version (e.g. "
|
|
110
|
+
* - `firefox-esr` requires an ESR version (e.g. "140.9.0esr", "128.0.1esr").
|
|
111
111
|
* - `firefox-beta` requires a beta version (e.g. "147.0b1").
|
|
112
112
|
* - `firefox` (stable) rejects both ESR and beta version strings.
|
|
113
113
|
*
|
|
@@ -97,10 +97,10 @@ export function assertObject(value, name) {
|
|
|
97
97
|
}
|
|
98
98
|
/**
|
|
99
99
|
* Validates a Firefox version string.
|
|
100
|
-
* Accepts formats like "
|
|
100
|
+
* Accepts formats like "140.9.0", "140.9.1", "140.9.0esr", "147.0b1"
|
|
101
101
|
*/
|
|
102
102
|
export function isValidFirefoxVersion(version) {
|
|
103
|
-
// Stable/ESR:
|
|
103
|
+
// Stable/ESR: 140.9.0, 140.9.1, 140.9.0esr, 128.0.1esr
|
|
104
104
|
// Beta: 147.0b1, 147.0b2
|
|
105
105
|
return /^[1-9]\d{0,2}\.\d+(?:b[1-9]\d*|\.\d+(?:esr)?|esr)?$/.test(version);
|
|
106
106
|
}
|
|
@@ -160,7 +160,7 @@ export function inferProductFromVersion(version) {
|
|
|
160
160
|
* Validates that a Firefox product and version are compatible.
|
|
161
161
|
*
|
|
162
162
|
* Rules:
|
|
163
|
-
* - `firefox-esr` requires an ESR version (e.g. "
|
|
163
|
+
* - `firefox-esr` requires an ESR version (e.g. "140.9.0esr", "128.0.1esr").
|
|
164
164
|
* - `firefox-beta` requires a beta version (e.g. "147.0b1").
|
|
165
165
|
* - `firefox` (stable) rejects both ESR and beta version strings.
|
|
166
166
|
*
|