@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
@@ -4,9 +4,9 @@
4
4
  // inserted after boot), title changes update the live instance, and removal
5
5
  // disposes it. Real DOM, real Bootstrap — the tip element actually renders.
6
6
  //
7
- // The harness wires the renderer Manager in the PRELOAD world (contextIsolation
7
+ // The harness wires the renderer instance in the PRELOAD world (contextIsolation
8
8
  // — see harness/renderer-preload.js), so instance-level assertions and the
9
- // show trigger go through the `window.__emTestTooltip` probe (page-world
9
+ // show trigger go through the `window.__omegaTestTooltip` probe (page-world
10
10
  // synthetic mouse events can't reach preload-world listeners). Real
11
11
  // hover-in-one-world behavior + `window.bootstrap` page exposure are covered
12
12
  // by consumer boot suites.
@@ -25,10 +25,10 @@ module.exports = defineCases({
25
25
  {
26
26
  name: 'the Bootstrap bundle loads — Tooltip is available',
27
27
  run: (ctx) => {
28
- if (!window.__emTestTooltip.available()) {
29
- throw new Error(`Bootstrap bundle failed to load: ${window.__emTestTooltip.error() || '(no require error — wiring bailed earlier)'}`);
28
+ if (!window.__omegaTestTooltip.available()) {
29
+ throw new Error(`Bootstrap bundle failed to load: ${window.__omegaTestTooltip.error() || '(no require error, wiring bailed earlier)'}`);
30
30
  }
31
- ctx.expect(window.__emTestTooltip.available()).toBe(true);
31
+ ctx.expect(window.__omegaTestTooltip.available()).toBe(true);
32
32
  },
33
33
  },
34
34
  {
@@ -51,9 +51,9 @@ module.exports = defineCases({
51
51
  document.body.appendChild(el);
52
52
 
53
53
  // The auto-init observer creates the instance without any consumer code.
54
- await until(() => window.__emTestTooltip.hasInstance('tt-show'));
54
+ await until(() => window.__omegaTestTooltip.hasInstance('tt-show'));
55
55
 
56
- const shown = window.__emTestTooltip.showDirect('tt-show');
56
+ const shown = window.__omegaTestTooltip.showDirect('tt-show');
57
57
  ctx.expect(shown).toBe(true);
58
58
  await until(() => document.querySelector('.tooltip .tooltip-inner'));
59
59
  ctx.expect(document.querySelector('.tooltip .tooltip-inner').textContent).toBe('Hello from @omega.js/desktop');
@@ -80,13 +80,13 @@ module.exports = defineCases({
80
80
  el.setAttribute('data-bs-toggle', 'tooltip');
81
81
  el.setAttribute('data-bs-title', 'before');
82
82
  document.body.appendChild(el);
83
- await until(() => window.__emTestTooltip.hasInstance('tt-retitle'));
83
+ await until(() => window.__omegaTestTooltip.hasInstance('tt-retitle'));
84
84
 
85
85
  el.setAttribute('data-bs-title', 'after');
86
86
  // The observer applies setContent asynchronously (mutation microtask) —
87
87
  // give it a beat, then show and assert the rendered text.
88
88
  await new Promise((r) => setTimeout(r, 100));
89
- ctx.expect(window.__emTestTooltip.showDirect('tt-retitle')).toBe(true);
89
+ ctx.expect(window.__omegaTestTooltip.showDirect('tt-retitle')).toBe(true);
90
90
  await until(() => document.querySelector('.tooltip .tooltip-inner'));
91
91
  ctx.expect(document.querySelector('.tooltip .tooltip-inner').textContent).toBe('after');
92
92
 
@@ -118,7 +118,7 @@ module.exports = defineCases({
118
118
  el.setAttribute('title', 'plain title');
119
119
  document.body.appendChild(el);
120
120
 
121
- await until(() => window.__emTestTooltip.hasInstance('tt-title-only'));
121
+ await until(() => window.__omegaTestTooltip.hasInstance('tt-title-only'));
122
122
 
123
123
  // The loop starved macrotasks — a timer firing IS the proof the
124
124
  // main thread survived the mutation settling.
@@ -129,8 +129,8 @@ module.exports = defineCases({
129
129
  // instance alive, and the tip renders the original text.
130
130
  ctx.expect(el.hasAttribute('title')).toBe(false);
131
131
  ctx.expect(el.getAttribute('data-bs-original-title')).toBe('plain title');
132
- ctx.expect(window.__emTestTooltip.hasInstance('tt-title-only')).toBe(true);
133
- ctx.expect(window.__emTestTooltip.showDirect('tt-title-only')).toBe(true);
132
+ ctx.expect(window.__omegaTestTooltip.hasInstance('tt-title-only')).toBe(true);
133
+ ctx.expect(window.__omegaTestTooltip.showDirect('tt-title-only')).toBe(true);
134
134
  await until(() => document.querySelector('.tooltip .tooltip-inner'));
135
135
  ctx.expect(document.querySelector('.tooltip .tooltip-inner').textContent).toBe('plain title');
136
136
 
@@ -155,11 +155,11 @@ module.exports = defineCases({
155
155
  el.setAttribute('data-bs-toggle', 'tooltip');
156
156
  el.setAttribute('data-bs-title', 'bye');
157
157
  document.body.appendChild(el);
158
- await until(() => window.__emTestTooltip.hasInstance('tt-dispose'));
158
+ await until(() => window.__omegaTestTooltip.hasInstance('tt-dispose'));
159
159
 
160
160
  el.remove();
161
- await until(() => !window.__emTestTooltip.hasInstance('tt-dispose'));
162
- ctx.expect(window.__emTestTooltip.hasInstance('tt-dispose')).toBe(false);
161
+ await until(() => !window.__omegaTestTooltip.hasInstance('tt-dispose'));
162
+ ctx.expect(window.__omegaTestTooltip.hasInstance('tt-dispose')).toBe(false);
163
163
  },
164
164
  },
165
165
  ],
@@ -1,5 +1,6 @@
1
- // Renderer-layer suite — asserts the `window.desktop` surface exposed by preload is shaped
2
- // correctly and that the storage proxy round-trips through IPC into the main store.
1
+ // Renderer-layer suite: asserts the `window.desktop` surface exposed by preload is shaped
2
+ // correctly, that the renderer instance carries it as `omega.desktop`, and that the
3
+ // storage proxy round-trips through IPC into the main store.
3
4
  //
4
5
  // Runs inside a hidden BrowserWindow spawned by the test harness. The renderer harness
5
6
  // reconstructs each `run` function via `new Function('ctx', body)` so the function bodies
@@ -10,7 +11,7 @@ const defineCases = require('../../../vendor/devkit/test/define-cases.js');
10
11
  module.exports = defineCases({
11
12
  type: 'suite',
12
13
  layer: 'renderer',
13
- description: 'window.desktop surface + storage proxy roundtrip',
14
+ description: 'window.desktop surface + omega.desktop + storage proxy roundtrip',
14
15
  tests: [
15
16
  {
16
17
  name: 'window.desktop is exposed and is an object',
@@ -19,6 +20,25 @@ module.exports = defineCases({
19
20
  ctx.expect(window.desktop).toBeTruthy();
20
21
  },
21
22
  },
23
+ {
24
+ // The preload global keeps its name and its shape: everything that
25
+ // crosses to the main process, under main's names
26
+ name: 'window.desktop carries the bridge namespaces, unchanged',
27
+ run: (ctx) => {
28
+ ctx.expect(Object.keys(window.desktop).sort()).toEqual(['analytics', 'autoUpdater', 'context', 'fontawesome', 'ipc', 'logger', 'remoteConfig', 'storage', 'theme', 'usage']);
29
+ },
30
+ },
31
+ {
32
+ // The renderer instance puts the SAME object under `omega.desktop`;
33
+ // `omega.storage` stays the client's page store, the app store is
34
+ // `omega.desktop.storage`
35
+ name: 'the renderer instance\'s omega.desktop IS the preload bridge',
36
+ run: (ctx) => {
37
+ ctx.expect(window.__omegaTestInstance.desktopIsBridge()).toBe(true);
38
+ ctx.expect(window.__omegaTestInstance.desktopKeys()).toEqual(Object.keys(window.desktop).sort());
39
+ ctx.expect(window.__omegaTestInstance.storageIsPageStore()).toBe(true);
40
+ },
41
+ },
22
42
  {
23
43
  name: 'window.desktop.ipc has invoke / on / send',
24
44
  run: (ctx) => {
@@ -29,10 +49,10 @@ module.exports = defineCases({
29
49
  },
30
50
  {
31
51
  // wave-5 F4: ipc.on used to return ipcRenderer (stripped to a useless
32
- // object across the contextBridge) — docs/ipc.md promises an unsubscribe fn.
52
+ // object across the contextBridge) — docs/desktop/ipc.md promises an unsubscribe fn.
33
53
  name: 'ipc.on returns an unsubscribe function (docs contract)',
34
54
  run: (ctx) => {
35
- const off = window.desktop.ipc.on('em-test:noop-channel', () => {});
55
+ const off = window.desktop.ipc.on('omega-test:noop-channel', () => {});
36
56
  ctx.expect(typeof off).toBe('function');
37
57
  off(); // must not throw
38
58
  },
@@ -66,7 +86,7 @@ module.exports = defineCases({
66
86
  {
67
87
  name: 'storage.set + storage.get round-trips through IPC',
68
88
  run: async (ctx) => {
69
- const key = '__em_renderer_test_value';
89
+ const key = '__omega_renderer_test_value';
70
90
  await window.desktop.storage.set(key, { hello: 'world', n: 42 });
71
91
  const value = await window.desktop.storage.get(key);
72
92
  ctx.expect(value).toEqual({ hello: 'world', n: 42 });
@@ -76,7 +96,7 @@ module.exports = defineCases({
76
96
  {
77
97
  name: 'storage.has reports correctly',
78
98
  run: async (ctx) => {
79
- const key = '__em_renderer_has_test';
99
+ const key = '__omega_renderer_has_test';
80
100
  await window.desktop.storage.set(key, 'x');
81
101
  const yes = await window.desktop.storage.has(key);
82
102
  ctx.expect(yes).toBe(true);
@@ -88,7 +108,7 @@ module.exports = defineCases({
88
108
  {
89
109
  name: 'storage.delete removes the key',
90
110
  run: async (ctx) => {
91
- const key = '__em_renderer_delete_test';
111
+ const key = '__omega_renderer_delete_test';
92
112
  await window.desktop.storage.set(key, 'gone');
93
113
  await window.desktop.storage.delete(key);
94
114
  const value = await window.desktop.storage.get(key, 'fallback');
@@ -1,6 +1,6 @@
1
1
  // TEST_EXTENDED_MODE warning — SSOT for consistent messaging.
2
2
  //
3
- // The headline + shape live in @omega.js/devkit (mirrored across @omega.js/backend/BXM/UJM); these
3
+ // The headline + shape live in @omega.js/devkit (shared by every framework); these
4
4
  // detail lines describe @omega.js/desktop's blast radius. Used by the test command (printed to
5
5
  // console + teed to logs/test.log).
6
6
  const { makeExtendedModeWarning } = require('../../vendor/devkit/test/extended-mode-warning.js');
@@ -0,0 +1,56 @@
1
+ // boot-harness: hands the booted main-process instance to the boot test lane's
2
+ // harness. The runner sets OMEGA_TEST_BOOT=1 + OMEGA_TEST_BOOT_HARNESS=<absolute path>
3
+ // + OMEGA_TEST_BOOT_SPEC=<path> before spawning electron; the harness emits
4
+ // __OMEGA_TEST__ JSON lines on stdout (parsed by test/runners/boot.js) then
5
+ // app.exit()s.
6
+ //
7
+ // A runtime env-var path, never a static `require('./test/harness/...')`:
8
+ // @omega.js/desktop is bundled into the consumer's bundle, and a static require would
9
+ // either get inlined (bundling test code into production) or dead-code-eliminated.
10
+ // An env-var path stays external and can only resolve when the runner sets it.
11
+
12
+ const { TEST_EVENT_PREFIX } = require('./test-events.js');
13
+
14
+ /**
15
+ * Start the boot harness against `omega` when this process is a boot test run.
16
+ * @param {object} omega - the initialized main-process instance.
17
+ */
18
+ function startBootHarness(omega) {
19
+ // Only a boot test run carries the flag; every other boot returns here
20
+ if (process.env.OMEGA_TEST_BOOT !== '1') {
21
+ return;
22
+ }
23
+
24
+ global.__omega_instance = omega;
25
+ const harnessPath = process.env.OMEGA_TEST_BOOT_HARNESS;
26
+
27
+ if (!harnessPath) {
28
+ fail('OMEGA_TEST_BOOT=1 but OMEGA_TEST_BOOT_HARNESS not set');
29
+ return;
30
+ }
31
+
32
+ // Defer the harness so the consumer's `omega.initialize().then(() => { ... })`
33
+ // callback gets a chance to run first. @omega.js/desktop doesn't auto-create any
34
+ // windows; the consumer's main.js does it inside .then(). Run synchronously and
35
+ // that callback hasn't fired yet, so `omega.windows.get('main')` would be null.
36
+ // setImmediate flushes the microtask queue (where promise callbacks live)
37
+ // before the boot harness inspects state.
38
+ setImmediate(() => {
39
+ try {
40
+ // A variable specifier, so the bundler leaves the call alone and it
41
+ // resolves at RUNTIME against the path the runner set (see above).
42
+ const harness = require(harnessPath);
43
+ harness.run(omega);
44
+ } catch (e) {
45
+ fail(`boot harness failed to load: ${e.message}`);
46
+ }
47
+ });
48
+ }
49
+
50
+ // Report a fatal harness event on the runner's channel and end the run
51
+ function fail(message) {
52
+ process.stdout.write(`${TEST_EVENT_PREFIX}${JSON.stringify({ event: 'fatal', message })}\n`);
53
+ require('electron').app.exit(1);
54
+ }
55
+
56
+ module.exports = startBootHarness;
@@ -1,4 +1,4 @@
1
- // The build-mode pipeline shared by the `build`, `package`, and `publish` verbs.
1
+ // The pipeline shared by the `build`, `package`, `publish` and `dev` verbs.
2
2
  //
3
3
  // The CLI verbs are canonical and the synced projectScripts are thin
4
4
  // `omega <verb>` aliases, so a verb must run the pipeline ITSELF and never
@@ -10,8 +10,8 @@
10
10
  // Libraries
11
11
  const { execute } = require('node-powertools');
12
12
 
13
- function gulpCommand(task) {
14
- return `npm run gulp -- ${task}`;
13
+ function gulpCommand(task, args = []) {
14
+ return `npm run gulp -- ${[task, ...args].join(' ')}`;
15
15
  }
16
16
 
17
17
  // Default step implementations — required lazily so requiring a plan never
@@ -30,7 +30,7 @@ const RUNNERS = {
30
30
  'ship-keys': () => require('./ship-keys.js').assertShipKeys(),
31
31
  // `strict` rides the STEP: publish declares it (#891), a bare verb does not.
32
32
  'validate-certs': (options, step) => require('../commands/validate-certs.js')({ ...options, strict: step.strict === true || options.strict === true }),
33
- gulp: (options, step) => execute(gulpCommand(step.task), { log: true }),
33
+ gulp: (options, step) => execute(gulpCommand(step.task, step.args), { log: true }),
34
34
  };
35
35
 
36
36
  async function runPipeline(plan, options, runners) {
@@ -1,5 +1,5 @@
1
- // Runtime mode helpers, shared across all three context Managers (main /
2
- // renderer / preload) and the build-time Manager.
1
+ // Runtime mode helpers: plain functions the process `Omega` classes (src/main.js,
2
+ // src/preload.js, src/renderer.js) and the build-time module (src/build.js) call.
3
3
  //
4
4
  // The environment half is NOT implemented here any more
5
5
  // ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)). It is
@@ -57,20 +57,7 @@ function getVersion() {
57
57
  }
58
58
  }
59
59
 
60
- // Mix the helpers into a Manager constructor's prototype + the constructor itself
61
- // (so `Manager.isTesting()` works statically too). The environment four come from
62
- // the shared module's own attachTo(), so every desktop entry point and every
63
- // sibling framework hangs the identical functions; getVersion() is desktop's and
64
- // is attached beside them. The URL helpers in url-helpers.js depend on
65
- // this.getEnvironment() existing, so this attachTo() runs first.
66
- function attachTo(Manager) {
67
- environment.attachTo(Manager);
68
- Manager.prototype.getVersion = getVersion;
69
- Manager.getVersion = getVersion;
70
- }
71
-
72
60
  module.exports = {
73
- attachTo,
74
61
  isDevelopment: environment.isDevelopment,
75
62
  isProduction: environment.isProduction,
76
63
  isTesting: environment.isTesting,
@@ -35,6 +35,8 @@
35
35
  const fs = require('fs');
36
36
  const os = require('os');
37
37
  const path = require('path');
38
+ const { envLine, assertEnvReadsBack } = require('../vendor/config/index.js');
39
+ const { setEnvLines } = require('../vendor/devkit/env-lines.js');
38
40
 
39
41
  // Runner files live under %LOCALAPPDATA%\omega-runner — a per-user path that
40
42
  // doesn't need admin to read/write. Set OMEGA_RUNNER_HOME to override.
@@ -308,37 +310,20 @@ function ensureRunnerEnvFile(home) {
308
310
  return true;
309
311
  }
310
312
 
311
- // Write values into the file IN PLACE: an existing `KEY=` line (commented or
312
- // not) is replaced, a key the file never had is appended. Comments and order
313
- // survive, so the file stays the one a person reads.
313
+ // Write values into the file IN PLACE through devkit's setEnvLines: a key's
314
+ // first line or `# KEY=""` placeholder takes the new line and later ones drop,
315
+ // so dotenv reads the new value; a key the file never had is appended. Comments
316
+ // and order survive, so the file stays the one a person reads.
314
317
  function writeRunnerEnvValues(home, values) {
315
- // Every value double-quoted, the one .env quoting rule this repo writes
316
- // everywhere. dotenv reads a double-quoted value back verbatim and has no
317
- // escape for a `"` inside one, so a value carrying one cannot be written at
318
- // all: refuse it — naming the key and the character — before the file is
319
- // touched, rather than save a value that reads back wrong.
320
- const serialize = (key, value) => `${key}="${value}"`;
321
- for (const [key, value] of Object.entries(values)) {
322
- if (String(value).includes('"')) {
323
- throw new Error(`${key} contains a double quote (") — a .env value cannot carry one. Remove it, then set ${key} again.`);
324
- }
325
- }
318
+ // envLine is the one .env serializer; it refuses, naming the key, a value
319
+ // dotenv would read back changed, before the file is touched.
320
+ const lineFor = Object.fromEntries(Object.entries(values).map(([key, value]) => [key, envLine(key, value)]));
326
321
 
327
322
  ensureRunnerEnvFile(home);
328
- const file = runnerEnvFile(home);
329
- const lines = fs.readFileSync(file, 'utf8').split(/\r?\n/);
330
- const seen = new Set();
331
-
332
- const out = lines.map((line) => {
333
- const m = /^\s*#?\s*([A-Z][A-Z0-9_]*)\s*=/.exec(line);
334
- if (!m || !(m[1] in values) || seen.has(m[1])) return line;
335
- seen.add(m[1]);
336
- return serialize(m[1], String(values[m[1]]));
337
- });
338
- for (const [key, value] of Object.entries(values)) {
339
- if (!seen.has(key)) out.push(serialize(key, String(value)));
340
- }
341
- fs.writeFileSync(file, out.join('\n').replace(/\n*$/, '\n'));
323
+ const file = runnerEnvFile(home);
324
+ const content = setEnvLines(fs.readFileSync(file, 'utf8'), lineFor);
325
+ assertEnvReadsBack(content, values);
326
+ fs.writeFileSync(file, content);
342
327
  return file;
343
328
  }
344
329
 
@@ -21,8 +21,8 @@
21
21
 
22
22
  const { shipPlan, missingShipKeys, shipKeyRefusal } = require('../vendor/devkit/ship-plan.js');
23
23
 
24
- const Manager = new (require('../build.js'));
25
- const logger = Manager.logger('ship-keys');
24
+ const build = require('../build.js');
25
+ const logger = build.logger('ship-keys');
26
26
 
27
27
  /**
28
28
  * Refuse a publish whose declared formats have no credential to ship with.
@@ -36,7 +36,7 @@ const logger = Manager.logger('ship-keys');
36
36
  function assertShipKeys(options) {
37
37
  options = options || {};
38
38
 
39
- const config = options.config || Manager.getConfig();
39
+ const config = options.config || build.getConfig();
40
40
  const plan = shipPlan(config, 'desktop');
41
41
  const missing = missingShipKeys(plan, options.env || process.env);
42
42
 
@@ -0,0 +1,51 @@
1
+ // signing-status: logs whether a PACKAGED app is code-signed, and by whom, so
2
+ // runtime.log answers "did this build ship signed?" without a terminal. Fire and
3
+ // forget: the checks run async and only ever log. An unpackaged (dev or test)
4
+ // boot has nothing signed to report, so it skips.
5
+
6
+ /**
7
+ * Log this app's signing status (packaged apps only).
8
+ * @param {object} logger - the main process's logger.
9
+ */
10
+ function logSigningStatus(logger) {
11
+ try {
12
+ if (!require('electron').app.isPackaged) {
13
+ return;
14
+ }
15
+
16
+ const { execFile } = require('child_process');
17
+
18
+ if (process.platform === 'darwin') {
19
+ const appIndex = process.execPath.indexOf('.app');
20
+ if (appIndex === -1) throw new Error('no .app in execPath');
21
+ const appPath = process.execPath.substring(0, appIndex + 4);
22
+ execFile('codesign', ['--verify', '--deep', '--strict', appPath], (err) => {
23
+ if (err) {
24
+ logger.warn(`signing: NOT signed (${err.message.split('\n')[0]})`);
25
+ return;
26
+ }
27
+ execFile('codesign', ['-dv', appPath], { encoding: 'utf8' }, (e2, stdout, stderr) => {
28
+ const authority = (stderr || '').match(/Authority=(.+)/);
29
+ const adhoc = (stderr || '').includes('Signature=adhoc');
30
+ const label = adhoc ? 'ad-hoc' : (authority ? authority[1] : 'unknown');
31
+ logger.log(`signing: signed (${label})`);
32
+ });
33
+ });
34
+ } else if (process.platform === 'win32') {
35
+ execFile('powershell', ['-NoProfile', '-Command', `(Get-AuthenticodeSignature '${process.execPath}').Status`], { encoding: 'utf8' }, (err, stdout) => {
36
+ const status = (stdout || '').trim();
37
+ if (err || status === 'NotSigned') {
38
+ logger.warn('signing: NOT signed');
39
+ } else {
40
+ logger.log(`signing: signed (${status})`);
41
+ }
42
+ });
43
+ } else {
44
+ logger.log('signing: n/a (Linux has no OS-level code signing)');
45
+ }
46
+ } catch (e) {
47
+ logger.warn(`signing: check failed (${e.message})`);
48
+ }
49
+ }
50
+
51
+ module.exports = logSigningStatus;
@@ -0,0 +1,7 @@
1
+ // The ONE prefix a desktop test harness writes before each JSON event line on
2
+ // stdout (test/harness/main-entry.js, test/harness/boot-entry.js,
3
+ // utils/boot-harness.js) and each runner reads back (test/runners/electron.js,
4
+ // test/runners/boot.js).
5
+ const TEST_EVENT_PREFIX = '__OMEGA_TEST__';
6
+
7
+ module.exports = { TEST_EVENT_PREFIX };
@@ -8,23 +8,23 @@
8
8
  // - main.js — app-level activation suppression on macOS (accessory policy via
9
9
  // app.dock.hide(), so a launching test app never steals keyboard focus)
10
10
  // - test/harness/main-entry.js — same suppression for the spawned harness app,
11
- // which initializes its Manager only after app ready (too late to prevent
11
+ // which initializes its omega instance only after app ready (too late to prevent
12
12
  // the launch activation)
13
13
  //
14
- // Pass the Manager when you have one: its isTesting() reads the environment the
15
- // Manager's own config was baked with. Without one (the harness, pre-Manager
14
+ // Pass the omega instance when you have one: its isTesting() reads the environment
15
+ // its own config was baked with. Without one (the harness, pre-initialize
16
16
  // code) the standalone check reads the process's OMEGA_ENVIRONMENT, the one
17
17
  // input every lane sets ([#817](https://github.com/Omega-JS-Stack/omega/issues/817));
18
18
  // the test runners spawn their children naming `testing`.
19
19
  //
20
20
  // Usage:
21
21
  // const isTestStealth = require('./utils/test-stealth.js');
22
- // if (isTestStealth(manager)) { ... }
22
+ // if (isTestStealth(omega)) { ... }
23
23
 
24
24
  const { isTesting } = require('./mode-helpers.js');
25
25
 
26
- function isTestStealth(manager) {
27
- const testing = manager ? manager.isTesting() : isTesting();
26
+ function isTestStealth(omega) {
27
+ const testing = omega ? omega.isTesting() : isTesting();
28
28
  return testing && process.env.OMEGA_TEST_SHOW !== '1';
29
29
  }
30
30
 
@@ -1,13 +1,14 @@
1
- // Backend URL helpers, shared across all Manager contexts (main / renderer / preload /
2
- // build). Mirror @omega.js/client's contract so @omega.js/desktop apps can hit the same dev/prod backends as
3
- // UJM and BXM consumers.
1
+ // Backend URL helpers: plain functions the process `Omega` classes (main / renderer /
2
+ // preload) call, each passing itself as `context`. Mirror
3
+ // @omega.js/client's contract so @omega.js/desktop apps can hit the same dev/prod backends as
4
+ // @omega.js/web and @omega.js/extension consumers.
4
5
  //
5
6
  // `getEnvironment()` is the SINGLE SOURCE OF TRUTH and lives in src/utils/mode-helpers.js
6
- // (alongside the is*() family; mirrors @omega.js/backend/UJM/BXM). It returns exactly ONE of
7
+ // (alongside the is*() family, the same on every framework). It returns exactly ONE of
7
8
  // 'development' | 'testing' | 'production' (mutually exclusive; testing wins).
8
9
  //
9
- // `getFunctionsUrl()` / `getApiUrl()` / `getWebsiteUrl()` route through
10
- // `this.getEnvironment()` and resolve to LOCAL urls in BOTH development AND testing —
10
+ // `getFunctionsUrl()` / `getApiUrl()` / `getWebsiteUrl()` route through the context's
11
+ // `getEnvironment()` and resolve to LOCAL urls in BOTH development AND testing,
11
12
  // callers normally pass NO argument. An explicit `environment` arg is an override
12
13
  // (used mainly by tests to pin a specific environment's mapping).
13
14
 
@@ -54,9 +55,16 @@ function requiredPort(context, envName, name) {
54
55
  return port;
55
56
  }
56
57
 
57
- function getFunctionsUrl(environment) {
58
- const env = environment || this.getEnvironment();
59
- const projectId = this?.config?.cloud?.config?.projectId;
58
+ /**
59
+ * The Cloud Functions base: the local emulator in development and testing, the
60
+ * project's cloudfunctions.net host in production.
61
+ * @param {object} context - the instance asking (its `config` and `getEnvironment()`).
62
+ * @param {string} [environment] - an override of the running environment.
63
+ * @returns {string} the functions base URL.
64
+ */
65
+ function getFunctionsUrl(context, environment) {
66
+ const env = environment || context.getEnvironment();
67
+ const projectId = context.config?.cloud?.config?.projectId;
60
68
 
61
69
  if (!projectId) {
62
70
  throw new Error('cloud.config.projectId not set in config/omega.json5');
@@ -66,15 +74,22 @@ function getFunctionsUrl(environment) {
66
74
  // same three-step chain getApiUrl() walks: the OMEGA_*_PORT env channel (N7),
67
75
  // then the baked map, then the classic default.
68
76
  if (env === 'development' || env === 'testing') {
69
- const port = requiredPort(this, 'OMEGA_FUNCTIONS_PORT', 'functions');
77
+ const port = requiredPort(context, 'OMEGA_FUNCTIONS_PORT', 'functions');
70
78
  return `http://localhost:${port}/${projectId}/us-central1`;
71
79
  }
72
80
 
73
81
  return `https://us-central1-${projectId}.cloudfunctions.net`;
74
82
  }
75
83
 
76
- function getApiUrl(environment) {
77
- const env = environment || this.getEnvironment();
84
+ /**
85
+ * The API base: the local stack in development and testing, the brand's api
86
+ * subdomain in production.
87
+ * @param {object} context - the instance asking (its `config` and `getEnvironment()`).
88
+ * @param {string} [environment] - an override of the running environment.
89
+ * @returns {string} the API base URL.
90
+ */
91
+ function getApiUrl(context, environment) {
92
+ const env = environment || context.getEnvironment();
78
93
 
79
94
  // Local for development OR testing; production otherwise. Mirrors
80
95
  // @omega.js/backend's getApiUrl (N7): a resolved OMEGA_HTTPS_PORT means
@@ -82,16 +97,16 @@ function getApiUrl(environment) {
82
97
  // hosting emulator (env port, then baked port). Neither resolved is a broken
83
98
  // build, not a case to assume the classic 5002 through (#834).
84
99
  if (env === 'development' || env === 'testing') {
85
- const httpsPort = localPort(this, 'OMEGA_HTTPS_PORT', 'https');
100
+ const httpsPort = localPort(context, 'OMEGA_HTTPS_PORT', 'https');
86
101
  return httpsPort
87
102
  ? `https://localhost:${httpsPort}`
88
- : `http://localhost:${requiredPort(this, 'OMEGA_HOSTING_PORT', 'hosting')}`;
103
+ : `http://localhost:${requiredPort(context, 'OMEGA_HOSTING_PORT', 'hosting')}`;
89
104
  }
90
105
 
91
106
  // Prod: api.<brand host>. Mirrors @omega.js/client.getApiUrl. Never derive
92
107
  // from authDomain — it is an auth concern (the brand host, with /__/auth/*
93
108
  // self-hosted at build time) and must stay free to change independently.
94
- const brandUrl = this?.config?.brand?.url;
109
+ const brandUrl = context.config?.brand?.url;
95
110
  if (!brandUrl) {
96
111
  throw new Error('brand.url not set in config/omega.json5');
97
112
  }
@@ -113,20 +128,25 @@ function getApiUrl(environment) {
113
128
  // Prod → `config.brand.url`. Use this whenever app code wants to link out to "the
114
129
  // website" (Help → Website tray/menu items, "Open in browser," billing portal
115
130
  // landings) so dev runs don't punch out to the real domain.
116
- function getWebsiteUrl(environment) {
117
- const env = environment || this.getEnvironment();
131
+ /**
132
+ * @param {object} context - the instance asking (its `config` and `getEnvironment()`).
133
+ * @param {string} [environment] - an override of the running environment.
134
+ * @returns {string} the website origin (dev) or brand.url (production).
135
+ */
136
+ function getWebsiteUrl(context, environment) {
137
+ const env = environment || context.getEnvironment();
118
138
 
119
139
  // Local for development OR testing; production otherwise.
120
140
  if (env === 'development' || env === 'testing') {
121
- const origin = this?.config?.dev?.origin;
141
+ const origin = context.config?.dev?.origin;
122
142
  if (origin) {
123
143
  return origin;
124
144
  }
125
145
 
126
- return `https://localhost:${requiredPort(this, 'OMEGA_WEBSITE_PORT', 'website')}`;
146
+ return `https://localhost:${requiredPort(context, 'OMEGA_WEBSITE_PORT', 'website')}`;
127
147
  }
128
148
 
129
- const url = this?.config?.brand?.url;
149
+ const url = context.config?.brand?.url;
130
150
  if (!url) {
131
151
  throw new Error('brand.url not set in config/omega.json5');
132
152
  }
@@ -134,19 +154,25 @@ function getWebsiteUrl(environment) {
134
154
  }
135
155
 
136
156
  // Sign-in URL that round-trips an auth token back to the app. Points at the brand
137
- // website's /signin page (UJM), chained through its /token page so a successful login
157
+ // website's /signin page, chained through its /token page so a successful login
138
158
  // mints a Firebase custom token and redirects to `<brand.id>://auth/token` — the
139
- // deep-link built-in that hands the token to client-bridge (signInWithCustomToken).
159
+ // deep-link built-in that hands the token to lib/auth.js (signInWithCustomToken).
140
160
  // Same env split as getWebsiteUrl: dev/test → the local website, prod → brand.url.
141
161
  // The token page redirects with ?authToken=<token> — the ONE modern shape the
142
- // auth/token route reads (legacy-app formats are UJM's concern, not @omega.js/desktop's).
162
+ // auth/token route reads (older formats are not read).
143
163
  //
144
164
  // `returnUrl` overrides the final hop (default: `<brand.id>://auth/token`). Used by
145
165
  // lib/auth-flow.js in dev, where the custom scheme isn't OS-registered — the flow
146
166
  // returns to a loopback HTTP listener instead (RFC 8252 §7.3).
147
- function getAuthUrl(environment, returnUrl) {
148
- const site = this.getWebsiteUrl(environment);
149
- const brandId = this?.config?.brand?.id;
167
+ /**
168
+ * @param {object} context - the instance asking (its `config` and `getEnvironment()`).
169
+ * @param {string} [environment] - an override of the running environment.
170
+ * @param {string} [returnUrl] - the final hop, `<brand.id>://auth/token` by default.
171
+ * @returns {string} the sign-in URL.
172
+ */
173
+ function getAuthUrl(context, environment, returnUrl) {
174
+ const site = getWebsiteUrl(context, environment);
175
+ const brandId = context.config?.brand?.id;
150
176
  if (!brandId) {
151
177
  throw new Error('brand.id not set in config/omega.json5');
152
178
  }
@@ -159,23 +185,7 @@ function getAuthUrl(environment, returnUrl) {
159
185
  return signinUrl.toString();
160
186
  }
161
187
 
162
- // Mix the URL helpers into a Manager constructor's prototype + the constructor itself.
163
- // getEnvironment() is NOT attached here — it's the SSOT in src/utils/mode-helpers.js.
164
- // These helpers call `this.getEnvironment()`, so mode-helpers' attachTo() must run before
165
- // (or alongside) this one — every Manager entry point attaches mode-helpers first.
166
- function attachTo(Manager) {
167
- Manager.prototype.getFunctionsUrl = getFunctionsUrl;
168
- Manager.prototype.getApiUrl = getApiUrl;
169
- Manager.prototype.getWebsiteUrl = getWebsiteUrl;
170
- Manager.prototype.getAuthUrl = getAuthUrl;
171
- Manager.getFunctionsUrl = getFunctionsUrl;
172
- Manager.getApiUrl = getApiUrl;
173
- Manager.getWebsiteUrl = getWebsiteUrl;
174
- Manager.getAuthUrl = getAuthUrl;
175
- }
176
-
177
188
  module.exports = {
178
- attachTo,
179
189
  localPort,
180
190
  requiredPort,
181
191
  getFunctionsUrl,