@omega.js/desktop 0.52.0 → 0.54.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 (345) hide show
  1. package/README.md +53 -48
  2. package/dist/assets/css/core/_initialize.scss +1 -1
  3. package/dist/assets/js/core/app-shell.js +14 -15
  4. package/dist/assets/themes/_template/_theme.js +6 -6
  5. package/dist/assets/themes/base/_includes/global/sections/account.html +4 -4
  6. package/dist/assets/themes/base/_includes/global/sections/app-sidebar.html +5 -5
  7. package/dist/assets/themes/base/_layouts/frontend/pages/account/index.html +3 -3
  8. package/dist/assets/themes/base/_layouts/frontend/pages/alternatives/index.html +1 -1
  9. package/dist/assets/themes/base/_layouts/frontend/pages/blog/tags/tag.html +1 -1
  10. package/dist/assets/themes/base/_layouts/frontend/pages/payment/confirmation.html +1 -1
  11. package/dist/assets/themes/base/_sections/marketing/newsletter-cta/section.js +2 -3
  12. package/dist/assets/themes/base/_sections/verts/unit/section.html +1 -1
  13. package/dist/assets/themes/base/_sections/verts/unit/section.js +3 -4
  14. package/dist/assets/themes/base/_theme.js +4 -3
  15. package/dist/assets/themes/bootstrap/_theme.js +2 -2
  16. package/dist/assets/themes/bootstrap/overrides/_links.scss +1 -1
  17. package/dist/assets/themes/classy/_theme.js +8 -6
  18. package/dist/assets/themes/classy/css/marketing/_sections.scss +1 -2
  19. package/dist/assets/themes/classy/js/hero-demo-form.js +3 -2
  20. package/dist/assets/themes/neobrutalism/_theme.js +5 -5
  21. package/dist/assets/themes/neobrutalism/js/pages/test/libraries/layers/index.js +1 -1
  22. package/dist/assets/themes/newsflash/_theme.js +6 -6
  23. package/dist/assets/themes/newsflash/js/pages/test/libraries/layers/index.js +1 -1
  24. package/dist/build.js +87 -111
  25. package/dist/cli-run.js +4 -1
  26. package/dist/cli.js +3 -3
  27. package/dist/commands/build.js +2 -2
  28. package/dist/commands/cdp/capture.js +2 -2
  29. package/dist/commands/cdp/client.js +1 -1
  30. package/dist/commands/cdp/quit.js +2 -2
  31. package/dist/commands/cdp/relaunch.js +2 -2
  32. package/dist/commands/cdp/theme.js +1 -1
  33. package/dist/commands/cdp.js +1 -1
  34. package/dist/commands/clean.js +4 -5
  35. package/dist/commands/deploy.js +4 -4
  36. package/dist/commands/dev.js +25 -0
  37. package/dist/commands/finalize-release.js +4 -4
  38. package/dist/commands/launch.js +2 -2
  39. package/dist/commands/lib/deploy-precheck.js +3 -3
  40. package/dist/commands/lib/ensure-target.js +18 -23
  41. package/dist/commands/lib/migrate.js +17 -0
  42. package/dist/commands/logs.js +1 -1
  43. package/dist/commands/package.js +2 -2
  44. package/dist/commands/publish.js +2 -2
  45. package/dist/commands/release.js +4 -4
  46. package/dist/commands/runner.js +11 -11
  47. package/dist/commands/sign-windows.js +5 -5
  48. package/dist/commands/test.js +8 -8
  49. package/dist/commands/update.js +7 -6
  50. package/dist/commands/validate-certs.js +4 -4
  51. package/dist/commands/version.js +3 -3
  52. package/dist/defaults/.github/workflows/build.yml +18 -18
  53. package/dist/defaults/_.gitignore +0 -2
  54. package/dist/defaults/_mas/README.md +3 -3
  55. package/dist/defaults/config/certs/README.md +1 -1
  56. package/dist/defaults/config/omega.json5 +43 -43
  57. package/dist/defaults/docs/README.md +3 -3
  58. package/dist/defaults/gulpfile.js +1 -1
  59. package/dist/defaults/hooks/build/post.js +2 -2
  60. package/dist/defaults/hooks/build/pre.js +2 -2
  61. package/dist/defaults/hooks/deploy/pre.js +1 -1
  62. package/dist/defaults/hooks/notarize/post.js +2 -2
  63. package/dist/defaults/hooks/release/post.js +2 -2
  64. package/dist/defaults/hooks/release/pre.js +2 -2
  65. package/dist/defaults/src/assets/js/components/about/index.js +3 -5
  66. package/dist/defaults/src/assets/js/components/main/index.js +3 -5
  67. package/dist/defaults/src/assets/js/components/settings/index.js +3 -5
  68. package/dist/defaults/src/assets/scss/pages/about.scss +1 -1
  69. package/dist/defaults/src/assets/scss/pages/main.scss +1 -1
  70. package/dist/defaults/src/assets/scss/pages/settings.scss +1 -1
  71. package/dist/defaults/src/integrations/context-menu/index.js +13 -13
  72. package/dist/defaults/src/integrations/menu/index.js +8 -8
  73. package/dist/defaults/src/integrations/tray/index.js +12 -12
  74. package/dist/defaults/src/main.js +5 -7
  75. package/dist/defaults/src/preload.js +4 -6
  76. package/dist/defaults/test/README.md +5 -5
  77. package/dist/defaults/test/_init.js +1 -1
  78. package/dist/gulp/main.js +9 -10
  79. package/dist/gulp/tasks/audit.js +11 -14
  80. package/dist/gulp/tasks/build-config.js +8 -8
  81. package/dist/gulp/tasks/bundle.js +16 -16
  82. package/dist/gulp/tasks/defaults.js +3 -3
  83. package/dist/gulp/tasks/distribute.js +2 -2
  84. package/dist/gulp/tasks/html.js +9 -9
  85. package/dist/gulp/tasks/package-quick.js +3 -3
  86. package/dist/gulp/tasks/package.js +3 -3
  87. package/dist/gulp/tasks/release.js +3 -3
  88. package/dist/gulp/tasks/sass.js +6 -6
  89. package/dist/gulp/tasks/serve.js +4 -4
  90. package/dist/hooks/notarize-artifacts.js +1 -1
  91. package/dist/hooks/notarize.js +1 -1
  92. package/dist/index.js +5 -8
  93. package/dist/lib/_environment-mixin.js +50 -0
  94. package/dist/lib/_lifecycle-mixin.js +45 -0
  95. package/dist/lib/analytics.js +33 -35
  96. package/dist/lib/app-state.js +14 -14
  97. package/dist/lib/auth-flow.js +18 -18
  98. package/dist/lib/auth-persistence.js +12 -12
  99. package/dist/lib/auth.js +421 -0
  100. package/dist/lib/auto-updater.js +49 -49
  101. package/dist/lib/context-menu.js +13 -13
  102. package/dist/lib/context.js +19 -19
  103. package/dist/lib/deep-link.js +34 -34
  104. package/dist/lib/fontawesome.js +5 -5
  105. package/dist/lib/ipc.js +4 -4
  106. package/dist/lib/menu.js +25 -25
  107. package/dist/lib/protocol.js +5 -5
  108. package/dist/lib/remote-config.js +22 -22
  109. package/dist/lib/remote-scripts.js +21 -21
  110. package/dist/lib/restart-manager/index.js +29 -29
  111. package/dist/lib/restart-manager/install.js +1 -1
  112. package/dist/lib/restart-manager/protocol.js +1 -1
  113. package/dist/lib/sign-helpers/exec-with-limit.js +1 -1
  114. package/dist/lib/sign-helpers/sign-events.js +1 -1
  115. package/dist/lib/startup.js +18 -13
  116. package/dist/lib/storage.js +10 -10
  117. package/dist/lib/templating.js +16 -16
  118. package/dist/lib/theme.js +10 -10
  119. package/dist/lib/tray.js +27 -27
  120. package/dist/lib/usage.js +11 -11
  121. package/dist/lib/window-manager.js +26 -26
  122. package/dist/main.js +399 -483
  123. package/dist/preload.js +236 -176
  124. package/dist/renderer.js +417 -391
  125. package/dist/test/fixtures/consumer-app/config/omega.json5 +1 -1
  126. package/dist/test/fixtures/consumer-app/src/assets/js/components/main/index.js +8 -11
  127. package/dist/test/fixtures/consumer-app/src/main.js +5 -7
  128. package/dist/test/fixtures/consumer-app/src/preload.js +2 -2
  129. package/dist/test/harness/boot-entry.js +22 -20
  130. package/dist/test/harness/main-entry.js +31 -30
  131. package/dist/test/harness/renderer-entry.js +5 -5
  132. package/dist/test/harness/renderer-preload.js +137 -141
  133. package/dist/test/index.js +10 -10
  134. package/dist/test/runner.js +2 -2
  135. package/dist/test/runners/boot.js +7 -6
  136. package/dist/test/runners/electron.js +3 -2
  137. package/dist/test/runners/render-event.js +2 -2
  138. package/dist/test/suites/boot/consumer-app-boots.test.js +57 -26
  139. package/dist/test/suites/boot/restart-manager.test.js +2 -2
  140. package/dist/test/suites/boot/storage-bundled.test.js +5 -5
  141. package/dist/test/suites/boot/theme.test.js +13 -13
  142. package/dist/test/suites/build/audit.test.js +21 -8
  143. package/dist/test/suites/build/auth-persistence-resolve.test.js +6 -6
  144. package/dist/test/suites/build/boot-fixture.test.js +2 -2
  145. package/dist/test/suites/build/boot-runner-timeout.test.js +6 -5
  146. package/dist/test/suites/build/brand-scss.test.js +1 -1
  147. package/dist/test/suites/build/build-json-bake.test.js +1 -1
  148. package/dist/test/suites/build/build-workflow-jobs.test.js +2 -2
  149. package/dist/test/suites/build/cli.test.js +30 -2
  150. package/dist/test/suites/build/config-schema.test.js +5 -5
  151. package/dist/test/suites/build/defaults-em-dash.test.js +22 -0
  152. package/dist/test/suites/build/defaults-scaffold.test.js +21 -7
  153. package/dist/test/suites/build/deploy-direct.test.js +7 -5
  154. package/dist/test/suites/build/deploy-dispatch.test.js +2 -1
  155. package/dist/test/suites/build/deploy-hook.test.js +7 -5
  156. package/dist/test/suites/build/dev-verb.test.js +67 -0
  157. package/dist/test/suites/build/ensure-target.test.js +13 -5
  158. package/dist/test/suites/build/env-delivery.test.js +2 -2
  159. package/dist/test/suites/build/esm-only-dependency.test.js +2 -2
  160. package/dist/test/suites/build/exports.test.js +9 -8
  161. package/dist/test/suites/build/get-config.test.js +4 -4
  162. package/dist/test/suites/build/manifest-deps.test.js +1 -1
  163. package/dist/test/suites/build/merge-line-files.test.js +7 -7
  164. package/dist/test/suites/build/migrate.test.js +29 -0
  165. package/dist/test/suites/build/omega-shell.test.js +34 -2
  166. package/dist/test/suites/build/omega.test.js +350 -0
  167. package/dist/test/suites/build/project-scripts-deps.test.js +6 -10
  168. package/dist/test/suites/build/renderer-auth-bridge.test.js +211 -78
  169. package/dist/test/suites/build/runner-env-write.test.js +73 -0
  170. package/dist/test/suites/build/runner.test.js +11 -10
  171. package/dist/test/suites/build/sentry.test.js +2 -2
  172. package/dist/test/suites/build/setup-scripts.test.js +27 -0
  173. package/dist/test/suites/build/sign-windows-e2e.test.js +2 -2
  174. package/dist/test/suites/build/templating.test.js +3 -3
  175. package/dist/test/suites/build/test-stealth.test.js +7 -9
  176. package/dist/test/suites/build/url-helpers.test.js +55 -56
  177. package/dist/test/suites/build/validate-config.test.js +15 -4
  178. package/dist/test/suites/build/verb-logs.test.js +20 -0
  179. package/dist/test/suites/build/wave5-pins.test.js +2 -2
  180. package/dist/test/suites/main/analytics.test.js +59 -59
  181. package/dist/test/suites/main/app-state.test.js +66 -66
  182. package/dist/test/suites/main/auth-flow.test.js +41 -41
  183. package/dist/test/suites/main/auth-persistence.test.js +54 -43
  184. package/dist/test/suites/main/{client-bridge.integration.test.js → auth.integration.test.js} +10 -9
  185. package/dist/test/suites/main/auth.test.js +336 -0
  186. package/dist/test/suites/main/auto-updater.test.js +134 -134
  187. package/dist/test/suites/main/boot-sequence.test.js +37 -49
  188. package/dist/test/suites/main/context-menu.test.js +51 -50
  189. package/dist/test/suites/main/context.test.js +25 -25
  190. package/dist/test/suites/main/deep-link.test.js +74 -74
  191. package/dist/test/suites/main/fontawesome.test.js +27 -27
  192. package/dist/test/suites/main/ipc.test.js +35 -35
  193. package/dist/test/suites/main/menu.test.js +101 -100
  194. package/dist/test/suites/main/protocol.test.js +19 -19
  195. package/dist/test/suites/main/remote-config.test.js +63 -63
  196. package/dist/test/suites/main/remote-scripts.test.js +103 -103
  197. package/dist/test/suites/main/request.test.js +71 -0
  198. package/dist/test/suites/main/restart-manager.test.js +33 -33
  199. package/dist/test/suites/main/startup-paths-and-ua.test.js +4 -4
  200. package/dist/test/suites/main/startup.test.js +26 -26
  201. package/dist/test/suites/main/stealth-window.test.js +1 -1
  202. package/dist/test/suites/main/storage.test.js +25 -25
  203. package/dist/test/suites/main/theme.test.js +34 -34
  204. package/dist/test/suites/main/tray.test.js +79 -79
  205. package/dist/test/suites/main/url-helpers.test.js +133 -133
  206. package/dist/test/suites/main/usage.test.js +25 -25
  207. package/dist/test/suites/main/window-bounds.test.js +27 -27
  208. package/dist/test/suites/main/window-manager.test.js +44 -44
  209. package/dist/test/suites/renderer/analytics-bridge.test.js +5 -5
  210. package/dist/test/suites/renderer/cross-context-helpers.test.js +37 -31
  211. package/dist/test/suites/renderer/round-trip.test.js +3 -3
  212. package/dist/test/suites/renderer/tooltips.test.js +15 -15
  213. package/dist/test/suites/renderer/{window-em-surface.test.js → window-desktop-surface.test.js} +28 -8
  214. package/dist/test/utils/extended-mode-warning.js +1 -1
  215. package/dist/utils/boot-harness.js +56 -0
  216. package/dist/utils/build-pipeline.js +4 -4
  217. package/dist/utils/mode-helpers.js +2 -15
  218. package/dist/utils/runner-env.js +13 -28
  219. package/dist/utils/ship-keys.js +3 -3
  220. package/dist/utils/signing-status.js +51 -0
  221. package/dist/utils/test-events.js +7 -0
  222. package/dist/utils/test-stealth.js +6 -6
  223. package/dist/utils/url-helpers.js +52 -42
  224. package/dist/utils/user-agent.js +44 -0
  225. package/dist/vendor/account/engine.js +3 -3
  226. package/dist/vendor/account/index.js +14 -45
  227. package/dist/vendor/account/resolve-account.js +44 -0
  228. package/dist/vendor/account/schema.js +1 -1
  229. package/dist/vendor/account/user.js +99 -0
  230. package/dist/vendor/config/client-config.js +1 -1
  231. package/dist/vendor/config/company.js +46 -14
  232. package/dist/vendor/config/defaults.js +30 -7
  233. package/dist/vendor/config/edit.js +25 -3
  234. package/dist/vendor/config/env-delivery.js +1 -1
  235. package/dist/vendor/config/env-schema.js +3 -6
  236. package/dist/vendor/config/env.js +34 -22
  237. package/dist/vendor/config/environment.js +11 -30
  238. package/dist/vendor/config/index.js +21 -28
  239. package/dist/vendor/config/load.js +16 -9
  240. package/dist/vendor/config/platforms.js +1 -1
  241. package/dist/vendor/config/repo.js +10 -27
  242. package/dist/vendor/config/schema-client.js +64 -0
  243. package/dist/vendor/config/schema-cloud.js +38 -0
  244. package/dist/vendor/config/schema-manager.js +118 -0
  245. package/dist/vendor/config/schema-overrides.js +68 -0
  246. package/dist/vendor/config/schema.js +104 -160
  247. package/dist/vendor/config/site-global.js +2 -3
  248. package/dist/vendor/config/validate.js +97 -78
  249. package/dist/vendor/config/winback.js +1 -1
  250. package/dist/vendor/devkit/actions-secrets.js +1 -1
  251. package/dist/vendor/devkit/agents-md.js +233 -0
  252. package/dist/vendor/devkit/attach-log-file.js +16 -2
  253. package/dist/vendor/devkit/build-json.js +1 -1
  254. package/dist/vendor/devkit/ci-workflows.js +30 -30
  255. package/dist/vendor/devkit/cli-router.js +16 -11
  256. package/dist/vendor/devkit/defaults-engine.js +15 -51
  257. package/dist/vendor/devkit/deploy-snapshot.js +44 -9
  258. package/dist/vendor/devkit/env-lines.js +183 -0
  259. package/dist/vendor/devkit/local.js +64 -10
  260. package/dist/vendor/devkit/lockfile.js +32 -13
  261. package/dist/vendor/devkit/logger.js +7 -2
  262. package/dist/vendor/devkit/merge-line-files.js +219 -177
  263. package/dist/vendor/devkit/omega-bin.js +208 -111
  264. package/dist/vendor/devkit/preludes/docs-sync.js +52 -0
  265. package/dist/vendor/devkit/preludes/index.js +1 -0
  266. package/dist/vendor/devkit/target-picker.js +45 -0
  267. package/dist/vendor/devkit/test/dashed-files.js +37 -0
  268. package/dist/vendor/devkit/test/run-verb-under-tee.js +71 -0
  269. package/dist/vendor/devkit/test/runner-core.js +6 -6
  270. package/dist/vendor/devkit/update.js +15 -15
  271. package/dist/vendor/devkit/verb-scripts.js +40 -0
  272. package/dist/vendor/devkit/verbs.js +170 -0
  273. package/dist/vendor/monitoring/env.js +2 -2
  274. package/dist/vendor/monitoring/index.js +1 -1
  275. package/dist/vendor/monitoring/main.js +1 -1
  276. package/dist/vendor/monitoring/preload.js +1 -1
  277. package/dist/vendor/monitoring/renderer.js +1 -1
  278. package/package.json +19 -26
  279. package/dist/commands/install.js +0 -37
  280. package/dist/defaults/AGENTS.md +0 -110
  281. package/dist/defaults/CLAUDE.md +0 -1
  282. package/dist/lib/client-bridge.js +0 -374
  283. package/dist/lib/logger.js +0 -4
  284. package/dist/test/suites/build/manager.test.js +0 -213
  285. package/dist/test/suites/main/client-bridge.test.js +0 -262
  286. package/dist/vendor/config/env-retired.js +0 -137
  287. package/dist/vendor/config/retired-keys.js +0 -635
  288. package/docs/analytics.md +0 -140
  289. package/docs/app-state.md +0 -92
  290. package/docs/audit.md +0 -69
  291. package/docs/auto-updater.md +0 -243
  292. package/docs/boot-sequence.md +0 -39
  293. package/docs/build-system.md +0 -169
  294. package/docs/cdp-debugging.md +0 -169
  295. package/docs/client-bridge.md +0 -269
  296. package/docs/common-mistakes.md +0 -21
  297. package/docs/config-schema.md +0 -120
  298. package/docs/context-menu.md +0 -112
  299. package/docs/context.md +0 -81
  300. package/docs/css.md +0 -90
  301. package/docs/deep-link.md +0 -186
  302. package/docs/environment-detection.md +0 -112
  303. package/docs/fontawesome.md +0 -107
  304. package/docs/hooks.md +0 -89
  305. package/docs/icons.md +0 -79
  306. package/docs/index.md +0 -317
  307. package/docs/installer-options.md +0 -165
  308. package/docs/ipc.md +0 -61
  309. package/docs/lib-modules.md +0 -53
  310. package/docs/logging.md +0 -229
  311. package/docs/menu.md +0 -160
  312. package/docs/releasing.md +0 -239
  313. package/docs/remote-config.md +0 -118
  314. package/docs/remote-scripts.md +0 -144
  315. package/docs/restart-manager.md +0 -144
  316. package/docs/runner.md +0 -290
  317. package/docs/sentry.md +0 -97
  318. package/docs/shared/agent-docs.md +0 -89
  319. package/docs/shared/analytics.md +0 -612
  320. package/docs/shared/brands.md +0 -57
  321. package/docs/shared/breaking-changes.md +0 -851
  322. package/docs/shared/config.md +0 -1952
  323. package/docs/shared/deploys.md +0 -341
  324. package/docs/shared/icons.md +0 -219
  325. package/docs/shared/local-dev.md +0 -167
  326. package/docs/shared/logging.md +0 -205
  327. package/docs/shared/monitoring.md +0 -167
  328. package/docs/shared/publishing.md +0 -187
  329. package/docs/shared/rulings.md +0 -34
  330. package/docs/shared/testing.md +0 -147
  331. package/docs/shared/theming.md +0 -629
  332. package/docs/shared/translation.md +0 -333
  333. package/docs/shared/updates.md +0 -61
  334. package/docs/signing.md +0 -293
  335. package/docs/startup.md +0 -142
  336. package/docs/storage.md +0 -59
  337. package/docs/templating.md +0 -101
  338. package/docs/test-boot-layer.md +0 -157
  339. package/docs/test-framework.md +0 -362
  340. package/docs/themes.md +0 -149
  341. package/docs/tooltips.md +0 -99
  342. package/docs/tray.md +0 -164
  343. package/docs/usage.md +0 -58
  344. package/docs/verts.md +0 -62
  345. package/docs/windows.md +0 -149
@@ -32,7 +32,6 @@ const path = require('node:path');
32
32
  const { findBrandRoot } = require('./load.js');
33
33
  const { resolveCompany } = require('./company.js');
34
34
  const { ENV_SCHEMA, envFileGroups, envSchemaEntry } = require('./env-schema.js');
35
- const { assertNoRetiredEnvKeys } = require('./env-retired.js');
36
35
  // The one vocabulary lives with the one environment module (#817); this file
37
36
  // re-exports it so the .env overlay names and the runtime answer stay one list.
38
37
  const { ENV_ENVIRONMENTS } = require('./environment.js');
@@ -322,11 +321,8 @@ function reloadEnv(startDir, { target, environment = envEnvironment() } = {}) {
322
321
  /**
323
322
  * Parse one .env file into a plain map. Missing files read as empty.
324
323
  *
325
- * The ONE place a `.env` layer is read, so it is also where a RETIRED key is
326
- * refused ([#893](https://github.com/Omega-JS-Stack/omega/issues/893)): there
327
- * is no dual-read, so a line for a key that moved into config is a value
328
- * nothing consults, and both readers below (the process cascade and the
329
- * artifact composer) fail on it naming the move.
324
+ * The layer is OPEN: an .env may carry keys outside omega, so a key nothing
325
+ * reads (a retired one included) is simply unread. `omega migrate` names those.
330
326
  *
331
327
  * @param {string|null} envPath
332
328
  * @returns {Object<string, string>} Parsed key → value.
@@ -334,10 +330,7 @@ function reloadEnv(startDir, { target, environment = envEnvironment() } = {}) {
334
330
  function parseEnvFile(envPath) {
335
331
  if (!envPath || !fs.existsSync(envPath)) return {};
336
332
 
337
- const parsed = require('dotenv').parse(fs.readFileSync(envPath, 'utf8'));
338
- assertNoRetiredEnvKeys(parsed, envPath);
339
-
340
- return parsed;
333
+ return require('dotenv').parse(fs.readFileSync(envPath, 'utf8'));
341
334
  }
342
335
 
343
336
  /**
@@ -441,34 +434,53 @@ function composeTargetEnv({ targetDir, target, environment = envEnvironment() })
441
434
  }
442
435
 
443
436
  /**
444
- * Serialize one value as a double-quoted .env line — the serializer SSOT every
445
- * writeback rides (this composer, the manager's brand .env writeback and
446
- * scaffold stub). Backslashes, quotes and newlines escape so a multi-line blob
447
- * stays line-safe (dotenv expands `\n` back on read).
437
+ * Throw unless dotenv reads every given value back from `content` exactly as
438
+ * given. The error names the keys, never a value.
439
+ *
440
+ * @param {string} content - .env content holding the written lines.
441
+ * @param {Object<string, string>} values - The values those lines must carry.
442
+ */
443
+ function assertEnvReadsBack(content, values) {
444
+ const parsed = require('dotenv').parse(content);
445
+ const changed = Object.keys(values).filter((key) => parsed[key] !== String(values[key]));
446
+ if (changed.length === 0) return;
447
+
448
+ throw new Error(`.env: the value of ${changed.join(', ')} would not read back unchanged from KEY="value" (dotenv expands a literal \\n or \\r, a quote followed by # ends the value, and a trailing backslash can run into the next line)`);
449
+ }
450
+
451
+ /**
452
+ * Serialize one value as a double-quoted .env line, the serializer SSOT every
453
+ * writeback rides. The value goes in raw (dotenv reads `"`, `\`, `'`, `#` back
454
+ * unchanged); a real newline or carriage return becomes `\n` / `\r`, which
455
+ * dotenv expands back. A value dotenv would read back changed, such as a
456
+ * literal backslash-n or backslash-r, throws naming the key only.
448
457
  *
449
458
  * @param {string} key - Env var name.
450
459
  * @param {string} value - Value to serialize.
451
460
  * @returns {string} `KEY="value"`.
452
461
  */
453
462
  function envLine(key, value) {
454
- const escaped = String(value)
455
- .replace(/\\/g, '\\\\')
456
- .replace(/"/g, '\\"')
457
- .replace(/\n/g, '\\n');
463
+ const raw = String(value).replace(/\n/g, '\\n').replace(/\r/g, '\\r');
464
+ const line = `${key}="${raw}"`;
465
+ assertEnvReadsBack(line, { [key]: value });
458
466
 
459
- return `${key}="${escaped}"`;
467
+ return line;
460
468
  }
461
469
 
462
470
  /**
463
- * Serialize composed values as .env content — one envLine per key.
471
+ * Serialize composed values as .env content, one envLine per key. The whole
472
+ * file is judged too: a value ending in a backslash can carry dotenv's read
473
+ * into the next line, which no single line shows.
464
474
  *
465
475
  * @param {Object<string, string>} values
466
476
  * @returns {string} The file content, newline-terminated.
467
477
  */
468
478
  function serializeEnv(values) {
469
479
  const lines = Object.entries(values).map(([key, value]) => envLine(key, value));
480
+ const content = `${lines.join('\n')}\n`;
481
+ assertEnvReadsBack(content, values);
470
482
 
471
- return `${lines.join('\n')}\n`;
483
+ return content;
472
484
  }
473
485
 
474
- module.exports = { loadEnv, reloadEnv, ENV_ENVIRONMENTS, envEnvironment, resolveEnvChain, envLayerFiles, loadEnvChain, loadEnvRoots, applyDeliverAs, composeTargetEnv, envLine, serializeEnv };
486
+ module.exports = { loadEnv, reloadEnv, ENV_ENVIRONMENTS, envEnvironment, resolveEnvChain, envLayerFiles, loadEnvChain, loadEnvRoots, applyDeliverAs, composeTargetEnv, assertEnvReadsBack, envLine, serializeEnv };
@@ -3,8 +3,8 @@
3
3
  * ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)).
4
4
  *
5
5
  * Four calls, one implementation, one call form everywhere: `getEnvironment()`
6
- * plus `isDevelopment()` / `isProduction()` / `isTesting()`, mixed into a
7
- * framework's Manager with `attachTo()`. @omega.js/backend, @omega.js/desktop,
6
+ * plus `isDevelopment()` / `isProduction()` / `isTesting()`, called directly
7
+ * by every framework's `omega` instance and build module. @omega.js/backend, @omega.js/desktop,
8
8
  * @omega.js/extension and @omega.js/web each carried their own copy of this
9
9
  * logic, each with its own signal list and its own DEFAULT, and the copies
10
10
  * disagreed: desktop answered `production` with no signal while the extension
@@ -18,7 +18,7 @@
18
18
  * neither env nor files, it is `config.environment`, the build fact every
19
19
  * surface already bakes into `OMEGA_BUILD_JSON.config`
20
20
  * ([#896](https://github.com/Omega-JS-Stack/omega/issues/896)), reached as
21
- * `this.config.environment` off the Manager the call is made on. Nothing else
21
+ * `this.config.environment` off the instance the call is made on. Nothing else
22
22
  * is consulted: no `app.isPackaged`, no `manifest.update_url`, no `NODE_ENV`,
23
23
  * no terminal sniffing.
24
24
  *
@@ -31,7 +31,7 @@
31
31
  * already resolves its config, through `setEnvironment()` below (the only
32
32
  * writer, so a fourth word can never reach the variable): the backend's boot
33
33
  * takes the .env cascade's ambient answer, the desktop and extension build
34
- * Managers take `production` under their build-mode flag and the ambient answer
34
+ * modules take `production` under their build-mode flag and the ambient answer
35
35
  * otherwise, and web's verbs name their own (`omega build` is production,
36
36
  * `omega dev` is development).
37
37
  *
@@ -64,7 +64,7 @@ function fromProcess() {
64
64
 
65
65
  /**
66
66
  * The browser input: the build fact baked into `OMEGA_BUILD_JSON.config`,
67
- * reached through the Manager the call was made on.
67
+ * reached through the instance the call was made on.
68
68
  * @param {object} [context] - the `this` of the call.
69
69
  * @returns {string|undefined} the raw value.
70
70
  */
@@ -75,7 +75,7 @@ function fromBakedConfig(context) {
75
75
  /**
76
76
  * The running environment, from the one input.
77
77
  *
78
- * @this {object} [context] - a Manager carrying the baked `config`.
78
+ * @this {object} [context] - an instance carrying the baked `config`.
79
79
  * @returns {'development'|'testing'|'production'} exactly one of the three.
80
80
  * @throws {Error} when neither input names one of the three.
81
81
  */
@@ -92,7 +92,7 @@ function getEnvironment() {
92
92
  }
93
93
 
94
94
  /**
95
- * @this {object} [context] - a Manager carrying the baked `config`.
95
+ * @this {object} [context] - an instance carrying the baked `config`.
96
96
  * @returns {boolean} true only in development (never in testing).
97
97
  */
98
98
  function isDevelopment() {
@@ -100,7 +100,7 @@ function isDevelopment() {
100
100
  }
101
101
 
102
102
  /**
103
- * @this {object} [context] - a Manager carrying the baked `config`.
103
+ * @this {object} [context] - an instance carrying the baked `config`.
104
104
  * @returns {boolean} true only in production, a real positive check.
105
105
  */
106
106
  function isProduction() {
@@ -108,7 +108,7 @@ function isProduction() {
108
108
  }
109
109
 
110
110
  /**
111
- * @this {object} [context] - a Manager carrying the baked `config`.
111
+ * @this {object} [context] - an instance carrying the baked `config`.
112
112
  * @returns {boolean} true only while a test lane runs this process.
113
113
  */
114
114
  function isTesting() {
@@ -136,7 +136,7 @@ function setEnvironment(value) {
136
136
 
137
137
  /**
138
138
  * The environment a NODE BUILD LANE is for, decided once for the two frameworks
139
- * whose build Manager names it at load (@omega.js/desktop and
139
+ * whose build module names it at load (@omega.js/desktop and
140
140
  * @omega.js/extension, which carried byte-identical copies of this expression).
141
141
  * Two rules, no sniffing:
142
142
  *
@@ -151,31 +151,13 @@ function setEnvironment(value) {
151
151
  * writer. This is the only default anywhere near this module, and it belongs to
152
152
  * a build lane alone: a READER still gets no default at all.
153
153
  *
154
- * @param {boolean} buildMode - The lane's build-mode flag (`Manager.isBuildMode()`).
154
+ * @param {boolean} buildMode - The lane's build-mode flag (`build.isBuildMode()`).
155
155
  * @returns {'development'|'testing'|'production'} the word that lane is for.
156
156
  */
157
157
  function buildLaneEnvironment(buildMode) {
158
158
  return buildMode ? 'production' : (fromProcess() || 'development');
159
159
  }
160
160
 
161
- /**
162
- * Mix the surface into a Manager constructor's prototype AND the constructor
163
- * itself, so `Manager.isTesting()` works statically too. The idiom every
164
- * framework already attaches with.
165
- *
166
- * @param {Function} Manager - the constructor to extend.
167
- */
168
- function attachTo(Manager) {
169
- Manager.prototype.getEnvironment = getEnvironment;
170
- Manager.prototype.isDevelopment = isDevelopment;
171
- Manager.prototype.isProduction = isProduction;
172
- Manager.prototype.isTesting = isTesting;
173
- Manager.getEnvironment = getEnvironment;
174
- Manager.isDevelopment = isDevelopment;
175
- Manager.isProduction = isProduction;
176
- Manager.isTesting = isTesting;
177
- }
178
-
179
161
  module.exports = {
180
162
  ENV_ENVIRONMENTS,
181
163
  ENVIRONMENT_VAR,
@@ -185,5 +167,4 @@ module.exports = {
185
167
  isTesting,
186
168
  setEnvironment,
187
169
  buildLaneEnvironment,
188
- attachTo,
189
170
  };
@@ -9,12 +9,11 @@
9
9
  * `type`, and any shared key inside a target entry overrides the shared value
10
10
  * for that surface (one agnostic deep merge).
11
11
  *
12
- * Replaces the per-framework config zoo (UJM's _config.yml + JSON split,
13
- * EM's config/electron-manager.json, @omega.js/backend's backend-manager-config.json,
14
- * BXM's config) with NO dual-read: each framework flips to omega.json5
15
- * outright and legacy brands migrate their file once (docs/shared/config.md has
16
- * the mapping tables). omega-manager's disperse enumerates SHARED_SECTIONS
17
- * instead of hardcoding per-target mapping blocks.
12
+ * Replaces the per-framework legacy config files with NO dual-read: each
13
+ * framework reads omega.json5 outright and legacy brands migrate their file
14
+ * once (docs/shared/config.md has the mapping tables). @omega.js/manager's
15
+ * disperse enumerates SHARED_SECTIONS instead of hardcoding per-target mapping
16
+ * blocks.
18
17
  *
19
18
  * Private workspace package — vendored/bundled into the published frameworks
20
19
  * at prepare time, never published on its own.
@@ -24,19 +23,17 @@ const { TARGETS, CUSTOM_TARGET_TYPE, isCustomTargetEntry, BACKEND_PROJECT_TYPES,
24
23
  const { clientConfig, CLIENT_FACT_KEYS } = require('./client-config.js');
25
24
  const { deepMerge } = require('./merge.js');
26
25
  const { findSecretKeys, SECRET_KEY_PATTERN } = require('./secrets.js');
27
- const { findRetiredKeys, RETIRED_KEYS, RETIRED_PATHS } = require('./retired-keys.js');
28
26
  const { chosenProvider } = require('./providers.js');
29
- const { validateConfig, runSchema, formatErrors, resolvedBrandHost } = require('./validate.js');
30
- const { loadConfig, composeTargetConfig, hasOmegaConfig, resolveConfigPath, getEnabledTargets, findBrandRoot, findBrandConfigPath, resolveBrandRoot, FILE_NAME, CONFIG_LOCATIONS } = require('./load.js');
31
- const { ENV_ENVIRONMENTS, ENVIRONMENT_VAR, getEnvironment, isDevelopment, isProduction, isTesting, setEnvironment, buildLaneEnvironment, attachTo: attachEnvironment } = require('./environment.js');
32
- const { loadEnv, reloadEnv, envEnvironment, resolveEnvChain, envLayerFiles, loadEnvChain, loadEnvRoots, applyDeliverAs, composeTargetEnv, envLine, serializeEnv } = require('./env.js');
27
+ const { validateConfig, undeclaredPaths, undeclaredAuthoredPaths, runSchema, formatErrors, resolvedBrandHost } = require('./validate.js');
28
+ const { loadConfig, composeTargetConfig, hasOmegaConfig, resolveConfigPath, overlayPath, getEnabledTargets, findBrandRoot, findBrandConfigPath, resolveBrandRoot, FILE_NAME, CONFIG_LOCATIONS } = require('./load.js');
29
+ const { ENV_ENVIRONMENTS, ENVIRONMENT_VAR, getEnvironment, isDevelopment, isProduction, isTesting, setEnvironment, buildLaneEnvironment } = require('./environment.js');
30
+ const { loadEnv, reloadEnv, envEnvironment, resolveEnvChain, envLayerFiles, loadEnvChain, loadEnvRoots, applyDeliverAs, composeTargetEnv, assertEnvReadsBack, envLine, serializeEnv } = require('./env.js');
33
31
  const { ENV_SCHEMA, ENV_GROUPS, DELIVERY_MODES, envFileGroups, envSchemaEntry, envKeysForTarget, generatedEnvKeys, requiredEnvKeys, envKeysByGroup } = require('./env-schema.js');
34
32
  const { WORKFLOW_OWNED_KEYS, deliveredKeys, workflowSecretKeys, envFileKeys, artifactEnvValues, bakeKeys, bakeSourceKeys, publishSecretKeys, renderSecretsBlock, renderEnvFileKeys } = require('./env-delivery.js');
35
33
  const { checkEnvRules } = require('./env-rules.js');
36
- const { RETIRED_ENV_KEYS, findRetiredEnvKeys, assertNoRetiredEnvKeys } = require('./env-retired.js');
37
34
  const { resolveCompany, recordBrand, readRegistry, registryFile, COMPANY_DIR, COMPANY_RESOLVED_FILE, COMPANY_SELF } = require('./company.js');
38
- const { applyConfigEdits, writeConfigValues, applyConfigRemovals, removeConfigValues } = require('./edit.js');
39
- const { schemaDefaults, missingDefaults, defaultComments } = require('./defaults.js');
35
+ const { applyConfigEdits, writeConfigValues, writeConfigFileValues, applyConfigRemovals, removeConfigValues, removeConfigFileValues } = require('./edit.js');
36
+ const { schemaDefaults, missingDefaults, defaultComments, planMerge, setAtPath } = require('./defaults.js');
40
37
  const { applyCanonicalOrder, CANONICAL_TOP_LEVEL_ORDER } = require('./order.js');
41
38
  const { resolveSeedMode } = require('./seed.js');
42
39
  const { resolveHook, loadHook } = require('./hooks.js');
@@ -56,6 +53,7 @@ module.exports = {
56
53
  composeTargetConfig,
57
54
  hasOmegaConfig,
58
55
  resolveConfigPath,
56
+ overlayPath,
59
57
  getEnabledTargets,
60
58
  findBrandRoot,
61
59
  findBrandConfigPath,
@@ -79,8 +77,7 @@ module.exports = {
79
77
  ENV_ENVIRONMENTS,
80
78
  // The ONE environment module every target answers from (#817): one input
81
79
  // (OMEGA_ENVIRONMENT on Node, the baked config.environment in a browser),
82
- // no per-surface default, a missing input is a loud error. `attachEnvironment`
83
- // is its attachTo(), named for what it mixes in.
80
+ // no per-surface default, a missing input is a loud error.
84
81
  ENVIRONMENT_VAR,
85
82
  getEnvironment,
86
83
  isDevelopment,
@@ -88,9 +85,8 @@ module.exports = {
88
85
  isTesting,
89
86
  setEnvironment,
90
87
  // The word a node BUILD LANE is for, from its build-mode flag and whatever a
91
- // parent lane named: the desktop and extension build Managers set this
88
+ // parent lane named: the desktop and extension build modules set this
92
89
  buildLaneEnvironment,
93
- attachEnvironment,
94
90
  // The AMBIENT answer a lane resolves when nothing named one for it, and the
95
91
  // producer of the input above
96
92
  envEnvironment,
@@ -104,6 +100,7 @@ module.exports = {
104
100
  composeTargetEnv,
105
101
 
106
102
  // The .env serializer SSOT — every writeback renders through these
103
+ assertEnvReadsBack,
107
104
  envLine,
108
105
  serializeEnv,
109
106
 
@@ -139,13 +136,6 @@ module.exports = {
139
136
  // `requiredWhen`; every consumer calls it, none keeps its own if
140
137
  checkEnvRules,
141
138
 
142
- // The .env half of the retired-key register (#893): a key that moved into
143
- // config fails the layer that still declares it, naming the move. Every
144
- // `.env` read goes through parseEnvFile, so nothing can miss the check
145
- RETIRED_ENV_KEYS,
146
- findRetiredEnvKeys,
147
- assertNoRetiredEnvKeys,
148
-
149
139
  // The ONE company resolver (#677): `company: { id }` in, the company's public
150
140
  // facts plus its tree on this machine out. The config chain, the .env chain,
151
141
  // owner hooks and the desktop signing tree all inherit through its `file()`,
@@ -165,8 +155,10 @@ module.exports = {
165
155
  // Writeback (comment-preserving edits + canonical top-level key order)
166
156
  applyConfigEdits,
167
157
  writeConfigValues,
158
+ writeConfigFileValues,
168
159
  applyConfigRemovals,
169
160
  removeConfigValues,
161
+ removeConfigFileValues,
170
162
  applyCanonicalOrder,
171
163
  CANONICAL_TOP_LEVEL_ORDER,
172
164
 
@@ -174,6 +166,8 @@ module.exports = {
174
166
  // heal list the manage walk materializes into a brand's omega.json5
175
167
  schemaDefaults,
176
168
  missingDefaults,
169
+ planMerge,
170
+ setAtPath,
177
171
  defaultComments,
178
172
 
179
173
  // Layer-aware consumer seeding (brand target = no local-layer config at all)
@@ -247,6 +241,8 @@ module.exports = {
247
241
 
248
242
  // Validation
249
243
  validateConfig,
244
+ undeclaredPaths,
245
+ undeclaredAuthoredPaths,
250
246
  runSchema,
251
247
  formatErrors,
252
248
 
@@ -257,9 +253,6 @@ module.exports = {
257
253
 
258
254
  findSecretKeys,
259
255
  SECRET_KEY_PATTERN,
260
- findRetiredKeys,
261
- RETIRED_KEYS,
262
- RETIRED_PATHS,
263
256
 
264
257
  // The one provider shape (#425) — `role.providers.<provider>`, where key
265
258
  // presence is the pick and `false` is the deliberate off switch
@@ -58,8 +58,7 @@
58
58
  *
59
59
  * Secrets hard-fail: raw files are scanned BEFORE any merge — a secret in
60
60
  * any target section (requested or not) throws. Schema findings come back
61
- * as `errors` so callers pick their strictness (audit throws, boot warns —
62
- * EM's proven two-mode usage).
61
+ * as `errors` so callers pick their strictness (audit throws, boot warns).
63
62
  */
64
63
 
65
64
  const fs = require('node:fs');
@@ -67,7 +66,7 @@ const path = require('node:path');
67
66
  const JSON5 = require('json5');
68
67
 
69
68
  const { deepMerge, isPlainObject } = require('./merge.js');
70
- const { resolveCompany, recordBrand } = require('./company.js');
69
+ const { resolveCompany, recordBrand, RESOLVED_COMPANY_KEYS } = require('./company.js');
71
70
  const { findSecretKeys } = require('./secrets.js');
72
71
  const { validateConfig } = require('./validate.js');
73
72
  const { TARGETS } = require('./schema.js');
@@ -135,10 +134,22 @@ function resolveOverlayEnvironment(environment, fallback) {
135
134
  function resolveOverlayPath(basePath, environment) {
136
135
  if (!basePath || !environment) return null;
137
136
 
138
- const overlay = path.join(path.dirname(basePath), `${path.basename(FILE_NAME, '.json5')}.${environment}.json5`);
137
+ const overlay = overlayPath(basePath, environment);
139
138
  return fs.existsSync(overlay) ? overlay : null;
140
139
  }
141
140
 
141
+ /**
142
+ * The ONE spelling of a layer's environment overlay: `omega.<environment>.json5`
143
+ * beside its base file, whether or not either exists. Every reader and writer
144
+ * of an overlay names it through here.
145
+ * @param {string} basePath - The layer's omega.json5 path.
146
+ * @param {string} environment - One of ENV_ENVIRONMENTS.
147
+ * @returns {string} Absolute overlay path.
148
+ */
149
+ function overlayPath(basePath, environment) {
150
+ return path.join(path.dirname(basePath), `${path.basename(FILE_NAME, '.json5')}.${environment}.json5`);
151
+ }
152
+
142
153
  /**
143
154
  * Cheap probe: does this project have an omega.json5 at all? Frameworks use it
144
155
  * to fail soft in non-consumer dirs (seeded-empty config); tooling uses it as
@@ -302,10 +313,6 @@ function stripTargets(config) {
302
313
  return shared;
303
314
  }
304
315
 
305
- // The `company` keys the LOADER fills (#677): authored, they would be
306
- // overwritten at every load, so an author hears about it at the file.
307
- const RESOLVED_COMPANY_KEYS = ['name', 'url', 'images'];
308
-
309
316
  /**
310
317
  * The company keys nobody types, refused where a human writes them: the BRAND
311
318
  * file and the COMPANY file (#677). The local layer is deliberately exempt,
@@ -738,4 +745,4 @@ function composeTargetConfig(projectDir, target, options) {
738
745
  return { config, files: { local: localPath, brand: brandPath, company: companyPath } };
739
746
  }
740
747
 
741
- module.exports = { loadConfig, composeTargetConfig, hasOmegaConfig, resolveConfigPath, getEnabledTargets, findBrandRoot, findBrandConfigPath, resolveBrandRoot, FILE_NAME, CONFIG_LOCATIONS, TARGET_SUBDIRS };
748
+ module.exports = { loadConfig, composeTargetConfig, hasOmegaConfig, resolveConfigPath, overlayPath, getEnabledTargets, findBrandRoot, findBrandConfigPath, resolveBrandRoot, FILE_NAME, CONFIG_LOCATIONS, TARGET_SUBDIRS };
@@ -181,7 +181,7 @@ function enabledFormats(config, target) {
181
181
 
182
182
  /**
183
183
  * The product name a desktop target packages under: the same derivation
184
- * @omega.js/desktop's `Manager.getConfig()` applies (`app.productName` then
184
+ * @omega.js/desktop's `build.getConfig()` applies (`app.productName` then
185
185
  * `brand.name`), so the website reads the name the packager actually used.
186
186
  *
187
187
  * @param {object} config - Desktop-shaped config (`{ app, brand }`).
@@ -1,31 +1,14 @@
1
1
  /**
2
- * @omega.js/config repo: the ONE derivation of every repo a brand owns
3
- * ([#883](https://github.com/Omega-JS-Stack/omega/issues/883)).
4
- *
5
- * ONE config block says where a brand hosts its code:
6
- *
7
- * repo: { provider: 'github', org: 'Acme-Org' }
8
- *
9
- * and nothing else. Presence of the block enables the repo service, exactly
10
- * as a target's key presence enables a target; `provider` defaults to `github`
11
- * and `org` is the only typed value. No repo NAME is ever configured: every
12
- * name derives from the `<brand.id>-<role>` rule (Ian 2026-09-07,
13
- * [#809](https://github.com/Omega-JS-Stack/omega/issues/809)), one function per
14
- * role, so nobody types a repo name to get the right one:
15
- *
16
- * - `<brand.id>-omega` the SOURCE monorepo (`sourceRepo`)
17
- * - `<brand.id>-releases` the public release channel (`releasesRepo`)
18
- * - `<brand.id>-<name>` one per web target that GitHub hosts (`websiteRepo`)
19
- *
20
- * A repo name that must differ is a brand id that must differ: the override
21
- * keys (`repo.providers.github.repo`, the top-level `github` block,
22
- * `targets.<name>.github.repo`, `targets.desktop.releases.owner/repo`) are
23
- * retired, each with a row in retired-keys.js.
24
- *
25
- * Visibility is NOT in omega.json5 either: the brand root's package.json
26
- * `private` field is the one statement of it (`brandVisibility`), absent
27
- * meaning private, because every brand monorepo is private by default
28
- * (Ian 2026-09-11).
2
+ * @omega.js/config repo: the ONE derivation of every repo a brand owns. One
3
+ * block says where a brand hosts its code, `repo: { provider: 'github', org }`:
4
+ * its presence enables the repo service, `provider` defaults to `github`, and
5
+ * `org` is the only typed value. No repo NAME is configured anywhere; each
6
+ * derives from `<brand.id>-<role>`, one function per role: `<brand.id>-omega`
7
+ * the source monorepo (`sourceRepo`), `<brand.id>-releases` the public release
8
+ * channel (`releasesRepo`), `<brand.id>-<name>` per GitHub-hosted web target
9
+ * (`websiteRepo`). The old override keys are rows in @omega.js/manager's
10
+ * src/migrate/retired-keys.js. Visibility is the brand root package.json's
11
+ * `private` field (`brandVisibility`), absent meaning private.
29
12
  */
30
13
 
31
14
  const fs = require('node:fs');
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Schema rules for the `client` blob: the @omega.js/client settings bag a web
3
+ * target carries. The bag is OPEN (the client normalizes it against its own
4
+ * defaults); only the keys a brand authors, and consent, are typed.
5
+ */
6
+
7
+ const CLIENT_RULES = [
8
+ {
9
+ path: 'client',
10
+ type: 'object',
11
+ open: true,
12
+ required: false,
13
+ description: "The @omega.js/client runtime settings (auth, firebase, exitPopup, …), merged over the client's own defaults. Open by design: only consent and the keys a brand authors are typed below.",
14
+ },
15
+
16
+ // Consent decides whether a visitor is tracked at all: a typo that silently
17
+ // disabled the banner would ship a site with no consent gate and no error.
18
+ {
19
+ path: 'client.consent.enabled',
20
+ type: 'boolean',
21
+ required: false,
22
+ default: true,
23
+ description: 'The consent banner + the provider-script gate (default true). false ships NO banner: legal only for a site that loads no analytics/marketing provider at all.',
24
+ },
25
+ {
26
+ path: 'client.consent.config.position',
27
+ type: 'string',
28
+ required: false,
29
+ enum: ['bottom-left', 'bottom-right', 'bottom'],
30
+ description: "Where the panel sits. 'bottom' is the centered full-width form.",
31
+ },
32
+ {
33
+ path: 'client.consent.config.content',
34
+ type: 'object',
35
+ required: false,
36
+ description: "Banner copy: message, panelIntro, accept, customize, acceptAll, acceptNone (a literal `{terms}`/`{cookies}` links the terms/cookie-policy page). Category labels are framework copy: a brand renames the buttons, not the categories.",
37
+ },
38
+
39
+ // The keys a BRAND authors: each one reaches the client payload and changes
40
+ // what the site does, so each one is typed.
41
+ {
42
+ path: 'client.auth.config.policy',
43
+ type: 'string',
44
+ required: false,
45
+ enum: ['authenticated', 'unauthenticated', 'disabled'],
46
+ description: "Who a page is FOR: 'authenticated' redirects a signed-out visitor to the signin route, 'unauthenticated' redirects a signed-in one away, 'disabled' skips the auth module entirely (a vert iframe). Absent = no policy, which is the site-wide answer: the auth/admin layouts set theirs in page frontmatter, so a brand only sets this to blanket a whole site.",
47
+ },
48
+ {
49
+ path: 'client.exitPopup.enabled',
50
+ type: 'boolean',
51
+ required: false,
52
+ default: true,
53
+ description: 'The exit-intent offer popup (default true). false ships no popup at all; its copy, timeout and avatars live under client.exitPopup.config.',
54
+ },
55
+ {
56
+ path: 'client.serviceWorker.enabled',
57
+ type: 'boolean',
58
+ required: false,
59
+ default: true,
60
+ description: 'Registers the site service worker (default true): the offline/refresh lane and the push-notification registration ride it. false unregisters any worker the visitor already has.',
61
+ },
62
+ ];
63
+
64
+ module.exports = { CLIENT_RULES };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Schema rules for `cloud.config`, the provider's web-app config. For firebase
3
+ * it is the console's config verbatim: public by design (the web API key is no
4
+ * secret), and every key the Firebase web SDK takes is typed.
5
+ */
6
+
7
+ const FIREBASE_WEB_KEYS = {
8
+ apiKey: 'The web API key the Firebase SDKs identify the project with. Public by design: it ships in every browser bundle.',
9
+ authDomain: "The Firebase Auth domain: the BRAND host, where the web build self-hosts /__/auth/* (docs/shared/config.md → authDomain).",
10
+ databaseURL: 'The Realtime Database URL, for a project that has one.',
11
+ storageBucket: 'The default Cloud Storage bucket.',
12
+ messagingSenderId: 'The Cloud Messaging sender id web push registers against.',
13
+ appId: 'The Firebase web app id.',
14
+ measurementId: 'The Google Analytics measurement id Firebase links to the web app.',
15
+ };
16
+
17
+ const CLOUD_CONFIG_RULES = [
18
+ {
19
+ path: 'cloud.config',
20
+ type: 'object',
21
+ required: false,
22
+ description: 'Provider app config. For firebase: the web-app config verbatim from the console. Public by design: the web API key is not a secret.',
23
+ },
24
+ {
25
+ path: 'cloud.config.projectId',
26
+ type: 'string',
27
+ required: false,
28
+ description: 'Drives auth, emulator project selection, analytics uuidv5 namespace, remote-config URL fallbacks.',
29
+ },
30
+ ...Object.entries(FIREBASE_WEB_KEYS).map(([key, description]) => ({
31
+ path: `cloud.config.${key}`,
32
+ type: 'string',
33
+ required: false,
34
+ description,
35
+ })),
36
+ ];
37
+
38
+ module.exports = { CLOUD_CONFIG_RULES };