@omega.js/desktop 0.51.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 (289) hide show
  1. package/README.md +18 -13
  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 +145 -48
  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/.github/workflows/build.yml +2 -0
  48. package/dist/defaults/AGENTS.md +17 -8
  49. package/dist/defaults/config/omega.json5 +7 -7
  50. package/dist/defaults/hooks/build/post.js +1 -1
  51. package/dist/defaults/hooks/build/pre.js +1 -1
  52. package/dist/defaults/hooks/deploy/pre.js +1 -1
  53. package/dist/defaults/hooks/release/post.js +1 -1
  54. package/dist/defaults/hooks/release/pre.js +1 -1
  55. package/dist/defaults/src/assets/js/components/about/index.js +3 -5
  56. package/dist/defaults/src/assets/js/components/main/index.js +3 -5
  57. package/dist/defaults/src/assets/js/components/settings/index.js +3 -5
  58. package/dist/defaults/src/integrations/context-menu/index.js +2 -2
  59. package/dist/defaults/src/integrations/menu/index.js +3 -3
  60. package/dist/defaults/src/integrations/tray/index.js +3 -3
  61. package/dist/defaults/src/main.js +3 -5
  62. package/dist/defaults/src/preload.js +3 -5
  63. package/dist/defaults/test/README.md +2 -2
  64. package/dist/gulp/main.js +9 -10
  65. package/dist/gulp/tasks/audit.js +7 -7
  66. package/dist/gulp/tasks/build-config.js +8 -8
  67. package/dist/gulp/tasks/bundle.js +16 -16
  68. package/dist/gulp/tasks/defaults.js +3 -3
  69. package/dist/gulp/tasks/distribute.js +2 -2
  70. package/dist/gulp/tasks/html.js +9 -9
  71. package/dist/gulp/tasks/package-quick.js +3 -3
  72. package/dist/gulp/tasks/package.js +3 -3
  73. package/dist/gulp/tasks/release.js +3 -3
  74. package/dist/gulp/tasks/sass.js +6 -6
  75. package/dist/gulp/tasks/serve.js +4 -4
  76. package/dist/hooks/notarize-artifacts.js +1 -1
  77. package/dist/hooks/notarize.js +1 -1
  78. package/dist/index.js +5 -8
  79. package/dist/lib/_environment-mixin.js +50 -0
  80. package/dist/lib/_lifecycle-mixin.js +45 -0
  81. package/dist/lib/analytics.js +33 -35
  82. package/dist/lib/app-state.js +14 -14
  83. package/dist/lib/auth-flow.js +18 -18
  84. package/dist/lib/auth-persistence.js +12 -12
  85. package/dist/lib/auth.js +421 -0
  86. package/dist/lib/auto-updater.js +49 -49
  87. package/dist/lib/context-menu.js +13 -13
  88. package/dist/lib/context.js +19 -19
  89. package/dist/lib/deep-link.js +34 -34
  90. package/dist/lib/fontawesome.js +5 -5
  91. package/dist/lib/ipc.js +4 -4
  92. package/dist/lib/menu.js +25 -25
  93. package/dist/lib/protocol.js +5 -5
  94. package/dist/lib/remote-config.js +22 -22
  95. package/dist/lib/remote-scripts.js +21 -21
  96. package/dist/lib/restart-manager/index.js +28 -28
  97. package/dist/lib/sign-helpers/exec-with-limit.js +1 -1
  98. package/dist/lib/sign-helpers/sign-events.js +1 -1
  99. package/dist/lib/startup.js +18 -13
  100. package/dist/lib/storage.js +10 -10
  101. package/dist/lib/templating.js +16 -16
  102. package/dist/lib/theme.js +10 -10
  103. package/dist/lib/tray.js +27 -27
  104. package/dist/lib/usage.js +11 -11
  105. package/dist/lib/window-manager.js +26 -26
  106. package/dist/main.js +398 -483
  107. package/dist/preload.js +236 -176
  108. package/dist/renderer.js +417 -391
  109. package/dist/runner/job-started.js +1 -1
  110. package/dist/test/fixtures/consumer-app/config/omega.json5 +1 -1
  111. package/dist/test/fixtures/consumer-app/src/assets/js/components/main/index.js +8 -11
  112. package/dist/test/fixtures/consumer-app/src/main.js +5 -7
  113. package/dist/test/fixtures/consumer-app/src/preload.js +2 -2
  114. package/dist/test/harness/boot-entry.js +22 -20
  115. package/dist/test/harness/main-entry.js +31 -30
  116. package/dist/test/harness/renderer-entry.js +5 -5
  117. package/dist/test/harness/renderer-preload.js +137 -141
  118. package/dist/test/index.js +10 -10
  119. package/dist/test/runner.js +2 -2
  120. package/dist/test/runners/boot.js +7 -6
  121. package/dist/test/runners/electron.js +3 -2
  122. package/dist/test/runners/render-event.js +2 -2
  123. package/dist/test/suites/boot/consumer-app-boots.test.js +57 -26
  124. package/dist/test/suites/boot/restart-manager.test.js +2 -2
  125. package/dist/test/suites/boot/storage-bundled.test.js +5 -5
  126. package/dist/test/suites/boot/theme.test.js +13 -13
  127. package/dist/test/suites/build/audit.test.js +1 -1
  128. package/dist/test/suites/build/auth-persistence-resolve.test.js +6 -6
  129. package/dist/test/suites/build/boot-fixture.test.js +2 -2
  130. package/dist/test/suites/build/boot-runner-timeout.test.js +6 -5
  131. package/dist/test/suites/build/brand-scss.test.js +1 -1
  132. package/dist/test/suites/build/build-json-bake.test.js +1 -1
  133. package/dist/test/suites/build/cli.test.js +2 -2
  134. package/dist/test/suites/build/config-schema.test.js +5 -5
  135. package/dist/test/suites/build/defaults-scaffold.test.js +2 -2
  136. package/dist/test/suites/build/deploy-hook.test.js +3 -3
  137. package/dist/test/suites/build/ensure-target.test.js +2 -2
  138. package/dist/test/suites/build/env-delivery.test.js +2 -2
  139. package/dist/test/suites/build/esm-only-dependency.test.js +2 -2
  140. package/dist/test/suites/build/exports.test.js +9 -8
  141. package/dist/test/suites/build/get-config.test.js +4 -4
  142. package/dist/test/suites/build/manifest-deps.test.js +1 -1
  143. package/dist/test/suites/build/merge-line-files.test.js +1 -1
  144. package/dist/test/suites/build/omega-shell.test.js +34 -2
  145. package/dist/test/suites/build/omega.test.js +350 -0
  146. package/dist/test/suites/build/renderer-auth-bridge.test.js +211 -78
  147. package/dist/test/suites/build/runner.test.js +612 -5
  148. package/dist/test/suites/build/sentry.test.js +2 -2
  149. package/dist/test/suites/build/sign-windows-e2e.test.js +2 -2
  150. package/dist/test/suites/build/templating.test.js +3 -3
  151. package/dist/test/suites/build/test-stealth.test.js +7 -9
  152. package/dist/test/suites/build/url-helpers.test.js +55 -56
  153. package/dist/test/suites/build/validate-config.test.js +2 -2
  154. package/dist/test/suites/build/wave5-pins.test.js +2 -2
  155. package/dist/test/suites/main/analytics.test.js +59 -59
  156. package/dist/test/suites/main/app-state.test.js +66 -66
  157. package/dist/test/suites/main/auth-flow.test.js +41 -41
  158. package/dist/test/suites/main/auth-persistence.test.js +54 -43
  159. package/dist/test/suites/main/{client-bridge.integration.test.js → auth.integration.test.js} +10 -9
  160. package/dist/test/suites/main/auth.test.js +336 -0
  161. package/dist/test/suites/main/auto-updater.test.js +134 -134
  162. package/dist/test/suites/main/boot-sequence.test.js +37 -49
  163. package/dist/test/suites/main/context-menu.test.js +51 -50
  164. package/dist/test/suites/main/context.test.js +25 -25
  165. package/dist/test/suites/main/deep-link.test.js +74 -74
  166. package/dist/test/suites/main/fontawesome.test.js +27 -27
  167. package/dist/test/suites/main/ipc.test.js +35 -35
  168. package/dist/test/suites/main/menu.test.js +101 -100
  169. package/dist/test/suites/main/protocol.test.js +19 -19
  170. package/dist/test/suites/main/remote-config.test.js +63 -63
  171. package/dist/test/suites/main/remote-scripts.test.js +103 -103
  172. package/dist/test/suites/main/request.test.js +71 -0
  173. package/dist/test/suites/main/restart-manager.test.js +33 -33
  174. package/dist/test/suites/main/startup-paths-and-ua.test.js +4 -4
  175. package/dist/test/suites/main/startup.test.js +26 -26
  176. package/dist/test/suites/main/stealth-window.test.js +1 -1
  177. package/dist/test/suites/main/storage.test.js +25 -25
  178. package/dist/test/suites/main/theme.test.js +34 -34
  179. package/dist/test/suites/main/tray.test.js +79 -79
  180. package/dist/test/suites/main/url-helpers.test.js +133 -133
  181. package/dist/test/suites/main/usage.test.js +25 -25
  182. package/dist/test/suites/main/window-bounds.test.js +27 -27
  183. package/dist/test/suites/main/window-manager.test.js +44 -44
  184. package/dist/test/suites/renderer/analytics-bridge.test.js +5 -5
  185. package/dist/test/suites/renderer/cross-context-helpers.test.js +37 -31
  186. package/dist/test/suites/renderer/round-trip.test.js +3 -3
  187. package/dist/test/suites/renderer/tooltips.test.js +15 -15
  188. package/dist/test/suites/renderer/{window-em-surface.test.js → window-desktop-surface.test.js} +27 -7
  189. package/dist/test/utils/extended-mode-warning.js +1 -1
  190. package/dist/utils/boot-harness.js +56 -0
  191. package/dist/utils/mode-helpers.js +2 -15
  192. package/dist/utils/ship-keys.js +3 -3
  193. package/dist/utils/signing-status.js +51 -0
  194. package/dist/utils/test-events.js +7 -0
  195. package/dist/utils/test-stealth.js +6 -6
  196. package/dist/utils/url-helpers.js +52 -42
  197. package/dist/utils/user-agent.js +44 -0
  198. package/dist/vendor/account/engine.js +3 -3
  199. package/dist/vendor/account/index.js +14 -45
  200. package/dist/vendor/account/resolve-account.js +44 -0
  201. package/dist/vendor/account/schema.js +1 -1
  202. package/dist/vendor/account/user.js +99 -0
  203. package/dist/vendor/config/client-config.js +1 -1
  204. package/dist/vendor/config/environment.js +11 -30
  205. package/dist/vendor/config/index.js +13 -12
  206. package/dist/vendor/config/load.js +1 -2
  207. package/dist/vendor/config/platforms.js +1 -1
  208. package/dist/vendor/config/repo.js +24 -0
  209. package/dist/vendor/config/retired-keys.js +2 -2
  210. package/dist/vendor/config/schema.js +5 -8
  211. package/dist/vendor/config/site-global.js +2 -3
  212. package/dist/vendor/config/validate.js +1 -2
  213. package/dist/vendor/config/winback.js +1 -1
  214. package/dist/vendor/devkit/actions-secrets.js +1 -1
  215. package/dist/vendor/devkit/attach-log-file.js +1 -1
  216. package/dist/vendor/devkit/brand-version.js +162 -1
  217. package/dist/vendor/devkit/build-json.js +1 -1
  218. package/dist/vendor/devkit/cli-router.js +3 -4
  219. package/dist/vendor/devkit/defaults-engine.js +9 -11
  220. package/dist/vendor/devkit/deploy.js +64 -4
  221. package/dist/vendor/devkit/git-remote.js +78 -1
  222. package/dist/vendor/devkit/local.js +53 -3
  223. package/dist/vendor/devkit/lockfile.js +127 -0
  224. package/dist/vendor/devkit/merge-line-files.js +2 -3
  225. package/dist/vendor/devkit/pack-local.js +4 -7
  226. package/dist/vendor/devkit/preludes/origin-heal.js +35 -49
  227. package/dist/vendor/devkit/target-secrets.js +34 -45
  228. package/dist/vendor/devkit/test/runner-core.js +6 -6
  229. package/dist/vendor/monitoring/env.js +2 -2
  230. package/dist/vendor/monitoring/index.js +1 -1
  231. package/dist/vendor/monitoring/main.js +1 -1
  232. package/dist/vendor/monitoring/preload.js +1 -1
  233. package/dist/vendor/monitoring/renderer.js +1 -1
  234. package/docs/analytics.md +8 -8
  235. package/docs/app-state.md +19 -19
  236. package/docs/audit.md +4 -4
  237. package/docs/{client-bridge.md → auth.md} +88 -73
  238. package/docs/auto-updater.md +8 -8
  239. package/docs/boot-sequence.md +11 -6
  240. package/docs/build-system.md +1 -1
  241. package/docs/cdp-debugging.md +1 -1
  242. package/docs/common-mistakes.md +7 -7
  243. package/docs/config-schema.md +1 -1
  244. package/docs/context-menu.md +13 -13
  245. package/docs/context.md +11 -11
  246. package/docs/css.md +3 -9
  247. package/docs/deep-link.md +25 -25
  248. package/docs/environment-detection.md +16 -16
  249. package/docs/fontawesome.md +7 -5
  250. package/docs/hooks.md +8 -8
  251. package/docs/index.md +39 -28
  252. package/docs/ipc.md +10 -10
  253. package/docs/lib-modules.md +9 -9
  254. package/docs/logging.md +12 -14
  255. package/docs/menu.md +18 -18
  256. package/docs/releasing.md +4 -2
  257. package/docs/remote-config.md +9 -9
  258. package/docs/remote-scripts.md +12 -12
  259. package/docs/restart-manager.md +8 -8
  260. package/docs/runner.md +12 -10
  261. package/docs/sentry.md +4 -4
  262. package/docs/shared/analytics.md +1 -1
  263. package/docs/shared/brands.md +1 -1
  264. package/docs/shared/breaking-changes.md +79 -13
  265. package/docs/shared/config.md +24 -21
  266. package/docs/shared/deploys.md +30 -7
  267. package/docs/shared/local-dev.md +5 -3
  268. package/docs/shared/logging.md +1 -1
  269. package/docs/shared/monitoring.md +5 -5
  270. package/docs/shared/testing.md +2 -2
  271. package/docs/shared/theming.md +1 -1
  272. package/docs/shared/translation.md +19 -10
  273. package/docs/signing.md +1 -1
  274. package/docs/startup.md +16 -16
  275. package/docs/storage.md +11 -11
  276. package/docs/templating.md +3 -3
  277. package/docs/test-boot-layer.md +12 -12
  278. package/docs/test-framework.md +17 -17
  279. package/docs/themes.md +7 -7
  280. package/docs/tooltips.md +2 -2
  281. package/docs/tray.md +31 -31
  282. package/docs/usage.md +7 -7
  283. package/docs/verts.md +1 -1
  284. package/docs/windows.md +22 -22
  285. package/package.json +3 -4
  286. package/dist/lib/client-bridge.js +0 -374
  287. package/dist/lib/logger.js +0 -4
  288. package/dist/test/suites/build/manager.test.js +0 -213
  289. package/dist/test/suites/main/client-bridge.test.js +0 -262
@@ -0,0 +1,127 @@
1
+ /**
2
+ * lockfile: regenerate an install root's OWN package-lock.json
3
+ * ([#938](https://github.com/Omega-JS-Stack/omega/issues/938)).
4
+ *
5
+ * ONE helper for its three callers: the pack step (`pack-local`, the staged
6
+ * shape), `omega i local` (`linkLocalPackages`) and `omega i live`
7
+ * (`restoreRegistrySpecs`).
8
+ *
9
+ * Two things a plain `npm install` gets wrong here, and this answers both:
10
+ * - `--prefix` makes npm treat `root` as the install root. Without it, npm in
11
+ * a directory that is itself a WORKSPACE of an outer root (every in-repo
12
+ * brand, under the omega monorepo's `brands/*`) climbs to that outer root
13
+ * and writes ITS lockfile, leaving the brand's own untouched.
14
+ * - npm KEEPS a locked link whose target's version satisfies a registry spec,
15
+ * so a lock from the local era (`link: true` into a checkout already at the
16
+ * published number) would survive the flip. Every @omega.js entry the
17
+ * deploy gate would refuse (`brandLockfileDrift`) is dropped first, with its
18
+ * link target, so npm resolves those afresh and keeps every other pin.
19
+ * - npm also honors a STALE path entry, a folder the lock names that is no
20
+ * longer on disk (a renamed target), and re-creates whatever link its
21
+ * dependencies declare. Those entries go first, with everything under them
22
+ * and every `node_modules/` link pointing into them.
23
+ *
24
+ * Transactional: a failed npm run writes the lock back byte for byte.
25
+ */
26
+ const fs = require('fs');
27
+ const path = require('path');
28
+ const jetpack = require('fs-jetpack');
29
+
30
+ const { safeInstall } = require('./safe-install.js');
31
+ const { brandLockfileDrift, staleLockPaths } = require('./brand-version.js');
32
+
33
+ /** A path equal to base, or nested beneath it. */
34
+ const under = (value, base) => value === base || value.startsWith(`${base}/`);
35
+
36
+ /**
37
+ * Drop every stale path entry (`staleLockPaths`), everything nested under it,
38
+ * and every `node_modules/` entry whose `resolved` points into it.
39
+ *
40
+ * @param {object} lock - The parsed lock (mutated).
41
+ * @param {string} root - The install root the keys are relative to.
42
+ * @returns {string[]} The stale paths dropped (the outermost of each tree).
43
+ */
44
+ function dropStalePaths(lock, root) {
45
+ const stale = staleLockPaths({ root, packages: lock.packages });
46
+ const outermost = stale.filter((key) => !stale.some((other) => other !== key && under(key, other)));
47
+
48
+ for (const [key, entry] of Object.entries(lock.packages)) {
49
+ const pointsInto = entry && typeof entry.resolved === 'string' && outermost.some((base) => under(entry.resolved, base));
50
+ if (outermost.some((base) => under(key, base)) || pointsInto) delete lock.packages[key];
51
+ }
52
+
53
+ return outermost;
54
+ }
55
+
56
+ /**
57
+ * Drop every lock entry `drift` names, plus a dropped link's target entry and
58
+ * everything nested under it (the checkout's own dependencies).
59
+ *
60
+ * @param {object} lock - The parsed lock (mutated).
61
+ * @param {Array<{ key: string|null, entry: object|undefined }>} drift - What the gate refused.
62
+ * @returns {string[]} The names whose entries were dropped.
63
+ */
64
+ function dropDrift(lock, drift) {
65
+ const dropped = [];
66
+
67
+ for (const { name, key, entry } of drift) {
68
+ // An absent entry has nothing to drop (npm adds it from the manifest), and
69
+ // one inside a stale path is already gone with it.
70
+ if (!key || !lock.packages[key]) continue;
71
+
72
+ delete lock.packages[key];
73
+ dropped.push(name);
74
+
75
+ if (entry.link && entry.resolved) {
76
+ for (const other of Object.keys(lock.packages)) {
77
+ if (under(other, entry.resolved)) delete lock.packages[other];
78
+ }
79
+ }
80
+ }
81
+
82
+ return dropped;
83
+ }
84
+
85
+ /**
86
+ * Regenerate `root`'s package-lock.json from its manifests, lock-only: no
87
+ * scripts, no node_modules writes.
88
+ *
89
+ * @param {object} options
90
+ * @param {string} options.root - The install root whose lock is regenerated.
91
+ * @param {function} [options.log] - Line sink (silent when omitted).
92
+ * @returns {Promise<void>}
93
+ */
94
+ async function regenerateLockfile({ root, log }) {
95
+ const { lockPath, lock, drift } = brandLockfileDrift({ root });
96
+ const original = lock ? jetpack.read(lockPath) : null;
97
+
98
+ if (lock && lock.packages) {
99
+ const pruned = dropStalePaths(lock, root);
100
+ const dropped = dropDrift(lock, drift);
101
+
102
+ if (pruned.length || dropped.length) {
103
+ jetpack.write(lockPath, `${JSON.stringify(lock, null, 2)}\n`);
104
+ }
105
+ if (log && pruned.length) log(`Pruned the lock entries of folders no longer on disk (${pruned.join(', ')}) so npm stops honoring what they declare`);
106
+ if (log && dropped.length) log(`Dropped the stale lock entries of ${dropped.join(', ')} so npm resolves them from the manifests`);
107
+ }
108
+
109
+ if (log) log(`Regenerating ${path.basename(root)}/package-lock.json...`);
110
+
111
+ // The REAL path: npm writes a link's `resolved` relative to the physical
112
+ // directory, so a prefix spelled through an alias (macOS /var for
113
+ // /private/var, a symlinked brand dir) reads those paths from the wrong place.
114
+ const prefix = fs.realpathSync(root);
115
+
116
+ try {
117
+ await safeInstall(
118
+ `npm install --package-lock-only --ignore-scripts --no-audit --no-fund --prefix "${prefix}"`,
119
+ { log: false, config: { cwd: prefix } },
120
+ );
121
+ } catch (error) {
122
+ if (original !== null) jetpack.write(lockPath, original);
123
+ throw error;
124
+ }
125
+ }
126
+
127
+ module.exports = { regenerateLockfile };
@@ -1,7 +1,6 @@
1
1
  // Merge line-based files (.env, .gitignore, AGENTS.md) during framework setup —
2
- // the OMEGA marker-section protocol. Canonical version is EM's (it added .env
3
- // double-quote normalization and order-safe key substitution over the older
4
- // BXM/UJM inline copies) plus @omega.js/backend's custom-key promotion (a key the framework
2
+ // the OMEGA marker-section protocol: .env double-quote normalization,
3
+ // order-safe key substitution, and custom-key promotion (a key the framework
5
4
  // newly adopts into its Default section is promoted UP from the user's Custom
6
5
  // section with their value, instead of appearing empty in Default and set in
7
6
  // Custom).
@@ -47,6 +47,7 @@ const path = require('path');
47
47
  const jetpack = require('fs-jetpack');
48
48
  const powertools = require('node-powertools');
49
49
  const chalk = require('chalk').default;
50
+ const { regenerateLockfile } = require('./lockfile.js');
50
51
 
51
52
  // Constants
52
53
  const STAGING_DIR = 'omega_modules';
@@ -369,15 +370,11 @@ async function stageLocalPackages({ dir, log = () => {} }) {
369
370
  }
370
371
 
371
372
  // A remote install runs `npm ci`, so the uploaded lockfile must match the
372
- // staged shape. `--prefix` is what makes npm treat THIS dir as the install
373
- // root: run inside a workspace it would otherwise climb to the workspace
374
- // root and write that one's lockfile instead.
373
+ // staged shape, regenerated from scratch (the one helper keeps it THIS
374
+ // dir's lock, never an enclosing workspace root's).
375
375
  log(` ${chalk.dim('→')} Regenerating package-lock.json for the staged shape...`);
376
376
  jetpack.remove(lockPath);
377
- await powertools.execute(
378
- `npm install --package-lock-only --ignore-scripts --no-audit --no-fund --prefix "${root}"`,
379
- { log: false, config: { cwd: root } },
380
- );
377
+ await regenerateLockfile({ root });
381
378
  } catch (error) {
382
379
  // Loud and clean: the deploy stops here, and the tree goes back exactly as
383
380
  // it was rather than sitting half-staged.
@@ -32,21 +32,22 @@
32
32
  * - anything else: the remote is rewritten to the answered `full_name`,
33
33
  * keeping its own url form, and the heal is stated in one line.
34
34
  *
35
- * Then DRIFT, on whatever the answer was: `repo.org` stays the one typed value
36
- * in `config/omega.json5`, and an owner GitHub reports that differs from it is
37
- * stated in one line and nothing more. The prelude never writes config: which
38
- * of the two is wrong (the config, or where the repo lives) is a human's call,
39
- * and the manager's repo service only ensures repos UNDER `repo.org`.
35
+ * Then DRIFT, on whatever the answer was: the WHOLE slug GitHub answers against
36
+ * the source repo the config derives (`@omega.js/config`'s `repoDrift`, so a
37
+ * rename drifts as surely as a transfer,
38
+ * [#934](https://github.com/Omega-JS-Stack/omega/issues/934)), stated in one
39
+ * line and nothing more. Never fatal: this runs before every verb, and a fatal
40
+ * boot would lock out the verbs that fix the mismatch. The verbs that ACT on
41
+ * the derived repo (the manage walk, the deploy) refuse on the same line
42
+ * instead. The prelude never writes config: which of the two is wrong (the
43
+ * config, or where the repo lives) is a human's call.
40
44
  *
41
45
  * The WRITE is the one thing that fails loudly: a `git remote set-url` refused
42
46
  * after a `get-url` just answered is not an external condition, it is a broken
43
47
  * invariant, and the runner stops the boot on it.
44
48
  */
45
49
 
46
- const path = require('node:path');
47
- const jetpack = require('fs-jetpack');
48
-
49
- const { parseRemoteUrl, retargetRemoteUrl, remoteUrl, setRemoteUrl } = require('../git-remote.js');
50
+ const { readOrigin, retargetRemoteUrl, setRemoteUrl } = require('../git-remote.js');
50
51
  const github = require('../github-repo.js');
51
52
 
52
53
  // The one network read runs on EVERY verb boot, so a network that hangs (a
@@ -61,7 +62,7 @@ const GITHUB_READ_TIMEOUT_MS = 10000;
61
62
  * @param {function} [context.execFn] - Injectable git exec (tests).
62
63
  * @param {function} [context.resolveRepo] - Injectable `(owner, name) => repo|null` (tests).
63
64
  * @param {function} [context.log] - Injectable line printer (tests).
64
- * @returns {{ healed: boolean, reason?: string, from?: string, to?: string, drift?: { owner: string, org: string } }}
65
+ * @returns {{ healed: boolean, reason?: string, from?: string, to?: string, drift?: { origin: string, derived: string } }}
65
66
  */
66
67
  function run(context = {}) {
67
68
  const { brandRoot, execFn } = context;
@@ -72,21 +73,12 @@ function run(context = {}) {
72
73
 
73
74
  if (!brandRoot) return { healed: false, reason: 'no-brand' };
74
75
 
75
- // One stat, before anything else: most boots in this monorepo's own trees and
76
- // in every fixture brand end here.
77
- if (!jetpack.exists(path.join(brandRoot, '.git'))) return { healed: false, reason: 'no-git' };
76
+ // One stat before anything else (most boots in this monorepo's own trees and
77
+ // in every fixture brand end there), then the remote itself.
78
+ const current = readOrigin({ dir: brandRoot, execFn });
79
+ if (!current.slug) return { healed: false, reason: current.reason };
78
80
 
79
- let url;
80
- try {
81
- url = remoteUrl({ dir: brandRoot, execFn });
82
- } catch (e) {
83
- return { healed: false, reason: 'no-origin' };
84
- }
85
-
86
- const current = parseRemoteUrl(url);
87
- if (!current) return { healed: false, reason: 'foreign-remote' };
88
-
89
- const from = `${current.owner}/${current.repo}`;
81
+ const { url, slug: from } = current;
90
82
 
91
83
  // The ONE network read, on the slug the checkout carries: GitHub follows its
92
84
  // own redirect and names where that repo lives now.
@@ -109,44 +101,38 @@ function run(context = {}) {
109
101
  result = { healed: true, from, to };
110
102
  }
111
103
 
112
- const drift = configDrift(brandRoot, context.config, to.split('/')[0]);
104
+ const config = composedConfig(brandRoot, context.config);
105
+ const { repoDrift, sourceRepo } = require('../../config/index.js');
106
+ const drift = config ? repoDrift(to, config) : null;
107
+
113
108
  if (drift) {
114
- log(`omega: origin lives under ${drift.owner} but repo.org is ${drift.org}: fix repo.org in config/omega.json5 or move the repo`);
115
- result.drift = drift;
109
+ log(`omega: ${drift}`);
110
+ result.drift = { origin: to, derived: sourceRepo(config).slug };
116
111
  }
117
112
 
118
113
  return result;
119
114
  }
120
115
 
121
116
  /**
122
- * The gap between where the repo LIVES and the org the config types, or null
123
- * when there is none to state. The config is loaded here when the caller has
124
- * none, and an unloadable one answers "no drift": a config the boot cannot read
125
- * is the VERB's failure to report, in its own words, never a prelude's. A brand
126
- * declaring no `repo` block types no org, so there is nothing to disagree with.
117
+ * The composed config the drift is read against: the caller's when it has one,
118
+ * else loaded here, and an unloadable one answers null ("no drift"): a config
119
+ * the boot cannot read is the VERB's failure to report, in its own words, never
120
+ * a prelude's.
127
121
  *
128
122
  * @param {string} brandRoot - The brand root.
129
123
  * @param {object} [config] - The composed config, when the caller has it.
130
- * @param {string} owner - The owner GitHub resolved the repo under.
131
- * @returns {{ owner: string, org: string }|null}
124
+ * @returns {object|null}
132
125
  */
133
- function configDrift(brandRoot, config, owner) {
134
- const { loadConfig, repoBlock } = require('../../config/index.js');
126
+ function composedConfig(brandRoot, config) {
127
+ if (config) return config;
135
128
 
136
- let block;
137
- if (config) {
138
- block = repoBlock(config);
139
- } else {
140
- try {
141
- block = repoBlock(loadConfig(brandRoot).config);
142
- } catch (e) {
143
- return null;
144
- }
145
- }
146
-
147
- if (!block || block.org.toLowerCase() === owner.toLowerCase()) return null;
129
+ const { loadConfig } = require('../../config/index.js');
148
130
 
149
- return { owner, org: block.org };
131
+ try {
132
+ return loadConfig(brandRoot).config;
133
+ } catch (e) {
134
+ return null;
135
+ }
150
136
  }
151
137
 
152
138
  module.exports = {
@@ -31,7 +31,10 @@
31
31
  * config (`repo.org`, the SOURCE repo). An inferred git remote is not proof: a
32
32
  * target vendored into a framework/test monorepo, a cloned starter still
33
33
  * pointing at the template author, or any fork would publish this brand's
34
- * `.env` to a stranger's Actions.
34
+ * `.env` to a stranger's Actions. A checkout that could be the brand's own
35
+ * and whose origin names another repo REFUSES on `repoDrift`'s one line
36
+ * ([#934](https://github.com/Omega-JS-Stack/omega/issues/934)), the
37
+ * same refusal the deploy lane and the manage walk make.
35
38
  * 4. PUBLISH — each collected key becomes a repo Actions secret via devkit's
36
39
  * `gh` boundary (values on stdin, never logged).
37
40
  *
@@ -70,11 +73,12 @@
70
73
  * sends nothing. The refusal still THROWS in a dry run: a plan that cannot be
71
74
  * made is loud.
72
75
  */
73
- const { composeTargetEnv, loadConfig } = require('../config/index.js');
76
+ const { composeTargetEnv, loadConfig, sourceRepo } = require('../config/index.js');
74
77
  const { publishSecretKeys } = require('../config/env-delivery.js');
75
78
  const { checkEnvRules } = require('../config/env-rules.js');
76
79
  const { publishActionsSecrets } = require('./actions-secrets.js');
77
- const { resolveRepo, resolveDeployLane } = require('./deploy.js');
80
+ const { assertOriginMatches } = require('./git-remote.js');
81
+ const { findBrandRoot } = require('./local.js');
78
82
  const { targetSeams } = require('./target-seams.js');
79
83
 
80
84
  /**
@@ -200,26 +204,18 @@ function missingRequiredSecrets(options) {
200
204
  }
201
205
 
202
206
  /**
203
- * The brand's SOURCE repo as `owner/name`, from the target's resolved config:
204
- * the one the workflows and their secrets live on, derived as
205
- * `<brand.id>-omega` under `repo.org` (#883). Null when the config declares
206
- * nothing usable or doesn't load.
207
+ * The target's resolved PRODUCTION config, like every other read this publish
208
+ * makes (#895): the repo a release's secrets belong to is the one the
209
+ * production config names. Null when it doesn't load.
207
210
  *
208
211
  * @param {object} options
209
212
  * @param {string} options.targetDir - The target root.
210
213
  * @param {string} options.target - Target name ('web', 'extension', …).
211
- * @returns {string|null}
214
+ * @returns {object|null}
212
215
  */
213
- function declaredBrandRepo(options) {
216
+ function productionConfig(options) {
214
217
  try {
215
- const { loadConfig, sourceRepo } = require('../config/index.js');
216
- // PRODUCTION, like every other read this publish makes (#895): the repo a
217
- // release's secrets belong to is the one the production config names.
218
- const { config } = loadConfig(options.targetDir, options.target, { environment: 'production' });
219
- if (!config) return null;
220
-
221
- const source = sourceRepo(config);
222
- return source ? source.slug : null;
218
+ return loadConfig(options.targetDir, options.target, { environment: 'production' }).config || null;
223
219
  } catch (e) {
224
220
  return null;
225
221
  }
@@ -241,7 +237,6 @@ function declaredBrandRepo(options) {
241
237
  * @param {Object<string, string>} [options.extraSecrets] - Override for the
242
238
  * target's already-valued keys, merged OVER the composed set (tests).
243
239
  * @param {function} [options.execFn] - Injectable `gh` exec (tests).
244
- * @param {function} [options.gitExecFn] - Injectable `git` exec for remote discovery (tests).
245
240
  * @returns {{ skipped: string }|{ planned: string[] }|{ published: string[], failed: Array<object> }}
246
241
  */
247
242
  function publishTargetSecrets(options) {
@@ -297,38 +292,32 @@ function publishTargetSecrets(options) {
297
292
  return { skipped: 'no-secrets' };
298
293
  }
299
294
 
300
- const declared = declaredBrandRepo({ targetDir, target });
301
- if (!declared) {
295
+ const config = productionConfig({ targetDir, target });
296
+ const source = config ? sourceRepo(config) : null;
297
+ if (!source) {
302
298
  logger.warn('Skipping secret publication: this brand names no GitHub repo in config (repo.org). Set it, then re-run `omega deploy`.');
303
299
  return { skipped: 'no-declared-repo' };
304
300
  }
305
301
 
306
- // A NESTED brand (its root is not the toplevel of the git repo it sits in)
307
- // has a remote that answers the ENCLOSING repo by construction, and its
308
- // deploy pushes a snapshot to the DECLARED repo regardless
309
- // ([#872](https://github.com/Omega-JS-Stack/omega/issues/872)), so the
310
- // mismatch guard would only ever skip a publish that is correct. Every other
311
- // guard stays: what the guard protects against is a checkout that COULD have
312
- // been the brand's own and is not.
313
- const { nested } = resolveDeployLane({ dir: targetDir, execFn: options.gitExecFn });
314
- const repo = declared;
315
-
316
- if (!nested) {
317
- let remote;
318
- try {
319
- const { owner, repo: name } = resolveRepo({ cwd: targetDir, execFn: options.gitExecFn });
320
- remote = `${owner}/${name}`;
321
- } catch (e) {
322
- logger.warn(`Skipping secret publication — no GitHub remote here (${e.message})`);
323
- return { skipped: 'no-remote' };
324
- }
325
-
326
- if (declared.toLowerCase() !== remote.toLowerCase()) {
327
- logger.warn(`Skipping secret publication — the git remote here is ${remote}, but this brand's repo is ${declared}. Run \`omega deploy\` from the brand's own checkout.`);
328
- return { skipped: 'repo-mismatch' };
329
- }
302
+ // The ONE origin gate the deploy lane and the manage walk use
303
+ // ([#934](https://github.com/Omega-JS-Stack/omega/issues/934)): the brand
304
+ // root's own origin (the local remote, which the boot prelude has already
305
+ // healed onto GitHub's redirect) must BE the derived source repo, or the
306
+ // publish REFUSES on the one drift line, because arming a repo that is not
307
+ // the derived one is the harm itself. No `.git` AT the brand root is nothing
308
+ // to compare: a NESTED brand's remote is the enclosing repo's by
309
+ // construction, and its deploy pushes to the derived repo regardless
310
+ // ([#872](https://github.com/Omega-JS-Stack/omega/issues/872)). A checkout
311
+ // with no GitHub origin (nobody pushed it yet, or it is hosted elsewhere) has
312
+ // no repo to arm, so it skips.
313
+ const origin = assertOriginMatches({ dir: findBrandRoot(targetDir), config });
314
+ if (origin.reason === 'no-origin' || origin.reason === 'foreign-remote') {
315
+ logger.warn(`Skipping secret publication: no GitHub remote here (${origin.reason})`);
316
+ return { skipped: 'no-remote' };
330
317
  }
331
318
 
319
+ const repo = source.slug;
320
+
332
321
  // The PLAN, and nothing else (#895): what the composition answered, by NAME.
333
322
  // It runs after the refusal and the two guards above on purpose, so a dry run
334
323
  // is a real preview of whether the deploy would publish at all: every one of
@@ -347,4 +336,4 @@ function publishTargetSecrets(options) {
347
336
  return result;
348
337
  }
349
338
 
350
- module.exports = { collectTargetSecrets, declaredBrandRepo, missingRequiredSecrets, publishTargetSecrets };
339
+ module.exports = { collectTargetSecrets, missingRequiredSecrets, publishTargetSecrets };
@@ -1,7 +1,7 @@
1
1
  // Shared test-runner core for the OMEGA frameworks — discovery, suite/group/standalone
2
- // execution, filtering, skip semantics, init hooks, and reporting. Extracted from UJM's
3
- // runner (the canonical 3-layer build/page/boot model); BXM/EM/UJM differ only in title,
4
- // package name, CLI target alias, and their special layers — all injected via config.
2
+ // execution, filtering, skip semantics, init hooks, and reporting, on the 3-layer
3
+ // build/page/boot model. The frameworks differ only in title, package name, CLI
4
+ // target alias, and their special layers — all injected via config.
5
5
  //
6
6
  // Test-definition forms supported (see each framework's test/index.js for docs):
7
7
  // - Standalone: module.exports = { layer, description, run, cleanup, timeout, skip };
@@ -12,7 +12,7 @@
12
12
  // Suites stop on first failure (sequential, share state). Groups run all tests regardless.
13
13
  //
14
14
  // createRunner(config) config surface:
15
- // title — heading printed at the top of a run ('Browser Extension Manager Tests')
15
+ // title — heading printed at the top of a run ('OMEGA Extension Tests')
16
16
  // packageName — framework npm name; cwd package === this ⇒ framework self-test mode
17
17
  // (framework boot/ suites only run in self-test mode — they assert on
18
18
  // the framework's own fixture consumer)
@@ -28,7 +28,7 @@
28
28
  // options, results, projectRoot }) => void }]
29
29
  // The callback owns runner loading, skip messaging, and results
30
30
  // mutation — framework glue stays framework-side.
31
- // bootDefaultTimeout — per-test default for boot-layer inspect() (UJM/BXM 20000, EM 15000)
31
+ // bootDefaultTimeout — per-test default for boot-layer inspect() (each framework's runner sets its own)
32
32
  // boot: { run: async ({ tests, suites, options, results, projectRoot }) => void }
33
33
  // Called with the aggregated flat boot test list plus the boot-BOUND
34
34
  // suites (at least one of the two is non-empty).
@@ -37,7 +37,7 @@
37
37
  // partitions that FILE into the boot layer whatever its `layer` says,
38
38
  // and hands it to boot.run WHOLE (`suites: [{ file, mod }]`) instead
39
39
  // of flattening it into the inspect list: for suites that need the
40
- // boot lane's built app but run their own way (EM's `view:` renderer
40
+ // boot lane's built app but run their own way (desktop's `view:` renderer
41
41
  // suites). Default: () => false. An array-form file is never bound.
42
42
 
43
43
  const path = require('path');
@@ -21,7 +21,7 @@
21
21
  * signal with its own opinion: a build-mode run of a development artifact
22
22
  * reported as production, and a packaged production app whose lane did not
23
23
  * carry the flag reported as development. @omega.js/backend still passes its
24
- * own answer in (`Manager.isProduction()`), and a boolean a host supplies
24
+ * own answer in (`omega.isProduction()`), and a boolean a host supplies
25
25
  * always wins.
26
26
  */
27
27
 
@@ -30,7 +30,7 @@ const { isProduction } = require('../config/environment.js');
30
30
  /**
31
31
  * Read the environment gates for core.resolveConfig().
32
32
  * @param {object} [host] - the host's own signals, and the context the one
33
- * environment is read off (a Manager carrying the baked `config`)
33
+ * environment is read off (an Omega instance carrying the baked `config`)
34
34
  * @param {boolean} [host.isProduction] - overrides the one environment's answer
35
35
  * @param {boolean} [host.allowInDev] - the host's own dev opt-in (e.g. @omega.js/backend's `reportErrorsInDev`)
36
36
  * @returns {{ killed: boolean, killedReason: string|null, isProduction: boolean, allowInDev: boolean }}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * The @omega.js/monitoring entry — the Electron context-aware delegator (#380).
3
- * Lifted from @omega.js/desktop's lib/sentry/index.js: a desktop Manager
3
+ * Lifted from @omega.js/desktop's lib/sentry/index.js: a desktop Omega instance
4
4
  * singleton requires this file from whichever process it is in, and every call
5
5
  * forwards to the right per-context module.
6
6
  *
@@ -25,7 +25,7 @@ const main = {
25
25
  _Sentry: null,
26
26
 
27
27
  /**
28
- * @param {object} host - the desktop Manager: { config, getVersion() }
28
+ * @param {object} host - the desktop Omega instance: { config, getVersion() }
29
29
  */
30
30
  initialize(host) {
31
31
  main._initialized = true;
@@ -18,7 +18,7 @@ const preload = {
18
18
  _enabled: false,
19
19
 
20
20
  /**
21
- * @param {object} host - the desktop Manager: { config }
21
+ * @param {object} host - the desktop Omega instance: { config }
22
22
  */
23
23
  initialize(host) {
24
24
  const { shouldEnable, reason } = resolveConfig(host && host.config && host.config.monitoring, readGates(host));
@@ -21,7 +21,7 @@ const renderer = {
21
21
  _Sentry: null,
22
22
 
23
23
  /**
24
- * @param {object} host - the desktop Manager: { config, getVersion() }
24
+ * @param {object} host - the desktop Omega instance: { config, getVersion() }
25
25
  */
26
26
  initialize(host) {
27
27
  renderer._initialized = true;
package/docs/analytics.md CHANGED
@@ -51,11 +51,11 @@ The `bundle` task's esbuild `define` bakes `process.env.GOOGLE_ANALYTICS_SECRET`
51
51
  ## API
52
52
 
53
53
  ```js
54
- manager.analytics.event('button_click', { button_id: 'cta' });
55
- manager.analytics.pageview('/settings');
56
- manager.analytics.screenview('SettingsScreen');
57
- manager.analytics.setUserProperties({ plan: 'premium', trial: false });
58
- manager.analytics.setUserId('firebase-uid-abc'); // usually wired automatically
54
+ omega.analytics.event('button_click', { button_id: 'cta' });
55
+ omega.analytics.pageview('/settings');
56
+ omega.analytics.screenview('SettingsScreen');
57
+ omega.analytics.setUserProperties({ plan: 'premium', trial: false });
58
+ omega.analytics.setUserId('firebase-uid-abc'); // usually wired automatically
59
59
  ```
60
60
 
61
61
  Same surface in renderer:
@@ -71,10 +71,10 @@ The renderer surface is fire-and-forget IPC (`ipcRenderer.send`) for events; onl
71
71
 
72
72
  ## The renderer NEVER sends — it forwards ([#411](https://github.com/Omega-JS-Stack/omega/issues/411))
73
73
 
74
- A renderer's own `omega.analytics().event(...)` — the embedded @omega.js/client, the surface a vert click or a permission prompt fires through — routes to the bridge above and is delivered by the MAIN process's sender. There is exactly one sender per install:
74
+ A renderer's own `omega.analytics.event(...)` (the embedded @omega.js/client, the surface a vert click or a permission prompt fires through) routes to the bridge above and is delivered by the MAIN process's sender. There is exactly one sender per install:
75
75
 
76
76
  ```
77
- renderer: omega.analytics().event('vert_click', { … })
77
+ renderer: omega.analytics.event('vert_click', { … })
78
78
  → @omega.js/client reads config.analyticsBridge (src/renderer.js injects the
79
79
  preload's window.desktop.analytics when it boots the client)
80
80
  → ipcRenderer.send('desktop:analytics:event', { name, params })
@@ -136,5 +136,5 @@ free-typed string here.
136
136
  ## Tests
137
137
 
138
138
  - `src/test/suites/main/analytics.test.js` — disabled paths, uuidv5 stability, the catalog contract (canonical name in, GA4 descriptor out; unknown names never post), queueing, auth-bridge wiring, IPC handlers, secret-not-leaked guard.
139
- - `src/test/suites/renderer/analytics-bridge.test.js` — renderer-side surface shape, `getStatus` round-trip, and the #411 pin: a renderer-originated `omega.analytics().event(...)` reaches main's sender exactly once, and the payload GA would receive carries main's `client_id` and main's session id, while the bridged client holds no secret and no device id of its own (the harness hands it credentials on purpose). The harness taps main's transport (`harness/main-entry.js`) so a renderer suite can read back what the sender was handed — a test run never reaches a real GA property. Harness fidelity, stated plainly: it drives the real client and the real IPC channel into the real main-process sender, but the client runs in the preload world holding the bridge object directly, not the contextBridge proxy a page bundle gets — the proxy hop is the one link this pin does not exercise.
139
+ - `src/test/suites/renderer/analytics-bridge.test.js`: renderer-side surface shape, `getStatus` round-trip, and the #411 pin: a renderer-originated `omega.analytics.event(...)` reaches main's sender exactly once, and the payload GA would receive carries main's `client_id` and main's session id, while the bridged client holds no secret and no device id of its own (the harness hands it credentials on purpose). The harness taps main's transport (`harness/main-entry.js`) so a renderer suite can read back what the sender was handed: a test run never reaches a real GA property. Harness fidelity, stated plainly: it drives the real client and the real IPC channel into the real main-process sender, but the client runs in the preload world holding the bridge object directly, not the contextBridge proxy a page bundle gets, the proxy hop is the one link this pin does not exercise.
140
140
  - `packages/client/test/analytics.test.js` — the client half: the bridge is the injected config value alone (a planted `window.desktop` bridges nothing), a bridged client drops credentials and mints no device id, an uncatalogued name never leaves the renderer, and a forward that throws never reaches the caller.
package/docs/app-state.md CHANGED
@@ -2,24 +2,24 @@
2
2
 
3
3
  Storage-backed launch flags + crash sentinel. Tells you *whether* this is the first launch ever, *how many* times the app has launched, *whether* the previous run crashed, and *whether* the version changed.
4
4
 
5
- ## Public API on `manager.appState`
5
+ ## Public API on `omega.appState`
6
6
 
7
7
  ```js
8
- manager.appState.isFirstLaunch() // boolean — true ONLY on the very first boot
9
- manager.appState.getLaunchCount() // number — total successful launches (including this one)
10
- manager.appState.getInstalledAt() // Date — first ever launch timestamp
11
- manager.appState.getLastLaunchAt() // Date | null — previous launch (null on first)
12
- manager.appState.getLastQuitAt() // Date | null — previous graceful quit; null if it crashed
13
- manager.appState.recoveredFromCrash() // boolean — previous run did not exit cleanly
8
+ omega.appState.isFirstLaunch() // boolean: true ONLY on the very first boot
9
+ omega.appState.getLaunchCount() // number: total successful launches (including this one)
10
+ omega.appState.getInstalledAt() // Date: first ever launch timestamp
11
+ omega.appState.getLastLaunchAt() // Date | null: previous launch (null on first)
12
+ omega.appState.getLastQuitAt() // Date | null: previous graceful quit; null if it crashed
13
+ omega.appState.recoveredFromCrash() // boolean: previous run did not exit cleanly
14
14
 
15
- manager.appState.getVersion() // string | null — package version of this launch
16
- manager.appState.getPreviousVersion() // string | null — version before this launch
17
- manager.appState.wasUpgraded() // boolean — true if THIS launch's version differs from the prior
15
+ omega.appState.getVersion() // string | null: package version of this launch
16
+ omega.appState.getPreviousVersion() // string | null: version before this launch
17
+ omega.appState.wasUpgraded() // boolean: true if THIS launch's version differs from the prior
18
18
 
19
- manager.appState.launchedAtLogin() // boolean — OS booted us via openAtLogin
20
- manager.appState.launchedFromDeepLink() // boolean — argv had a deep-link payload (set by lib/deep-link)
19
+ omega.appState.launchedAtLogin() // boolean: OS booted us via openAtLogin
20
+ omega.appState.launchedFromDeepLink() // boolean: argv had a deep-link payload (set by lib/deep-link)
21
21
 
22
- manager.appState.reset() // wipe persisted state (test helper / factory-reset command)
22
+ omega.appState.reset() // wipe persisted state (test helper / factory-reset command)
23
23
  ```
24
24
 
25
25
  ## Storage shape (key `appState`)
@@ -66,24 +66,24 @@ appState.getPreviousVersion() // '1.0.0' (preserved — useful for "what's new"
66
66
  ### Show onboarding on first launch
67
67
 
68
68
  ```js
69
- if (manager.appState.isFirstLaunch()) {
70
- manager.windows.show('onboarding');
69
+ if (omega.appState.isFirstLaunch()) {
70
+ omega.windows.show('onboarding');
71
71
  }
72
72
  ```
73
73
 
74
74
  ### Crash report ping
75
75
 
76
76
  ```js
77
- if (manager.appState.recoveredFromCrash()) {
78
- manager.sentry.captureMessage('recovered from crash', 'warning');
77
+ if (omega.appState.recoveredFromCrash()) {
78
+ omega.sentry.captureMessage('recovered from crash', 'warning');
79
79
  }
80
80
  ```
81
81
 
82
82
  ### What's new modal after upgrade
83
83
 
84
84
  ```js
85
- if (manager.appState.wasUpgraded()) {
86
- manager.windows.show('changelog');
85
+ if (omega.appState.wasUpgraded()) {
86
+ omega.windows.show('changelog');
87
87
  }
88
88
  ```
89
89