@hominis/fireforge 0.9.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 (316) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE.md +294 -0
  3. package/README.md +435 -0
  4. package/dist/bin/fireforge.d.ts +10 -0
  5. package/dist/bin/fireforge.js +29 -0
  6. package/dist/src/cli.d.ts +33 -0
  7. package/dist/src/cli.js +180 -0
  8. package/dist/src/commands/bootstrap.d.ts +9 -0
  9. package/dist/src/commands/bootstrap.js +73 -0
  10. package/dist/src/commands/build.d.ts +11 -0
  11. package/dist/src/commands/build.js +102 -0
  12. package/dist/src/commands/config.d.ts +13 -0
  13. package/dist/src/commands/config.js +135 -0
  14. package/dist/src/commands/discard.d.ts +12 -0
  15. package/dist/src/commands/discard.js +84 -0
  16. package/dist/src/commands/doctor.d.ts +18 -0
  17. package/dist/src/commands/doctor.js +356 -0
  18. package/dist/src/commands/download.d.ts +11 -0
  19. package/dist/src/commands/download.js +127 -0
  20. package/dist/src/commands/export-all.d.ts +11 -0
  21. package/dist/src/commands/export-all.js +122 -0
  22. package/dist/src/commands/export-shared.d.ts +48 -0
  23. package/dist/src/commands/export-shared.js +208 -0
  24. package/dist/src/commands/export.d.ts +13 -0
  25. package/dist/src/commands/export.js +178 -0
  26. package/dist/src/commands/furnace/apply.d.ts +7 -0
  27. package/dist/src/commands/furnace/apply.js +80 -0
  28. package/dist/src/commands/furnace/create.d.ts +8 -0
  29. package/dist/src/commands/furnace/create.js +377 -0
  30. package/dist/src/commands/furnace/deploy.d.ts +8 -0
  31. package/dist/src/commands/furnace/deploy.js +338 -0
  32. package/dist/src/commands/furnace/diff.d.ts +7 -0
  33. package/dist/src/commands/furnace/diff.js +119 -0
  34. package/dist/src/commands/furnace/index.d.ts +16 -0
  35. package/dist/src/commands/furnace/index.js +121 -0
  36. package/dist/src/commands/furnace/list.d.ts +5 -0
  37. package/dist/src/commands/furnace/list.js +65 -0
  38. package/dist/src/commands/furnace/override.d.ts +8 -0
  39. package/dist/src/commands/furnace/override.js +188 -0
  40. package/dist/src/commands/furnace/preview.d.ts +7 -0
  41. package/dist/src/commands/furnace/preview.js +96 -0
  42. package/dist/src/commands/furnace/remove.d.ts +8 -0
  43. package/dist/src/commands/furnace/remove.js +159 -0
  44. package/dist/src/commands/furnace/scan.d.ts +5 -0
  45. package/dist/src/commands/furnace/scan.js +112 -0
  46. package/dist/src/commands/furnace/status.d.ts +7 -0
  47. package/dist/src/commands/furnace/status.js +137 -0
  48. package/dist/src/commands/furnace/validate.d.ts +6 -0
  49. package/dist/src/commands/furnace/validate.js +91 -0
  50. package/dist/src/commands/furnace/validation-output.d.ts +7 -0
  51. package/dist/src/commands/furnace/validation-output.js +22 -0
  52. package/dist/src/commands/import.d.ts +11 -0
  53. package/dist/src/commands/import.js +241 -0
  54. package/dist/src/commands/lint.d.ts +10 -0
  55. package/dist/src/commands/lint.js +118 -0
  56. package/dist/src/commands/package.d.ts +11 -0
  57. package/dist/src/commands/package.js +80 -0
  58. package/dist/src/commands/re-export.d.ts +12 -0
  59. package/dist/src/commands/re-export.js +242 -0
  60. package/dist/src/commands/rebase/abort.d.ts +7 -0
  61. package/dist/src/commands/rebase/abort.js +49 -0
  62. package/dist/src/commands/rebase/confirm.d.ts +18 -0
  63. package/dist/src/commands/rebase/confirm.js +33 -0
  64. package/dist/src/commands/rebase/continue.d.ts +7 -0
  65. package/dist/src/commands/rebase/continue.js +81 -0
  66. package/dist/src/commands/rebase/index.d.ts +22 -0
  67. package/dist/src/commands/rebase/index.js +127 -0
  68. package/dist/src/commands/rebase/patch-loop.d.ts +9 -0
  69. package/dist/src/commands/rebase/patch-loop.js +135 -0
  70. package/dist/src/commands/rebase/summary.d.ts +12 -0
  71. package/dist/src/commands/rebase/summary.js +43 -0
  72. package/dist/src/commands/rebase.d.ts +4 -0
  73. package/dist/src/commands/rebase.js +6 -0
  74. package/dist/src/commands/register.d.ts +13 -0
  75. package/dist/src/commands/register.js +67 -0
  76. package/dist/src/commands/reset.d.ts +11 -0
  77. package/dist/src/commands/reset.js +83 -0
  78. package/dist/src/commands/resolve.d.ts +9 -0
  79. package/dist/src/commands/resolve.js +124 -0
  80. package/dist/src/commands/run.d.ts +9 -0
  81. package/dist/src/commands/run.js +91 -0
  82. package/dist/src/commands/setup-support.d.ts +23 -0
  83. package/dist/src/commands/setup-support.js +310 -0
  84. package/dist/src/commands/setup.d.ts +11 -0
  85. package/dist/src/commands/setup.js +94 -0
  86. package/dist/src/commands/status.d.ts +11 -0
  87. package/dist/src/commands/status.js +268 -0
  88. package/dist/src/commands/test.d.ts +12 -0
  89. package/dist/src/commands/test.js +182 -0
  90. package/dist/src/commands/token-coverage.d.ts +5 -0
  91. package/dist/src/commands/token-coverage.js +57 -0
  92. package/dist/src/commands/token.d.ts +14 -0
  93. package/dist/src/commands/token.js +121 -0
  94. package/dist/src/commands/watch.d.ts +9 -0
  95. package/dist/src/commands/watch.js +112 -0
  96. package/dist/src/commands/wire.d.ts +13 -0
  97. package/dist/src/commands/wire.js +149 -0
  98. package/dist/src/core/ast-utils.d.ts +47 -0
  99. package/dist/src/core/ast-utils.js +57 -0
  100. package/dist/src/core/brand-validation.d.ts +7 -0
  101. package/dist/src/core/brand-validation.js +15 -0
  102. package/dist/src/core/branding.d.ts +49 -0
  103. package/dist/src/core/branding.js +229 -0
  104. package/dist/src/core/browser-wire.d.ts +40 -0
  105. package/dist/src/core/browser-wire.js +66 -0
  106. package/dist/src/core/build-prepare.d.ts +25 -0
  107. package/dist/src/core/build-prepare.js +93 -0
  108. package/dist/src/core/config-mutate.d.ts +15 -0
  109. package/dist/src/core/config-mutate.js +51 -0
  110. package/dist/src/core/config-paths.d.ts +28 -0
  111. package/dist/src/core/config-paths.js +65 -0
  112. package/dist/src/core/config-state.d.ts +28 -0
  113. package/dist/src/core/config-state.js +152 -0
  114. package/dist/src/core/config-validate.d.ts +11 -0
  115. package/dist/src/core/config-validate.js +141 -0
  116. package/dist/src/core/config.d.ts +39 -0
  117. package/dist/src/core/config.js +70 -0
  118. package/dist/src/core/file-lock.d.ts +11 -0
  119. package/dist/src/core/file-lock.js +80 -0
  120. package/dist/src/core/firefox-archive.d.ts +40 -0
  121. package/dist/src/core/firefox-archive.js +63 -0
  122. package/dist/src/core/firefox-cache.d.ts +23 -0
  123. package/dist/src/core/firefox-cache.js +134 -0
  124. package/dist/src/core/firefox-download.d.ts +21 -0
  125. package/dist/src/core/firefox-download.js +129 -0
  126. package/dist/src/core/firefox-extract.d.ts +21 -0
  127. package/dist/src/core/firefox-extract.js +53 -0
  128. package/dist/src/core/firefox.d.ts +34 -0
  129. package/dist/src/core/firefox.js +78 -0
  130. package/dist/src/core/furnace-apply-helpers.d.ts +21 -0
  131. package/dist/src/core/furnace-apply-helpers.js +244 -0
  132. package/dist/src/core/furnace-apply.d.ts +16 -0
  133. package/dist/src/core/furnace-apply.js +147 -0
  134. package/dist/src/core/furnace-config.d.ts +94 -0
  135. package/dist/src/core/furnace-config.js +372 -0
  136. package/dist/src/core/furnace-constants.d.ts +4 -0
  137. package/dist/src/core/furnace-constants.js +6 -0
  138. package/dist/src/core/furnace-registration-ast.d.ts +24 -0
  139. package/dist/src/core/furnace-registration-ast.js +218 -0
  140. package/dist/src/core/furnace-registration-remove.d.ts +14 -0
  141. package/dist/src/core/furnace-registration-remove.js +89 -0
  142. package/dist/src/core/furnace-registration-validate.d.ts +20 -0
  143. package/dist/src/core/furnace-registration-validate.js +40 -0
  144. package/dist/src/core/furnace-registration.d.ts +29 -0
  145. package/dist/src/core/furnace-registration.js +96 -0
  146. package/dist/src/core/furnace-rollback.d.ts +20 -0
  147. package/dist/src/core/furnace-rollback.js +66 -0
  148. package/dist/src/core/furnace-scanner.d.ts +40 -0
  149. package/dist/src/core/furnace-scanner.js +143 -0
  150. package/dist/src/core/furnace-stories.d.ts +37 -0
  151. package/dist/src/core/furnace-stories.js +185 -0
  152. package/dist/src/core/furnace-validate-accessibility.d.ts +6 -0
  153. package/dist/src/core/furnace-validate-accessibility.js +32 -0
  154. package/dist/src/core/furnace-validate-checks.d.ts +4 -0
  155. package/dist/src/core/furnace-validate-checks.js +7 -0
  156. package/dist/src/core/furnace-validate-compatibility.d.ts +6 -0
  157. package/dist/src/core/furnace-validate-compatibility.js +57 -0
  158. package/dist/src/core/furnace-validate-helpers.d.ts +28 -0
  159. package/dist/src/core/furnace-validate-helpers.js +129 -0
  160. package/dist/src/core/furnace-validate-registration.d.ts +37 -0
  161. package/dist/src/core/furnace-validate-registration.js +220 -0
  162. package/dist/src/core/furnace-validate-structure.d.ts +6 -0
  163. package/dist/src/core/furnace-validate-structure.js +66 -0
  164. package/dist/src/core/furnace-validate.d.ts +16 -0
  165. package/dist/src/core/furnace-validate.js +103 -0
  166. package/dist/src/core/git-base.d.ts +47 -0
  167. package/dist/src/core/git-base.js +50 -0
  168. package/dist/src/core/git-diff.d.ts +63 -0
  169. package/dist/src/core/git-diff.js +246 -0
  170. package/dist/src/core/git-file-ops.d.ts +65 -0
  171. package/dist/src/core/git-file-ops.js +141 -0
  172. package/dist/src/core/git-status.d.ts +65 -0
  173. package/dist/src/core/git-status.js +163 -0
  174. package/dist/src/core/git.d.ts +113 -0
  175. package/dist/src/core/git.js +363 -0
  176. package/dist/src/core/license-headers.d.ts +36 -0
  177. package/dist/src/core/license-headers.js +83 -0
  178. package/dist/src/core/mach-build-artifacts.d.ts +29 -0
  179. package/dist/src/core/mach-build-artifacts.js +117 -0
  180. package/dist/src/core/mach-mozconfig.d.ts +17 -0
  181. package/dist/src/core/mach-mozconfig.js +50 -0
  182. package/dist/src/core/mach-python.d.ts +16 -0
  183. package/dist/src/core/mach-python.js +126 -0
  184. package/dist/src/core/mach.d.ts +106 -0
  185. package/dist/src/core/mach.js +166 -0
  186. package/dist/src/core/manifest-helpers.d.ts +25 -0
  187. package/dist/src/core/manifest-helpers.js +96 -0
  188. package/dist/src/core/manifest-register.d.ts +30 -0
  189. package/dist/src/core/manifest-register.js +65 -0
  190. package/dist/src/core/manifest-rules.d.ts +39 -0
  191. package/dist/src/core/manifest-rules.js +151 -0
  192. package/dist/src/core/manifest-tokenizers.d.ts +34 -0
  193. package/dist/src/core/manifest-tokenizers.js +84 -0
  194. package/dist/src/core/parser-fallback.d.ts +36 -0
  195. package/dist/src/core/parser-fallback.js +43 -0
  196. package/dist/src/core/patch-apply-fuzz.d.ts +29 -0
  197. package/dist/src/core/patch-apply-fuzz.js +70 -0
  198. package/dist/src/core/patch-apply.d.ts +46 -0
  199. package/dist/src/core/patch-apply.js +235 -0
  200. package/dist/src/core/patch-export.d.ts +99 -0
  201. package/dist/src/core/patch-export.js +314 -0
  202. package/dist/src/core/patch-files.d.ts +11 -0
  203. package/dist/src/core/patch-files.js +51 -0
  204. package/dist/src/core/patch-lint.d.ts +72 -0
  205. package/dist/src/core/patch-lint.js +403 -0
  206. package/dist/src/core/patch-lock.d.ts +8 -0
  207. package/dist/src/core/patch-lock.js +29 -0
  208. package/dist/src/core/patch-manifest-consistency.d.ts +24 -0
  209. package/dist/src/core/patch-manifest-consistency.js +135 -0
  210. package/dist/src/core/patch-manifest-io.d.ts +36 -0
  211. package/dist/src/core/patch-manifest-io.js +77 -0
  212. package/dist/src/core/patch-manifest-query.d.ts +48 -0
  213. package/dist/src/core/patch-manifest-query.js +124 -0
  214. package/dist/src/core/patch-manifest-validate.d.ts +22 -0
  215. package/dist/src/core/patch-manifest-validate.js +72 -0
  216. package/dist/src/core/patch-manifest.d.ts +11 -0
  217. package/dist/src/core/patch-manifest.js +12 -0
  218. package/dist/src/core/patch-parse.d.ts +43 -0
  219. package/dist/src/core/patch-parse.js +143 -0
  220. package/dist/src/core/patch-transform.d.ts +21 -0
  221. package/dist/src/core/patch-transform.js +138 -0
  222. package/dist/src/core/rebase-session.d.ts +47 -0
  223. package/dist/src/core/rebase-session.js +65 -0
  224. package/dist/src/core/register-browser-content.d.ts +11 -0
  225. package/dist/src/core/register-browser-content.js +116 -0
  226. package/dist/src/core/register-module.d.ts +11 -0
  227. package/dist/src/core/register-module.js +76 -0
  228. package/dist/src/core/register-shared-css.d.ts +11 -0
  229. package/dist/src/core/register-shared-css.js +117 -0
  230. package/dist/src/core/register-test-manifest.d.ts +18 -0
  231. package/dist/src/core/register-test-manifest.js +99 -0
  232. package/dist/src/core/state-file.d.ts +4 -0
  233. package/dist/src/core/state-file.js +25 -0
  234. package/dist/src/core/token-coverage.d.ts +12 -0
  235. package/dist/src/core/token-coverage.js +74 -0
  236. package/dist/src/core/token-manager.d.ts +55 -0
  237. package/dist/src/core/token-manager.js +387 -0
  238. package/dist/src/core/wire-destroy.d.ts +21 -0
  239. package/dist/src/core/wire-destroy.js +103 -0
  240. package/dist/src/core/wire-dom-fragment.d.ts +23 -0
  241. package/dist/src/core/wire-dom-fragment.js +129 -0
  242. package/dist/src/core/wire-init.d.ts +23 -0
  243. package/dist/src/core/wire-init.js +201 -0
  244. package/dist/src/core/wire-subscript.d.ts +20 -0
  245. package/dist/src/core/wire-subscript.js +134 -0
  246. package/dist/src/core/wire-targets.d.ts +7 -0
  247. package/dist/src/core/wire-targets.js +9 -0
  248. package/dist/src/core/wire-utils.d.ts +88 -0
  249. package/dist/src/core/wire-utils.js +279 -0
  250. package/dist/src/errors/base.d.ts +60 -0
  251. package/dist/src/errors/base.js +87 -0
  252. package/dist/src/errors/build.d.ts +52 -0
  253. package/dist/src/errors/build.js +114 -0
  254. package/dist/src/errors/codes.d.ts +29 -0
  255. package/dist/src/errors/codes.js +30 -0
  256. package/dist/src/errors/config.d.ts +31 -0
  257. package/dist/src/errors/config.js +61 -0
  258. package/dist/src/errors/download.d.ts +42 -0
  259. package/dist/src/errors/download.js +95 -0
  260. package/dist/src/errors/furnace.d.ts +10 -0
  261. package/dist/src/errors/furnace.js +22 -0
  262. package/dist/src/errors/git.d.ts +41 -0
  263. package/dist/src/errors/git.js +99 -0
  264. package/dist/src/errors/patch.d.ts +10 -0
  265. package/dist/src/errors/patch.js +26 -0
  266. package/dist/src/errors/rebase.d.ts +20 -0
  267. package/dist/src/errors/rebase.js +30 -0
  268. package/dist/src/index.d.ts +21 -0
  269. package/dist/src/index.js +21 -0
  270. package/dist/src/types/cli.d.ts +14 -0
  271. package/dist/src/types/cli.js +2 -0
  272. package/dist/src/types/commands/index.d.ts +6 -0
  273. package/dist/src/types/commands/index.js +6 -0
  274. package/dist/src/types/commands/options.d.ts +239 -0
  275. package/dist/src/types/commands/options.js +6 -0
  276. package/dist/src/types/commands/patches.d.ts +89 -0
  277. package/dist/src/types/commands/patches.js +6 -0
  278. package/dist/src/types/commands/project.d.ts +71 -0
  279. package/dist/src/types/commands/project.js +6 -0
  280. package/dist/src/types/config.d.ts +101 -0
  281. package/dist/src/types/config.js +2 -0
  282. package/dist/src/types/furnace.d.ts +158 -0
  283. package/dist/src/types/furnace.js +2 -0
  284. package/dist/src/types/index.d.ts +6 -0
  285. package/dist/src/types/index.js +6 -0
  286. package/dist/src/utils/errors.d.ts +2 -0
  287. package/dist/src/utils/errors.js +15 -0
  288. package/dist/src/utils/fs.d.ts +72 -0
  289. package/dist/src/utils/fs.js +179 -0
  290. package/dist/src/utils/logger.d.ts +58 -0
  291. package/dist/src/utils/logger.js +120 -0
  292. package/dist/src/utils/options.d.ts +8 -0
  293. package/dist/src/utils/options.js +16 -0
  294. package/dist/src/utils/package-root.d.ts +10 -0
  295. package/dist/src/utils/package-root.js +53 -0
  296. package/dist/src/utils/parse.d.ts +110 -0
  297. package/dist/src/utils/parse.js +200 -0
  298. package/dist/src/utils/paths.d.ts +10 -0
  299. package/dist/src/utils/paths.js +43 -0
  300. package/dist/src/utils/platform.d.ts +38 -0
  301. package/dist/src/utils/platform.js +56 -0
  302. package/dist/src/utils/process.d.ts +80 -0
  303. package/dist/src/utils/process.js +188 -0
  304. package/dist/src/utils/regex.d.ts +24 -0
  305. package/dist/src/utils/regex.js +40 -0
  306. package/dist/src/utils/validation.d.ts +133 -0
  307. package/dist/src/utils/validation.js +250 -0
  308. package/package.json +106 -0
  309. package/templates/configs/common.mozconfig +24 -0
  310. package/templates/configs/darwin.mozconfig +10 -0
  311. package/templates/configs/linux.mozconfig +12 -0
  312. package/templates/configs/win32.mozconfig +14 -0
  313. package/templates/licenses/0BSD.md +14 -0
  314. package/templates/licenses/EUPL-1.2.md +294 -0
  315. package/templates/licenses/GPL-2.0-or-later.md +339 -0
  316. package/templates/licenses/MPL-2.0.md +383 -0
@@ -0,0 +1,229 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ import { join } from 'node:path';
3
+ import { FireForgeError } from '../errors/base.js';
4
+ import { ExitCode } from '../errors/codes.js';
5
+ import { copyDir, pathExists, readText, writeText } from '../utils/fs.js';
6
+ import { warn } from '../utils/logger.js';
7
+ /**
8
+ * Error thrown when branding operations fail.
9
+ */
10
+ export class BrandingError extends FireForgeError {
11
+ code = ExitCode.PATCH_ERROR;
12
+ get userMessage() {
13
+ return `Branding Error: ${this.message}\n\nBranding is required to set MOZ_APP_VENDOR, MOZ_MACBUNDLE_ID, and other Firefox identity values.`;
14
+ }
15
+ }
16
+ /**
17
+ * Sets up the custom branding directory for the browser.
18
+ *
19
+ * This creates a branding directory based on Firefox's unofficial branding,
20
+ * with customized values for:
21
+ * - configure.sh: MOZ_APP_DISPLAYNAME, MOZ_MACBUNDLE_ID
22
+ * - brand.properties: brandShorterName, brandShortName, brandFullName
23
+ * - brand.ftl: -brand-shorter-name, -brand-short-name, etc.
24
+ *
25
+ * @param engineDir - Path to the engine directory
26
+ * @param config - Branding configuration
27
+ */
28
+ export async function setupBranding(engineDir, config) {
29
+ const brandingDir = join(engineDir, 'browser', 'branding', config.binaryName);
30
+ const unofficialDir = join(engineDir, 'browser', 'branding', 'unofficial');
31
+ // Check if unofficial branding exists as our base
32
+ if (!(await pathExists(unofficialDir))) {
33
+ throw new BrandingError(`Unofficial branding directory not found at ${unofficialDir}`);
34
+ }
35
+ // Copy unofficial branding as base (if our branding doesn't exist yet)
36
+ if (!(await pathExists(brandingDir))) {
37
+ await copyDir(unofficialDir, brandingDir);
38
+ }
39
+ // Create/update configure.sh with custom values
40
+ await createConfigureScript(brandingDir, config);
41
+ // Update localization files
42
+ await updateBrandProperties(brandingDir, config);
43
+ await updateBrandFtl(brandingDir, config);
44
+ // Patch moz.configure for MOZ_APP_VENDOR
45
+ await patchMozConfigure(engineDir, config);
46
+ }
47
+ /**
48
+ * Creates the branding configure.sh script.
49
+ */
50
+ async function createConfigureScript(brandingDir, config) {
51
+ const configureShPath = join(brandingDir, 'configure.sh');
52
+ await writeText(configureShPath, buildConfigureScriptContent(config));
53
+ }
54
+ function buildConfigureScriptContent(config) {
55
+ return `# This Source Code Form is subject to the terms of the Mozilla Public
56
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
57
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
58
+
59
+ MOZ_APP_DISPLAYNAME="${escapeShellValue(config.name)}"
60
+ MOZ_MACBUNDLE_ID="${escapeShellValue(config.appId)}"
61
+ `;
62
+ }
63
+ /**
64
+ * Updates the brand.properties localization file.
65
+ */
66
+ async function updateBrandProperties(brandingDir, config) {
67
+ const propsPath = join(brandingDir, 'locales', 'en-US', 'brand.properties');
68
+ if (!(await pathExists(propsPath))) {
69
+ warn('brand.properties not found in branding directory — browser will use default strings');
70
+ return;
71
+ }
72
+ await writeText(propsPath, buildBrandPropertiesContent(config));
73
+ }
74
+ function buildBrandPropertiesContent(config) {
75
+ return `# This Source Code Form is subject to the terms of the Mozilla Public
76
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
77
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
78
+
79
+ brandShorterName=${escapePropertiesValue(config.name)}
80
+ brandShortName=${escapePropertiesValue(config.name)}
81
+ brandFullName=${escapePropertiesValue(config.name)}
82
+ `;
83
+ }
84
+ /**
85
+ * Updates the brand.ftl localization file.
86
+ */
87
+ async function updateBrandFtl(brandingDir, config) {
88
+ const ftlPath = join(brandingDir, 'locales', 'en-US', 'brand.ftl');
89
+ if (!(await pathExists(ftlPath))) {
90
+ warn('brand.ftl not found in branding directory — browser will use default strings');
91
+ return;
92
+ }
93
+ await writeText(ftlPath, buildBrandFtlContent(config));
94
+ }
95
+ function buildBrandFtlContent(config) {
96
+ return `# This Source Code Form is subject to the terms of the Mozilla Public
97
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
98
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
99
+
100
+ ## Brand names
101
+ ##
102
+ ## These brand names can be used in messages.
103
+
104
+ -brand-shorter-name = ${escapeFtlValue(config.name)}
105
+ -brand-short-name = ${escapeFtlValue(config.name)}
106
+ -brand-shortcut-name = ${escapeFtlValue(config.name)}
107
+ -brand-full-name = ${escapeFtlValue(config.name)}
108
+ -brand-product-name = ${escapeFtlValue(config.name)}
109
+ -vendor-short-name = ${escapeFtlValue(config.vendor)}
110
+ trademarkInfo = { " " }
111
+ `;
112
+ }
113
+ /**
114
+ * Patches browser/moz.configure to set custom vendor.
115
+ *
116
+ * Mozilla's build system requires MOZ_APP_VENDOR to be set via imply_option
117
+ * in moz.configure, not through mozconfig.
118
+ */
119
+ async function patchMozConfigure(engineDir, config) {
120
+ const mozConfigurePath = join(engineDir, 'browser', 'moz.configure');
121
+ if (!(await pathExists(mozConfigurePath))) {
122
+ throw new BrandingError(`browser/moz.configure not found at ${mozConfigurePath}`);
123
+ }
124
+ let content = await readText(mozConfigurePath);
125
+ // Replace MOZ_APP_VENDOR imply_option
126
+ const vendorRegex = /imply_option\("MOZ_APP_VENDOR",\s*"[^"]*"\)/;
127
+ if (!vendorRegex.test(content)) {
128
+ throw new BrandingError('Could not find MOZ_APP_VENDOR imply_option in browser/moz.configure');
129
+ }
130
+ content = content.replace(vendorRegex, buildMozConfigureVendorLine(config));
131
+ await writeText(mozConfigurePath, content);
132
+ }
133
+ function buildMozConfigureVendorLine(config) {
134
+ return `imply_option("MOZ_APP_VENDOR", "${escapeString(config.vendor)}")`;
135
+ }
136
+ /**
137
+ * Escapes a string for use in Python/configure file.
138
+ */
139
+ function escapeString(value) {
140
+ return value
141
+ .replace(/\\/g, '\\\\')
142
+ .replace(/"/g, '\\"')
143
+ .replace(/\n/g, '\\n')
144
+ .replace(/\r/g, '\\r')
145
+ .replace(/\t/g, '\\t');
146
+ }
147
+ /**
148
+ * Escapes a string for use inside a shell double-quoted context.
149
+ * Prevents command injection via $, backticks, !, and escape sequences.
150
+ */
151
+ function escapeShellValue(value) {
152
+ return value
153
+ .replace(/\\/g, '\\\\')
154
+ .replace(/"/g, '\\"')
155
+ .replace(/\$/g, '\\$')
156
+ .replace(/`/g, '\\`')
157
+ .replace(/!/g, '\\!');
158
+ }
159
+ /**
160
+ * Escapes a string for use in .properties file values.
161
+ * Prevents key/value injection via = and : delimiters.
162
+ */
163
+ function escapePropertiesValue(value) {
164
+ return value
165
+ .replace(/\\/g, '\\\\')
166
+ .replace(/\n/g, '\\n')
167
+ .replace(/\r/g, '\\r')
168
+ .replace(/\t/g, '\\t');
169
+ }
170
+ /**
171
+ * Escapes a string for use in Fluent (.ftl) file values.
172
+ * Prevents placeables injection via { and }.
173
+ */
174
+ function escapeFtlValue(value) {
175
+ return value.replace(/\\/g, '\\\\').replace(/\{/g, '\\{').replace(/\}/g, '\\}');
176
+ }
177
+ /**
178
+ * Checks if branding has been set up for the given configuration.
179
+ *
180
+ * @param engineDir - Path to the engine directory
181
+ * @param config - Branding configuration to check for
182
+ * @returns true if branding is already set up
183
+ */
184
+ export async function isBrandingSetup(engineDir, config) {
185
+ const brandingDir = join(engineDir, 'browser', 'branding', config.binaryName);
186
+ const configureShPath = join(brandingDir, 'configure.sh');
187
+ const propsPath = join(brandingDir, 'locales', 'en-US', 'brand.properties');
188
+ const ftlPath = join(brandingDir, 'locales', 'en-US', 'brand.ftl');
189
+ const mozConfigurePath = join(engineDir, 'browser', 'moz.configure');
190
+ if (!(await pathExists(configureShPath))) {
191
+ return false;
192
+ }
193
+ const configureContent = await readText(configureShPath);
194
+ if (configureContent !== buildConfigureScriptContent(config)) {
195
+ return false;
196
+ }
197
+ if (await pathExists(propsPath)) {
198
+ const propsContent = await readText(propsPath);
199
+ if (propsContent !== buildBrandPropertiesContent(config)) {
200
+ return false;
201
+ }
202
+ }
203
+ if (await pathExists(ftlPath)) {
204
+ const ftlContent = await readText(ftlPath);
205
+ if (ftlContent !== buildBrandFtlContent(config)) {
206
+ return false;
207
+ }
208
+ }
209
+ if (!(await pathExists(mozConfigurePath))) {
210
+ return false;
211
+ }
212
+ const mozConfigureContent = await readText(mozConfigurePath);
213
+ return mozConfigureContent.includes(buildMozConfigureVendorLine(config));
214
+ }
215
+ /**
216
+ * Checks whether a file path belongs to the tool-managed branding directory.
217
+ * @param file - File path (relative to engine root)
218
+ * @param binaryName - The configured binary name (used as branding directory name)
219
+ * @returns true if the path is managed by branding tooling
220
+ */
221
+ export function isBrandingManagedPath(file, binaryName) {
222
+ const normalized = file.replace(/\\/g, '/');
223
+ const brandingRoot = `browser/branding/${binaryName}`;
224
+ return (normalized === 'browser/moz.configure' ||
225
+ normalized === brandingRoot ||
226
+ normalized === `${brandingRoot}/` ||
227
+ normalized.startsWith(`${brandingRoot}/`));
228
+ }
229
+ //# sourceMappingURL=branding.js.map
@@ -0,0 +1,40 @@
1
+ import type { RegisterResult } from './manifest-register.js';
2
+ export declare const DEFAULT_BROWSER_SUBSCRIPT_DIR = "browser/base/content";
3
+ /**
4
+ * Result of a wire operation.
5
+ */
6
+ export interface WireResult {
7
+ /** Whether the subscript was added to browser-main.js */
8
+ subscriptAdded: boolean;
9
+ /** Whether the init expression was added to browser-init.js */
10
+ initAdded: boolean;
11
+ /** Whether the destroy expression was added to browser-init.js */
12
+ destroyAdded: boolean;
13
+ /** Whether the DOM fragment was inserted into browser.xhtml */
14
+ domInserted: boolean;
15
+ /** Result of jar.mn registration */
16
+ jarMnResult: RegisterResult;
17
+ }
18
+ export interface WireOptions {
19
+ /** Init expression to add to browser-init.js onLoad() */
20
+ init?: string | undefined;
21
+ /** Destroy expression to add to browser-init.js onUnload() */
22
+ destroy?: string | undefined;
23
+ /** Path to `.inc.xhtml` file relative to engine root */
24
+ domFilePath?: string | undefined;
25
+ /** Dry run — don't write any files */
26
+ dryRun?: boolean | undefined;
27
+ /** Insert init block after the block containing this name */
28
+ after?: string | undefined;
29
+ /** Subscript directory relative to engine/ (default: "browser/base/content") */
30
+ subscriptDir?: string | undefined;
31
+ }
32
+ /**
33
+ * Wires a chrome subscript into the browser.
34
+ *
35
+ * @param root - Project root directory
36
+ * @param name - Subscript name (without .js extension)
37
+ * @param options - Wire options
38
+ * @returns Wire result
39
+ */
40
+ export declare function wireSubscript(root: string, name: string, options?: WireOptions): Promise<WireResult>;
@@ -0,0 +1,66 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ import { join, relative } from 'node:path';
3
+ import { toRootRelativePath } from '../utils/paths.js';
4
+ import { getProjectPaths } from './config.js';
5
+ import { registerBrowserContent } from './manifest-register.js';
6
+ import { addDestroyToBrowserInit, addDomFragment, addInitToBrowserInit, addSubscriptToBrowserMain, } from './wire-targets.js';
7
+ export const DEFAULT_BROWSER_SUBSCRIPT_DIR = 'browser/base/content';
8
+ const BROWSER_BASE_DIR = 'browser/base';
9
+ /**
10
+ * Wires a chrome subscript into the browser.
11
+ *
12
+ * @param root - Project root directory
13
+ * @param name - Subscript name (without .js extension)
14
+ * @param options - Wire options
15
+ * @returns Wire result
16
+ */
17
+ export async function wireSubscript(root, name, options = {}) {
18
+ const { engine: engineDir } = getProjectPaths(root);
19
+ const subscriptDir = toRootRelativePath(engineDir, options.subscriptDir ?? DEFAULT_BROWSER_SUBSCRIPT_DIR);
20
+ // Compute jar.mn source path relative to browser/base/
21
+ let jarMnSourcePath;
22
+ if (subscriptDir !== DEFAULT_BROWSER_SUBSCRIPT_DIR) {
23
+ const relPath = relative(join(engineDir, BROWSER_BASE_DIR), join(engineDir, subscriptDir)).replace(/\\/g, '/');
24
+ jarMnSourcePath = `${relPath}/${name}.js`;
25
+ }
26
+ if (options.dryRun) {
27
+ return {
28
+ subscriptAdded: true,
29
+ initAdded: !!options.init,
30
+ destroyAdded: !!options.destroy,
31
+ domInserted: !!options.domFilePath,
32
+ jarMnResult: {
33
+ manifest: 'browser/base/jar.mn',
34
+ entry: `[dry-run] Would register content/browser/${name}.js`,
35
+ skipped: false,
36
+ },
37
+ };
38
+ }
39
+ // 1. Add subscript to browser-main.js
40
+ const subscriptAdded = await addSubscriptToBrowserMain(engineDir, name);
41
+ // 2. Add init expression to browser-init.js (if provided)
42
+ let initAdded = false;
43
+ if (options.init) {
44
+ initAdded = await addInitToBrowserInit(engineDir, options.init, options.after);
45
+ }
46
+ // 3. Add destroy expression to browser-init.js onUnload() (if provided)
47
+ let destroyAdded = false;
48
+ if (options.destroy) {
49
+ destroyAdded = await addDestroyToBrowserInit(engineDir, options.destroy);
50
+ }
51
+ // 4. Add #include directive to browser.xhtml (if provided)
52
+ let domInserted = false;
53
+ if (options.domFilePath) {
54
+ domInserted = await addDomFragment(engineDir, toRootRelativePath(engineDir, options.domFilePath));
55
+ }
56
+ // 5. Register in jar.mn
57
+ const jarMnResult = await registerBrowserContent(engineDir, `${name}.js`, undefined, jarMnSourcePath);
58
+ return {
59
+ subscriptAdded,
60
+ initAdded,
61
+ destroyAdded,
62
+ domInserted,
63
+ jarMnResult,
64
+ };
65
+ }
66
+ //# sourceMappingURL=browser-wire.js.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Shared pre-flight logic for build and package commands:
3
+ * story cleanup, branding setup, Furnace component application, and mozconfig generation.
4
+ */
5
+ import type { FireForgeConfig, ProjectPaths } from '../types/config.js';
6
+ /**
7
+ * Result of the build preparation phase.
8
+ */
9
+ export interface BuildPreparation {
10
+ /** Number of Furnace components applied (0 if none or no furnace.json) */
11
+ furnaceApplied: number;
12
+ }
13
+ /**
14
+ * Runs the shared pre-flight steps for build and package commands:
15
+ * 1. Cleans Furnace stories from engine (prevents leaking into production)
16
+ * 2. Sets up branding directory if not already done
17
+ * 3. Applies Furnace components if furnace.json exists
18
+ * 4. Generates mozconfig
19
+ *
20
+ * @param projectRoot - Root directory of the project
21
+ * @param paths - Resolved project paths
22
+ * @param config - Loaded FireForge configuration
23
+ * @returns Preparation results
24
+ */
25
+ export declare function prepareBuildEnvironment(projectRoot: string, paths: ProjectPaths, config: FireForgeConfig): Promise<BuildPreparation>;
@@ -0,0 +1,93 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Shared pre-flight logic for build and package commands:
4
+ * story cleanup, branding setup, Furnace component application, and mozconfig generation.
5
+ */
6
+ import { spinner, warn } from '../utils/logger.js';
7
+ import { isBrandingSetup, setupBranding } from './branding.js';
8
+ import { applyAllComponents } from './furnace-apply.js';
9
+ import { furnaceConfigExists, loadFurnaceConfig } from './furnace-config.js';
10
+ import { cleanStories } from './furnace-stories.js';
11
+ import { generateMozconfig } from './mach.js';
12
+ /**
13
+ * Runs the shared pre-flight steps for build and package commands:
14
+ * 1. Cleans Furnace stories from engine (prevents leaking into production)
15
+ * 2. Sets up branding directory if not already done
16
+ * 3. Applies Furnace components if furnace.json exists
17
+ * 4. Generates mozconfig
18
+ *
19
+ * @param projectRoot - Root directory of the project
20
+ * @param paths - Resolved project paths
21
+ * @param config - Loaded FireForge configuration
22
+ * @returns Preparation results
23
+ */
24
+ export async function prepareBuildEnvironment(projectRoot, paths, config) {
25
+ // Clean stories before build to ensure they don't leak into production binary
26
+ await cleanStories(paths.engine);
27
+ // Set up custom branding directory and patch moz.configure
28
+ const brandingConfig = {
29
+ name: config.name,
30
+ vendor: config.vendor,
31
+ appId: config.appId,
32
+ binaryName: config.binaryName,
33
+ };
34
+ if (!(await isBrandingSetup(paths.engine, brandingConfig))) {
35
+ const brandingSpinner = spinner('Setting up branding...');
36
+ try {
37
+ await setupBranding(paths.engine, brandingConfig);
38
+ brandingSpinner.stop('Branding configured');
39
+ }
40
+ catch (error) {
41
+ brandingSpinner.error('Failed to set up branding');
42
+ throw error;
43
+ }
44
+ }
45
+ // Apply Furnace components if furnace.json exists
46
+ let furnaceApplied = 0;
47
+ if (await furnaceConfigExists(projectRoot)) {
48
+ const furnaceConfig = await loadFurnaceConfig(projectRoot);
49
+ const hasComponents = Object.keys(furnaceConfig.overrides).length > 0 ||
50
+ Object.keys(furnaceConfig.custom).length > 0;
51
+ if (hasComponents) {
52
+ const furnaceSpinner = spinner('Applying Furnace components...');
53
+ try {
54
+ const result = await applyAllComponents(projectRoot);
55
+ furnaceApplied = result.applied.length;
56
+ if (furnaceApplied > 0) {
57
+ furnaceSpinner.stop(`Applied ${furnaceApplied} component${furnaceApplied === 1 ? '' : 's'}`);
58
+ }
59
+ else {
60
+ furnaceSpinner.stop('Components up to date');
61
+ }
62
+ if (result.errors.length > 0) {
63
+ for (const err of result.errors) {
64
+ warn(`Furnace: ${err.name} — ${err.error}`);
65
+ }
66
+ }
67
+ for (const applied of result.applied) {
68
+ if (applied.stepErrors && applied.stepErrors.length > 0) {
69
+ for (const stepErr of applied.stepErrors) {
70
+ warn(`Furnace: ${applied.name} [${stepErr.step}] ${stepErr.error}`);
71
+ }
72
+ }
73
+ }
74
+ }
75
+ catch (error) {
76
+ furnaceSpinner.error('Failed to apply Furnace components');
77
+ throw error;
78
+ }
79
+ }
80
+ }
81
+ // Generate mozconfig
82
+ const mozconfigSpinner = spinner('Generating mozconfig...');
83
+ try {
84
+ await generateMozconfig(paths.configs, paths.engine, config);
85
+ mozconfigSpinner.stop('mozconfig generated');
86
+ }
87
+ catch (error) {
88
+ mozconfigSpinner.error('Failed to generate mozconfig');
89
+ throw error;
90
+ }
91
+ return { furnaceApplied };
92
+ }
93
+ //# sourceMappingURL=build-prepare.js.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Immutable config mutation with dot-path keys.
3
+ */
4
+ import type { FireForgeConfig } from '../types/config.js';
5
+ /**
6
+ * Creates a mutated copy of a config with a nested key set to a new value,
7
+ * optionally re-validated.
8
+ * @param config - Original config
9
+ * @param key - Dot-separated config path
10
+ * @param value - New value
11
+ * @param skipValidation - If true, skip re-validation (for --force)
12
+ * @returns The mutated config
13
+ */
14
+ export declare function mutateConfig(config: FireForgeConfig, key: string, value: unknown, skipValidation?: false): FireForgeConfig;
15
+ export declare function mutateConfig(config: FireForgeConfig, key: string, value: unknown, skipValidation: true): Record<string, unknown>;
@@ -0,0 +1,51 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Immutable config mutation with dot-path keys.
4
+ */
5
+ import { ConfigError } from '../errors/config.js';
6
+ import { toError } from '../utils/errors.js';
7
+ import { verbose } from '../utils/logger.js';
8
+ import { isObject } from '../utils/validation.js';
9
+ import { validateConfig } from './config-validate.js';
10
+ function cloneConfigDocument(config) {
11
+ const cloned = structuredClone(config);
12
+ if (!isObject(cloned)) {
13
+ throw new ConfigError('Config clone unexpectedly produced a non-object value');
14
+ }
15
+ return cloned;
16
+ }
17
+ function getOrCreateChildRecord(parent, key) {
18
+ const existing = parent[key];
19
+ if (isObject(existing)) {
20
+ return existing;
21
+ }
22
+ const child = {};
23
+ parent[key] = child;
24
+ return child;
25
+ }
26
+ export function mutateConfig(config, key, value, skipValidation = false) {
27
+ const raw = cloneConfigDocument(config);
28
+ const parts = key.split('.');
29
+ let current = raw;
30
+ for (let i = 0; i < parts.length - 1; i++) {
31
+ const part = parts[i];
32
+ if (part === undefined)
33
+ continue;
34
+ current = getOrCreateChildRecord(current, part);
35
+ }
36
+ const lastPart = parts[parts.length - 1];
37
+ if (lastPart !== undefined) {
38
+ current[lastPart] = value;
39
+ }
40
+ if (!skipValidation) {
41
+ return validateConfig(raw);
42
+ }
43
+ try {
44
+ validateConfig(raw);
45
+ }
46
+ catch (error) {
47
+ verbose(`Skipping config revalidation for forced mutation on "${key}": ${toError(error).message}`);
48
+ }
49
+ return raw;
50
+ }
51
+ //# sourceMappingURL=config-mutate.js.map
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Project path derivation from a root directory.
3
+ */
4
+ import type { ProjectPaths } from '../types/config.js';
5
+ /** Name of the configuration file */
6
+ export declare const CONFIG_FILENAME = "fireforge.json";
7
+ /** Name of the fireforge data directory */
8
+ export declare const FIREFORGE_DIR = ".fireforge";
9
+ /** Name of the state file */
10
+ export declare const STATE_FILENAME = "state.json";
11
+ /** Name of the engine directory */
12
+ export declare const ENGINE_DIR = "engine";
13
+ /** Name of the patches directory */
14
+ export declare const PATCHES_DIR = "patches";
15
+ /** Name of the configs directory */
16
+ export declare const CONFIGS_DIR = "configs";
17
+ /** Name of the source directory */
18
+ export declare const SRC_DIR = "src";
19
+ /** Supported top-level fireforge.json keys backed by the current schema. */
20
+ export declare const SUPPORTED_CONFIG_ROOT_KEYS: readonly ["name", "vendor", "appId", "binaryName", "firefox", "build", "license", "wire"];
21
+ /** Supported config paths that can be read or set without --force. */
22
+ export declare const SUPPORTED_CONFIG_PATHS: readonly ["name", "vendor", "appId", "binaryName", "license", "firefox", "firefox.version", "firefox.product", "build", "build.jobs", "wire", "wire.subscriptDir"];
23
+ /**
24
+ * Gets all project paths based on a root directory.
25
+ * @param root - Root directory of the project
26
+ * @returns All project paths
27
+ */
28
+ export declare function getProjectPaths(root: string): ProjectPaths;
@@ -0,0 +1,65 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Project path derivation from a root directory.
4
+ */
5
+ import { join } from 'node:path';
6
+ /** Name of the configuration file */
7
+ export const CONFIG_FILENAME = 'fireforge.json';
8
+ /** Name of the fireforge data directory */
9
+ export const FIREFORGE_DIR = '.fireforge';
10
+ /** Name of the state file */
11
+ export const STATE_FILENAME = 'state.json';
12
+ /** Name of the engine directory */
13
+ export const ENGINE_DIR = 'engine';
14
+ /** Name of the patches directory */
15
+ export const PATCHES_DIR = 'patches';
16
+ /** Name of the configs directory */
17
+ export const CONFIGS_DIR = 'configs';
18
+ /** Name of the source directory */
19
+ export const SRC_DIR = 'src';
20
+ /** Supported top-level fireforge.json keys backed by the current schema. */
21
+ export const SUPPORTED_CONFIG_ROOT_KEYS = [
22
+ 'name',
23
+ 'vendor',
24
+ 'appId',
25
+ 'binaryName',
26
+ 'firefox',
27
+ 'build',
28
+ 'license',
29
+ 'wire',
30
+ ];
31
+ /** Supported config paths that can be read or set without --force. */
32
+ export const SUPPORTED_CONFIG_PATHS = [
33
+ 'name',
34
+ 'vendor',
35
+ 'appId',
36
+ 'binaryName',
37
+ 'license',
38
+ 'firefox',
39
+ 'firefox.version',
40
+ 'firefox.product',
41
+ 'build',
42
+ 'build.jobs',
43
+ 'wire',
44
+ 'wire.subscriptDir',
45
+ ];
46
+ /**
47
+ * Gets all project paths based on a root directory.
48
+ * @param root - Root directory of the project
49
+ * @returns All project paths
50
+ */
51
+ export function getProjectPaths(root) {
52
+ const fireforgeDir = join(root, FIREFORGE_DIR);
53
+ return {
54
+ root,
55
+ config: join(root, CONFIG_FILENAME),
56
+ fireforgeDir,
57
+ state: join(fireforgeDir, STATE_FILENAME),
58
+ engine: join(root, ENGINE_DIR),
59
+ patches: join(root, PATCHES_DIR),
60
+ configs: join(root, CONFIGS_DIR),
61
+ src: join(root, SRC_DIR),
62
+ componentsDir: join(root, 'components'),
63
+ };
64
+ }
65
+ //# sourceMappingURL=config-paths.js.map
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Project state file management (.fireforge/state.json).
3
+ */
4
+ import type { FireForgeState } from '../types/config.js';
5
+ /**
6
+ * Validates a parsed project state object and returns a typed FireForgeState.
7
+ * @param data - Parsed JSON state data
8
+ * @returns Validated FireForgeState
9
+ */
10
+ export declare function validateFireForgeState(data: unknown): FireForgeState;
11
+ /**
12
+ * Loads the fireforge state, or returns defaults if it doesn't exist.
13
+ * @param root - Root directory of the project
14
+ * @returns FireForge state
15
+ */
16
+ export declare function loadState(root: string): Promise<FireForgeState>;
17
+ /**
18
+ * Saves the fireforge state.
19
+ * @param root - Root directory of the project
20
+ * @param state - State to save
21
+ */
22
+ export declare function saveState(root: string, state: FireForgeState): Promise<void>;
23
+ /**
24
+ * Updates specific fields in the fireforge state.
25
+ * @param root - Root directory of the project
26
+ * @param updates - Fields to update, or a transactional updater function
27
+ */
28
+ export declare function updateState(root: string, updates: Partial<FireForgeState> | ((current: FireForgeState) => FireForgeState)): Promise<void>;