@omega.js/desktop 0.52.0 → 0.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. package/README.md +17 -12
  2. package/dist/assets/css/core/_initialize.scss +1 -1
  3. package/dist/assets/js/core/app-shell.js +14 -15
  4. package/dist/assets/themes/_template/_theme.js +6 -6
  5. package/dist/assets/themes/base/_includes/global/sections/account.html +4 -4
  6. package/dist/assets/themes/base/_includes/global/sections/app-sidebar.html +5 -5
  7. package/dist/assets/themes/base/_layouts/frontend/pages/account/index.html +3 -3
  8. package/dist/assets/themes/base/_layouts/frontend/pages/alternatives/index.html +1 -1
  9. package/dist/assets/themes/base/_layouts/frontend/pages/blog/tags/tag.html +1 -1
  10. package/dist/assets/themes/base/_layouts/frontend/pages/payment/confirmation.html +1 -1
  11. package/dist/assets/themes/base/_sections/marketing/newsletter-cta/section.js +2 -3
  12. package/dist/assets/themes/base/_sections/verts/unit/section.html +1 -1
  13. package/dist/assets/themes/base/_sections/verts/unit/section.js +3 -4
  14. package/dist/assets/themes/base/_theme.js +4 -3
  15. package/dist/assets/themes/bootstrap/_theme.js +2 -2
  16. package/dist/assets/themes/bootstrap/overrides/_links.scss +1 -1
  17. package/dist/assets/themes/classy/_theme.js +8 -6
  18. package/dist/assets/themes/classy/css/marketing/_sections.scss +1 -2
  19. package/dist/assets/themes/classy/js/hero-demo-form.js +3 -2
  20. package/dist/assets/themes/neobrutalism/_theme.js +5 -5
  21. package/dist/assets/themes/neobrutalism/js/pages/test/libraries/layers/index.js +1 -1
  22. package/dist/assets/themes/newsflash/_theme.js +6 -6
  23. package/dist/assets/themes/newsflash/js/pages/test/libraries/layers/index.js +1 -1
  24. package/dist/build.js +87 -111
  25. package/dist/cli.js +1 -1
  26. package/dist/commands/build.js +2 -2
  27. package/dist/commands/cdp/capture.js +2 -2
  28. package/dist/commands/cdp/quit.js +2 -2
  29. package/dist/commands/cdp/relaunch.js +2 -2
  30. package/dist/commands/cdp/theme.js +1 -1
  31. package/dist/commands/clean.js +2 -2
  32. package/dist/commands/deploy.js +4 -4
  33. package/dist/commands/finalize-release.js +4 -4
  34. package/dist/commands/install.js +3 -3
  35. package/dist/commands/launch.js +2 -2
  36. package/dist/commands/lib/deploy-precheck.js +3 -3
  37. package/dist/commands/lib/ensure-target.js +6 -6
  38. package/dist/commands/package.js +2 -2
  39. package/dist/commands/publish.js +2 -2
  40. package/dist/commands/release.js +3 -3
  41. package/dist/commands/runner.js +11 -11
  42. package/dist/commands/sign-windows.js +5 -5
  43. package/dist/commands/test.js +4 -4
  44. package/dist/commands/update.js +2 -2
  45. package/dist/commands/validate-certs.js +4 -4
  46. package/dist/commands/version.js +3 -3
  47. package/dist/defaults/AGENTS.md +17 -8
  48. package/dist/defaults/config/omega.json5 +7 -7
  49. package/dist/defaults/hooks/build/post.js +1 -1
  50. package/dist/defaults/hooks/build/pre.js +1 -1
  51. package/dist/defaults/hooks/deploy/pre.js +1 -1
  52. package/dist/defaults/hooks/release/post.js +1 -1
  53. package/dist/defaults/hooks/release/pre.js +1 -1
  54. package/dist/defaults/src/assets/js/components/about/index.js +3 -5
  55. package/dist/defaults/src/assets/js/components/main/index.js +3 -5
  56. package/dist/defaults/src/assets/js/components/settings/index.js +3 -5
  57. package/dist/defaults/src/integrations/context-menu/index.js +2 -2
  58. package/dist/defaults/src/integrations/menu/index.js +3 -3
  59. package/dist/defaults/src/integrations/tray/index.js +3 -3
  60. package/dist/defaults/src/main.js +3 -5
  61. package/dist/defaults/src/preload.js +3 -5
  62. package/dist/defaults/test/README.md +2 -2
  63. package/dist/gulp/main.js +9 -10
  64. package/dist/gulp/tasks/audit.js +7 -7
  65. package/dist/gulp/tasks/build-config.js +8 -8
  66. package/dist/gulp/tasks/bundle.js +16 -16
  67. package/dist/gulp/tasks/defaults.js +3 -3
  68. package/dist/gulp/tasks/distribute.js +2 -2
  69. package/dist/gulp/tasks/html.js +9 -9
  70. package/dist/gulp/tasks/package-quick.js +3 -3
  71. package/dist/gulp/tasks/package.js +3 -3
  72. package/dist/gulp/tasks/release.js +3 -3
  73. package/dist/gulp/tasks/sass.js +6 -6
  74. package/dist/gulp/tasks/serve.js +4 -4
  75. package/dist/hooks/notarize-artifacts.js +1 -1
  76. package/dist/hooks/notarize.js +1 -1
  77. package/dist/index.js +5 -8
  78. package/dist/lib/_environment-mixin.js +50 -0
  79. package/dist/lib/_lifecycle-mixin.js +45 -0
  80. package/dist/lib/analytics.js +33 -35
  81. package/dist/lib/app-state.js +14 -14
  82. package/dist/lib/auth-flow.js +18 -18
  83. package/dist/lib/auth-persistence.js +12 -12
  84. package/dist/lib/auth.js +421 -0
  85. package/dist/lib/auto-updater.js +49 -49
  86. package/dist/lib/context-menu.js +13 -13
  87. package/dist/lib/context.js +19 -19
  88. package/dist/lib/deep-link.js +34 -34
  89. package/dist/lib/fontawesome.js +5 -5
  90. package/dist/lib/ipc.js +4 -4
  91. package/dist/lib/menu.js +25 -25
  92. package/dist/lib/protocol.js +5 -5
  93. package/dist/lib/remote-config.js +22 -22
  94. package/dist/lib/remote-scripts.js +21 -21
  95. package/dist/lib/restart-manager/index.js +28 -28
  96. package/dist/lib/sign-helpers/exec-with-limit.js +1 -1
  97. package/dist/lib/sign-helpers/sign-events.js +1 -1
  98. package/dist/lib/startup.js +18 -13
  99. package/dist/lib/storage.js +10 -10
  100. package/dist/lib/templating.js +16 -16
  101. package/dist/lib/theme.js +10 -10
  102. package/dist/lib/tray.js +27 -27
  103. package/dist/lib/usage.js +11 -11
  104. package/dist/lib/window-manager.js +26 -26
  105. package/dist/main.js +398 -483
  106. package/dist/preload.js +236 -176
  107. package/dist/renderer.js +417 -391
  108. package/dist/test/fixtures/consumer-app/config/omega.json5 +1 -1
  109. package/dist/test/fixtures/consumer-app/src/assets/js/components/main/index.js +8 -11
  110. package/dist/test/fixtures/consumer-app/src/main.js +5 -7
  111. package/dist/test/fixtures/consumer-app/src/preload.js +2 -2
  112. package/dist/test/harness/boot-entry.js +22 -20
  113. package/dist/test/harness/main-entry.js +31 -30
  114. package/dist/test/harness/renderer-entry.js +5 -5
  115. package/dist/test/harness/renderer-preload.js +137 -141
  116. package/dist/test/index.js +10 -10
  117. package/dist/test/runner.js +2 -2
  118. package/dist/test/runners/boot.js +7 -6
  119. package/dist/test/runners/electron.js +3 -2
  120. package/dist/test/runners/render-event.js +2 -2
  121. package/dist/test/suites/boot/consumer-app-boots.test.js +57 -26
  122. package/dist/test/suites/boot/restart-manager.test.js +2 -2
  123. package/dist/test/suites/boot/storage-bundled.test.js +5 -5
  124. package/dist/test/suites/boot/theme.test.js +13 -13
  125. package/dist/test/suites/build/audit.test.js +1 -1
  126. package/dist/test/suites/build/auth-persistence-resolve.test.js +6 -6
  127. package/dist/test/suites/build/boot-fixture.test.js +2 -2
  128. package/dist/test/suites/build/boot-runner-timeout.test.js +6 -5
  129. package/dist/test/suites/build/brand-scss.test.js +1 -1
  130. package/dist/test/suites/build/build-json-bake.test.js +1 -1
  131. package/dist/test/suites/build/cli.test.js +2 -2
  132. package/dist/test/suites/build/config-schema.test.js +5 -5
  133. package/dist/test/suites/build/defaults-scaffold.test.js +2 -2
  134. package/dist/test/suites/build/deploy-hook.test.js +3 -3
  135. package/dist/test/suites/build/ensure-target.test.js +2 -2
  136. package/dist/test/suites/build/env-delivery.test.js +2 -2
  137. package/dist/test/suites/build/esm-only-dependency.test.js +2 -2
  138. package/dist/test/suites/build/exports.test.js +9 -8
  139. package/dist/test/suites/build/get-config.test.js +4 -4
  140. package/dist/test/suites/build/manifest-deps.test.js +1 -1
  141. package/dist/test/suites/build/merge-line-files.test.js +1 -1
  142. package/dist/test/suites/build/omega-shell.test.js +34 -2
  143. package/dist/test/suites/build/omega.test.js +350 -0
  144. package/dist/test/suites/build/renderer-auth-bridge.test.js +211 -78
  145. package/dist/test/suites/build/runner.test.js +2 -2
  146. package/dist/test/suites/build/sentry.test.js +2 -2
  147. package/dist/test/suites/build/sign-windows-e2e.test.js +2 -2
  148. package/dist/test/suites/build/templating.test.js +3 -3
  149. package/dist/test/suites/build/test-stealth.test.js +7 -9
  150. package/dist/test/suites/build/url-helpers.test.js +55 -56
  151. package/dist/test/suites/build/validate-config.test.js +2 -2
  152. package/dist/test/suites/build/wave5-pins.test.js +2 -2
  153. package/dist/test/suites/main/analytics.test.js +59 -59
  154. package/dist/test/suites/main/app-state.test.js +66 -66
  155. package/dist/test/suites/main/auth-flow.test.js +41 -41
  156. package/dist/test/suites/main/auth-persistence.test.js +54 -43
  157. package/dist/test/suites/main/{client-bridge.integration.test.js → auth.integration.test.js} +10 -9
  158. package/dist/test/suites/main/auth.test.js +336 -0
  159. package/dist/test/suites/main/auto-updater.test.js +134 -134
  160. package/dist/test/suites/main/boot-sequence.test.js +37 -49
  161. package/dist/test/suites/main/context-menu.test.js +51 -50
  162. package/dist/test/suites/main/context.test.js +25 -25
  163. package/dist/test/suites/main/deep-link.test.js +74 -74
  164. package/dist/test/suites/main/fontawesome.test.js +27 -27
  165. package/dist/test/suites/main/ipc.test.js +35 -35
  166. package/dist/test/suites/main/menu.test.js +101 -100
  167. package/dist/test/suites/main/protocol.test.js +19 -19
  168. package/dist/test/suites/main/remote-config.test.js +63 -63
  169. package/dist/test/suites/main/remote-scripts.test.js +103 -103
  170. package/dist/test/suites/main/request.test.js +71 -0
  171. package/dist/test/suites/main/restart-manager.test.js +33 -33
  172. package/dist/test/suites/main/startup-paths-and-ua.test.js +4 -4
  173. package/dist/test/suites/main/startup.test.js +26 -26
  174. package/dist/test/suites/main/stealth-window.test.js +1 -1
  175. package/dist/test/suites/main/storage.test.js +25 -25
  176. package/dist/test/suites/main/theme.test.js +34 -34
  177. package/dist/test/suites/main/tray.test.js +79 -79
  178. package/dist/test/suites/main/url-helpers.test.js +133 -133
  179. package/dist/test/suites/main/usage.test.js +25 -25
  180. package/dist/test/suites/main/window-bounds.test.js +27 -27
  181. package/dist/test/suites/main/window-manager.test.js +44 -44
  182. package/dist/test/suites/renderer/analytics-bridge.test.js +5 -5
  183. package/dist/test/suites/renderer/cross-context-helpers.test.js +37 -31
  184. package/dist/test/suites/renderer/round-trip.test.js +3 -3
  185. package/dist/test/suites/renderer/tooltips.test.js +15 -15
  186. package/dist/test/suites/renderer/{window-em-surface.test.js → window-desktop-surface.test.js} +27 -7
  187. package/dist/test/utils/extended-mode-warning.js +1 -1
  188. package/dist/utils/boot-harness.js +56 -0
  189. package/dist/utils/mode-helpers.js +2 -15
  190. package/dist/utils/ship-keys.js +3 -3
  191. package/dist/utils/signing-status.js +51 -0
  192. package/dist/utils/test-events.js +7 -0
  193. package/dist/utils/test-stealth.js +6 -6
  194. package/dist/utils/url-helpers.js +52 -42
  195. package/dist/utils/user-agent.js +44 -0
  196. package/dist/vendor/account/engine.js +3 -3
  197. package/dist/vendor/account/index.js +14 -45
  198. package/dist/vendor/account/resolve-account.js +44 -0
  199. package/dist/vendor/account/schema.js +1 -1
  200. package/dist/vendor/account/user.js +99 -0
  201. package/dist/vendor/config/client-config.js +1 -1
  202. package/dist/vendor/config/environment.js +11 -30
  203. package/dist/vendor/config/index.js +8 -11
  204. package/dist/vendor/config/load.js +1 -2
  205. package/dist/vendor/config/platforms.js +1 -1
  206. package/dist/vendor/config/retired-keys.js +2 -2
  207. package/dist/vendor/config/schema.js +5 -8
  208. package/dist/vendor/config/site-global.js +2 -3
  209. package/dist/vendor/config/validate.js +1 -2
  210. package/dist/vendor/config/winback.js +1 -1
  211. package/dist/vendor/devkit/actions-secrets.js +1 -1
  212. package/dist/vendor/devkit/attach-log-file.js +1 -1
  213. package/dist/vendor/devkit/build-json.js +1 -1
  214. package/dist/vendor/devkit/cli-router.js +3 -4
  215. package/dist/vendor/devkit/defaults-engine.js +9 -11
  216. package/dist/vendor/devkit/local.js +2 -0
  217. package/dist/vendor/devkit/merge-line-files.js +2 -3
  218. package/dist/vendor/devkit/test/runner-core.js +6 -6
  219. package/dist/vendor/monitoring/env.js +2 -2
  220. package/dist/vendor/monitoring/index.js +1 -1
  221. package/dist/vendor/monitoring/main.js +1 -1
  222. package/dist/vendor/monitoring/preload.js +1 -1
  223. package/dist/vendor/monitoring/renderer.js +1 -1
  224. package/docs/analytics.md +8 -8
  225. package/docs/app-state.md +19 -19
  226. package/docs/audit.md +4 -4
  227. package/docs/{client-bridge.md → auth.md} +88 -73
  228. package/docs/auto-updater.md +8 -8
  229. package/docs/boot-sequence.md +11 -6
  230. package/docs/build-system.md +1 -1
  231. package/docs/cdp-debugging.md +1 -1
  232. package/docs/common-mistakes.md +7 -7
  233. package/docs/config-schema.md +1 -1
  234. package/docs/context-menu.md +13 -13
  235. package/docs/context.md +11 -11
  236. package/docs/css.md +3 -9
  237. package/docs/deep-link.md +25 -25
  238. package/docs/environment-detection.md +16 -16
  239. package/docs/fontawesome.md +7 -5
  240. package/docs/hooks.md +8 -8
  241. package/docs/index.md +38 -27
  242. package/docs/ipc.md +10 -10
  243. package/docs/lib-modules.md +9 -9
  244. package/docs/logging.md +12 -14
  245. package/docs/menu.md +18 -18
  246. package/docs/remote-config.md +9 -9
  247. package/docs/remote-scripts.md +12 -12
  248. package/docs/restart-manager.md +8 -8
  249. package/docs/sentry.md +4 -4
  250. package/docs/shared/analytics.md +1 -1
  251. package/docs/shared/breaking-changes.md +79 -13
  252. package/docs/shared/config.md +17 -21
  253. package/docs/shared/logging.md +1 -1
  254. package/docs/shared/monitoring.md +5 -5
  255. package/docs/shared/testing.md +2 -2
  256. package/docs/shared/theming.md +1 -1
  257. package/docs/shared/translation.md +19 -10
  258. package/docs/startup.md +16 -16
  259. package/docs/storage.md +11 -11
  260. package/docs/templating.md +3 -3
  261. package/docs/test-boot-layer.md +12 -12
  262. package/docs/test-framework.md +17 -17
  263. package/docs/themes.md +7 -7
  264. package/docs/tooltips.md +2 -2
  265. package/docs/tray.md +31 -31
  266. package/docs/usage.md +7 -7
  267. package/docs/verts.md +1 -1
  268. package/docs/windows.md +22 -22
  269. package/package.json +3 -4
  270. package/dist/lib/client-bridge.js +0 -374
  271. package/dist/lib/logger.js +0 -4
  272. package/dist/test/suites/build/manager.test.js +0 -213
  273. package/dist/test/suites/main/client-bridge.test.js +0 -262
@@ -1,18 +1,18 @@
1
1
  // Renderer test-harness preload. Bridges between the harness BrowserWindow and the parent
2
- // main-process harness via two channels:
2
+ // main-process harness via three channels:
3
3
  //
4
- // __emTest:ready — renderer signals it's ready to receive suites
5
- // __emTest:result — renderer emits per-test results / suite-start / fatal
6
- // __emTest:suites — main sends serialized renderer suites for execution
4
+ // __omegaTest:ready : renderer signals it's ready to receive suites
5
+ // __omegaTest:result : renderer emits per-test results / suite-start / fatal
6
+ // __omegaTest:suites : main sends serialized renderer suites for execution
7
7
  //
8
8
  // Also exposes the production-style `window.desktop` surface (mirrors src/preload.js so renderer
9
- // test suites can assert on it).
9
+ // test suites can assert on it), and builds the REAL renderer instance in this world.
10
10
 
11
11
  const { contextBridge, ipcRenderer } = require('electron');
12
12
 
13
13
  // Mirror the production preload's forwarding logger so renderer-layer tests can
14
14
  // verify that logger.log/warn/error actually emits 'desktop:log:forward' to main.
15
- // Kept minimal — same channel name as production (src/preload.js).
15
+ // Kept minimal: same channel name as production (src/preload.js).
16
16
  function makeForwardingLogger() {
17
17
  const FORWARD_CHANNEL = 'desktop:log:forward';
18
18
  const methods = ['log', 'info', 'warn', 'error', 'debug'];
@@ -20,7 +20,7 @@ function makeForwardingLogger() {
20
20
  for (const m of methods) {
21
21
  const fileLevel = m === 'log' ? 'info' : m;
22
22
  out[m] = function () {
23
- const args = ['[em]', ...Array.from(arguments)];
23
+ const args = ['[omega]', ...Array.from(arguments)];
24
24
  const fn = console[m] || console.log;
25
25
  try { fn.apply(console, args); } catch (_) { /* ignore */ }
26
26
  try {
@@ -38,74 +38,17 @@ function makeForwardingLogger() {
38
38
  return out;
39
39
  }
40
40
 
41
- contextBridge.exposeInMainWorld('__emTest', {
41
+ contextBridge.exposeInMainWorld('__omegaTest', {
42
42
  // Signal main that the harness page is loaded and ready to accept suites.
43
- ready: () => ipcRenderer.send('__emTest:ready'),
43
+ ready: () => { instanceBuilt.then(() => ipcRenderer.send('__omegaTest:ready')); },
44
44
  // Forward a result event up to main, which prints it.
45
- emit: (evt) => ipcRenderer.send('__emTest:result', evt),
45
+ emit: (evt) => ipcRenderer.send('__omegaTest:result', evt),
46
46
  // Subscribe to incoming suite payloads.
47
47
  onSuites: (handler) => {
48
- ipcRenderer.on('__emTest:suites', (_e, suites) => handler(suites));
48
+ ipcRenderer.on('__omegaTest:suites', (_e, suites) => handler(suites));
49
49
  },
50
50
  });
51
51
 
52
- // Expose a thin bridge to the actual renderer Manager so renderer-layer tests can
53
- // assert on its cross-context helpers (isDevelopment / isProduction / isTesting /
54
- // getVersion / getEnvironment / getApiUrl / getFunctionsUrl / getWebsiteUrl). We
55
- // instantiate the renderer Manager here in the preload (before contextIsolation
56
- // closes off `require`) and forward each helper as a sync contextBridge function.
57
- // We deliberately do NOT call `manager.initialize()` — that touches @omega.js/client /
58
- // firebase / IPC, which is heavy + flaky for a helper-shape assertion. Instead we
59
- // stub `manager.config` from a built-time-injected blob so config-dependent
60
- // helpers (getEnvironment fallback, getWebsiteUrl prod path) have something to read.
61
- let testManager;
62
- try {
63
- // The renderer test harness loads the renderer Manager by absolute dist path
64
- // injected by the boot harness. In its absence, fall back to require-by-name
65
- // (works when the harness is run from a consumer with @omega.js/desktop in node_modules).
66
- const RendererManager = process.env.OMEGA_TEST_RENDERER_MANAGER_PATH
67
- ? require(process.env.OMEGA_TEST_RENDERER_MANAGER_PATH)
68
- : require('@omega.js/desktop/renderer');
69
- testManager = new RendererManager();
70
- // Seed config the way a real BUILD bakes it, so the URL helpers have the same
71
- // inputs here that they have in a shipped renderer. Tests can mutate this via
72
- // __emTestManager.config.set().
73
- // `environment` is the build fact every OMEGA surface bakes
74
- // ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)), which is
75
- // what a real renderer (no process.env) answers from.
76
- // `dev.ports` is the resolved local map, whose floor is @omega.js/config's
77
- // classic numbers ([#834](https://github.com/Omega-JS-Stack/omega/issues/834)):
78
- // nothing carries a browser-side copy of them any more, so an artifact
79
- // without the map cannot reach a localhost port at all.
80
- testManager.config = {
81
- environment: 'production',
82
- dev: { ports: { ...require('../../vendor/config/index.js').CLASSIC_PORTS } },
83
- brand: { url: 'https://example.com' },
84
- cloud: { provider: 'firebase', config: { projectId: 'demo-app', authDomain: 'demo-app.firebaseapp.com' } },
85
- };
86
- } catch (e) {
87
- console.warn('[renderer-preload] Could not instantiate renderer Manager for tests:', e.message);
88
- }
89
-
90
- // Wire the renderer Manager's DOM enhancements (FontAwesome auto-render +
91
- // Bootstrap tooltip auto-init) against THIS document. In production these run
92
- // in the page world (the consumer's esbuild bundle); here the preload world
93
- // stands in — the DOM is shared, so injected SVGs / tooltip tips are visible
94
- // to page-world test suites. The Manager reads `window.desktop.ipc` which only
95
- // exists in the page world, so hand it the preload's ipcRenderer directly.
96
- try {
97
- if (testManager) {
98
- testManager.ipc = {
99
- invoke: (channel, payload) => ipcRenderer.invoke(channel, payload),
100
- };
101
- testManager._wireFontAwesome();
102
- testManager._wireTooltips();
103
- }
104
- } catch (e) {
105
- console.warn('[renderer-preload] Could not wire DOM enhancements:', e.message);
106
- }
107
-
108
-
109
52
  // Mirror the production preload surface so renderer test suites can assert against it.
110
53
  const desktopSurface = {
111
54
  ipc: {
@@ -135,7 +78,7 @@ const desktopSurface = {
135
78
  },
136
79
  },
137
80
  // Mirror production preload's theme surface (get/set via IPC; onChange via
138
- // matchMedia — the real mechanism, since themeSource flips prefers-color-scheme).
81
+ // matchMedia, the real mechanism, since themeSource flips prefers-color-scheme).
139
82
  theme: {
140
83
  get: () => ipcRenderer.invoke('desktop:theme:get'),
141
84
  set: (source) => ipcRenderer.invoke('desktop:theme:set', { source }),
@@ -189,65 +132,107 @@ const desktopSurface = {
189
132
 
190
133
  contextBridge.exposeInMainWorld('desktop', desktopSurface);
191
134
 
192
- // Defined ABOVE the client wiring below, which injects `desktopSurface.analytics`
193
- // as that client's analytics bridge ([#411](https://github.com/Omega-JS-Stack/omega/issues/411)):
194
- // the surface has to exist before the wiring reads it. Observed, not assumed —
195
- // with this block further down, the wiring resolved nothing.
135
+ // The REAL renderer instance, built here in the preload world (before contextIsolation
136
+ // closes off `require`): the same module a view's entry requires. Its constructor
137
+ // reads `window.desktop`, which contextBridge exposes to the PAGE world only, so this
138
+ // world gets the same surface first. Suites assert on it through the probes below.
139
+ //
140
+ // initialize() is deliberately NOT called: it boots Firebase and the auth bridge,
141
+ // which is heavy + flaky for a helper-shape assertion. The config is seeded the way a
142
+ // real BUILD bakes it instead:
143
+ // `environment` is the build fact every OMEGA surface bakes
144
+ // ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)), which is
145
+ // what a real renderer (no process.env) answers from.
146
+ // `dev.ports` is the resolved local map, whose floor is @omega.js/config's
147
+ // classic numbers ([#834](https://github.com/Omega-JS-Stack/omega/issues/834)):
148
+ // nothing carries a browser-side copy of them any more, so an artifact
149
+ // without the map cannot reach a localhost port at all.
150
+ // `advertising` configures AdSense ON PURPOSE and no inhouse source: the
151
+ // house-lane pin is exactly what must keep the provider lane (remote script)
152
+ // from ever being attempted, and a source-less house render collapses
153
+ // deterministically with zero network.
154
+ // `analyticsBridge` is INJECTED exactly the way src/renderer.js injects it in
155
+ // production ([#411](https://github.com/Omega-JS-Stack/omega/issues/411)): the
156
+ // preload's own analytics surface, handed over as config.
157
+ let testOmega;
158
+ let buildError = null;
159
+
160
+ // The ESM modules renderer.js requires. Electron's preload loader has no
161
+ // require(esm) (a production renderer is esbuild-bundled, so it never needs one):
162
+ // each is loaded through import() first and seated in require's cache, and
163
+ // renderer.js's own require() then finds it there.
164
+ const RENDERER_ESM = ['@omega.js/client', '@omega.js/client/modules/request.js', './assets/js/core/app-shell.js'];
165
+
166
+ async function buildInstance() {
167
+ const Module = require('module');
168
+ const { pathToFileURL } = require('url');
196
169
 
197
- // Wire the verts auto-bind against THIS document. Production hands the client
198
- // singleton to _wireAds via manager.initialize(); here the preload requires
199
- // the REAL @omega.js/client (same resolution _wireFontAwesome uses) and seeds
200
- // its config directly — full initialize() is deliberately skipped (firebase,
201
- // heavy). AdSense is INTENTIONALLY configured and no inhouse source is: the
202
- // house-lane pin is exactly what must keep the provider lane (remote script)
203
- // from ever being attempted, and a source-less house render collapses
204
- // deterministically with zero network.
205
- (async () => {
206
- try {
207
- if (!testManager) return;
208
- // The client is pure ESM — Electron's preload require() can't load it
209
- // (unlike the CJS-compatible icon-renderer), so go through the Node ESM
210
- // loader. Resolves well before suites arrive from main.
211
- const wmMod = await import('@omega.js/client');
212
- testManager.omega = wmMod.default || wmMod;
213
- testManager.omega.config = Object.assign({}, testManager.omega.config, {
214
- advertising: {
215
- providers: { adsense: { client: 'ca-pub-test' } },
216
- },
217
- // The analytics bridge, INJECTED exactly the way src/renderer.js injects
218
- // it in production ([#411](https://github.com/Omega-JS-Stack/omega/issues/411)):
219
- // the preload's own analytics surface, handed over as config. The client
220
- // reads this key and nothing else — no global is involved either side.
221
- analyticsBridge: desktopSurface.analytics,
222
- });
223
- testManager._wireAds();
170
+ window.desktop = desktopSurface;
224
171
 
225
- // Analytics, BRIDGED: the real client resolves the injected bridge and
226
- // forwards every event over IPC to main's ONE sender. Same
227
- // `analytics().init()` call `manager.initialize()` makes — the rest of
228
- // initialize (firebase, auth) stays out, as everywhere else here.
229
- //
230
- // Credentials are handed in ON PURPOSE, the mistake desktop's build must
231
- // never make: a bridged renderer has to DROP them (`analytics-bridge`
232
- // renderer suite pins that it holds neither).
233
- testManager.omega.analytics().init({
234
- id: 'G-RENDERER1',
235
- secret: 'harness-renderer-secret',
236
- projectId: 'demo-app',
237
- bridge: testManager.omega._resolveAnalyticsBridge(),
238
- });
239
- } catch (e) {
240
- console.warn('[renderer-preload] Could not wire verts auto-bind:', e.message);
172
+ // The main harness hands over the renderer's absolute dist path. In its absence,
173
+ // fall back to resolve-by-name (a consumer with @omega.js/desktop in node_modules).
174
+ const rendererPath = process.env.OMEGA_TEST_RENDERER_PATH || require.resolve('@omega.js/desktop/renderer');
175
+ const rendererRequire = Module.createRequire(rendererPath);
176
+
177
+ for (const specifier of RENDERER_ESM) {
178
+ const file = rendererRequire.resolve(specifier);
179
+ if (require.cache[file]) continue;
180
+ const seated = new Module(file);
181
+ seated.filename = file;
182
+ seated.exports = await import(pathToFileURL(file).href);
183
+ seated.loaded = true;
184
+ require.cache[file] = seated;
241
185
  }
242
- })();
186
+
187
+ testOmega = require(rendererPath);
188
+
189
+ testOmega.config = {
190
+ environment: 'production',
191
+ dev: { ports: { ...require('../../vendor/config/index.js').CLASSIC_PORTS } },
192
+ brand: { url: 'https://example.com' },
193
+ cloud: { provider: 'firebase', config: { projectId: 'demo-app', authDomain: 'demo-app.firebaseapp.com' } },
194
+ advertising: {
195
+ providers: { adsense: { client: 'ca-pub-test' } },
196
+ },
197
+ analyticsBridge: desktopSurface.analytics,
198
+ };
199
+
200
+ // Wire the instance's DOM enhancements (FontAwesome auto-render, Bootstrap tooltip
201
+ // auto-init, the verts auto-bind) against THIS document. In production these run in
202
+ // the page world (the consumer's esbuild bundle); here the preload world stands in:
203
+ // the DOM is shared, so injected SVGs / tooltip tips / bound verts are visible to
204
+ // page-world test suites.
205
+ testOmega.enableFontAwesome();
206
+ testOmega._wireTooltips();
207
+ testOmega._wireAds();
208
+
209
+ // Analytics, BRIDGED: the real client resolves the injected bridge and forwards
210
+ // every event over IPC to main's ONE sender. Same `analytics.init()` call
211
+ // initialize() makes; the rest of initialize (firebase, auth) stays out.
212
+ // Credentials are handed in ON PURPOSE, the mistake desktop's build must never
213
+ // make: a bridged renderer has to DROP them (the `analytics-bridge` renderer suite
214
+ // pins that it holds neither).
215
+ testOmega.analytics.init({
216
+ id: 'G-RENDERER1',
217
+ secret: 'harness-renderer-secret',
218
+ projectId: 'demo-app',
219
+ bridge: testOmega._resolveAnalyticsBridge(),
220
+ });
221
+ }
222
+
223
+ // Settled before the page tells main it is ready, so no suite runs ahead of the instance
224
+ const instanceBuilt = buildInstance().catch((e) => {
225
+ buildError = e.stack || e.message;
226
+ console.warn('[renderer-preload] Could not build the renderer instance for tests:', e.message);
227
+ });
243
228
 
244
229
  // Page-world probe for the bridged client analytics: `event()` is the call a
245
- // renderer's own code makes (`omega.analytics().event(...)`), `state()` reads
230
+ // renderer's own code makes (`omega.analytics.event(...)`), `state()` reads
246
231
  // back what the module holds so a suite can pin that no second sender exists.
247
- contextBridge.exposeInMainWorld('__emTestClientAnalytics', {
248
- event: (name, params) => testManager?.omega?.analytics().event(name, params),
232
+ contextBridge.exposeInMainWorld('__omegaTestClientAnalytics', {
233
+ event: (name, params) => testOmega?.analytics.event(name, params),
249
234
  state: () => {
250
- const a = testManager?.omega?.analytics();
235
+ const a = testOmega?.analytics;
251
236
  return {
252
237
  initialized: Boolean(a?.initialized),
253
238
  bridged: Boolean(a?.bridge),
@@ -258,19 +243,19 @@ contextBridge.exposeInMainWorld('__emTestClientAnalytics', {
258
243
  });
259
244
 
260
245
  // Tooltip instances live in the preload world (page world can't reach the
261
- // bootstrap namespace across the contextIsolation boundary) — expose a probe so
246
+ // bootstrap namespace across the contextIsolation boundary): expose a probe so
262
247
  // page-world suites can assert instance lifecycle by element id. `error()`
263
248
  // surfaces WHY the Bootstrap bundle failed to load (renderer.js swallows the
264
249
  // require error into a logger.warn that the harness can't see).
265
- contextBridge.exposeInMainWorld('__emTestTooltip', {
266
- available: () => Boolean(testManager?.bootstrap?.Tooltip),
267
- // Lazy — by call time the DOM exists, so a require failure here is the real
250
+ contextBridge.exposeInMainWorld('__omegaTestTooltip', {
251
+ available: () => Boolean(testOmega?.bootstrap?.Tooltip),
252
+ // Lazy: by call time the DOM exists, so a require failure here is the real
268
253
  // reason the bundle can't load (not just "no documentElement yet").
269
254
  error: () => {
270
255
  try {
271
- if (process.env.OMEGA_TEST_RENDERER_MANAGER_PATH) {
256
+ if (process.env.OMEGA_TEST_RENDERER_PATH) {
272
257
  const path = require('path');
273
- require(path.join(path.dirname(process.env.OMEGA_TEST_RENDERER_MANAGER_PATH), 'assets', 'js', 'bootstrap.bundle.js'));
258
+ require(path.join(path.dirname(process.env.OMEGA_TEST_RENDERER_PATH), 'assets', 'js', 'bootstrap.bundle.js'));
274
259
  }
275
260
  return null;
276
261
  } catch (e) {
@@ -279,16 +264,16 @@ contextBridge.exposeInMainWorld('__emTestTooltip', {
279
264
  },
280
265
  hasInstance: (id) => {
281
266
  const el = document.getElementById(id);
282
- return Boolean(el && testManager?.bootstrap?.Tooltip?.getInstance(el));
267
+ return Boolean(el && testOmega?.bootstrap?.Tooltip?.getInstance(el));
283
268
  },
284
269
  // Show the tooltip from the PRELOAD world. Synthetic mouse events dispatched
285
270
  // by page-world test code don't cross the contextIsolation boundary to the
286
271
  // preload world's Bootstrap listeners, so hover can't be simulated from a
287
- // suite — real single-world hover behavior is covered by consumer boot
272
+ // suite; real single-world hover behavior is covered by consumer boot
288
273
  // suites. Returns true or the error message.
289
274
  showDirect: (id) => {
290
275
  try {
291
- testManager.bootstrap.Tooltip.getOrCreateInstance(document.getElementById(id)).show();
276
+ testOmega.bootstrap.Tooltip.getOrCreateInstance(document.getElementById(id)).show();
292
277
  return true;
293
278
  } catch (e) {
294
279
  return e.message;
@@ -296,20 +281,31 @@ contextBridge.exposeInMainWorld('__emTestTooltip', {
296
281
  },
297
282
  });
298
283
 
299
- contextBridge.exposeInMainWorld('__emTestManager', {
300
- isDevelopment: () => testManager?.isDevelopment(),
301
- isProduction: () => testManager?.isProduction(),
302
- isTesting: () => testManager?.isTesting(),
303
- getVersion: () => testManager?.getVersion(),
304
- getEnvironment: () => testManager?.getEnvironment(),
305
- getApiUrl: (env) => testManager?.getApiUrl(env),
306
- getFunctionsUrl:(env) => testManager?.getFunctionsUrl(env),
307
- getWebsiteUrl: (env) => testManager?.getWebsiteUrl(env),
284
+ // The instance's own surface, for the page world: the environment helpers, the URL
285
+ // helpers, and what `omega.desktop` is. Each is forwarded as a sync contextBridge
286
+ // function.
287
+ contextBridge.exposeInMainWorld('__omegaTestInstance', {
288
+ built: () => Boolean(testOmega),
289
+ // WHY the instance did not build (the console.warn above lands where the runner can't see it)
290
+ error: () => buildError,
291
+ isDevelopment: () => testOmega?.isDevelopment(),
292
+ isProduction: () => testOmega?.isProduction(),
293
+ isTesting: () => testOmega?.isTesting(),
294
+ getVersion: () => testOmega?.getVersion(),
295
+ getEnvironment: () => testOmega?.getEnvironment(),
296
+ getApiUrl: (env) => testOmega?.getApiUrl(env),
297
+ getFunctionsUrl:(env) => testOmega?.getFunctionsUrl(env),
298
+ getWebsiteUrl: (env) => testOmega?.getWebsiteUrl(env),
299
+ // `omega.desktop` IS the preload's bridge object, under main's names
300
+ desktopIsBridge: () => Boolean(testOmega) && testOmega.desktop === window.desktop,
301
+ desktopKeys: () => (testOmega ? Object.keys(testOmega.desktop).sort() : []),
302
+ // The client's page store stays `omega.storage`; the app store is `omega.desktop.storage`
303
+ storageIsPageStore: () => Boolean(testOmega) && testOmega.storage !== testOmega.desktop.storage,
308
304
  // Mutator used by tests to flip config flags between assertions.
309
305
  setConfig: (path, value) => {
310
- if (!testManager) return;
306
+ if (!testOmega) return;
311
307
  const parts = path.split('.');
312
- let obj = testManager.config;
308
+ let obj = testOmega.config;
313
309
  for (let i = 0; i < parts.length - 1; i++) {
314
310
  obj[parts[i]] = obj[parts[i]] || {};
315
311
  obj = obj[parts[i]];
@@ -8,14 +8,14 @@
8
8
  // description: 'config has brand.id',
9
9
  // timeout: 5000,
10
10
  // run: async (ctx) => {
11
- // const cfg = Manager.getConfig();
11
+ // const cfg = require('../build.js').getConfig();
12
12
  // ctx.expect(cfg.brand.id).toBeTruthy();
13
13
  // },
14
14
  // cleanup: async (ctx) => { ... },
15
15
  // };
16
16
  //
17
17
  // Boot layer — spawns the consumer's actual built main bundle (dist/main.bundle.js)
18
- // and runs `inspect` against the live manager. Replaces shell-level `npm start && sleep && kill`
18
+ // and runs `inspect` against the live omega instance. Replaces shell-level `npm start && sleep && kill`
19
19
  // smoke tests with deterministic, signal-driven pass/fail. Use this to verify the WHOLE
20
20
  // integration: consumer scaffolds, brand config, custom integrations, real boot order.
21
21
  //
@@ -23,10 +23,10 @@
23
23
  // layer: 'boot',
24
24
  // description: 'tray boots with default items',
25
25
  // timeout: 15000,
26
- // inspect: async ({ manager, expect, projectRoot }) => {
27
- // expect(manager.tray.has('open')).toBe(true);
28
- // expect(manager.tray.has('check-for-updates')).toBe(true);
29
- // expect(manager.menu.isRendered()).toBe(true);
26
+ // inspect: async ({ omega, expect, projectRoot }) => {
27
+ // expect(omega.tray.has('open')).toBe(true);
28
+ // expect(omega.tray.has('check-for-updates')).toBe(true);
29
+ // expect(omega.menu.isRendered()).toBe(true);
30
30
  // },
31
31
  // };
32
32
  //
@@ -36,9 +36,9 @@
36
36
  // layer: 'main',
37
37
  // description: 'storage round-trip',
38
38
  // tests: [
39
- // { name: 'set value', run: async (ctx) => { ctx.state.key = 'foo'; ctx.manager.storage.set('foo', 'bar'); } },
40
- // { name: 'get value', run: async (ctx) => { ctx.expect(ctx.manager.storage.get('foo')).toBe('bar'); } },
41
- // { name: 'delete', run: async (ctx) => { ctx.manager.storage.delete('foo'); } },
39
+ // { name: 'set value', run: async (ctx) => { ctx.state.key = 'foo'; ctx.omega.storage.set('foo', 'bar'); } },
40
+ // { name: 'get value', run: async (ctx) => { ctx.expect(ctx.omega.storage.get('foo')).toBe('bar'); } },
41
+ // { name: 'delete', run: async (ctx) => { ctx.omega.storage.delete('foo'); } },
42
42
  // ],
43
43
  // };
44
44
  //
@@ -57,7 +57,7 @@
57
57
  // - ctx.state — shared object across tests in a suite/group
58
58
  // - ctx.skip(reason) — throw to skip the current test at runtime
59
59
  // - ctx.layer — current layer name
60
- // - ctx.manager — @omega.js/desktop Manager instance (main layer only — added in 2.3b)
60
+ // - ctx.omega : the booted @omega.js/desktop main-process instance (main layer only)
61
61
  // - ctx.page — BrowserWindow page (renderer layer only — added in 2.3c)
62
62
 
63
63
  module.exports = {
@@ -9,7 +9,7 @@
9
9
  // - 'build' runs in plain Node (runner core).
10
10
  // - 'main' spawns Electron via runners/electron.js, runs in the main process.
11
11
  // - 'renderer' runs in a hidden BrowserWindow in the same spawned Electron process.
12
- // - 'boot' spawns the consumer's actual built bundle and inspects the live manager.
12
+ // - 'boot' spawns the consumer's actual built bundle and inspects the live omega instance.
13
13
  //
14
14
  // Electron / boot runners are lazy-loaded so a missing electron doesn't prevent build-layer
15
15
  // tests from running. The layer callbacks below require() them only when those layers exist.
@@ -68,7 +68,7 @@ const runner = createRunner({
68
68
  ],
69
69
 
70
70
  boot: {
71
- // Spawn the consumer's actual built bundle and inspect the live manager (the core
71
+ // Spawn the consumer's actual built bundle and inspect the live omega instance (the core
72
72
  // aggregates boot tests into the flat `tests` list). `suites` are the boot-bound
73
73
  // renderer suites (`view: '<name>'`), which run in a real window of that same app.
74
74
  run: async ({ tests, suites, results, projectRoot }) => {
@@ -1,5 +1,5 @@
1
1
  // Boot-runner — spawns electron with the consumer's actual built main bundle, runs
2
- // inspect functions against the live manager, then quits cleanly.
2
+ // inspect functions against the live omega instance, then quits cleanly.
3
3
  //
4
4
  // Differences from runners/electron.js:
5
5
  // - electron.js spawns electron with `harness/main-entry.js` and tests @omega.js/desktop lib code in isolation.
@@ -27,6 +27,7 @@ const { spawn, spawnSync } = require('child_process');
27
27
  const chalk = require('chalk').default;
28
28
  const distSnapshot = require('../utils/dist-snapshot.js');
29
29
  const { renderEvent } = require('./render-event.js');
30
+ const { TEST_EVENT_PREFIX } = require('../../utils/test-events.js');
30
31
 
31
32
  // How long a booted app gets to say anything at all before the run is declared
32
33
  // failed. Generous: the app under test is the consumer's real one, cold.
@@ -44,8 +45,8 @@ async function runBootTests({ tests, suites, projectRoot, frameworkDistRoot }) {
44
45
 
45
46
  // OMEGA_TEST_BOOT_PROJECT — boot a different project root than the CWD. Auto-set to the
46
47
  // bundled fixture when @omega.js/desktop self-tests (see commands/test.js); set it explicitly to boot a
47
- // real consumer (e.g. deployment-playground-desktop) without cd-ing into it. Mirrors
48
- // BXM's OMEGA_TEST_BOOT_PROJECT / UJM's UJ_TEST_BOOT_PROJECT.
48
+ // real consumer (e.g. deployment-playground-desktop) without cd-ing into it. The
49
+ // same switch every framework's boot runner reads.
49
50
  const effectiveRoot = process.env.OMEGA_TEST_BOOT_PROJECT
50
51
  ? path.resolve(process.env.OMEGA_TEST_BOOT_PROJECT)
51
52
  : projectRoot;
@@ -147,7 +148,7 @@ async function bootProject({ tests, suites, effectiveRoot, frameworkDistRoot })
147
148
 
148
149
  const bootEntry = path.join(frameworkDistRoot, 'test', 'harness', 'boot-entry.js');
149
150
 
150
- // Tell the consumer's main.js to publish the manager + run the boot harness.
151
+ // Tell the consumer's main.js to publish the instance + run the boot harness.
151
152
  // Three env vars are picked up by @omega.js/desktop's main.js after init completes:
152
153
  // OMEGA_TEST_BOOT — gate; "1" turns on harness loading
153
154
  // OMEGA_TEST_BOOT_HARNESS — absolute path to harness module (resolved here so it works
@@ -232,9 +233,9 @@ function runBootChild({ electronBin, args, childEnv, effectiveRoot, specFile, sk
232
233
  while ((nl = buffer.indexOf('\n')) >= 0) {
233
234
  const line = buffer.slice(0, nl);
234
235
  buffer = buffer.slice(nl + 1);
235
- if (line.startsWith('__EM_TEST__')) {
236
+ if (line.startsWith(TEST_EVENT_PREFIX)) {
236
237
  armBudget();
237
- renderEvent(JSON.parse(line.slice('__EM_TEST__'.length)), counts);
238
+ renderEvent(JSON.parse(line.slice(TEST_EVENT_PREFIX.length)), counts);
238
239
  } else if (process.env.OMEGA_TEST_DEBUG && line.trim().length > 0) {
239
240
  process.stdout.write(chalk.gray(` ${line}\n`));
240
241
  }
@@ -5,6 +5,7 @@ const path = require('path');
5
5
  const { spawn } = require('child_process');
6
6
  const chalk = require('chalk').default;
7
7
  const { renderEvent } = require('./render-event.js');
8
+ const { TEST_EVENT_PREFIX } = require('../../utils/test-events.js');
8
9
 
9
10
  function runElectronTests({ harnessEntry, suiteFiles, rendererSuiteFiles, filter, projectRoot }) {
10
11
  rendererSuiteFiles = rendererSuiteFiles || [];
@@ -59,8 +60,8 @@ function runElectronTests({ harnessEntry, suiteFiles, rendererSuiteFiles, filter
59
60
  while ((nl = buffer.indexOf('\n')) >= 0) {
60
61
  const line = buffer.slice(0, nl);
61
62
  buffer = buffer.slice(nl + 1);
62
- if (line.startsWith('__EM_TEST__')) {
63
- renderEvent(JSON.parse(line.slice('__EM_TEST__'.length)), counts);
63
+ if (line.startsWith(TEST_EVENT_PREFIX)) {
64
+ renderEvent(JSON.parse(line.slice(TEST_EVENT_PREFIX.length)), counts);
64
65
  } else if (line.trim().length > 0) {
65
66
  // Pass-through other electron stdout (logger lines from @omega.js/desktop init, etc.)
66
67
  // Indent so they don't disrupt the layout.
@@ -1,4 +1,4 @@
1
- // Harness-event rendering: the ONE home of "what a `__EM_TEST__` envelope looks like on
1
+ // Harness-event rendering: the ONE home of "what a `__OMEGA_TEST__` envelope looks like on
2
2
  // screen" and of the counts it folds into.
3
3
  //
4
4
  // Both runners parse the same JSON-line protocol (runners/electron.js from the spawned
@@ -10,7 +10,7 @@ const chalk = require('chalk').default;
10
10
 
11
11
  /**
12
12
  * Render one harness event and fold it into the run's counts.
13
- * @param {object} evt - A parsed `__EM_TEST__` envelope from a harness.
13
+ * @param {object} evt - A parsed `__OMEGA_TEST__` envelope from a harness.
14
14
  * @param {object} counts - `{ passed, failed, skipped }`, mutated in place.
15
15
  * @returns {void}
16
16
  */