@omega.js/desktop 0.50.0 → 0.51.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 (267) hide show
  1. package/README.md +1 -1
  2. package/dist/assets/css/tokens/_index.scss +1 -1
  3. package/dist/assets/themes/base/_includes/frontend/sections/account-section-header.html +4 -1
  4. package/dist/assets/themes/base/_includes/frontend/sections/footer.html +13 -6
  5. package/dist/assets/themes/base/_includes/frontend/sections/nav.html +10 -8
  6. package/dist/assets/themes/base/_includes/global/sections/account.html +3 -1
  7. package/dist/assets/themes/base/_includes/global/sections/app-sidebar.html +12 -8
  8. package/dist/assets/themes/base/_includes/global/sections/app-topbar.html +10 -6
  9. package/dist/assets/themes/base/_includes/global/sections/page-header.html +8 -4
  10. package/dist/assets/themes/base/_layouts/backend/pages/dashboard/index.html +24 -24
  11. package/dist/assets/themes/base/_layouts/frontend/pages/about.html +10 -10
  12. package/dist/assets/themes/base/_layouts/frontend/pages/account/index.html +35 -35
  13. package/dist/assets/themes/base/_layouts/frontend/pages/alternatives/index.html +4 -4
  14. package/dist/assets/themes/base/_layouts/frontend/pages/auth/signin.html +1 -1
  15. package/dist/assets/themes/base/_layouts/frontend/pages/auth/signup.html +4 -4
  16. package/dist/assets/themes/base/_layouts/frontend/pages/contact.html +3 -3
  17. package/dist/assets/themes/base/_layouts/frontend/pages/download.html +34 -33
  18. package/dist/assets/themes/base/_layouts/frontend/pages/extension/index.html +11 -11
  19. package/dist/assets/themes/base/_layouts/frontend/pages/legal/document.html +1 -1
  20. package/dist/assets/themes/base/_layouts/frontend/pages/status.html +1 -1
  21. package/dist/assets/themes/base/_layouts/frontend/pages/team/index.html +9 -7
  22. package/dist/assets/themes/base/_layouts/frontend/pages/team/member.html +5 -3
  23. package/dist/assets/themes/base/_sections/about/letter/section.html +1 -1
  24. package/dist/assets/themes/base/_sections/about/letter/section.json5 +4 -4
  25. package/dist/assets/themes/base/_sections/marketing/bento/section.html +1 -1
  26. package/dist/assets/themes/base/_sections/marketing/bento/section.json5 +15 -15
  27. package/dist/assets/themes/base/_sections/marketing/cta/section.json5 +1 -1
  28. package/dist/assets/themes/base/_sections/marketing/hero/section.html +6 -6
  29. package/dist/assets/themes/base/_sections/marketing/hero/section.json5 +10 -10
  30. package/dist/assets/themes/base/_sections/marketing/product-demo/section.html +1 -1
  31. package/dist/assets/themes/base/_sections/marketing/product-demo/section.json5 +2 -2
  32. package/dist/assets/themes/base/_sections/marketing/stats/section.html +1 -1
  33. package/dist/assets/themes/base/_sections/marketing/stats/section.json5 +5 -5
  34. package/dist/assets/themes/base/_sections/marketing/trusted-by/section.html +1 -1
  35. package/dist/assets/themes/base/_sections/marketing/trusted-by/section.json5 +2 -2
  36. package/dist/assets/themes/neobrutalism/_layouts/frontend/pages/index.html +10 -10
  37. package/dist/assets/themes/newsflash/_layouts/frontend/pages/index.html +10 -10
  38. package/dist/assets/themes/newsflash/_sections/marketing/desks/section.html +2 -2
  39. package/dist/assets/themes/newsflash/_sections/marketing/desks/section.json5 +4 -4
  40. package/dist/build.js +69 -28
  41. package/dist/cli-run.js +20 -13
  42. package/dist/cli.js +12 -7
  43. package/dist/commands/build.js +0 -2
  44. package/dist/commands/deploy.js +116 -44
  45. package/dist/commands/finalize-release.js +5 -4
  46. package/dist/commands/launch.js +12 -7
  47. package/dist/commands/lib/deploy-precheck.js +66 -34
  48. package/dist/commands/lib/ensure-target.js +71 -11
  49. package/dist/commands/package.js +0 -1
  50. package/dist/commands/publish.js +11 -4
  51. package/dist/commands/release.js +99 -252
  52. package/dist/commands/runner.js +42 -5
  53. package/dist/commands/sign-windows.js +46 -15
  54. package/dist/commands/test.js +4 -3
  55. package/dist/commands/validate-certs.js +291 -115
  56. package/dist/config/page-template.html +4 -0
  57. package/dist/defaults/.github/workflows/build.yml +144 -64
  58. package/dist/defaults/AGENTS.md +3 -2
  59. package/dist/defaults/_.gitignore +4 -2
  60. package/dist/defaults/config/certs/README.md +25 -45
  61. package/dist/defaults/config/omega.json5 +66 -32
  62. package/dist/defaults/hooks/deploy/pre.js +10 -0
  63. package/dist/defaults/src/assets/scss/main.scss +12 -2
  64. package/dist/defaults/src/integrations/tray/index.js +1 -1
  65. package/dist/gulp/main.js +13 -25
  66. package/dist/gulp/tasks/audit.js +18 -6
  67. package/dist/gulp/tasks/build-config.js +181 -60
  68. package/dist/gulp/tasks/bundle.js +108 -36
  69. package/dist/gulp/tasks/release.js +86 -4
  70. package/dist/gulp/tasks/sass.js +11 -0
  71. package/dist/hooks/lib/notarize-tools.js +137 -0
  72. package/dist/hooks/notarize-artifacts.js +57 -0
  73. package/dist/hooks/notarize.js +59 -8
  74. package/dist/lib/auth-persistence.js +25 -0
  75. package/dist/lib/client-bridge.js +11 -8
  76. package/dist/lib/deep-link.js +15 -8
  77. package/dist/lib/protocol.js +7 -1
  78. package/dist/lib/restart-manager/install.js +6 -3
  79. package/dist/lib/sign-helpers/auto-unlock.js +65 -27
  80. package/dist/lib/sign-helpers/console-lock.js +34 -0
  81. package/dist/lib/sign-helpers/exec-with-limit.js +68 -0
  82. package/dist/lib/sign-helpers/resolve-icons.js +6 -4
  83. package/dist/lib/tray.js +7 -6
  84. package/dist/main.js +16 -0
  85. package/dist/preload.js +8 -0
  86. package/dist/renderer.js +16 -4
  87. package/dist/runner/job-started.js +104 -0
  88. package/dist/test/fixtures/consumer-app/config/omega.json5 +7 -0
  89. package/dist/test/fixtures/consumer-app/package.json +1 -1
  90. package/dist/test/fixtures/consumer-app/src/assets/js/components/main/index.js +7 -1
  91. package/dist/test/harness/main-entry.js +2 -1
  92. package/dist/test/harness/renderer-preload.js +12 -3
  93. package/dist/test/runners/boot.js +101 -11
  94. package/dist/test/runners/electron.js +1 -1
  95. package/dist/test/suites/boot/consumer-app-boots.test.js +54 -0
  96. package/dist/test/suites/build/audit.test.js +45 -6
  97. package/dist/test/suites/build/auth-persistence-resolve.test.js +119 -0
  98. package/dist/test/suites/build/auto-unlock.test.js +105 -0
  99. package/dist/test/suites/build/boot-runner-timeout.test.js +253 -0
  100. package/dist/test/suites/build/brand-scss.test.js +106 -0
  101. package/dist/test/suites/build/build-config.test.js +146 -36
  102. package/dist/test/suites/build/build-json-bake.test.js +245 -0
  103. package/dist/test/suites/build/build-verbs.test.js +48 -15
  104. package/dist/test/suites/build/build-workflow-jobs.test.js +190 -0
  105. package/dist/test/suites/build/cli.test.js +32 -10
  106. package/dist/test/suites/build/config-schema.test.js +4 -4
  107. package/dist/test/suites/build/console-lock.test.js +51 -0
  108. package/dist/test/suites/build/defaults-scaffold.test.js +71 -2
  109. package/dist/test/suites/build/deploy-direct.test.js +241 -0
  110. package/dist/test/suites/build/deploy-dispatch.test.js +287 -0
  111. package/dist/test/suites/build/deploy-hook.test.js +169 -0
  112. package/dist/test/suites/build/ensure-target.test.js +14 -2
  113. package/dist/test/suites/build/env-delivery.test.js +19 -10
  114. package/dist/test/suites/build/env-watch.test.js +18 -7
  115. package/dist/test/suites/build/esm-only-dependency.test.js +127 -0
  116. package/dist/test/suites/build/exec-with-limit.test.js +53 -0
  117. package/dist/test/suites/build/finalize-release.test.js +2 -2
  118. package/dist/test/suites/build/get-config.test.js +120 -8
  119. package/dist/test/suites/build/github-utils.test.js +12 -6
  120. package/dist/test/suites/build/license-stamp.test.js +6 -4
  121. package/dist/test/suites/build/manager.test.js +88 -68
  122. package/dist/test/suites/build/manifest-deps.test.js +116 -0
  123. package/dist/test/suites/build/merge-line-files.test.js +27 -4
  124. package/dist/test/suites/build/notarize-artifacts.test.js +135 -0
  125. package/dist/test/suites/build/notarize-tools.test.js +38 -0
  126. package/dist/test/suites/build/notarize.test.js +207 -0
  127. package/dist/test/suites/build/release-pipeline.test.js +38 -60
  128. package/dist/test/suites/build/release-skipped-upload.test.js +107 -0
  129. package/dist/test/suites/build/resolve-icons.test.js +35 -35
  130. package/dist/test/suites/build/runner-job-guard.test.js +182 -0
  131. package/dist/test/suites/build/runner.test.js +25 -2
  132. package/dist/test/suites/build/sentry.test.js +8 -3
  133. package/dist/test/suites/build/setup-scripts.test.js +3 -0
  134. package/dist/test/suites/build/sign-windows.test.js +92 -8
  135. package/dist/test/suites/build/test-stealth.test.js +17 -11
  136. package/dist/test/suites/build/url-helpers.test.js +37 -17
  137. package/dist/test/suites/build/validate-certs.test.js +428 -55
  138. package/dist/test/suites/build/validate-config.test.js +3 -3
  139. package/dist/test/suites/main/auth-flow.test.js +12 -0
  140. package/dist/test/suites/main/auth-persistence.test.js +14 -17
  141. package/dist/test/suites/main/auto-updater.test.js +2 -2
  142. package/dist/test/suites/main/boot-sequence.test.js +1 -1
  143. package/dist/test/suites/main/client-bridge.integration.test.js +5 -82
  144. package/dist/test/suites/main/client-bridge.test.js +19 -6
  145. package/dist/test/suites/main/deep-link.test.js +54 -0
  146. package/dist/test/suites/main/startup-paths-and-ua.test.js +1 -1
  147. package/dist/test/suites/main/url-helpers.test.js +81 -72
  148. package/dist/test/suites/renderer/cross-context-helpers.test.js +19 -16
  149. package/dist/utils/build-pipeline.js +10 -10
  150. package/dist/utils/github.js +12 -51
  151. package/dist/utils/load-env.js +66 -0
  152. package/dist/utils/mode-helpers.js +43 -111
  153. package/dist/utils/platform.js +37 -0
  154. package/dist/utils/runner-env.js +2 -1
  155. package/dist/utils/runner-job-guard.js +149 -0
  156. package/dist/utils/ship-keys.js +52 -0
  157. package/dist/utils/test-stealth.js +5 -3
  158. package/dist/utils/url-helpers.js +33 -17
  159. package/dist/vendor/config/bundle-id.js +53 -0
  160. package/dist/vendor/config/client-config.js +141 -0
  161. package/dist/vendor/config/company.js +334 -15
  162. package/dist/vendor/config/dev-facts.js +48 -0
  163. package/dist/vendor/config/env-delivery.js +231 -9
  164. package/dist/vendor/config/env-retired.js +137 -0
  165. package/dist/vendor/config/env-rules.js +22 -3
  166. package/dist/vendor/config/env-schema.js +234 -117
  167. package/dist/vendor/config/env.js +55 -26
  168. package/dist/vendor/config/environment.js +189 -0
  169. package/dist/vendor/config/hooks.js +13 -11
  170. package/dist/vendor/config/index.js +121 -44
  171. package/dist/vendor/config/load.js +366 -115
  172. package/dist/vendor/config/merge.js +2 -2
  173. package/dist/vendor/config/order.js +3 -3
  174. package/dist/vendor/config/platforms.js +276 -0
  175. package/dist/vendor/config/repo.js +226 -104
  176. package/dist/vendor/config/retired-keys.js +232 -27
  177. package/dist/vendor/config/schema.js +525 -99
  178. package/dist/vendor/config/site-global.js +63 -53
  179. package/dist/vendor/config/targets.js +187 -0
  180. package/dist/vendor/config/validate.js +119 -59
  181. package/dist/vendor/devkit/argv.js +118 -0
  182. package/dist/vendor/devkit/attach-log-file.js +21 -13
  183. package/dist/vendor/devkit/brand-tokens.js +278 -0
  184. package/dist/vendor/devkit/brand-version.js +264 -0
  185. package/dist/vendor/devkit/build-json.js +91 -0
  186. package/dist/vendor/devkit/bundle.js +48 -0
  187. package/dist/vendor/devkit/certificate-expiry.js +108 -0
  188. package/dist/vendor/devkit/certs.js +16 -194
  189. package/dist/vendor/devkit/ci-workflows.js +124 -8
  190. package/dist/vendor/devkit/cli-router.js +3 -3
  191. package/dist/vendor/devkit/defaults-engine.js +69 -7
  192. package/dist/vendor/devkit/deploy-follow.js +297 -0
  193. package/dist/vendor/devkit/deploy-precheck.js +23 -8
  194. package/dist/vendor/devkit/deploy-record.js +11 -27
  195. package/dist/vendor/devkit/deploy-snapshot.js +661 -0
  196. package/dist/vendor/devkit/deploy.js +445 -75
  197. package/dist/vendor/devkit/git-auth.js +73 -0
  198. package/dist/vendor/devkit/git-remote.js +95 -0
  199. package/dist/vendor/devkit/github-repo.js +290 -0
  200. package/dist/vendor/devkit/local.js +47 -0
  201. package/dist/vendor/devkit/merge-line-files.js +23 -16
  202. package/dist/vendor/devkit/omega-bin.js +18 -3
  203. package/dist/vendor/devkit/pack-local.js +391 -0
  204. package/dist/vendor/devkit/preludes/index.js +120 -0
  205. package/dist/vendor/devkit/preludes/origin-heal.js +156 -0
  206. package/dist/vendor/devkit/service-account.js +43 -0
  207. package/dist/vendor/devkit/ship-plan.js +112 -0
  208. package/dist/vendor/devkit/signing-env.js +180 -0
  209. package/dist/vendor/devkit/signing-tree.js +92 -0
  210. package/dist/vendor/devkit/target-seams.js +142 -0
  211. package/dist/vendor/devkit/target-secrets.js +235 -50
  212. package/dist/vendor/devkit/test/esm-only-fixture.js +48 -0
  213. package/dist/vendor/devkit/test/fixtures/esm-only-package/browser.js +19 -0
  214. package/dist/vendor/devkit/test/fixtures/esm-only-package/index.js +20 -0
  215. package/dist/vendor/devkit/test/fixtures/esm-only-package/package.json +13 -0
  216. package/dist/vendor/monitoring/env.js +20 -10
  217. package/dist/vendor/monitoring/main.js +1 -1
  218. package/dist/vendor/monitoring/preload.js +1 -1
  219. package/dist/vendor/monitoring/renderer.js +1 -1
  220. package/docs/analytics.md +1 -1
  221. package/docs/auto-updater.md +5 -5
  222. package/docs/boot-sequence.md +1 -1
  223. package/docs/build-system.md +15 -7
  224. package/docs/client-bridge.md +9 -7
  225. package/docs/config-schema.md +4 -4
  226. package/docs/css.md +8 -2
  227. package/docs/deep-link.md +12 -4
  228. package/docs/environment-detection.md +32 -24
  229. package/docs/hooks.md +3 -1
  230. package/docs/icons.md +7 -7
  231. package/docs/index.md +61 -23
  232. package/docs/installer-options.md +24 -21
  233. package/docs/logging.md +5 -5
  234. package/docs/releasing.md +25 -17
  235. package/docs/runner.md +40 -5
  236. package/docs/shared/brands.md +12 -6
  237. package/docs/shared/breaking-changes.md +375 -21
  238. package/docs/shared/config.md +757 -199
  239. package/docs/shared/deploys.md +194 -91
  240. package/docs/shared/icons.md +18 -0
  241. package/docs/shared/local-dev.md +24 -6
  242. package/docs/shared/logging.md +9 -6
  243. package/docs/shared/monitoring.md +27 -13
  244. package/docs/shared/publishing.md +3 -3
  245. package/docs/shared/rulings.md +2 -2
  246. package/docs/shared/testing.md +1 -1
  247. package/docs/shared/theming.md +26 -1
  248. package/docs/shared/translation.md +49 -7
  249. package/docs/shared/updates.md +1 -1
  250. package/docs/signing.md +59 -33
  251. package/docs/test-framework.md +10 -5
  252. package/docs/themes.md +15 -1
  253. package/package.json +18 -12
  254. package/bin/omega-desktop +0 -2
  255. package/dist/commands/push-secrets.js +0 -141
  256. package/dist/test/suites/build/deliver-certs.test.js +0 -95
  257. package/dist/test/suites/build/derive-signing-env.test.js +0 -122
  258. package/dist/test/suites/build/push-secrets.test.js +0 -226
  259. package/dist/test/suites/build/resolve-signing-cert.test.js +0 -342
  260. package/dist/utils/deliver-certs.js +0 -69
  261. package/dist/utils/derive-signing-env.js +0 -56
  262. package/dist/utils/resolve-signing-cert.js +0 -175
  263. package/dist/vendor/config/desktop-artifacts.js +0 -110
  264. package/dist/vendor/config/instances.js +0 -208
  265. /package/dist/defaults/config/icons/{macos → mac}/dmg.png +0 -0
  266. /package/dist/defaults/config/icons/{macos → mac}/icon.png +0 -0
  267. /package/dist/defaults/config/icons/{macos → mac}/tray.png +0 -0
@@ -56,11 +56,11 @@ module.exports = defineCases({
56
56
  },
57
57
  },
58
58
  {
59
- name: 'platforms.win.signing.strategy enum enforced under desktop',
59
+ name: 'platforms.windows.signing.strategy enum enforced under desktop',
60
60
  run: (ctx) => {
61
- const cfg = { ...VALID, platforms: { win: { signing: { strategy: 'banana' } } } };
61
+ const cfg = { ...VALID, platforms: { windows: { signing: { strategy: 'banana' } } } };
62
62
  const { errors } = validateConfig(cfg, { target: 'desktop' });
63
- ctx.expect(errors.some((e) => e.includes('platforms.win.signing.strategy'))).toBe(true);
63
+ ctx.expect(errors.some((e) => e.includes('platforms.windows.signing.strategy'))).toBe(true);
64
64
  },
65
65
  },
66
66
  {
@@ -20,17 +20,28 @@ function get(url) {
20
20
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
21
21
 
22
22
  // Stub the externals for one test body. Returns { opened, tokens, shown, restore }.
23
+ //
24
+ // The baked `dev` block is staged too: the sign-in chain starts at
25
+ // getWebsiteUrl(), which since
26
+ // [#834](https://github.com/Omega-JS-Stack/omega/issues/834) answers from the
27
+ // resolved dev map the bundle task bakes (whose floor is @omega.js/config's
28
+ // classic numbers) and throws when an artifact carries none. The harness manager
29
+ // loads src/defaults' config, which has no build behind it, so a real dev
30
+ // artifact's block is stated here.
23
31
  function stubExternals(ctx) {
24
32
  const electron = require('electron');
33
+ const { CLASSIC_PORTS } = require('../../../vendor/config/index.js');
25
34
  const opened = [];
26
35
  const tokens = [];
27
36
  const shown = [];
28
37
  const origOpen = electron.shell.openExternal;
29
38
  const origHandle = ctx.manager.omega.handleAuthToken;
30
39
  const origShow = ctx.manager.windows.show;
40
+ const origDev = ctx.manager.config.dev;
31
41
  electron.shell.openExternal = async (url) => { opened.push(url); };
32
42
  ctx.manager.omega.handleAuthToken = (t) => { tokens.push(t); };
33
43
  ctx.manager.windows.show = (name) => { shown.push(name); };
44
+ ctx.manager.config.dev = { ports: { ...CLASSIC_PORTS } };
34
45
  return {
35
46
  opened,
36
47
  tokens,
@@ -39,6 +50,7 @@ function stubExternals(ctx) {
39
50
  electron.shell.openExternal = origOpen;
40
51
  ctx.manager.omega.handleAuthToken = origHandle;
41
52
  ctx.manager.windows.show = origShow;
53
+ if (origDev !== undefined) ctx.manager.config.dev = origDev; else delete ctx.manager.config.dev;
42
54
  ctx.manager.authFlow.cancel();
43
55
  },
44
56
  };
@@ -25,22 +25,24 @@ module.exports = defineCases({
25
25
  description: 'auth-persistence (main)',
26
26
  tests: [
27
27
  {
28
- name: 'resolve(): default is safeStorage; explicit none disables; unknown warns to null',
28
+ name: 'resolve(): a test run is none, whatever the config says',
29
29
  run: async (ctx) => {
30
30
  const m = ctx.manager;
31
+ ctx.expect(m.isTesting()).toBe(true);
31
32
  m.config.omega = m.config.omega || {};
32
33
  const orig = m.config.omega.authPersistence;
33
34
  try {
35
+ // Unset, and explicitly asking for the vault, both land on none: the harness
36
+ // never signs a real user in, so it never asks the OS keychain
37
+ // ([#907](https://github.com/Omega-JS-Stack/omega/issues/907)).
34
38
  delete m.config.omega.authPersistence;
35
- const def = await authPersistence.resolve(m);
36
- // Default resolves to safeStorage when the OS vault is available, null otherwise —
37
- // both are valid environments; assert it never picks something else.
38
- if (def) ctx.expect(def.name).toBe('safeStorage');
39
+ ctx.expect(await authPersistence.resolve(m)).toBeNull();
40
+ ctx.expect(authPersistence.getActive()).toBeNull();
39
41
 
40
- m.config.omega.authPersistence = 'none';
42
+ m.config.omega.authPersistence = 'safeStorage';
41
43
  ctx.expect(await authPersistence.resolve(m)).toBeNull();
42
44
 
43
- m.config.omega.authPersistence = 'does-not-exist';
45
+ m.config.omega.authPersistence = 'none';
44
46
  ctx.expect(await authPersistence.resolve(m)).toBeNull();
45
47
  } finally {
46
48
  if (orig !== undefined) m.config.omega.authPersistence = orig;
@@ -50,23 +52,18 @@ module.exports = defineCases({
50
52
  },
51
53
  },
52
54
  {
53
- name: 'register(): validates the strategy surface and makes it selectable',
55
+ name: 'register(): validates the strategy surface and adds it to the registry',
54
56
  run: async (ctx) => {
55
- const m = ctx.manager;
56
57
  ctx.expect(() => authPersistence.register('bad', {})).toThrow(/must implement/);
57
58
 
58
59
  authPersistence.register('desktop-test-custom', fakeStrategy());
59
- m.config.omega = m.config.omega || {};
60
- const orig = m.config.omega.authPersistence;
61
60
  try {
62
- m.config.omega.authPersistence = 'desktop-test-custom';
63
- const active = await authPersistence.resolve(m);
64
- ctx.expect(active.name).toBe('desktop-test-custom');
61
+ // Selection by config is proven at the build layer, on a production manager:
62
+ // under test mode resolve() answers none before it reads a thing.
63
+ ctx.expect(authPersistence._strategies['desktop-test-custom'].name).toBe('desktop-test-custom');
64
+ ctx.expect(await authPersistence._strategies['desktop-test-custom'].available()).toBe(true);
65
65
  } finally {
66
- if (orig !== undefined) m.config.omega.authPersistence = orig;
67
- else delete m.config.omega.authPersistence;
68
66
  delete authPersistence._strategies['desktop-test-custom'];
69
- await authPersistence.resolve(m);
70
67
  }
71
68
  },
72
69
  },
@@ -1006,7 +1006,7 @@ module.exports = defineCases({
1006
1006
  // ─── Mode helpers (@omega.js/backend-pattern: isDevelopment / isProduction / isTesting) ────
1007
1007
 
1008
1008
  {
1009
- name: 'manager.isTesting() returns true under OMEGA_TEST_MODE (set by test runner)',
1009
+ name: 'manager.isTesting() returns true under OMEGA_ENVIRONMENT=testing (named by the test runner)',
1010
1010
  run: (ctx) => {
1011
1011
  ctx.expect(typeof ctx.manager.isTesting).toBe('function');
1012
1012
  ctx.expect(ctx.manager.isTesting()).toBe(true);
@@ -1015,7 +1015,7 @@ module.exports = defineCases({
1015
1015
  {
1016
1016
  name: 'manager.isDevelopment() is false during tests (testing takes precedence)',
1017
1017
  run: (ctx) => {
1018
- // The test runs unpackaged, but OMEGA_TEST_MODE=true → testing wins, so this is a
1018
+ // The test runs unpackaged, but the lane named testing, so this is a
1019
1019
  // TEST environment, not development. isDevelopment() is therefore false.
1020
1020
  ctx.expect(typeof ctx.manager.isDevelopment).toBe('function');
1021
1021
  ctx.expect(ctx.manager.isDevelopment()).toBe(false);
@@ -69,7 +69,7 @@ module.exports = defineCases({
69
69
  {
70
70
  name: 'getEnvironment returns testing under the test harness',
71
71
  run: (ctx) => {
72
- // The harness spawn sets OMEGA_TEST_MODE=true → testing wins over everything.
72
+ // The harness spawn names OMEGA_ENVIRONMENT=testing, the one input.
73
73
  ctx.expect(ctx.manager.getEnvironment()).toBe('testing');
74
74
  },
75
75
  },
@@ -1,23 +1,14 @@
1
1
  // Integration tests for client-bridge — actually hits Firebase.
2
2
  //
3
- // Skipped automatically unless OMEGA_TEST_FIREBASE_ADMIN_KEY (or GOOGLE_APPLICATION_CREDENTIALS)
4
- // points to a Firebase service-account JSON file. This keeps `npx omega test` fast & green
5
- // offline / on machines without backend creds.
3
+ // The SIGN-IN proof lives in #904: web, desktop and extension each sign in as a
4
+ // persona the backend emulator seeds, so this suite no longer mints a custom
5
+ // token from a service account and asks a brand for no test credential at all.
6
6
  //
7
- // To run:
8
- // 1. Install firebase-admin: `npm i -D firebase-admin` (already in @omega.js/desktop's devDeps)
9
- // 2. Drop a service-account JSON in a safe place
10
- // 3. Set OMEGA_TEST_FIREBASE_ADMIN_KEY=/path/to/file.json (or use GOOGLE_APPLICATION_CREDENTIALS)
11
- // 4. Optionally OMEGA_TEST_USER_UID=your-test-uid (defaults to 'desktop-test-user')
12
- // 5. `npx omega test`
7
+ // To run: `npx omega test --extended` (the cases below need a cloud.config in
8
+ // src/defaults/config/omega.json5 to have any Firebase to talk to).
13
9
 
14
- const fs = require('fs');
15
10
  const defineCases = require('../../../vendor/devkit/test/define-cases.js');
16
11
 
17
- const ADMIN_KEY = process.env.OMEGA_TEST_FIREBASE_ADMIN_KEY
18
- || process.env.GOOGLE_APPLICATION_CREDENTIALS
19
- || null;
20
- const USER_UID = process.env.OMEGA_TEST_USER_UID || 'desktop-test-user';
21
12
  // These hit REAL Firebase, so they're gated behind extended mode (the cross-framework
22
13
  // `TEST_EXTENDED_MODE` opt-in). `npx omega test --extended` (or TEST_EXTENDED_MODE=true) runs
23
14
  // them; default is skip so `npx omega test` stays fast + offline-safe.
@@ -26,13 +17,6 @@ const EXTENDED_OPTED_IN = process.env.TEST_EXTENDED_MODE === 'true'
26
17
 
27
18
  function checkSkipReason() {
28
19
  if (!EXTENDED_OPTED_IN) return 'extended tests skipped — pass --extended or set TEST_EXTENDED_MODE=true';
29
- if (!ADMIN_KEY) return 'no OMEGA_TEST_FIREBASE_ADMIN_KEY / GOOGLE_APPLICATION_CREDENTIALS';
30
- if (!fs.existsSync(ADMIN_KEY)) return `service-account file not found at ${ADMIN_KEY}`;
31
- try {
32
- require.resolve('firebase-admin');
33
- } catch (e) {
34
- return 'firebase-admin not installed (run: npm i -D firebase-admin)';
35
- }
36
20
  return null;
37
21
  }
38
22
 
@@ -58,37 +42,6 @@ module.exports = defineCases({
58
42
  ctx.expect(ctx.manager.omega._firebaseAuth).toBeTruthy();
59
43
  },
60
44
  },
61
- {
62
- name: 'admin can mint a custom token, bridge can sign in with it',
63
- run: async (ctx) => {
64
- if (!ctx.manager.omega._firebaseAuth) {
65
- ctx.skip('firebase not loaded');
66
- }
67
-
68
- const admin = require('firebase-admin');
69
- if (!admin.apps.length) {
70
- admin.initializeApp({
71
- credential: admin.credential.cert(require(ADMIN_KEY)),
72
- });
73
- }
74
-
75
- // Mint a custom token for the test UID.
76
- const token = await admin.auth().createCustomToken(USER_UID);
77
- ctx.expect(typeof token).toBe('string');
78
-
79
- // Hand it to the bridge.
80
- const result = await ctx.manager.omega.handleAuthToken(token);
81
-
82
- if (!result.success) {
83
- ctx.skip(`signInWithCustomToken failed: ${result.error || 'unknown'} — likely a project mismatch (cloud.config.projectId vs service-account project)`);
84
- }
85
- ctx.expect(result.user.uid).toBe(USER_UID);
86
-
87
- // Bridge state should reflect the signed-in user.
88
- const current = ctx.manager.omega.getCurrentUser();
89
- ctx.expect(current?.uid).toBe(USER_UID);
90
- },
91
- },
92
45
  {
93
46
  name: 'sign-out clears the current user and broadcasts',
94
47
  run: async (ctx) => {
@@ -100,35 +53,5 @@ module.exports = defineCases({
100
53
  ctx.expect(ctx.manager.omega.getCurrentUser()).toBeNull();
101
54
  },
102
55
  },
103
- {
104
- name: 'onAuthChange fires when state changes',
105
- run: async (ctx) => {
106
- if (!ctx.manager.omega._firebaseAuth) {
107
- ctx.skip('firebase not loaded');
108
- }
109
-
110
- const admin = require('firebase-admin');
111
- if (!admin.apps.length) {
112
- admin.initializeApp({
113
- credential: admin.credential.cert(require(ADMIN_KEY)),
114
- });
115
- }
116
-
117
- const calls = [];
118
- const off = ctx.manager.omega.onAuthChange((snap) => calls.push(snap));
119
-
120
- try {
121
- const token = await admin.auth().createCustomToken(USER_UID);
122
- await ctx.manager.omega.handleAuthToken(token);
123
-
124
- // Give onAuthStateChanged a tick to fire.
125
- await new Promise((r) => setTimeout(r, 200));
126
- ctx.expect(calls.length).toBeGreaterThan(0);
127
- ctx.expect(calls[calls.length - 1]?.uid).toBe(USER_UID);
128
- } finally {
129
- off();
130
- }
131
- },
132
- },
133
56
  ],
134
57
  });
@@ -1,7 +1,8 @@
1
1
  // Main-process tests for lib/client-bridge.js — unit-level coverage that doesn't hit Firebase.
2
2
  //
3
3
  // Real Firebase integration tests live in client-bridge.integration.test.js
4
- // (gated on OMEGA_TEST_FIREBASE_ADMIN_KEY presence).
4
+ // (gated on extended mode); the sign-in proof itself is #904's, through a
5
+ // persona the backend emulator seeds.
5
6
 
6
7
  const defineCases = require('../../../vendor/devkit/test/define-cases.js');
7
8
 
@@ -187,10 +188,10 @@ module.exports = defineCases({
187
188
  connectAuthEmulator: (auth, url, opts) => connects.push({ auth, url, opts }),
188
189
  };
189
190
 
190
- const run = (isTesting) => {
191
+ const run = (isTesting, dev) => {
191
192
  bridge._firebaseAuth = null;
192
193
  bridge._manager = {
193
- config: { cloud: { config: { apiKey: 'AIza-test', projectId: 'demo-desktop' } } },
194
+ config: { cloud: { config: { apiKey: 'AIza-test', projectId: 'demo-desktop' } }, ...(dev ? { dev } : {}) },
194
195
  isTesting: () => isTesting,
195
196
  };
196
197
  return bridge._getFirebaseAuth(null);
@@ -203,17 +204,29 @@ module.exports = defineCases({
203
204
  ctx.expect(run(false)).toBe(authInstance);
204
205
  ctx.expect(connects.length).toBe(0);
205
206
 
206
- // testing shape — classic 9099 when no resolved port is on the env channel
207
- ctx.expect(run(true)).toBe(authInstance);
207
+ // testing shape: the port comes from the map the bundle baked, which
208
+ // carries @omega.js/config's classic 9099 as its floor
209
+ // ([#834](https://github.com/Omega-JS-Stack/omega/issues/834)).
210
+ ctx.expect(run(true, { ports: { auth: 9099 } })).toBe(authInstance);
208
211
  ctx.expect(connects.length).toBe(1);
209
212
  ctx.expect(connects[0].auth).toBe(authInstance);
210
213
  ctx.expect(connects[0].url).toBe('http://localhost:9099');
211
214
 
212
215
  // a bumped port arrives on OMEGA_AUTH_PORT (N7)
213
216
  process.env.OMEGA_AUTH_PORT = '9199';
214
- run(true);
217
+ run(true, { ports: { auth: 9099 } });
215
218
  ctx.expect(connects.length).toBe(2);
216
219
  ctx.expect(connects[1].url).toBe('http://localhost:9199');
220
+
221
+ // Neither channel is a broken artifact, and it says so by name
222
+ // rather than dialling a port nothing identity-checks (#834).
223
+ delete process.env.OMEGA_AUTH_PORT;
224
+ let threw;
225
+ try { run(true); } catch (e) { threw = e; }
226
+ ctx.expect(threw).toBeDefined();
227
+ ctx.expect(threw.message).toMatch(/dev port for `auth`/);
228
+ ctx.expect(threw.message).toMatch(/bundle task/);
229
+ ctx.expect(connects.length).toBe(2);
217
230
  } finally {
218
231
  bridge._firebase = saved.firebase;
219
232
  bridge._firebaseModule = saved.module;
@@ -270,6 +270,60 @@ module.exports = defineCases({
270
270
  }
271
271
  },
272
272
  },
273
+ {
274
+ // #921: Electron re-serializes the duplicate's command line before second-instance
275
+ // fires (switches first, values detached at the end), so the duplicate's REAL argv
276
+ // rides along in additionalData. The event list below carries no url on purpose, so
277
+ // the case can only pass by reading the fourth argument.
278
+ name: 'second-instance reads argv/cwd from additionalData when it rides along',
279
+ run: (ctx) => {
280
+ const brandId = ctx.manager.config.brand.id;
281
+ const url = `${brandId}://dup/launch?k=v`;
282
+ let received;
283
+ const off = ctx.manager.deepLink.on('dup/launch', (c) => { received = c; });
284
+
285
+ try {
286
+ ctx.manager.protocol._electron.app.emit(
287
+ 'second-instance',
288
+ {},
289
+ ['/bin/app', '--title', '--message', '--allow-file-access-from-files', 'B', 'two'],
290
+ '/x',
291
+ { argv: ['/bin/app', '--title', 'B', url], cwd: '/y' },
292
+ );
293
+
294
+ ctx.expect(received).toBeTruthy();
295
+ ctx.expect(received.url).toBe(url);
296
+ ctx.expect(received.route).toBe('dup/launch');
297
+ ctx.expect(received.query).toEqual({ k: 'v' });
298
+ ctx.expect(received.source).toBe('warm-start');
299
+ ctx.expect(received.argv).toEqual(['/bin/app', '--title', 'B', url]);
300
+ ctx.expect(received.cwd).toBe('/y');
301
+ } finally {
302
+ off();
303
+ }
304
+ },
305
+ },
306
+ {
307
+ // A duplicate built before #921 passes no object, so the event's own argv still dispatches.
308
+ name: 'second-instance falls back to the event argv when no additionalData rides along',
309
+ run: (ctx) => {
310
+ const brandId = ctx.manager.config.brand.id;
311
+ const url = `${brandId}://dup/fallback?k=v`;
312
+ let received;
313
+ const off = ctx.manager.deepLink.on('dup/fallback', (c) => { received = c; });
314
+
315
+ try {
316
+ ctx.manager.protocol._electron.app.emit('second-instance', {}, ['/bin/app', url], '/z');
317
+
318
+ ctx.expect(received).toBeTruthy();
319
+ ctx.expect(received.url).toBe(url);
320
+ ctx.expect(received.argv).toEqual(['/bin/app', url]);
321
+ ctx.expect(received.cwd).toBe('/z');
322
+ } finally {
323
+ off();
324
+ }
325
+ },
326
+ },
273
327
  {
274
328
  name: 'handler errors do not stop subsequent handlers',
275
329
  run: (ctx) => {
@@ -18,7 +18,7 @@ module.exports = defineCases({
18
18
  run: (ctx) => {
19
19
  const { app } = require('electron');
20
20
  const userData = app.getPath('userData');
21
- // OMEGA_TEST_MODE=true → isTesting() → dedicated " (Testing)" dir, wiped at
21
+ // OMEGA_ENVIRONMENT=testing → isTesting() → dedicated " (Testing)" dir, wiped at
22
22
  // boot, so test runs never read or pollute dev ("(Development)") or
23
23
  // production data on the same machine.
24
24
  ctx.expect(typeof userData).toBe('string');
@@ -5,17 +5,19 @@
5
5
  // The manager (already bootstrapped by the test harness) is the natural object under test.
6
6
 
7
7
  const defineCases = require('../../../vendor/devkit/test/define-cases.js');
8
+ const { CLASSIC_PORTS, CLASSIC_DEV_ORIGIN } = require('../../../vendor/config/index.js');
8
9
 
9
- // Every case that pins a CLASSIC local answer silences the whole baked `dev`
10
- // block: the `dev.ports` map (#745) and the `dev.origin` the website publishes
11
- // (#747). The harness manager loads src/defaults' config, which carries no `dev`
12
- // block, so today this is a no-op guard; it exists so a harness that one day
13
- // seeds a real build blob cannot turn these classic pins red.
14
- function withoutBakedPorts(manager, fn) {
10
+ // Every case that pins a CLASSIC local answer states the baked `dev` block a
11
+ // real dev artifact carries: since
12
+ // [#834](https://github.com/Omega-JS-Stack/omega/issues/834) the bundle task
13
+ // bakes the classic map as the FLOOR of the resolved one, so the classics reach
14
+ // these helpers the way they reach a shipped dev build, from @omega.js/config,
15
+ // and no copy of the numbers lives in this file or in url-helpers.js.
16
+ function withClassicBakedPorts(manager, fn) {
15
17
  const original = manager.config.dev;
16
- delete manager.config.dev;
18
+ manager.config.dev = { ports: { ...CLASSIC_PORTS } };
17
19
  try { return fn(); } finally {
18
- if (original !== undefined) manager.config.dev = original;
20
+ if (original !== undefined) manager.config.dev = original; else delete manager.config.dev;
19
21
  }
20
22
  }
21
23
 
@@ -25,54 +27,62 @@ module.exports = defineCases({
25
27
  description: 'url-helpers (cross-context)',
26
28
  tests: [
27
29
  {
28
- name: 'getEnvironment: testing (OMEGA_TEST_MODE) wins; else config.em.environment',
30
+ // The environment reads ONE input
31
+ // ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)): the
32
+ // `OMEGA_ENVIRONMENT` variable the lane set, and the baked
33
+ // `config.environment` when the process has none (a packaged app, which
34
+ // has no parent lane to inherit from). The legacy `config.em.environment`
35
+ // override is gone with the copy that read it, and so are the
36
+ // app.isPackaged / OMEGA_BUILD_MODE / NODE_ENV sniffs.
37
+ name: 'getEnvironment: the process input, then the baked config.environment',
29
38
  run: (ctx) => {
30
39
  const m = ctx.manager;
31
- const orig = m.config?.em?.environment;
32
- const origTest = process.env.OMEGA_TEST_MODE;
33
- m.config.em = m.config.em || {};
40
+ const origConfigEnv = m.config.environment;
41
+ const origVar = process.env.OMEGA_ENVIRONMENT;
34
42
  try {
35
- // Testing takes precedence over the config override.
36
- process.env.OMEGA_TEST_MODE = 'true';
37
- m.config.em.environment = 'production';
38
- ctx.expect(m.getEnvironment()).toBe('testing');
39
- // With testing cleared, the config override is honored.
40
- delete process.env.OMEGA_TEST_MODE;
41
- m.config.em.environment = 'development';
42
- ctx.expect(m.getEnvironment()).toBe('development');
43
- m.config.em.environment = 'production';
44
- ctx.expect(m.getEnvironment()).toBe('production');
43
+ // The lane's variable is the answer wherever it exists.
44
+ m.config.environment = 'production';
45
+ for (const name of ['development', 'testing', 'production']) {
46
+ process.env.OMEGA_ENVIRONMENT = name;
47
+ ctx.expect(m.getEnvironment()).toBe(name);
48
+ }
49
+
50
+ // With no variable, the artifact's own baked word answers.
51
+ delete process.env.OMEGA_ENVIRONMENT;
52
+ for (const name of ['development', 'testing', 'production']) {
53
+ m.config.environment = name;
54
+ ctx.expect(m.getEnvironment()).toBe(name);
55
+ }
56
+
57
+ // Neither is a loud error, never a default.
58
+ delete m.config.environment;
59
+ let threw;
60
+ try { m.getEnvironment(); } catch (e) { threw = e; }
61
+ ctx.expect(threw).toBeDefined();
62
+ ctx.expect(threw.message).toMatch(/OMEGA_ENVIRONMENT/);
45
63
  } finally {
46
- m.config.em.environment = orig;
47
- if (origTest === undefined) delete process.env.OMEGA_TEST_MODE; else process.env.OMEGA_TEST_MODE = origTest;
64
+ if (origConfigEnv !== undefined) m.config.environment = origConfigEnv; else delete m.config.environment;
65
+ if (origVar !== undefined) process.env.OMEGA_ENVIRONMENT = origVar; else delete process.env.OMEGA_ENVIRONMENT;
48
66
  }
49
67
  },
50
68
  },
51
69
  {
52
- // In the MAIN process, app.isPackaged is the authoritative signal and beats the
53
- // OMEGA_BUILD_MODE fallback. The test harness is unpackaged, so once testing + config are
54
- // cleared, getEnvironment() resolves to 'development' from app.isPackaged === false —
55
- // regardless of OMEGA_BUILD_MODE. (The OMEGA_BUILD_MODE fallback only applies where `app` is
56
- // unavailable: renderer / preload / plain Node — covered by the build-layer manager test.)
57
- name: 'getEnvironment: app.isPackaged (unpackaged → development) wins over OMEGA_BUILD_MODE in main',
70
+ // The three checks DERIVE from getEnvironment(), on the REAL main-process
71
+ // Manager, so they can never disagree with it.
72
+ name: 'the three is*() checks derive from it, and exactly one is true',
58
73
  run: (ctx) => {
59
74
  const m = ctx.manager;
60
- const origEnv = m.config?.em?.environment;
61
- const origBuild = process.env.OMEGA_BUILD_MODE;
62
- const origTest = process.env.OMEGA_TEST_MODE;
63
- if (m.config.em) delete m.config.em.environment;
64
- delete process.env.OMEGA_TEST_MODE; // isolate from testing precedence
75
+ const origVar = process.env.OMEGA_ENVIRONMENT;
65
76
  try {
66
- // Unpackaged harness → 'development' even with OMEGA_BUILD_MODE set (app.isPackaged wins).
67
- process.env.OMEGA_BUILD_MODE = 'true';
68
- ctx.expect(m.getEnvironment()).toBe('development');
69
- delete process.env.OMEGA_BUILD_MODE;
70
- ctx.expect(m.getEnvironment()).toBe('development');
77
+ for (const name of ['development', 'testing', 'production']) {
78
+ process.env.OMEGA_ENVIRONMENT = name;
79
+ ctx.expect(m.isDevelopment()).toBe(name === 'development');
80
+ ctx.expect(m.isTesting()).toBe(name === 'testing');
81
+ ctx.expect(m.isProduction()).toBe(name === 'production');
82
+ ctx.expect([m.isDevelopment(), m.isTesting(), m.isProduction()].filter(Boolean).length).toBe(1);
83
+ }
71
84
  } finally {
72
- if (origEnv !== undefined) m.config.em.environment = origEnv;
73
- if (origBuild !== undefined) process.env.OMEGA_BUILD_MODE = origBuild;
74
- else delete process.env.OMEGA_BUILD_MODE;
75
- if (origTest !== undefined) process.env.OMEGA_TEST_MODE = origTest;
85
+ if (origVar !== undefined) process.env.OMEGA_ENVIRONMENT = origVar; else delete process.env.OMEGA_ENVIRONMENT;
76
86
  }
77
87
  },
78
88
  },
@@ -85,7 +95,7 @@ module.exports = defineCases({
85
95
  const orig = m.config.cloud.config.projectId;
86
96
  m.config.cloud.config.projectId = 'demo-app';
87
97
  try {
88
- withoutBakedPorts(m, () => {
98
+ withClassicBakedPorts(m, () => {
89
99
  ctx.expect(m.getFunctionsUrl('development')).toBe('http://localhost:5001/demo-app/us-central1');
90
100
  });
91
101
  } finally { m.config.cloud.config.projectId = orig; }
@@ -121,14 +131,14 @@ module.exports = defineCases({
121
131
  },
122
132
  },
123
133
  {
124
- name: 'getApiUrl: dev returns http://localhost:5002 (no published ports)',
134
+ name: 'getApiUrl: dev returns http://localhost:5002 from the baked classic map',
125
135
  run: (ctx) => {
126
136
  const origHttps = process.env.OMEGA_HTTPS_PORT;
127
137
  const origHosting = process.env.OMEGA_HOSTING_PORT;
128
138
  delete process.env.OMEGA_HTTPS_PORT;
129
139
  delete process.env.OMEGA_HOSTING_PORT;
130
140
  try {
131
- withoutBakedPorts(ctx.manager, () => {
141
+ withClassicBakedPorts(ctx.manager, () => {
132
142
  ctx.expect(ctx.manager.getApiUrl('development')).toBe('http://localhost:5002');
133
143
  });
134
144
  } finally {
@@ -147,7 +157,7 @@ module.exports = defineCases({
147
157
  delete process.env.OMEGA_HTTPS_PORT;
148
158
  delete process.env.OMEGA_HOSTING_PORT;
149
159
  try {
150
- withoutBakedPorts(ctx.manager, () => {
160
+ withClassicBakedPorts(ctx.manager, () => {
151
161
  ctx.expect(ctx.manager.getApiUrl('testing')).toBe('http://localhost:5002');
152
162
  });
153
163
  } finally {
@@ -243,12 +253,12 @@ module.exports = defineCases({
243
253
  },
244
254
  },
245
255
  {
246
- name: 'getWebsiteUrl: dev returns the classic dev origin https://localhost:4000',
256
+ name: 'getWebsiteUrl: dev returns https://localhost:4000 from the baked classic map',
247
257
  run: (ctx) => {
248
258
  const orig = process.env.OMEGA_WEBSITE_PORT;
249
259
  delete process.env.OMEGA_WEBSITE_PORT;
250
260
  try {
251
- withoutBakedPorts(ctx.manager, () => {
261
+ withClassicBakedPorts(ctx.manager, () => {
252
262
  ctx.expect(ctx.manager.getWebsiteUrl('development')).toBe('https://localhost:4000');
253
263
  });
254
264
  } finally {
@@ -326,7 +336,7 @@ module.exports = defineCases({
326
336
  const origId = m.config.brand.id;
327
337
  m.config.brand.id = 'demo';
328
338
  try {
329
- withoutBakedPorts(m, () => {
339
+ withClassicBakedPorts(m, () => {
330
340
  const url = new URL(m.getAuthUrl('development'));
331
341
  ctx.expect(url.origin).toBe('https://localhost:4000');
332
342
  ctx.expect(url.pathname).toBe('/signin');
@@ -372,10 +382,12 @@ module.exports = defineCases({
372
382
  m.config.brand.id = 'demo';
373
383
  try {
374
384
  const loopback = 'http://127.0.0.1:49152/auth/token?state=abc';
375
- const url = new URL(m.getAuthUrl('development', loopback));
376
- const tokenUrl = new URL(url.searchParams.get('authReturnUrl'));
377
- ctx.expect(tokenUrl.pathname).toBe('/token');
378
- ctx.expect(tokenUrl.searchParams.get('authReturnUrl')).toBe(loopback);
385
+ withClassicBakedPorts(m, () => {
386
+ const url = new URL(m.getAuthUrl('development', loopback));
387
+ const tokenUrl = new URL(url.searchParams.get('authReturnUrl'));
388
+ ctx.expect(tokenUrl.pathname).toBe('/token');
389
+ ctx.expect(tokenUrl.searchParams.get('authReturnUrl')).toBe(loopback);
390
+ });
379
391
  } finally {
380
392
  if (origId !== undefined) m.config.brand.id = origId; else delete m.config.brand.id;
381
393
  }
@@ -388,39 +400,36 @@ module.exports = defineCases({
388
400
  const orig = m.config.brand?.id;
389
401
  if (m.config.brand) delete m.config.brand.id;
390
402
  try {
391
- let threw;
392
- try { m.getAuthUrl('development'); } catch (e) { threw = e; }
393
- ctx.expect(threw).toBeDefined();
394
- ctx.expect(threw.message).toMatch(/brand\.id/);
403
+ withClassicBakedPorts(m, () => {
404
+ let threw;
405
+ try { m.getAuthUrl('development'); } catch (e) { threw = e; }
406
+ ctx.expect(threw).toBeDefined();
407
+ ctx.expect(threw.message).toMatch(/brand\.id/);
408
+ });
395
409
  } finally {
396
410
  if (orig !== undefined) m.config.brand.id = orig;
397
411
  }
398
412
  },
399
413
  },
400
414
  {
401
- name: 'getWebsiteUrl: respects current environment (config override) when no arg passed',
415
+ // With no argument, the getters take the CURRENT environment, which is
416
+ // the one input (#817): whatever the lane named for this process.
417
+ name: 'getWebsiteUrl: respects the current environment when no arg passed',
402
418
  run: (ctx) => {
403
419
  const m = ctx.manager;
404
- const origEnv = m.config.em?.environment;
405
- const origTest = process.env.OMEGA_TEST_MODE;
406
- m.config.em = m.config.em || {};
420
+ const origVar = process.env.OMEGA_ENVIRONMENT;
407
421
  m.config.brand = m.config.brand || {};
408
422
  const origUrl = m.config.brand.url;
409
423
  m.config.brand.url = 'https://example.com';
410
- // Clear OMEGA_TEST_MODE so the config override is exercised — otherwise testing wins
411
- // (correctly) and every URL resolves local regardless of config.
412
- delete process.env.OMEGA_TEST_MODE;
413
424
  try {
414
- m.config.em.environment = 'development';
415
- withoutBakedPorts(m, () => {
425
+ process.env.OMEGA_ENVIRONMENT = 'development';
426
+ withClassicBakedPorts(m, () => {
416
427
  ctx.expect(m.getWebsiteUrl()).toBe('https://localhost:4000');
417
428
  });
418
- m.config.em.environment = 'production';
429
+ process.env.OMEGA_ENVIRONMENT = 'production';
419
430
  ctx.expect(m.getWebsiteUrl()).toBe('https://example.com');
420
431
  } finally {
421
- if (origEnv !== undefined) m.config.em.environment = origEnv;
422
- else delete m.config.em.environment;
423
- if (origTest !== undefined) process.env.OMEGA_TEST_MODE = origTest;
432
+ if (origVar !== undefined) process.env.OMEGA_ENVIRONMENT = origVar; else delete process.env.OMEGA_ENVIRONMENT;
424
433
  m.config.brand.url = origUrl;
425
434
  }
426
435
  },