@omega.js/desktop 0.52.0 → 0.53.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 (273) hide show
  1. package/README.md +17 -12
  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.js +1 -1
  26. package/dist/commands/build.js +2 -2
  27. package/dist/commands/cdp/capture.js +2 -2
  28. package/dist/commands/cdp/quit.js +2 -2
  29. package/dist/commands/cdp/relaunch.js +2 -2
  30. package/dist/commands/cdp/theme.js +1 -1
  31. package/dist/commands/clean.js +2 -2
  32. package/dist/commands/deploy.js +4 -4
  33. package/dist/commands/finalize-release.js +4 -4
  34. package/dist/commands/install.js +3 -3
  35. package/dist/commands/launch.js +2 -2
  36. package/dist/commands/lib/deploy-precheck.js +3 -3
  37. package/dist/commands/lib/ensure-target.js +6 -6
  38. package/dist/commands/package.js +2 -2
  39. package/dist/commands/publish.js +2 -2
  40. package/dist/commands/release.js +3 -3
  41. package/dist/commands/runner.js +11 -11
  42. package/dist/commands/sign-windows.js +5 -5
  43. package/dist/commands/test.js +4 -4
  44. package/dist/commands/update.js +2 -2
  45. package/dist/commands/validate-certs.js +4 -4
  46. package/dist/commands/version.js +3 -3
  47. package/dist/defaults/AGENTS.md +17 -8
  48. package/dist/defaults/config/omega.json5 +7 -7
  49. package/dist/defaults/hooks/build/post.js +1 -1
  50. package/dist/defaults/hooks/build/pre.js +1 -1
  51. package/dist/defaults/hooks/deploy/pre.js +1 -1
  52. package/dist/defaults/hooks/release/post.js +1 -1
  53. package/dist/defaults/hooks/release/pre.js +1 -1
  54. package/dist/defaults/src/assets/js/components/about/index.js +3 -5
  55. package/dist/defaults/src/assets/js/components/main/index.js +3 -5
  56. package/dist/defaults/src/assets/js/components/settings/index.js +3 -5
  57. package/dist/defaults/src/integrations/context-menu/index.js +2 -2
  58. package/dist/defaults/src/integrations/menu/index.js +3 -3
  59. package/dist/defaults/src/integrations/tray/index.js +3 -3
  60. package/dist/defaults/src/main.js +3 -5
  61. package/dist/defaults/src/preload.js +3 -5
  62. package/dist/defaults/test/README.md +2 -2
  63. package/dist/gulp/main.js +9 -10
  64. package/dist/gulp/tasks/audit.js +7 -7
  65. package/dist/gulp/tasks/build-config.js +8 -8
  66. package/dist/gulp/tasks/bundle.js +16 -16
  67. package/dist/gulp/tasks/defaults.js +3 -3
  68. package/dist/gulp/tasks/distribute.js +2 -2
  69. package/dist/gulp/tasks/html.js +9 -9
  70. package/dist/gulp/tasks/package-quick.js +3 -3
  71. package/dist/gulp/tasks/package.js +3 -3
  72. package/dist/gulp/tasks/release.js +3 -3
  73. package/dist/gulp/tasks/sass.js +6 -6
  74. package/dist/gulp/tasks/serve.js +4 -4
  75. package/dist/hooks/notarize-artifacts.js +1 -1
  76. package/dist/hooks/notarize.js +1 -1
  77. package/dist/index.js +5 -8
  78. package/dist/lib/_environment-mixin.js +50 -0
  79. package/dist/lib/_lifecycle-mixin.js +45 -0
  80. package/dist/lib/analytics.js +33 -35
  81. package/dist/lib/app-state.js +14 -14
  82. package/dist/lib/auth-flow.js +18 -18
  83. package/dist/lib/auth-persistence.js +12 -12
  84. package/dist/lib/auth.js +421 -0
  85. package/dist/lib/auto-updater.js +49 -49
  86. package/dist/lib/context-menu.js +13 -13
  87. package/dist/lib/context.js +19 -19
  88. package/dist/lib/deep-link.js +34 -34
  89. package/dist/lib/fontawesome.js +5 -5
  90. package/dist/lib/ipc.js +4 -4
  91. package/dist/lib/menu.js +25 -25
  92. package/dist/lib/protocol.js +5 -5
  93. package/dist/lib/remote-config.js +22 -22
  94. package/dist/lib/remote-scripts.js +21 -21
  95. package/dist/lib/restart-manager/index.js +28 -28
  96. package/dist/lib/sign-helpers/exec-with-limit.js +1 -1
  97. package/dist/lib/sign-helpers/sign-events.js +1 -1
  98. package/dist/lib/startup.js +18 -13
  99. package/dist/lib/storage.js +10 -10
  100. package/dist/lib/templating.js +16 -16
  101. package/dist/lib/theme.js +10 -10
  102. package/dist/lib/tray.js +27 -27
  103. package/dist/lib/usage.js +11 -11
  104. package/dist/lib/window-manager.js +26 -26
  105. package/dist/main.js +398 -483
  106. package/dist/preload.js +236 -176
  107. package/dist/renderer.js +417 -391
  108. package/dist/test/fixtures/consumer-app/config/omega.json5 +1 -1
  109. package/dist/test/fixtures/consumer-app/src/assets/js/components/main/index.js +8 -11
  110. package/dist/test/fixtures/consumer-app/src/main.js +5 -7
  111. package/dist/test/fixtures/consumer-app/src/preload.js +2 -2
  112. package/dist/test/harness/boot-entry.js +22 -20
  113. package/dist/test/harness/main-entry.js +31 -30
  114. package/dist/test/harness/renderer-entry.js +5 -5
  115. package/dist/test/harness/renderer-preload.js +137 -141
  116. package/dist/test/index.js +10 -10
  117. package/dist/test/runner.js +2 -2
  118. package/dist/test/runners/boot.js +7 -6
  119. package/dist/test/runners/electron.js +3 -2
  120. package/dist/test/runners/render-event.js +2 -2
  121. package/dist/test/suites/boot/consumer-app-boots.test.js +57 -26
  122. package/dist/test/suites/boot/restart-manager.test.js +2 -2
  123. package/dist/test/suites/boot/storage-bundled.test.js +5 -5
  124. package/dist/test/suites/boot/theme.test.js +13 -13
  125. package/dist/test/suites/build/audit.test.js +1 -1
  126. package/dist/test/suites/build/auth-persistence-resolve.test.js +6 -6
  127. package/dist/test/suites/build/boot-fixture.test.js +2 -2
  128. package/dist/test/suites/build/boot-runner-timeout.test.js +6 -5
  129. package/dist/test/suites/build/brand-scss.test.js +1 -1
  130. package/dist/test/suites/build/build-json-bake.test.js +1 -1
  131. package/dist/test/suites/build/cli.test.js +2 -2
  132. package/dist/test/suites/build/config-schema.test.js +5 -5
  133. package/dist/test/suites/build/defaults-scaffold.test.js +2 -2
  134. package/dist/test/suites/build/deploy-hook.test.js +3 -3
  135. package/dist/test/suites/build/ensure-target.test.js +2 -2
  136. package/dist/test/suites/build/env-delivery.test.js +2 -2
  137. package/dist/test/suites/build/esm-only-dependency.test.js +2 -2
  138. package/dist/test/suites/build/exports.test.js +9 -8
  139. package/dist/test/suites/build/get-config.test.js +4 -4
  140. package/dist/test/suites/build/manifest-deps.test.js +1 -1
  141. package/dist/test/suites/build/merge-line-files.test.js +1 -1
  142. package/dist/test/suites/build/omega-shell.test.js +34 -2
  143. package/dist/test/suites/build/omega.test.js +350 -0
  144. package/dist/test/suites/build/renderer-auth-bridge.test.js +211 -78
  145. package/dist/test/suites/build/runner.test.js +2 -2
  146. package/dist/test/suites/build/sentry.test.js +2 -2
  147. package/dist/test/suites/build/sign-windows-e2e.test.js +2 -2
  148. package/dist/test/suites/build/templating.test.js +3 -3
  149. package/dist/test/suites/build/test-stealth.test.js +7 -9
  150. package/dist/test/suites/build/url-helpers.test.js +55 -56
  151. package/dist/test/suites/build/validate-config.test.js +2 -2
  152. package/dist/test/suites/build/wave5-pins.test.js +2 -2
  153. package/dist/test/suites/main/analytics.test.js +59 -59
  154. package/dist/test/suites/main/app-state.test.js +66 -66
  155. package/dist/test/suites/main/auth-flow.test.js +41 -41
  156. package/dist/test/suites/main/auth-persistence.test.js +54 -43
  157. package/dist/test/suites/main/{client-bridge.integration.test.js → auth.integration.test.js} +10 -9
  158. package/dist/test/suites/main/auth.test.js +336 -0
  159. package/dist/test/suites/main/auto-updater.test.js +134 -134
  160. package/dist/test/suites/main/boot-sequence.test.js +37 -49
  161. package/dist/test/suites/main/context-menu.test.js +51 -50
  162. package/dist/test/suites/main/context.test.js +25 -25
  163. package/dist/test/suites/main/deep-link.test.js +74 -74
  164. package/dist/test/suites/main/fontawesome.test.js +27 -27
  165. package/dist/test/suites/main/ipc.test.js +35 -35
  166. package/dist/test/suites/main/menu.test.js +101 -100
  167. package/dist/test/suites/main/protocol.test.js +19 -19
  168. package/dist/test/suites/main/remote-config.test.js +63 -63
  169. package/dist/test/suites/main/remote-scripts.test.js +103 -103
  170. package/dist/test/suites/main/request.test.js +71 -0
  171. package/dist/test/suites/main/restart-manager.test.js +33 -33
  172. package/dist/test/suites/main/startup-paths-and-ua.test.js +4 -4
  173. package/dist/test/suites/main/startup.test.js +26 -26
  174. package/dist/test/suites/main/stealth-window.test.js +1 -1
  175. package/dist/test/suites/main/storage.test.js +25 -25
  176. package/dist/test/suites/main/theme.test.js +34 -34
  177. package/dist/test/suites/main/tray.test.js +79 -79
  178. package/dist/test/suites/main/url-helpers.test.js +133 -133
  179. package/dist/test/suites/main/usage.test.js +25 -25
  180. package/dist/test/suites/main/window-bounds.test.js +27 -27
  181. package/dist/test/suites/main/window-manager.test.js +44 -44
  182. package/dist/test/suites/renderer/analytics-bridge.test.js +5 -5
  183. package/dist/test/suites/renderer/cross-context-helpers.test.js +37 -31
  184. package/dist/test/suites/renderer/round-trip.test.js +3 -3
  185. package/dist/test/suites/renderer/tooltips.test.js +15 -15
  186. package/dist/test/suites/renderer/{window-em-surface.test.js → window-desktop-surface.test.js} +27 -7
  187. package/dist/test/utils/extended-mode-warning.js +1 -1
  188. package/dist/utils/boot-harness.js +56 -0
  189. package/dist/utils/mode-helpers.js +2 -15
  190. package/dist/utils/ship-keys.js +3 -3
  191. package/dist/utils/signing-status.js +51 -0
  192. package/dist/utils/test-events.js +7 -0
  193. package/dist/utils/test-stealth.js +6 -6
  194. package/dist/utils/url-helpers.js +52 -42
  195. package/dist/utils/user-agent.js +44 -0
  196. package/dist/vendor/account/engine.js +3 -3
  197. package/dist/vendor/account/index.js +14 -45
  198. package/dist/vendor/account/resolve-account.js +44 -0
  199. package/dist/vendor/account/schema.js +1 -1
  200. package/dist/vendor/account/user.js +99 -0
  201. package/dist/vendor/config/client-config.js +1 -1
  202. package/dist/vendor/config/environment.js +11 -30
  203. package/dist/vendor/config/index.js +8 -11
  204. package/dist/vendor/config/load.js +1 -2
  205. package/dist/vendor/config/platforms.js +1 -1
  206. package/dist/vendor/config/retired-keys.js +2 -2
  207. package/dist/vendor/config/schema.js +5 -8
  208. package/dist/vendor/config/site-global.js +2 -3
  209. package/dist/vendor/config/validate.js +1 -2
  210. package/dist/vendor/config/winback.js +1 -1
  211. package/dist/vendor/devkit/actions-secrets.js +1 -1
  212. package/dist/vendor/devkit/attach-log-file.js +1 -1
  213. package/dist/vendor/devkit/build-json.js +1 -1
  214. package/dist/vendor/devkit/cli-router.js +3 -4
  215. package/dist/vendor/devkit/defaults-engine.js +9 -11
  216. package/dist/vendor/devkit/local.js +2 -0
  217. package/dist/vendor/devkit/merge-line-files.js +2 -3
  218. package/dist/vendor/devkit/test/runner-core.js +6 -6
  219. package/dist/vendor/monitoring/env.js +2 -2
  220. package/dist/vendor/monitoring/index.js +1 -1
  221. package/dist/vendor/monitoring/main.js +1 -1
  222. package/dist/vendor/monitoring/preload.js +1 -1
  223. package/dist/vendor/monitoring/renderer.js +1 -1
  224. package/docs/analytics.md +8 -8
  225. package/docs/app-state.md +19 -19
  226. package/docs/audit.md +4 -4
  227. package/docs/{client-bridge.md → auth.md} +88 -73
  228. package/docs/auto-updater.md +8 -8
  229. package/docs/boot-sequence.md +11 -6
  230. package/docs/build-system.md +1 -1
  231. package/docs/cdp-debugging.md +1 -1
  232. package/docs/common-mistakes.md +7 -7
  233. package/docs/config-schema.md +1 -1
  234. package/docs/context-menu.md +13 -13
  235. package/docs/context.md +11 -11
  236. package/docs/css.md +3 -9
  237. package/docs/deep-link.md +25 -25
  238. package/docs/environment-detection.md +16 -16
  239. package/docs/fontawesome.md +7 -5
  240. package/docs/hooks.md +8 -8
  241. package/docs/index.md +38 -27
  242. package/docs/ipc.md +10 -10
  243. package/docs/lib-modules.md +9 -9
  244. package/docs/logging.md +12 -14
  245. package/docs/menu.md +18 -18
  246. package/docs/remote-config.md +9 -9
  247. package/docs/remote-scripts.md +12 -12
  248. package/docs/restart-manager.md +8 -8
  249. package/docs/sentry.md +4 -4
  250. package/docs/shared/analytics.md +1 -1
  251. package/docs/shared/breaking-changes.md +79 -13
  252. package/docs/shared/config.md +17 -21
  253. package/docs/shared/logging.md +1 -1
  254. package/docs/shared/monitoring.md +5 -5
  255. package/docs/shared/testing.md +2 -2
  256. package/docs/shared/theming.md +1 -1
  257. package/docs/shared/translation.md +19 -10
  258. package/docs/startup.md +16 -16
  259. package/docs/storage.md +11 -11
  260. package/docs/templating.md +3 -3
  261. package/docs/test-boot-layer.md +12 -12
  262. package/docs/test-framework.md +17 -17
  263. package/docs/themes.md +7 -7
  264. package/docs/tooltips.md +2 -2
  265. package/docs/tray.md +31 -31
  266. package/docs/usage.md +7 -7
  267. package/docs/verts.md +1 -1
  268. package/docs/windows.md +22 -22
  269. package/package.json +3 -4
  270. package/dist/lib/client-bridge.js +0 -374
  271. package/dist/lib/logger.js +0 -4
  272. package/dist/test/suites/build/manager.test.js +0 -213
  273. package/dist/test/suites/main/client-bridge.test.js +0 -262
@@ -1,53 +1,22 @@
1
1
  /**
2
- * @omega.js/account — the single source of truth for the OMEGA user/account schema.
2
+ * @omega.js/account: the single source of truth for the OMEGA user/account schema.
3
3
  *
4
- * Today the account shape lives in two drifted places: @omega.js/backend's
5
- * src/manager/helpers/user.js (canonical — schema engine + tokens) and
6
- * @omega.js/client's DEFAULT_ACCOUNT in modules/auth.js (hand-rolled deep-merge,
7
- * missing flags/activity/personal branches and `everPaid`). This package
8
- * unifies them; each framework becomes a thin wrapper (@omega.js/backend keeps its
9
- * `new User(Manager, settings).properties` API, @omega.js/client keeps
10
- * `resolveAccount(rawData, firebaseUser)`).
4
+ * The account shape once lived in two drifted places: @omega.js/backend's user
5
+ * helper (canonical, schema engine + tokens) and @omega.js/client's hand-rolled
6
+ * DEFAULT_ACCOUNT (missing flags/activity/personal branches and `everPaid`).
7
+ * This package unifies them; each framework is a thin wrapper (the backend's
8
+ * src/omega/services/user.js, the client's modules/auth.js).
11
9
  *
12
- * resolveAccount(data, options):
13
- * options.generators — { uuid, randomId, apiKey } value generators for the
14
- * '$uuid'/'$randomId'/'$apiKey' schema tokens. @omega.js/backend injects real ones
15
- * (uuid v4, Utilities().randomId, uid-generator); the frontend passes none
16
- * and the fields resolve to null (real values always come from the backend).
17
- * options.user — optional auth-user overlay ({ uid, email }): fills
18
- * account.auth identity when the doc doesn't carry it (@omega.js/client's
19
- * resolveAccount(rawData, firebaseUser) semantic).
10
+ * Exports:
11
+ * User: the account as a class (user.js), the stored document as own fields
12
+ * plus the computed getters.
13
+ * resolveAccount(data, options): the plain resolved document (resolve-account.js).
14
+ * resolveSubscription(account): the subscription math (subscription.js).
20
15
  */
21
16
  const USER_SCHEMA = require('./schema.js');
22
- const { resolve } = require('./engine.js');
17
+ const resolveAccount = require('./resolve-account.js');
23
18
  const resolveSubscription = require('./subscription.js');
19
+ const User = require('./user.js');
24
20
  const features = require('./features.js');
25
21
 
26
- function resolveAccount(data, options) {
27
- options = options || {};
28
-
29
- // Time context — byte-identical to @omega.js/backend's node-powertools timestamps:
30
- // powertools.timestamp(d, { output: 'string' }) === d.toISOString(),
31
- // powertools.timestamp(d, { output: 'unix' }) === floor(ms / 1000).
32
- const now = new Date();
33
- const ctx = {
34
- generators: options.generators || {},
35
- now: now.toISOString(),
36
- nowUNIX: Math.floor(now.getTime() / 1000),
37
- oldDate: new Date(0).toISOString(),
38
- oldDateUNIX: 0,
39
- };
40
-
41
- const account = resolve(USER_SCHEMA, data || {}, ctx);
42
-
43
- // Auth-user overlay (frontend semantic): identity from the signed-in Firebase
44
- // user when the stored doc doesn't already carry it
45
- if (options.user) {
46
- account.auth.uid = account.auth.uid || options.user.uid || null;
47
- account.auth.email = account.auth.email || options.user.email || null;
48
- }
49
-
50
- return account;
51
- }
52
-
53
- module.exports = { USER_SCHEMA, resolveAccount, resolveSubscription, ...features };
22
+ module.exports = { USER_SCHEMA, User, resolveAccount, resolveSubscription, ...features };
@@ -0,0 +1,44 @@
1
+ /**
2
+ * resolveAccount: the ONE document resolution, shared by the User class and
3
+ * every caller that still wants the plain resolved object.
4
+ *
5
+ * resolveAccount(data, options):
6
+ * options.generators: { uuid, randomId, apiKey } value generators for the
7
+ * '$uuid'/'$randomId'/'$apiKey' schema tokens. @omega.js/backend injects real ones
8
+ * (uuid v4, Utilities().randomId, uid-generator); the frontend passes none
9
+ * and the fields resolve to null (real values always come from the backend).
10
+ * options.user: optional auth-user overlay ({ uid, email }): fills
11
+ * account.auth identity when the doc doesn't carry it (@omega.js/client's
12
+ * resolveAccount(rawData, firebaseUser) semantic).
13
+ */
14
+ const USER_SCHEMA = require('./schema.js');
15
+ const { resolve } = require('./engine.js');
16
+
17
+ function resolveAccount(data, options) {
18
+ options = options || {};
19
+
20
+ // Time context, byte-identical to @omega.js/backend's node-powertools timestamps:
21
+ // powertools.timestamp(d, { output: 'string' }) === d.toISOString(),
22
+ // powertools.timestamp(d, { output: 'unix' }) === floor(ms / 1000).
23
+ const now = new Date();
24
+ const ctx = {
25
+ generators: options.generators || {},
26
+ now: now.toISOString(),
27
+ nowUNIX: Math.floor(now.getTime() / 1000),
28
+ oldDate: new Date(0).toISOString(),
29
+ oldDateUNIX: 0,
30
+ };
31
+
32
+ const account = resolve(USER_SCHEMA, data || {}, ctx);
33
+
34
+ // Auth-user overlay (frontend semantic): identity from the signed-in Firebase
35
+ // user when the stored doc doesn't already carry it
36
+ if (options.user) {
37
+ account.auth.uid = account.auth.uid || options.user.uid || null;
38
+ account.auth.email = account.auth.email || options.user.email || null;
39
+ }
40
+
41
+ return account;
42
+ }
43
+
44
+ module.exports = resolveAccount;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * USER_SCHEMA — the canonical OMEGA user/account schema (pure data, no logic).
3
3
  *
4
- * Extracted verbatim from @omega.js/backend's src/manager/helpers/user.js, which is
4
+ * Extracted verbatim from @omega.js/backend's former user helper, which was
5
5
  * the authoritative shape (@omega.js/client's DEFAULT_ACCOUNT had drifted from it).
6
6
  *
7
7
  * Each leaf field is { type, default, nullable }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * User: the OMEGA account as one class, the same on the backend and in the browser.
3
+ *
4
+ * The own enumerable fields are the resolved stored document (every schema
5
+ * branch, in schema order), so `user.auth.uid` and `user.subscription.status`
6
+ * read as they always have and `toJSON()` is the one stored shape a Firestore
7
+ * write or an API response carries. Everything derived lives on the prototype
8
+ * as getters, computed on every read, so it never reaches the stored shape and
9
+ * never goes stale when code mutates `user.subscription` in place.
10
+ *
11
+ * `new User()` is the signed-out user: `authenticated` false, `plan` basic.
12
+ */
13
+ const resolveAccount = require('./resolve-account.js');
14
+ const resolveSubscription = require('./subscription.js');
15
+
16
+ /**
17
+ * An account: the stored document as own fields, identity-derived and
18
+ * subscription-derived facts as getters.
19
+ */
20
+ class User {
21
+ // The '$uuid'/'$randomId'/'$apiKey' token generators. Static because there is one host per process:
22
+ // the Node backend assigns { uuid, randomId, apiKey } once at boot; the browser never does, so those fields resolve to null.
23
+ static generators = {};
24
+
25
+ // The schema's own EMPTY discount node, which is what a CLEARED discount is
26
+ // ([#333](https://github.com/Omega-JS-Stack/omega/issues/333)). The webhook
27
+ // pipeline clears the node with a MERGE write, so every field has to be named or
28
+ // half of the old claim survives it. Read off the resolver rather than spelled
29
+ // out again: the node's shape keeps its one home in the schema, and a field
30
+ // added there is cleared without anyone remembering a second list.
31
+ static EMPTY_DISCOUNT = resolveAccount({}).subscription.discount;
32
+
33
+ /**
34
+ * @param {object} [document] - the stored account document (any partial object)
35
+ * @param {object|null} [identity] - { uid, email, displayName, photoURL, emailVerified }; a Firebase user satisfies it as-is
36
+ */
37
+ constructor(document = {}, identity = null) {
38
+ Object.assign(this, resolveAccount(document, { generators: User.generators, user: identity }));
39
+
40
+ // Non-enumerable so it never reaches toJSON() or Object.keys(): the profile
41
+ // comes from the sign-in, never from the stored document
42
+ const source = identity || {};
43
+ Object.defineProperty(this, 'profile', {
44
+ value: {
45
+ displayName: source.displayName || null,
46
+ photoURL: source.photoURL || null,
47
+ emailVerified: source.emailVerified === true,
48
+ },
49
+ writable: true,
50
+ });
51
+ }
52
+
53
+ /** True only when the account carries a non-empty uid. */
54
+ get authenticated() {
55
+ return typeof this.auth.uid === 'string' && this.auth.uid.length > 0;
56
+ }
57
+
58
+ /** The account's uid, or null when signed out. */
59
+ get uid() {
60
+ return this.auth.uid;
61
+ }
62
+
63
+ /** The account's email, or null when signed out. */
64
+ get email() {
65
+ return this.auth.email;
66
+ }
67
+
68
+ /** The plan the user has access to right now ('basic' when cancelled or suspended). */
69
+ get plan() {
70
+ return resolveSubscription(this).plan;
71
+ }
72
+
73
+ /** True when a paid plan is active (including trialing and cancelling). */
74
+ get active() {
75
+ return resolveSubscription(this).active;
76
+ }
77
+
78
+ /** True while a claimed trial on an active paid plan has not yet expired. */
79
+ get trialing() {
80
+ return resolveSubscription(this).trialing;
81
+ }
82
+
83
+ /** True when an active paid plan (not trialing) has a cancellation pending. */
84
+ get cancelling() {
85
+ return resolveSubscription(this).cancelling;
86
+ }
87
+
88
+ /** True when the user has ever paid (a payment start date exists). */
89
+ get everPaid() {
90
+ return resolveSubscription(this).everPaid;
91
+ }
92
+
93
+ /** The stored document alone: own enumerable fields, never getters or profile. */
94
+ toJSON() {
95
+ return { ...this };
96
+ }
97
+ }
98
+
99
+ module.exports = User;
@@ -88,7 +88,7 @@ function pickPaths(section, paths) {
88
88
 
89
89
  /**
90
90
  * The subset of a resolved config a browser may see.
91
- * @param {object} [resolved] - a resolved config (Manager.getConfig() output),
91
+ * @param {object} [resolved] - a resolved config (build.getConfig() output),
92
92
  * with this build's facts composed onto it.
93
93
  * @returns {object} the blob every browser surface bakes as OMEGA_BUILD_JSON.config.
94
94
  * @throws {Error} when a section that is about to ship carries a secret-shaped key.
@@ -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.
@@ -28,7 +27,7 @@ const { findRetiredKeys, RETIRED_KEYS, RETIRED_PATHS } = require('./retired-keys
28
27
  const { chosenProvider } = require('./providers.js');
29
28
  const { validateConfig, runSchema, formatErrors, resolvedBrandHost } = require('./validate.js');
30
29
  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');
30
+ const { ENV_ENVIRONMENTS, ENVIRONMENT_VAR, getEnvironment, isDevelopment, isProduction, isTesting, setEnvironment, buildLaneEnvironment } = require('./environment.js');
32
31
  const { loadEnv, reloadEnv, envEnvironment, resolveEnvChain, envLayerFiles, loadEnvChain, loadEnvRoots, applyDeliverAs, composeTargetEnv, envLine, serializeEnv } = require('./env.js');
33
32
  const { ENV_SCHEMA, ENV_GROUPS, DELIVERY_MODES, envFileGroups, envSchemaEntry, envKeysForTarget, generatedEnvKeys, requiredEnvKeys, envKeysByGroup } = require('./env-schema.js');
34
33
  const { WORKFLOW_OWNED_KEYS, deliveredKeys, workflowSecretKeys, envFileKeys, artifactEnvValues, bakeKeys, bakeSourceKeys, publishSecretKeys, renderSecretsBlock, renderEnvFileKeys } = require('./env-delivery.js');
@@ -79,8 +78,7 @@ module.exports = {
79
78
  ENV_ENVIRONMENTS,
80
79
  // The ONE environment module every target answers from (#817): one input
81
80
  // (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.
81
+ // no per-surface default, a missing input is a loud error.
84
82
  ENVIRONMENT_VAR,
85
83
  getEnvironment,
86
84
  isDevelopment,
@@ -88,9 +86,8 @@ module.exports = {
88
86
  isTesting,
89
87
  setEnvironment,
90
88
  // 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
89
+ // parent lane named: the desktop and extension build modules set this
92
90
  buildLaneEnvironment,
93
- attachEnvironment,
94
91
  // The AMBIENT answer a lane resolves when nothing named one for it, and the
95
92
  // producer of the input above
96
93
  envEnvironment,
@@ -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');
@@ -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 }`).
@@ -321,7 +321,7 @@ const RETIRED_PATHS = {
321
321
  },
322
322
 
323
323
  // ─── one home for the download/extension links (#610) ──────────────────
324
- // The legacy UJM page maps survived beside the derivation #85/#124 added,
324
+ // The hand-written page maps survived beside the derivation #85/#124 added,
325
325
  // so explicit config could silently override the release the desktop target
326
326
  // actually ships. Matched at their AUTHORED path: `targets.web` is where the
327
327
  // converter wrote them and where every carrying brand still has them, and
@@ -339,7 +339,7 @@ const RETIRED_PATHS = {
339
339
 
340
340
  // ─── the four schema-less web sections (#850) ─────────────────────────
341
341
  // Everything the build processes has a schema home (Ian 2026-09-09). These
342
- // four were the exception: legacy UJM presentation blocks the converter
342
+ // four were the exception: presentation blocks the converter
343
343
  // wrote under `targets.web`, which @omega.js/web carried in a PRIVATE list
344
344
  // (`WEB_ONLY_SECTIONS`) purely to let its own `config:` guard pass them.
345
345
  // The list is gone, so each one is a registered path instead of a key that
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Canonical schema for config/omega.json5 — pure data, no logic.
3
3
  *
4
- * Entry format is electron-manager's proven src/config/schema.js shape:
4
+ * Entry format:
5
5
  *
6
6
  * {
7
7
  * path: 'brand.id', // dot-path into the RESOLVED config
@@ -61,9 +61,7 @@
61
61
  * target entry overrides the shared value.
62
62
  *
63
63
  * SHARED_SCHEMA always applies; TARGET_SCHEMAS[target] adds that target's
64
- * refinements. Sections grow as each framework adopts dual-read — seed
65
- * entries come from EM's schema (desktop) and the sandbox brand's real @omega.js/backend
66
- * config (backend), never from guesses.
64
+ * refinements, seeded from real brand configs, never from guesses.
67
65
  */
68
66
 
69
67
  // The durations a winback coupon can be built for on every provider that
@@ -1486,7 +1484,7 @@ const TARGET_SCHEMAS = {
1486
1484
  },
1487
1485
  ],
1488
1486
 
1489
- // Seeded from the sandbox brand's real @omega.js/backend config (backend-manager-config.json).
1487
+ // Seeded from the sandbox brand's real @omega.js/backend config.
1490
1488
  backend: [
1491
1489
  // reviews, marketing, blog, dataRequest moved to SHARED_SCHEMA (#277); a
1492
1490
  // targets.backend block still overrides them through the merge chain.
@@ -1506,8 +1504,7 @@ const TARGET_SCHEMAS = {
1506
1504
  },
1507
1505
  ],
1508
1506
 
1509
- // Seeded from EM's proven src/config/schema.js. EM's per-OS `targets` key
1510
- // is renamed `platforms` here (avoids targets.desktop.targets).
1507
+ // The per-OS key is `platforms` (avoids targets.desktop.targets).
1511
1508
  desktop: [
1512
1509
  {
1513
1510
  path: 'app.category',
@@ -1703,7 +1700,7 @@ const TARGET_SCHEMAS = {
1703
1700
  path: 'autoUpdate.autoDownload',
1704
1701
  type: 'boolean',
1705
1702
  required: false,
1706
- description: 'Whether a found update downloads on its own. Unset reads as true; false leaves the download to `manager.autoUpdater` being asked for it.',
1703
+ description: 'Whether a found update downloads on its own. Unset reads as true; false leaves the download to `omega.autoUpdater` being asked for it.',
1707
1704
  },
1708
1705
  {
1709
1706
  path: 'autoUpdate.startupDelayMs',
@@ -3,8 +3,7 @@
3
3
  * `site.*` global, so existing template references port verbatim to the new
4
4
  * SSG (plan §2: toSiteGlobal()).
5
5
  *
6
- * Scoped by the real-usage audit (2026-07-06) of UJM's theme/blueprints +
7
- * somiibo: config-owned keys referenced in templates are the resolved
6
+ * Config-owned keys referenced in templates are the resolved
8
7
  * config's own shape, so this is an identity mapping plus: machinery keys
9
8
  * stripped (`targets`, `enabled`), `url` derived (explicit url, else
10
9
  * brand.url), `baseurl` defaulted. ENGINE-owned keys (posts, pages, data,
@@ -24,7 +23,7 @@
24
23
  * ([#610](https://github.com/Omega-JS-Stack/omega/issues/610)): the
25
24
  * `/download` page, the `/extension` page and the shortlink generator all
26
25
  * read `site.targets.desktop.releasesUrl` and
27
- * `site.targets.extension.listings` directly. The legacy UJM-shaped
26
+ * `site.targets.extension.listings` directly. The hand-written
28
27
  * `download`/`extension` page maps — and the derivation that filled them —
29
28
  * are gone; the validator refuses a config still carrying either key.
30
29
  *
@@ -1,8 +1,7 @@
1
1
  /**
2
2
  * Schema-driven validation for resolved omega.json5 configs.
3
3
  *
4
- * The rule walker (runSchema) is electron-manager's proven validate-config
5
- * engine ported verbatim: required/type/match/enum semantics, where match +
4
+ * The rule walker (runSchema) carries required/type/match/enum semantics, where match +
6
5
  * enum (and itemEnum, the same check per member of an array value) only run on
7
6
  * PRESENT values and a conditional `required` function
8
7
  * receives the full config. See schema.js for the rule format.
@@ -9,7 +9,7 @@
9
9
  * nothing at all still makes one: 50% off the next cycle, one cycle only.
10
10
  *
11
11
  * That default lives HERE and nowhere else. The backend's apply route resolves
12
- * `Manager.config.payment` through this function, and the web build bakes the
12
+ * `omega.config.payment` through this function, and the web build bakes the
13
13
  * SAME call into the client blob it emits — so the dialog the customer reads and
14
14
  * the coupon the provider creates can never disagree about the number.
15
15
  *
@@ -5,7 +5,7 @@
5
5
  * repo secrets: hand it a repo (`owner/name`) and a key → value map, it sets
6
6
  * each one. The transport is the `gh` CLI (`gh secret set KEY --repo o/n`,
7
7
  * which encrypts locally with the repo's public key before sending) — there is
8
- * NO libsodium/REST fallback here (UJM's path): without a usable `gh` this
8
+ * NO libsodium/REST fallback here: without a usable `gh` this
9
9
  * FAILS LOUDLY with install/auth instructions rather than growing a crypto
10
10
  * dependency to do what the CLI already does.
11
11
  *
@@ -161,7 +161,7 @@ function createTee() {
161
161
  // The roll is what the tee has no need for: a child that stays up for days (a
162
162
  // Firebase emulator) has to be truncatable MID-RUN, so a sibling process asks
163
163
  // for a fresh log by touching `resetPath` and the poll below honors it within
164
- // `pollMs`. Ported from BEM's emulator/serve commands, which carried a copy each.
164
+ // `pollMs`. The backend's emulator and serve commands share it.
165
165
  //
166
166
  // Writes go to an open fd synchronously, for the same reason the tee's do: the
167
167
  // lines describing a crash are the ones a buffered stream drops.
@@ -23,7 +23,7 @@ const { clientConfig } = require('../config/index.js');
23
23
  // ([#894](https://github.com/Omega-JS-Stack/omega/issues/894)): the build's
24
24
  // verdict (`environment`), whether it was a BUILD rather than a dev/watch run,
25
25
  // and whether it publishes. A surface's own extra verdicts (desktop's
26
- // `server`) stay inside that surface's Manager and never reach the artifact.
26
+ // `server`) stay inside that surface's Omega instance and never reach the artifact.
27
27
  const MODE_KEYS = ['environment', 'build', 'publish'];
28
28
 
29
29
  /**
@@ -2,19 +2,18 @@
2
2
  //
3
3
  // Every framework bin parses argv (src/argv.js) and hands the result to a Main class
4
4
  // whose process() resolves a command name and runs commands/<name>.js from the
5
- // framework's dist. That router was copy-pasted per framework (UJM/BXM/EM,
6
- // drift-identical); this is the single implementation. @omega.js/backend's CLI is a different
5
+ // framework's dist; this is the single implementation. @omega.js/backend's CLI is a different
7
6
  // design (colon-style utility commands dispatching stateful command classes)
8
7
  // and does not use this.
9
8
  //
10
- // Resolution order (unchanged from the framework copies):
9
+ // Resolution order:
11
10
  // 1. Positional command (`mgr build`) — matched against command names and
12
11
  // their aliases; unknown names pass through as-is (missing file = error).
13
12
  // 2. Flag-style alias (`mgr --build`, `mgr -b`) — first alias-table hit wins.
14
13
  // 3. The default command (OMEGA convention: help — `setup` is retired,
15
14
  // #675, and every verb runs its own local scaffold).
16
15
  //
17
- // dotenv loading and any process-env fixups (e.g. EM's ELECTRON_RUN_AS_NODE
16
+ // dotenv loading and any process-env fixups (e.g. desktop's ELECTRON_RUN_AS_NODE
18
17
  // strip) stay in the framework's cli.js/bin — they're framework concerns, not
19
18
  // dispatch.
20
19