@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.
- package/README.md +18 -13
- package/dist/assets/css/core/_initialize.scss +1 -1
- package/dist/assets/js/core/app-shell.js +14 -15
- package/dist/assets/themes/_template/_theme.js +6 -6
- package/dist/assets/themes/base/_includes/global/sections/account.html +4 -4
- package/dist/assets/themes/base/_includes/global/sections/app-sidebar.html +5 -5
- package/dist/assets/themes/base/_layouts/frontend/pages/account/index.html +3 -3
- package/dist/assets/themes/base/_layouts/frontend/pages/alternatives/index.html +1 -1
- package/dist/assets/themes/base/_layouts/frontend/pages/blog/tags/tag.html +1 -1
- package/dist/assets/themes/base/_layouts/frontend/pages/payment/confirmation.html +1 -1
- package/dist/assets/themes/base/_sections/marketing/newsletter-cta/section.js +2 -3
- package/dist/assets/themes/base/_sections/verts/unit/section.html +1 -1
- package/dist/assets/themes/base/_sections/verts/unit/section.js +3 -4
- package/dist/assets/themes/base/_theme.js +4 -3
- package/dist/assets/themes/bootstrap/_theme.js +2 -2
- package/dist/assets/themes/bootstrap/overrides/_links.scss +1 -1
- package/dist/assets/themes/classy/_theme.js +8 -6
- package/dist/assets/themes/classy/css/marketing/_sections.scss +1 -2
- package/dist/assets/themes/classy/js/hero-demo-form.js +3 -2
- package/dist/assets/themes/neobrutalism/_theme.js +5 -5
- package/dist/assets/themes/neobrutalism/js/pages/test/libraries/layers/index.js +1 -1
- package/dist/assets/themes/newsflash/_theme.js +6 -6
- package/dist/assets/themes/newsflash/js/pages/test/libraries/layers/index.js +1 -1
- package/dist/build.js +87 -111
- package/dist/cli.js +1 -1
- package/dist/commands/build.js +2 -2
- package/dist/commands/cdp/capture.js +2 -2
- package/dist/commands/cdp/quit.js +2 -2
- package/dist/commands/cdp/relaunch.js +2 -2
- package/dist/commands/cdp/theme.js +1 -1
- package/dist/commands/clean.js +2 -2
- package/dist/commands/deploy.js +4 -4
- package/dist/commands/finalize-release.js +4 -4
- package/dist/commands/install.js +3 -3
- package/dist/commands/launch.js +2 -2
- package/dist/commands/lib/deploy-precheck.js +3 -3
- package/dist/commands/lib/ensure-target.js +6 -6
- package/dist/commands/package.js +2 -2
- package/dist/commands/publish.js +2 -2
- package/dist/commands/release.js +3 -3
- package/dist/commands/runner.js +145 -48
- package/dist/commands/sign-windows.js +5 -5
- package/dist/commands/test.js +4 -4
- package/dist/commands/update.js +2 -2
- package/dist/commands/validate-certs.js +4 -4
- package/dist/commands/version.js +3 -3
- package/dist/defaults/.github/workflows/build.yml +2 -0
- package/dist/defaults/AGENTS.md +17 -8
- package/dist/defaults/config/omega.json5 +7 -7
- package/dist/defaults/hooks/build/post.js +1 -1
- package/dist/defaults/hooks/build/pre.js +1 -1
- package/dist/defaults/hooks/deploy/pre.js +1 -1
- package/dist/defaults/hooks/release/post.js +1 -1
- package/dist/defaults/hooks/release/pre.js +1 -1
- package/dist/defaults/src/assets/js/components/about/index.js +3 -5
- package/dist/defaults/src/assets/js/components/main/index.js +3 -5
- package/dist/defaults/src/assets/js/components/settings/index.js +3 -5
- package/dist/defaults/src/integrations/context-menu/index.js +2 -2
- package/dist/defaults/src/integrations/menu/index.js +3 -3
- package/dist/defaults/src/integrations/tray/index.js +3 -3
- package/dist/defaults/src/main.js +3 -5
- package/dist/defaults/src/preload.js +3 -5
- package/dist/defaults/test/README.md +2 -2
- package/dist/gulp/main.js +9 -10
- package/dist/gulp/tasks/audit.js +7 -7
- package/dist/gulp/tasks/build-config.js +8 -8
- package/dist/gulp/tasks/bundle.js +16 -16
- package/dist/gulp/tasks/defaults.js +3 -3
- package/dist/gulp/tasks/distribute.js +2 -2
- package/dist/gulp/tasks/html.js +9 -9
- package/dist/gulp/tasks/package-quick.js +3 -3
- package/dist/gulp/tasks/package.js +3 -3
- package/dist/gulp/tasks/release.js +3 -3
- package/dist/gulp/tasks/sass.js +6 -6
- package/dist/gulp/tasks/serve.js +4 -4
- package/dist/hooks/notarize-artifacts.js +1 -1
- package/dist/hooks/notarize.js +1 -1
- package/dist/index.js +5 -8
- package/dist/lib/_environment-mixin.js +50 -0
- package/dist/lib/_lifecycle-mixin.js +45 -0
- package/dist/lib/analytics.js +33 -35
- package/dist/lib/app-state.js +14 -14
- package/dist/lib/auth-flow.js +18 -18
- package/dist/lib/auth-persistence.js +12 -12
- package/dist/lib/auth.js +421 -0
- package/dist/lib/auto-updater.js +49 -49
- package/dist/lib/context-menu.js +13 -13
- package/dist/lib/context.js +19 -19
- package/dist/lib/deep-link.js +34 -34
- package/dist/lib/fontawesome.js +5 -5
- package/dist/lib/ipc.js +4 -4
- package/dist/lib/menu.js +25 -25
- package/dist/lib/protocol.js +5 -5
- package/dist/lib/remote-config.js +22 -22
- package/dist/lib/remote-scripts.js +21 -21
- package/dist/lib/restart-manager/index.js +28 -28
- package/dist/lib/sign-helpers/exec-with-limit.js +1 -1
- package/dist/lib/sign-helpers/sign-events.js +1 -1
- package/dist/lib/startup.js +18 -13
- package/dist/lib/storage.js +10 -10
- package/dist/lib/templating.js +16 -16
- package/dist/lib/theme.js +10 -10
- package/dist/lib/tray.js +27 -27
- package/dist/lib/usage.js +11 -11
- package/dist/lib/window-manager.js +26 -26
- package/dist/main.js +398 -483
- package/dist/preload.js +236 -176
- package/dist/renderer.js +417 -391
- package/dist/runner/job-started.js +1 -1
- package/dist/test/fixtures/consumer-app/config/omega.json5 +1 -1
- package/dist/test/fixtures/consumer-app/src/assets/js/components/main/index.js +8 -11
- package/dist/test/fixtures/consumer-app/src/main.js +5 -7
- package/dist/test/fixtures/consumer-app/src/preload.js +2 -2
- package/dist/test/harness/boot-entry.js +22 -20
- package/dist/test/harness/main-entry.js +31 -30
- package/dist/test/harness/renderer-entry.js +5 -5
- package/dist/test/harness/renderer-preload.js +137 -141
- package/dist/test/index.js +10 -10
- package/dist/test/runner.js +2 -2
- package/dist/test/runners/boot.js +7 -6
- package/dist/test/runners/electron.js +3 -2
- package/dist/test/runners/render-event.js +2 -2
- package/dist/test/suites/boot/consumer-app-boots.test.js +57 -26
- package/dist/test/suites/boot/restart-manager.test.js +2 -2
- package/dist/test/suites/boot/storage-bundled.test.js +5 -5
- package/dist/test/suites/boot/theme.test.js +13 -13
- package/dist/test/suites/build/audit.test.js +1 -1
- package/dist/test/suites/build/auth-persistence-resolve.test.js +6 -6
- package/dist/test/suites/build/boot-fixture.test.js +2 -2
- package/dist/test/suites/build/boot-runner-timeout.test.js +6 -5
- package/dist/test/suites/build/brand-scss.test.js +1 -1
- package/dist/test/suites/build/build-json-bake.test.js +1 -1
- package/dist/test/suites/build/cli.test.js +2 -2
- package/dist/test/suites/build/config-schema.test.js +5 -5
- package/dist/test/suites/build/defaults-scaffold.test.js +2 -2
- package/dist/test/suites/build/deploy-hook.test.js +3 -3
- package/dist/test/suites/build/ensure-target.test.js +2 -2
- package/dist/test/suites/build/env-delivery.test.js +2 -2
- package/dist/test/suites/build/esm-only-dependency.test.js +2 -2
- package/dist/test/suites/build/exports.test.js +9 -8
- package/dist/test/suites/build/get-config.test.js +4 -4
- package/dist/test/suites/build/manifest-deps.test.js +1 -1
- package/dist/test/suites/build/merge-line-files.test.js +1 -1
- package/dist/test/suites/build/omega-shell.test.js +34 -2
- package/dist/test/suites/build/omega.test.js +350 -0
- package/dist/test/suites/build/renderer-auth-bridge.test.js +211 -78
- package/dist/test/suites/build/runner.test.js +612 -5
- package/dist/test/suites/build/sentry.test.js +2 -2
- package/dist/test/suites/build/sign-windows-e2e.test.js +2 -2
- package/dist/test/suites/build/templating.test.js +3 -3
- package/dist/test/suites/build/test-stealth.test.js +7 -9
- package/dist/test/suites/build/url-helpers.test.js +55 -56
- package/dist/test/suites/build/validate-config.test.js +2 -2
- package/dist/test/suites/build/wave5-pins.test.js +2 -2
- package/dist/test/suites/main/analytics.test.js +59 -59
- package/dist/test/suites/main/app-state.test.js +66 -66
- package/dist/test/suites/main/auth-flow.test.js +41 -41
- package/dist/test/suites/main/auth-persistence.test.js +54 -43
- package/dist/test/suites/main/{client-bridge.integration.test.js → auth.integration.test.js} +10 -9
- package/dist/test/suites/main/auth.test.js +336 -0
- package/dist/test/suites/main/auto-updater.test.js +134 -134
- package/dist/test/suites/main/boot-sequence.test.js +37 -49
- package/dist/test/suites/main/context-menu.test.js +51 -50
- package/dist/test/suites/main/context.test.js +25 -25
- package/dist/test/suites/main/deep-link.test.js +74 -74
- package/dist/test/suites/main/fontawesome.test.js +27 -27
- package/dist/test/suites/main/ipc.test.js +35 -35
- package/dist/test/suites/main/menu.test.js +101 -100
- package/dist/test/suites/main/protocol.test.js +19 -19
- package/dist/test/suites/main/remote-config.test.js +63 -63
- package/dist/test/suites/main/remote-scripts.test.js +103 -103
- package/dist/test/suites/main/request.test.js +71 -0
- package/dist/test/suites/main/restart-manager.test.js +33 -33
- package/dist/test/suites/main/startup-paths-and-ua.test.js +4 -4
- package/dist/test/suites/main/startup.test.js +26 -26
- package/dist/test/suites/main/stealth-window.test.js +1 -1
- package/dist/test/suites/main/storage.test.js +25 -25
- package/dist/test/suites/main/theme.test.js +34 -34
- package/dist/test/suites/main/tray.test.js +79 -79
- package/dist/test/suites/main/url-helpers.test.js +133 -133
- package/dist/test/suites/main/usage.test.js +25 -25
- package/dist/test/suites/main/window-bounds.test.js +27 -27
- package/dist/test/suites/main/window-manager.test.js +44 -44
- package/dist/test/suites/renderer/analytics-bridge.test.js +5 -5
- package/dist/test/suites/renderer/cross-context-helpers.test.js +37 -31
- package/dist/test/suites/renderer/round-trip.test.js +3 -3
- package/dist/test/suites/renderer/tooltips.test.js +15 -15
- package/dist/test/suites/renderer/{window-em-surface.test.js → window-desktop-surface.test.js} +27 -7
- package/dist/test/utils/extended-mode-warning.js +1 -1
- package/dist/utils/boot-harness.js +56 -0
- package/dist/utils/mode-helpers.js +2 -15
- package/dist/utils/ship-keys.js +3 -3
- package/dist/utils/signing-status.js +51 -0
- package/dist/utils/test-events.js +7 -0
- package/dist/utils/test-stealth.js +6 -6
- package/dist/utils/url-helpers.js +52 -42
- package/dist/utils/user-agent.js +44 -0
- package/dist/vendor/account/engine.js +3 -3
- package/dist/vendor/account/index.js +14 -45
- package/dist/vendor/account/resolve-account.js +44 -0
- package/dist/vendor/account/schema.js +1 -1
- package/dist/vendor/account/user.js +99 -0
- package/dist/vendor/config/client-config.js +1 -1
- package/dist/vendor/config/environment.js +11 -30
- package/dist/vendor/config/index.js +13 -12
- package/dist/vendor/config/load.js +1 -2
- package/dist/vendor/config/platforms.js +1 -1
- package/dist/vendor/config/repo.js +24 -0
- package/dist/vendor/config/retired-keys.js +2 -2
- package/dist/vendor/config/schema.js +5 -8
- package/dist/vendor/config/site-global.js +2 -3
- package/dist/vendor/config/validate.js +1 -2
- package/dist/vendor/config/winback.js +1 -1
- package/dist/vendor/devkit/actions-secrets.js +1 -1
- package/dist/vendor/devkit/attach-log-file.js +1 -1
- package/dist/vendor/devkit/brand-version.js +162 -1
- package/dist/vendor/devkit/build-json.js +1 -1
- package/dist/vendor/devkit/cli-router.js +3 -4
- package/dist/vendor/devkit/defaults-engine.js +9 -11
- package/dist/vendor/devkit/deploy.js +64 -4
- package/dist/vendor/devkit/git-remote.js +78 -1
- package/dist/vendor/devkit/local.js +53 -3
- package/dist/vendor/devkit/lockfile.js +127 -0
- package/dist/vendor/devkit/merge-line-files.js +2 -3
- package/dist/vendor/devkit/pack-local.js +4 -7
- package/dist/vendor/devkit/preludes/origin-heal.js +35 -49
- package/dist/vendor/devkit/target-secrets.js +34 -45
- package/dist/vendor/devkit/test/runner-core.js +6 -6
- package/dist/vendor/monitoring/env.js +2 -2
- package/dist/vendor/monitoring/index.js +1 -1
- package/dist/vendor/monitoring/main.js +1 -1
- package/dist/vendor/monitoring/preload.js +1 -1
- package/dist/vendor/monitoring/renderer.js +1 -1
- package/docs/analytics.md +8 -8
- package/docs/app-state.md +19 -19
- package/docs/audit.md +4 -4
- package/docs/{client-bridge.md → auth.md} +88 -73
- package/docs/auto-updater.md +8 -8
- package/docs/boot-sequence.md +11 -6
- package/docs/build-system.md +1 -1
- package/docs/cdp-debugging.md +1 -1
- package/docs/common-mistakes.md +7 -7
- package/docs/config-schema.md +1 -1
- package/docs/context-menu.md +13 -13
- package/docs/context.md +11 -11
- package/docs/css.md +3 -9
- package/docs/deep-link.md +25 -25
- package/docs/environment-detection.md +16 -16
- package/docs/fontawesome.md +7 -5
- package/docs/hooks.md +8 -8
- package/docs/index.md +39 -28
- package/docs/ipc.md +10 -10
- package/docs/lib-modules.md +9 -9
- package/docs/logging.md +12 -14
- package/docs/menu.md +18 -18
- package/docs/releasing.md +4 -2
- package/docs/remote-config.md +9 -9
- package/docs/remote-scripts.md +12 -12
- package/docs/restart-manager.md +8 -8
- package/docs/runner.md +12 -10
- package/docs/sentry.md +4 -4
- package/docs/shared/analytics.md +1 -1
- package/docs/shared/brands.md +1 -1
- package/docs/shared/breaking-changes.md +79 -13
- package/docs/shared/config.md +24 -21
- package/docs/shared/deploys.md +30 -7
- package/docs/shared/local-dev.md +5 -3
- package/docs/shared/logging.md +1 -1
- package/docs/shared/monitoring.md +5 -5
- package/docs/shared/testing.md +2 -2
- package/docs/shared/theming.md +1 -1
- package/docs/shared/translation.md +19 -10
- package/docs/signing.md +1 -1
- package/docs/startup.md +16 -16
- package/docs/storage.md +11 -11
- package/docs/templating.md +3 -3
- package/docs/test-boot-layer.md +12 -12
- package/docs/test-framework.md +17 -17
- package/docs/themes.md +7 -7
- package/docs/tooltips.md +2 -2
- package/docs/tray.md +31 -31
- package/docs/usage.md +7 -7
- package/docs/verts.md +1 -1
- package/docs/windows.md +22 -22
- package/package.json +3 -4
- package/dist/lib/client-bridge.js +0 -374
- package/dist/lib/logger.js +0 -4
- package/dist/test/suites/build/manager.test.js +0 -213
- 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.
|
|
3
|
-
//
|
|
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
|
|
373
|
-
//
|
|
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
|
|
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:
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* and
|
|
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
|
|
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?: {
|
|
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
|
|
76
|
-
// in every fixture brand end
|
|
77
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
115
|
-
result.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
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
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
|
-
* @
|
|
131
|
-
* @returns {{ owner: string, org: string }|null}
|
|
124
|
+
* @returns {object|null}
|
|
132
125
|
*/
|
|
133
|
-
function
|
|
134
|
-
|
|
126
|
+
function composedConfig(brandRoot, config) {
|
|
127
|
+
if (config) return config;
|
|
135
128
|
|
|
136
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
|
204
|
-
*
|
|
205
|
-
*
|
|
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 {
|
|
214
|
+
* @returns {object|null}
|
|
212
215
|
*/
|
|
213
|
-
function
|
|
216
|
+
function productionConfig(options) {
|
|
214
217
|
try {
|
|
215
|
-
|
|
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
|
|
301
|
-
|
|
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
|
-
//
|
|
307
|
-
//
|
|
308
|
-
//
|
|
309
|
-
//
|
|
310
|
-
//
|
|
311
|
-
//
|
|
312
|
-
//
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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,
|
|
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
|
|
3
|
-
//
|
|
4
|
-
//
|
|
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 ('
|
|
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() (
|
|
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 (
|
|
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 (`
|
|
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 (
|
|
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
|
|
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
|
*
|
|
@@ -18,7 +18,7 @@ const preload = {
|
|
|
18
18
|
_enabled: false,
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* @param {object} host - the desktop
|
|
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
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
|
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
|
|
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
|
|
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 `
|
|
5
|
+
## Public API on `omega.appState`
|
|
6
6
|
|
|
7
7
|
```js
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
20
|
-
|
|
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
|
-
|
|
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 (
|
|
70
|
-
|
|
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 (
|
|
78
|
-
|
|
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 (
|
|
86
|
-
|
|
85
|
+
if (omega.appState.wasUpgraded()) {
|
|
86
|
+
omega.windows.show('changelog');
|
|
87
87
|
}
|
|
88
88
|
```
|
|
89
89
|
|