@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
package/docs/test-framework.md
CHANGED
|
@@ -4,16 +4,16 @@ Built-in test framework for both @omega.js/desktop itself and consumer projects.
|
|
|
4
4
|
|
|
5
5
|
## 🚫 NEVER mock — test against the real harness (HARD RULE)
|
|
6
6
|
|
|
7
|
-
**Do NOT hand-roll fake/stub/mock objects
|
|
7
|
+
**Do NOT hand-roll fake/stub/mock objects**: no mock `omega`, fake `ipc`/`storage`/`window`/`tray`, stubbed `app`/`BrowserWindow`, or fake IPC channels. Every test gets the **real** framework context:
|
|
8
8
|
|
|
9
9
|
- `build` runs real @omega.js/desktop helper code in plain Node.
|
|
10
|
-
- `main` / `renderer` / `boot` run inside a **real spawned Electron process**, where `ctx.
|
|
10
|
+
- `main` / `renderer` / `boot` run inside a **real spawned Electron process**, where `ctx.omega` (and boot's `inspect({ omega })`) is the **real booted main-process instance**: real `omega.storage`, `omega.ipc`, `omega.tray`, `omega.windows`, etc. Use them; exercise the code the way production does.
|
|
11
11
|
|
|
12
12
|
**Pure functions are the ONLY exception.** A function with zero I/O (config-defaults merge, icon-path resolver, schema validator, CLI alias resolver, a string/number transform) can be `require()`d and called directly with plain inputs — that's not mocking, there's nothing to mock. The moment a function touches `app.*` / `BrowserWindow` / `ipcMain` / `Tray` / the real bundle / an external service, it MUST run against the real harness in the appropriate layer (`main` / `renderer` / `boot`), not a stub.
|
|
13
13
|
|
|
14
14
|
**Real external APIs are gated behind extended mode (`TEST_EXTENDED_MODE`), NOT mocked** (see [Extended vs normal mode](#extended-vs-normal-mode) below). Normal mode skips them *in the source*; extended mode runs them for real. The test never fakes them. **Anything an extended test creates in a real external system MUST be cleaned up** by the test (via the suite's `cleanup(ctx)` hook) — external systems are not reset between runs.
|
|
15
15
|
|
|
16
|
-
If you find yourself writing `const mockX = {...}` to satisfy code under test, STOP
|
|
16
|
+
If you find yourself writing `const mockX = {...}` to satisfy code under test, STOP: pass the real `ctx.omega` (or its real sub-object), or, if the function is genuinely pure, call it directly with plain data.
|
|
17
17
|
|
|
18
18
|
### The ONLY two exceptions where a narrow stub is allowed
|
|
19
19
|
|
|
@@ -30,7 +30,7 @@ A feature is not done when it works — it's done when every surface it exposes
|
|
|
30
30
|
|
|
31
31
|
| Coverage | Layer | Proves |
|
|
32
32
|
|---|---|---|
|
|
33
|
-
| **Logic** | `build` / `main` | The feature's functions do the right thing when called directly (real
|
|
33
|
+
| **Logic** | `build` / `main` | The feature's functions do the right thing when called directly (the real booted `omega`, real storage, real IPC) |
|
|
34
34
|
| **UI** | `renderer` | The feature's interface is WIRED — a real event on the real DOM triggers the behavior and the visible result appears |
|
|
35
35
|
| **End-to-end** | `boot` | The feature survives in the consumer's actual built bundle (extend the boot suite's `inspect` assertions) |
|
|
36
36
|
|
|
@@ -85,7 +85,7 @@ TEST_EXTENDED_MODE=true npx omega test build/config
|
|
|
85
85
|
|
|
86
86
|
The target matches against the test file path. The source prefix scopes selection to framework-only or project-only tests — a prefixed target excludes the other source entirely:
|
|
87
87
|
|
|
88
|
-
- `mgr
|
|
88
|
+
- `mgr:`: the **universal cross-framework alias** for "the framework's own tests" (framework-only). Works identically in @omega.js/desktop, @omega.js/extension, @omega.js/web, and @omega.js/backend.
|
|
89
89
|
- `desktop:` / `framework:` — desktop-specific aliases for framework-only tests, equivalent to `mgr:`.
|
|
90
90
|
- `project:` — consumer project tests only.
|
|
91
91
|
|
|
@@ -111,20 +111,20 @@ Anything an extended suite creates externally must be torn down in its `cleanup(
|
|
|
111
111
|
|
|
112
112
|
### `OMEGA_ENVIRONMENT=testing`, the one input a test run names
|
|
113
113
|
|
|
114
|
-
Both @omega.js/desktop test runners (`runners/electron.js`, `runners/boot.js`) spawn their child with `OMEGA_ENVIRONMENT=testing`, the ONE environment input ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)), and nothing writes over an explicit one: the word a build baked into the artifact is the fallback for a packaged app, never an override ([#925](https://github.com/Omega-JS-Stack/omega/issues/925)). That powers `
|
|
114
|
+
Both @omega.js/desktop test runners (`runners/electron.js`, `runners/boot.js`) spawn their child with `OMEGA_ENVIRONMENT=testing`, the ONE environment input ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)), and nothing writes over an explicit one: the word a build baked into the artifact is the fallback for a packaged app, never an override ([#925](https://github.com/Omega-JS-Stack/omega/issues/925)). That powers `omega.isTesting()` (and the build module's `isTesting()`), the cross-context helper everything in @omega.js/desktop checks when it needs to behave differently in tests:
|
|
115
115
|
|
|
116
116
|
- `auto-updater` flips its idle threshold from 15min → 3s and its periodic tick from 60s → 500ms, AND short-circuits the native install-prompt dialog (so tests don't pop modal windows).
|
|
117
117
|
- **Every BrowserWindow surfaces stealth** — named windows via `window-manager._surface()` AND raw `new BrowserWindow()` ones (e.g. a consumer's automation popup) via a global `browser-window-created` hook registered in `main.js` step 1a-ii. The shared recipe lives in `src/utils/stealth-window.js`: shown INACTIVE (keyboard focus never leaves your editor), opacity 0, click-through (`setIgnoreMouseEvents`), and raw windows get `show()` rerouted to `showInactive()` + `focus()` no-op'd — a test run never interrupts you, and a stray real click physically can't land in the app, while synthetic test input (`executeJavaScript`, `sendInputEvent`, CDP) is unaffected. **`webContents.focus()` is suppressed separately** (a global `web-contents-created` hook in the same main.js block): it bypasses the window-level patches — it's a different object whose `focus()` reaches the native window directly and makes the invisible window KEY, grabbing the keyboard mid-typing even under the accessory policy (which only prevents *launch* activation, not key-window steals). Consumers call it legitimately (e.g. address-bar focus on tab select), so it's no-op'd per-contents under the same predicate. Set **`OMEGA_TEST_SHOW=1`** to surface windows normally and watch a run live (the predicate is evaluated per window, so flipping it mid-run works). Deliberately NOT `hide()`/`minimize()`: occluded windows get throttled by Chromium (`requestAnimationFrame` pauses, `document.visibilityState` flips to `hidden`) — tests would exercise a DIFFERENT runtime, whereas an opacity-0 shown-inactive window renders and behaves identically to a visible one. See [windows.md](windows.md).
|
|
118
118
|
- **App-level activation is suppressed too (macOS).** Launching a regular-policy app activates it — the menu bar and keyboard focus switch to the test process at launch even though every window surfaces inactive. Under the same stealth predicate (`src/utils/test-stealth.js` — Testing mode + `OMEGA_TEST_SHOW` unset), `main.js` (step 1a, before app ready) and the spawned test harness flip the app to the **accessory activation policy** (`app.dock.hide()` — the same switch `LSUIElement` bakes for packaged hidden-mode apps): the process never activates, never shows a dock icon, and never steals focus, while windows still render identically. `OMEGA_TEST_SHOW=1` restores normal activation along with visible windows. Verified by frontmost-app sampling across a full run: zero focus changes (previously four steals per run).
|
|
119
119
|
- `main.js#initialize` isolates userData per environment: testing runs get `<userData> (Testing)` — **wiped at boot**, so every test run starts from a clean slate (post-run state stays on disk for inspection until the next run; set `OMEGA_TEST_KEEP_USERDATA=1` to skip the wipe). Dev runs get ` (Development)`; production is untouched. See [boot-sequence.md](boot-sequence.md).
|
|
120
120
|
- **The main-layer harness exposes a CDP endpoint.** `test/harness/main-entry.js` appends `--remote-debugging-port=0` at require time (loopback-only, OS-assigned port) and publishes the resolved port as **`process.env.OMEGA_CDP_PORT`** before suites run (read from Chromium's `DevToolsActivePort` file; any value inherited from your shell is overwritten — that one points at your dev app, not the harness). Consumer suites can drive real browser automation against the harness Electron itself, e.g. `playwright-core`'s `connectOverCDP('http://127.0.0.1:' + process.env.OMEGA_CDP_PORT)`. Covered by `suites/main/harness-cdp.test.js`.
|
|
121
|
-
- Other lib code can branch on `
|
|
121
|
+
- Other lib code can branch on `omega.isTesting()` to suppress dock bounce, login-item changes, OS protocol-handler registration, etc.
|
|
122
122
|
|
|
123
123
|
Consumers writing their own tests name the same input in their own runner, for example in `package.json`:
|
|
124
124
|
```json
|
|
125
125
|
"test": "OMEGA_ENVIRONMENT=testing vitest"
|
|
126
126
|
```
|
|
127
|
-
Then in your code, gate test-only behavior on `
|
|
127
|
+
Then in your code, gate test-only behavior on `omega.isTesting()` instead of inventing yet another env var.
|
|
128
128
|
|
|
129
129
|
## Test discovery
|
|
130
130
|
|
|
@@ -170,14 +170,14 @@ module.exports = {
|
|
|
170
170
|
layer: 'main', // 'build' | 'main' | 'renderer'
|
|
171
171
|
description: 'storage (main)',
|
|
172
172
|
cleanup: async (ctx) => { // runs after the last test
|
|
173
|
-
ctx.
|
|
173
|
+
ctx.omega.storage.clear();
|
|
174
174
|
},
|
|
175
175
|
tests: [
|
|
176
176
|
{
|
|
177
177
|
name: 'set + get round-trip',
|
|
178
178
|
run: (ctx) => {
|
|
179
|
-
ctx.
|
|
180
|
-
ctx.expect(ctx.
|
|
179
|
+
ctx.omega.storage.set('hello', 'world');
|
|
180
|
+
ctx.expect(ctx.omega.storage.get('hello')).toBe('world');
|
|
181
181
|
},
|
|
182
182
|
},
|
|
183
183
|
{
|
|
@@ -232,7 +232,7 @@ module.exports = [
|
|
|
232
232
|
| Layer | Where it runs | Use for |
|
|
233
233
|
|---|---|---|
|
|
234
234
|
| `build` | Plain Node | CLI, package.json, config schema, gulp tasks |
|
|
235
|
-
| `main` | Spawned Electron main process |
|
|
235
|
+
| `main` | Spawned Electron main process | `omega.initialize()`, lib modules, IPC, windows |
|
|
236
236
|
| `renderer` | Hidden BrowserWindow: the framework's harness page by default, one of the project's own `src/views/` when the suite declares `view: '<name>'` | `window.desktop.*`, preload bridge, UI logic, your own views |
|
|
237
237
|
|
|
238
238
|
The runner partitions test files by layer at discovery time. The build layer runs inline; the main layer spawns Electron once with all main suites and parses JSON-line stdout.
|
|
@@ -246,7 +246,7 @@ ctx.expect(actual) // Jest-compatible expect()
|
|
|
246
246
|
ctx.state // shared object across tests in a suite/group
|
|
247
247
|
ctx.layer // 'build' | 'main' | 'renderer'
|
|
248
248
|
ctx.skip(reason) // skip from inside the test
|
|
249
|
-
ctx.
|
|
249
|
+
ctx.omega // (main layer only) the booted @omega.js/desktop main-process instance
|
|
250
250
|
```
|
|
251
251
|
|
|
252
252
|
## expect() matchers
|
|
@@ -290,15 +290,15 @@ All test output is also teed (ANSI-stripped) to `<projectRoot>/logs/test.log`, t
|
|
|
290
290
|
## Test harness internals (main layer)
|
|
291
291
|
|
|
292
292
|
- `runners/electron.js` spawns Electron with `harness/main-entry.js` as the app.
|
|
293
|
-
- `harness/main-entry.js` boots
|
|
293
|
+
- `harness/main-entry.js` boots `omega` with `skipWindowCreation: true`, runs the suites, emits results via `__OMEGA_TEST__{json}\n` lines on stdout (`TEST_EVENT_PREFIX`, [src/utils/test-events.js](../src/utils/test-events.js), the one prefix every harness writes and every runner reads).
|
|
294
294
|
- The runner parses those lines and renders @omega.js/backend-style output.
|
|
295
295
|
- stderr is always drained (otherwise the pipe fills and the harness blocks); printed only when `OMEGA_TEST_DEBUG=1`.
|
|
296
296
|
- `ELECTRON_RUN_AS_NODE` is stripped from the spawn env (would otherwise make Electron behave as Node and break the harness).
|
|
297
|
-
- **Consumer-scheme containment.** The consumer's `main.js`
|
|
297
|
+
- **Consumer-scheme containment.** The consumer's `main.js` (where the real `protocol.handle('<brand.id>', …)` lives) never runs in this harness, so `brand://` URLs loaded by main-layer suites would be UNHANDLED. Chromium treats a load on an unhandled scheme as an *external protocol* and hands it to the OS: and if an installed copy of the app owns the scheme (e.g. `/Applications/Brand.app` on macOS, registered via its `Info.plist`), Launch Services launches the installed production app mid-test-run. The harness contains this two ways after `omega` boots: (1) it registers a stub handler for the consumer's brand scheme (read from `<cwd>/config/omega.json5`) on the default session, so `brand://` loads commit in-process as a blank page; (2) it denies the `openExternal` permission on the default session and every session created after it (partitions included), so no navigation can hand ANY scheme to the OS during a test run. Suites that need real page content for `brand://` URLs belong in the boot layer, where the real app (and its real protocol handler) runs. A main-layer suite that genuinely needs its OWN handler for the brand scheme must call `protocol.unhandle(brand.id)` first: the harness stub holds the scheme on the default session.
|
|
298
298
|
|
|
299
299
|
## A test run never touches the OS keychain, and a blocked boot reports
|
|
300
300
|
|
|
301
|
-
The harness resolves auth persistence to the **`none`** strategy on every layer, main and boot alike, before any config is read: a brand that declares `omega.authPersistence: 'safeStorage'` still runs its tests with Firebase auth in memory, because the lanes never sign a real user in. That is a hard rule, not a nicety. The boot lane spawns the raw, unsigned `Electron` binary, which carries no keychain ACL, so one `safeStorage` read parks the entire run behind a macOS SecurityAgent prompt ([#907](https://github.com/Omega-JS-Stack/omega/issues/907)). ONE signal answers "is this a test run" on both layers, `
|
|
301
|
+
The harness resolves auth persistence to the **`none`** strategy on every layer, main and boot alike, before any config is read: a brand that declares `omega.authPersistence: 'safeStorage'` still runs its tests with Firebase auth in memory, because the lanes never sign a real user in. That is a hard rule, not a nicety. The boot lane spawns the raw, unsigned `Electron` binary, which carries no keychain ACL, so one `safeStorage` read parks the entire run behind a macOS SecurityAgent prompt ([#907](https://github.com/Omega-JS-Stack/omega/issues/907)). ONE signal answers "is this a test run" on both layers, `omega.isTesting()`: the boot lane boots the consumer's PRODUCTION artifact, and the word baked into it no longer writes over the `OMEGA_ENVIRONMENT=testing` the runner spawned it with ([#925](https://github.com/Omega-JS-Stack/omega/issues/925)), so the booted app reports the lane it is running in. And since a boot can block long before `main.js` requires the harness (where the per-test timeout lives), the boot runner carries its own budget, measured as SILENCE: every harness line rearms it, so a suite that legitimately runs longer keeps going, and a boot that produces no harness output for 60s (`OMEGA_TEST_BOOT_TIMEOUT_MS` overrides) counts its tests failed, prints `✗ boot: no harness output after 60s; last runtime.log line: "<line>"` from the booted app's `logs/runtime.log`, and ends the child instead of hanging `npx omega test`.
|
|
302
302
|
|
|
303
303
|
## Writing consumer tests
|
|
304
304
|
|
|
@@ -314,7 +314,7 @@ module.exports = {
|
|
|
314
314
|
{
|
|
315
315
|
name: 'storage starts empty',
|
|
316
316
|
run: (ctx) => {
|
|
317
|
-
ctx.expect(ctx.
|
|
317
|
+
ctx.expect(ctx.omega.storage.get('user')).toBeUndefined();
|
|
318
318
|
},
|
|
319
319
|
},
|
|
320
320
|
],
|
package/docs/themes.md
CHANGED
|
@@ -87,13 +87,13 @@ theme: {
|
|
|
87
87
|
}
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
-
## Appearance (light / dark / system)
|
|
90
|
+
## Appearance (light / dark / system): `omega.theme`
|
|
91
91
|
|
|
92
92
|
@omega.js/desktop owns appearance at runtime. `config.theme.appearance` is only the **app default**; the resolved appearance is applied and kept live by the theme lib:
|
|
93
93
|
|
|
94
94
|
- **`'system'` (default)** follows the OS preference **live** — when the OS flips, every page updates without a reload or restart.
|
|
95
95
|
- **`'light'` / `'dark'`** are explicit overrides.
|
|
96
|
-
- A user's runtime choice (`
|
|
96
|
+
- A user's runtime choice (`omega.theme.set(...)`) is **persisted in `omega.storage`** (`theme.appearance`) and wins over the config default on every boot.
|
|
97
97
|
|
|
98
98
|
### How it propagates
|
|
99
99
|
|
|
@@ -105,10 +105,10 @@ The applier is **opt-in by presence**: it only manages pages whose `<html>` alre
|
|
|
105
105
|
|
|
106
106
|
```js
|
|
107
107
|
// Main
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const unsub =
|
|
108
|
+
omega.theme.get(); // 'system' | 'light' | 'dark' (the chosen source)
|
|
109
|
+
omega.theme.resolved(); // 'light' | 'dark' (what's showing)
|
|
110
|
+
omega.theme.set('dark'); // apply + persist (throws on invalid values)
|
|
111
|
+
const unsub = omega.theme.onChange(({ source, resolved }) => { ... });
|
|
112
112
|
|
|
113
113
|
// Renderer (any page with the @omega.js/desktop preload)
|
|
114
114
|
await window.desktop.theme.get(); // { source, resolved }
|
|
@@ -120,7 +120,7 @@ Main also broadcasts `desktop:theme:changed { source, resolved }` to BrowserWind
|
|
|
120
120
|
|
|
121
121
|
### Declarative controls
|
|
122
122
|
|
|
123
|
-
Any element with `data-omega-theme-set` becomes a theme switch (wired by the renderer
|
|
123
|
+
Any element with `data-omega-theme-set` becomes a theme switch (wired by the renderer's `omega.initialize()`, event-delegated, so late-rendered controls work):
|
|
124
124
|
|
|
125
125
|
```html
|
|
126
126
|
<button data-omega-theme-set="light">Day</button>
|
package/docs/tooltips.md
CHANGED
|
@@ -52,7 +52,7 @@ control and put the tooltip on the wrapper:
|
|
|
52
52
|
## The rest of Bootstrap's JS
|
|
53
53
|
|
|
54
54
|
The full namespace is exposed at **`window.bootstrap`** (and
|
|
55
|
-
`
|
|
55
|
+
`omega.bootstrap`): `Tooltip`, `Popover`, `Collapse`, `Dropdown`, `Modal`,
|
|
56
56
|
`Offcanvas`, `Tab`, `Toast`, `Alert`, `Button`, `Carousel`, `ScrollSpy`. Only
|
|
57
57
|
tooltips are auto-initialized; the other components' standard **data-api**
|
|
58
58
|
works out of the box on plain Bootstrap markup (e.g.
|
|
@@ -94,6 +94,6 @@ runs from a preload, e.g. the test harness).
|
|
|
94
94
|
|
|
95
95
|
- `src/test/suites/renderer/tooltips.test.js` — bundle loads, auto-init on
|
|
96
96
|
insertion, live retitle, dispose-on-removal, tip cleanup. (The harness wires
|
|
97
|
-
the renderer
|
|
97
|
+
the renderer instance in the preload world: see the suite header for the
|
|
98
98
|
world-split notes; single-world hover behavior is covered by consumer boot
|
|
99
99
|
suites.)
|
package/docs/tray.md
CHANGED
|
@@ -4,19 +4,19 @@ File-based tray/menubar. @omega.js/desktop looks for `src/integrations/tray/inde
|
|
|
4
4
|
|
|
5
5
|
## Config
|
|
6
6
|
|
|
7
|
-
No config block. Path is conventional: `src/integrations/tray/index.js`. To opt out, call `
|
|
7
|
+
No config block. Path is conventional: `src/integrations/tray/index.js`. To opt out, call `omega.tray.disable()` from your main entry: idempotent, tears down any existing Tray.
|
|
8
8
|
|
|
9
9
|
## Definition file
|
|
10
10
|
|
|
11
11
|
```js
|
|
12
12
|
// src/integrations/tray/index.js
|
|
13
|
-
module.exports = ({
|
|
13
|
+
module.exports = ({ omega, tray }) => {
|
|
14
14
|
// @omega.js/desktop auto-resolves the tray icon from config/icons/<platform>/tray.png at build
|
|
15
15
|
// time, so explicit tray.icon() is OPTIONAL. Call it only to override.
|
|
16
16
|
// Note: on macOS, if you pass your own path, the filename MUST end in
|
|
17
17
|
// `Template.png` for the OS to auto-invert it in dark mode.
|
|
18
18
|
// tray.icon('src/assets/icons/my-trayTemplate.png');
|
|
19
|
-
tray.tooltip(
|
|
19
|
+
tray.tooltip(omega.config?.app?.productName);
|
|
20
20
|
|
|
21
21
|
// Easiest: start from @omega.js/desktop's default template.
|
|
22
22
|
tray.useDefaults();
|
|
@@ -25,7 +25,7 @@ module.exports = ({ manager, tray }) => {
|
|
|
25
25
|
tray.insertAfter('open', {
|
|
26
26
|
id: 'dashboard',
|
|
27
27
|
label: 'Open Dashboard',
|
|
28
|
-
click: () =>
|
|
28
|
+
click: () => omega.windows.show('dashboard'),
|
|
29
29
|
});
|
|
30
30
|
tray.update('open', { label: 'Show Window' });
|
|
31
31
|
tray.remove('website');
|
|
@@ -47,7 +47,7 @@ tray.clear() // start over
|
|
|
47
47
|
|
|
48
48
|
## Id-path API
|
|
49
49
|
|
|
50
|
-
Same shape across menu / tray / context-menu. Available **during definition** (on the `tray` builder arg) AND **at runtime** on `
|
|
50
|
+
Same shape across menu / tray / context-menu. Available **during definition** (on the `tray` builder arg) AND **at runtime** on `omega.tray`:
|
|
51
51
|
|
|
52
52
|
```js
|
|
53
53
|
.find(idPath) // live descriptor or null
|
|
@@ -69,8 +69,8 @@ Tray ids are **flat** — no `tray/` prefix (the lib namespace is implicit). For
|
|
|
69
69
|
| ID | Item |
|
|
70
70
|
|---|---|
|
|
71
71
|
| `title` | Disabled label showing the app name |
|
|
72
|
-
| `open` | "Open `<app>`"
|
|
73
|
-
| `check-for-updates` | Wired to `
|
|
72
|
+
| `open` | "Open `<app>`": calls `omega.windows.show('main')` |
|
|
73
|
+
| `check-for-updates` | Wired to `omega.autoUpdater` (label updates dynamically) |
|
|
74
74
|
| `website` | Visit `brand.url` (only present if configured) |
|
|
75
75
|
| `quit` | Quit the app |
|
|
76
76
|
|
|
@@ -84,9 +84,9 @@ tray.item({ id: 'account', label: 'Account', submenu: [
|
|
|
84
84
|
{ id: 'sign-out', label: 'Sign out', click: () => {} },
|
|
85
85
|
]});
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
omega.tray.find('account/sign-out');
|
|
88
|
+
omega.tray.update('account/sign-out', { enabled: false });
|
|
89
|
+
omega.tray.appendTo('account', { id: 'profile', label: 'Profile' });
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
## Item descriptors
|
|
@@ -103,30 +103,30 @@ Mirror Electron's [`MenuItemConstructorOptions`](https://www.electronjs.org/docs
|
|
|
103
103
|
| `click` | function | Wrapped to swallow errors so a bad handler can't kill the menu |
|
|
104
104
|
| `submenu` | array | Recursively resolved with the same conveniences |
|
|
105
105
|
|
|
106
|
-
## Runtime API on `
|
|
106
|
+
## Runtime API on `omega.tray`
|
|
107
107
|
|
|
108
108
|
```js
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
109
|
+
omega.tray.refresh() // re-evaluate dynamic state and re-render
|
|
110
|
+
omega.tray.define(fn) // replace the whole definition at runtime
|
|
111
|
+
omega.tray.disable() // tear down + stop responding (idempotent)
|
|
112
|
+
omega.tray.setIcon(path)
|
|
113
|
+
omega.tray.setTooltip(text)
|
|
114
|
+
omega.tray.addItem(descriptor) // append (preserves existing items)
|
|
115
|
+
omega.tray.clearItems()
|
|
116
|
+
omega.tray.destroy() // tear down (mostly for tests)
|
|
117
117
|
|
|
118
118
|
// Id-path API — same as listed above.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
119
|
+
omega.tray.find('quit')
|
|
120
|
+
omega.tray.update('quit', { label: 'Goodbye' })
|
|
121
|
+
omega.tray.remove('website')
|
|
122
|
+
omega.tray.insertAfter('open', { id: 'preferences', label: 'Preferences...', click: ... })
|
|
123
|
+
omega.tray.hide('check-for-updates')
|
|
124
124
|
|
|
125
125
|
// Inspection
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
126
|
+
omega.tray.getItems() // shallow copy of raw descriptors
|
|
127
|
+
omega.tray.getIcon()
|
|
128
|
+
omega.tray.getTooltip()
|
|
129
|
+
omega.tray.isRendered()
|
|
130
130
|
```
|
|
131
131
|
|
|
132
132
|
## Common patterns
|
|
@@ -135,8 +135,8 @@ manager.tray.isRendered()
|
|
|
135
135
|
|
|
136
136
|
```js
|
|
137
137
|
// in your renderer/main code, after sign-in:
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
omega.storage.set('user', { ... });
|
|
139
|
+
omega.tray.refresh(); // dynamic-label functions re-evaluate
|
|
140
140
|
```
|
|
141
141
|
|
|
142
142
|
### Hide updater item if you ship without auto-update
|
|
@@ -153,7 +153,7 @@ module.exports = ({ tray }) => {
|
|
|
153
153
|
### Replace the entire tray at runtime
|
|
154
154
|
|
|
155
155
|
```js
|
|
156
|
-
|
|
156
|
+
omega.tray.define(({ omega, tray }) => {
|
|
157
157
|
tray.icon('icons/dark-mode.png');
|
|
158
158
|
tray.item({ id: 'x', label: 'New layout', click: ... });
|
|
159
159
|
});
|
package/docs/usage.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# Usage
|
|
2
2
|
|
|
3
|
-
Tracks app-launch + hours-of-use stats. Sister of legacy @omega.js/desktop's Usage library, but uses `
|
|
3
|
+
Tracks app-launch + hours-of-use stats. Sister of legacy @omega.js/desktop's Usage library, but uses `omega.storage` instead of a separate electron-store.
|
|
4
4
|
|
|
5
5
|
## What's tracked
|
|
6
6
|
|
|
7
7
|
```js
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
omega.usage.opens() // total app launches
|
|
9
|
+
omega.usage.hoursTotal() // cumulative hours-of-use across clean exits
|
|
10
|
+
omega.usage.hoursThisSession() // live, computed from session start
|
|
11
|
+
omega.usage.installedAt() // ISO timestamp of first launch
|
|
12
|
+
omega.usage.toJSON() // all of the above as a structured-cloneable object
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## How it accumulates
|
|
@@ -51,7 +51,7 @@ const snap = await window.desktop.usage.get();
|
|
|
51
51
|
|
|
52
52
|
## Why not just use app-state?
|
|
53
53
|
|
|
54
|
-
`app-state.js` already tracks `launchCount` (= opens). We could fold these in. But `app-state` is concerned with first-launch / crash-sentinel / version-change semantics
|
|
54
|
+
`app-state.js` already tracks `launchCount` (= opens). We could fold these in. But `app-state` is concerned with first-launch / crash-sentinel / version-change semantics: `usage` is concerned with telemetry. Keeping them separate keeps each module focused. Both write to disjoint keys in `omega.storage`.
|
|
55
55
|
|
|
56
56
|
## Tests
|
|
57
57
|
|
package/docs/verts.md
CHANGED
|
@@ -12,7 +12,7 @@ zero consumer JS, same element vocabulary as the web `verts/unit` section and
|
|
|
12
12
|
|
|
13
13
|
## What the wiring does
|
|
14
14
|
|
|
15
|
-
`renderer.js _wireAds` (runs inside `
|
|
15
|
+
`renderer.js _wireAds` (runs inside `omega.initialize()`, same liveness
|
|
16
16
|
model as the FontAwesome/tooltip wiring) binds every `[data-omega-vert]`
|
|
17
17
|
element present at init AND inserted later (MutationObserver), marking bound
|
|
18
18
|
hosts `data-omega-vert-bound="house"`. Everything after the bind lives in the
|
package/docs/windows.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Windows
|
|
2
2
|
|
|
3
|
-
**Lazy named-window registry.** @omega.js/desktop does NOT auto-create any window. Your `main.js` calls `
|
|
3
|
+
**Lazy named-window registry.** @omega.js/desktop does NOT auto-create any window. Your `main.js` calls `omega.windows.create('main', { show: !startup.isLaunchHidden() })` from inside `omega.initialize().then(() => { ... })`. Always create `main`: its presence in the registry is what lets @omega.js/desktop's `app.on('activate')` (macOS dock click) and `app.on('second-instance')` (win/linux re-launch) handlers surface UI when the user double-clicks the running app. In hidden launches, pass `show: false` to keep the window invisible until something explicitly calls `windows.show('main')`. Use the registry for the common case (named, persistent, integrated windows). For one-off windows (a toast, a print preview), use `new BrowserWindow()` directly, `window-manager` doesn't get in the way.
|
|
4
4
|
|
|
5
5
|
## Re-surface on user re-launch
|
|
6
6
|
|
|
@@ -14,20 +14,20 @@ Both handlers are no-ops if `main` isn't in the registry. So consumers who genui
|
|
|
14
14
|
## API
|
|
15
15
|
|
|
16
16
|
```js
|
|
17
|
-
await
|
|
18
|
-
await
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
await omega.windows.create('main', overrides?) // canonical entry point
|
|
18
|
+
await omega.windows.createNamed('main', mgr, opts?) // identical; .create() is sugar
|
|
19
|
+
omega.windows.get('main') // BrowserWindow | null
|
|
20
|
+
omega.windows.show('main') // show + focus + auto app.dock.show()
|
|
21
|
+
omega.windows.hide('main')
|
|
22
|
+
omega.windows.close('main') // force-close (bypasses hideOnClose)
|
|
23
|
+
omega.windows.list() // string[] of currently-open names
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
`create()` is single-instance: a second call with the same name returns the existing window and focuses it (no double-create).
|
|
27
27
|
|
|
28
28
|
## Defaults
|
|
29
29
|
|
|
30
|
-
No JSON config required. @omega.js/desktop bakes in sensible defaults so `
|
|
30
|
+
No JSON config required. @omega.js/desktop bakes in sensible defaults so `omega.windows.create('main')` "just works":
|
|
31
31
|
|
|
32
32
|
| Window | Defaults |
|
|
33
33
|
|---|---|
|
|
@@ -37,8 +37,8 @@ No JSON config required. @omega.js/desktop bakes in sensible defaults so `manage
|
|
|
37
37
|
Override at the call site:
|
|
38
38
|
|
|
39
39
|
```js
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
omega.windows.create('main', { width: 1280, height: 800 });
|
|
41
|
+
omega.windows.create('settings', { width: 600, height: 480 });
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
## Config (optional)
|
|
@@ -60,7 +60,7 @@ Per-window keys:
|
|
|
60
60
|
| `view` | `main` | `<name>` | Folder under `src/views/`. Loads `dist/views/<view>/index.html`. |
|
|
61
61
|
| `width` / `height` | 1024 / 720 | 800 / 600 | Initial size (overridden by saved bounds if `persistBounds: true`). |
|
|
62
62
|
| `minWidth` / `minHeight` | 400 / 300 | 400 / 300 | |
|
|
63
|
-
| `show` | `true` | `true` | Auto-show on `ready-to-show`. `false` keeps the window hidden until `
|
|
63
|
+
| `show` | `true` | `true` | Auto-show on `ready-to-show`. `false` keeps the window hidden until `omega.windows.show()`. |
|
|
64
64
|
| `hideOnClose` | `true` | `false` | Discord-style: X click hides instead of closes. See "Hide-on-close" below. |
|
|
65
65
|
| `title` | `app.productName` | `app.productName` | Window title. |
|
|
66
66
|
| `backgroundColor` | `#ffffff` | `#ffffff` | Background color before the page loads. |
|
|
@@ -96,15 +96,15 @@ The `main` window's X button **hides instead of closes** by default. Real quit o
|
|
|
96
96
|
- Menu Quit (`main/quit` on mac, `file/quit` on win/linux)
|
|
97
97
|
- Tray Quit (`quit` item)
|
|
98
98
|
- Auto-updater install (`autoUpdater.installNow()`)
|
|
99
|
-
- Programmatic `
|
|
99
|
+
- Programmatic `omega.quit({ force: true })`
|
|
100
100
|
|
|
101
101
|
The window-manager close handler checks three flags before deciding to swallow vs let through:
|
|
102
102
|
|
|
103
103
|
| Flag | Set by | Means |
|
|
104
104
|
|---|---|---|
|
|
105
|
-
| `
|
|
106
|
-
| `
|
|
107
|
-
| `win._emForceClose` | `
|
|
105
|
+
| `omega._allowQuit` | `omega.quit({ force: true })`, `autoUpdater.installNow()` | Programmatic force: let the close go through. |
|
|
106
|
+
| `omega._isQuitting` | `app.on('before-quit')` (every quit path Electron knows about) | App is quitting: let close events flow naturally. |
|
|
107
|
+
| `win._emForceClose` | `omega.windows.close(name)` | Per-window override. |
|
|
108
108
|
|
|
109
109
|
Other named windows default to `hideOnClose: false` (X actually closes). Override per window via config or call-site overrides.
|
|
110
110
|
|
|
@@ -121,27 +121,27 @@ Every named window's position and size persist to storage on resize / move / max
|
|
|
121
121
|
|
|
122
122
|
## macOS dock auto-show
|
|
123
123
|
|
|
124
|
-
When `LSUIElement: true` is baked at build time (`startup.mode: 'hidden'`), the app launches with **no dock icon, no Cmd+Tab, no taskbar**. The first time `
|
|
124
|
+
When `LSUIElement: true` is baked at build time (`startup.mode: 'hidden'`), the app launches with **no dock icon, no Cmd+Tab, no taskbar**. The first time `omega.windows.create()` or `omega.windows.show()` runs, @omega.js/desktop calls `app.dock.show()` automatically: the dock icon appears alongside the window.
|
|
125
125
|
|
|
126
|
-
**And the inverse**: for `startup.mode: 'hidden'` apps, when the LAST visible named window hides (hide-on-close X, `windows.hide()`, any consumer `win.hide()`), @omega.js/desktop calls `app.dock.hide()` again
|
|
126
|
+
**And the inverse**: for `startup.mode: 'hidden'` apps, when the LAST visible named window hides (hide-on-close X, `windows.hide()`, any consumer `win.hide()`), @omega.js/desktop calls `app.dock.hide()` again: the app returns to its fully-invisible posture, dock and UI appearing and vanishing together. Normal-mode apps keep their dock icon for life; quit paths are untouched (`omega._isQuitting` guard).
|
|
127
127
|
|
|
128
128
|
This means agent / menubar apps can stay completely invisible until the user explicitly asks for UI:
|
|
129
129
|
|
|
130
130
|
```js
|
|
131
|
-
|
|
131
|
+
omega.initialize().then(() => {
|
|
132
132
|
// Don't call windows.create() here — app stays invisible.
|
|
133
133
|
// Surface UI later when something warrants it:
|
|
134
|
-
|
|
134
|
+
omega.tray.update('open', { click: () => omega.windows.create('main') });
|
|
135
135
|
});
|
|
136
136
|
```
|
|
137
137
|
|
|
138
138
|
## Auto-attach context-menu
|
|
139
139
|
|
|
140
|
-
Every window created via `
|
|
140
|
+
Every window created via `omega.windows.create()` is automatically wired up with the consumer's `src/integrations/context-menu/index.js` (see [context-menu.md](context-menu.md)). Idempotent per webContents (uses a WeakSet). For windows you create directly with `new BrowserWindow()`, call `omega.contextMenu.attach(win.webContents)` manually.
|
|
141
141
|
|
|
142
142
|
## Testing mode: stealth surfacing
|
|
143
143
|
|
|
144
|
-
When `
|
|
144
|
+
When `omega.isTesting()` (i.e. under `npx omega test`), every surfacing path in this lib (`ready-to-show`, `windows.show()`, the create-dedup focus) goes **stealth** instead of `win.show()`: `_surface()` applies the shared recipe from `src/utils/stealth-window.js` and surfaces via `showInactive()`, with no `win.focus()`/dock surfacing. **The full stealth story lives in [test-framework.md](test-framework.md) (SSOT)**: the recipe and why it's not `hide()`/`minimize()`, the raw-window `browser-window-created` hook, `webContents.focus()` suppression, macOS app-level activation suppression, and the **`OMEGA_TEST_SHOW=1`** opt-out. Covered by `suites/main/stealth-window.test.js`.
|
|
145
145
|
|
|
146
146
|
## Platform behavior
|
|
147
147
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omega.js/desktop",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.53.0",
|
|
4
4
|
"description": "OMEGA desktop framework — build, test, and package Electron apps for macOS, Windows, and Linux",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
"./lib/context-menu": "./dist/lib/context-menu.js",
|
|
24
24
|
"./lib/deep-link": "./dist/lib/deep-link.js",
|
|
25
25
|
"./lib/ipc": "./dist/lib/ipc.js",
|
|
26
|
-
"./lib/logger": "./dist/lib/logger.js",
|
|
27
26
|
"./lib/logger-lite": "./dist/lib/logger-lite.js",
|
|
28
27
|
"./lib/menu": "./dist/lib/menu.js",
|
|
29
28
|
"./lib/protocol": "./dist/lib/protocol.js",
|
|
@@ -33,7 +32,7 @@
|
|
|
33
32
|
"./lib/storage": "./dist/lib/storage.js",
|
|
34
33
|
"./lib/templating": "./dist/lib/templating.js",
|
|
35
34
|
"./lib/tray": "./dist/lib/tray.js",
|
|
36
|
-
"./lib/
|
|
35
|
+
"./lib/auth": "./dist/lib/auth.js",
|
|
37
36
|
"./lib/window-manager": "./dist/lib/window-manager.js",
|
|
38
37
|
"./cli": "./dist/cli-run.js",
|
|
39
38
|
"./ensure-target": "./dist/commands/lib/ensure-target.js",
|
|
@@ -155,7 +154,7 @@
|
|
|
155
154
|
"@fortawesome/fontawesome-free": "^7.3.0",
|
|
156
155
|
"@inquirer/prompts": "^8.5.2",
|
|
157
156
|
"@octokit/rest": "^22.0.1",
|
|
158
|
-
"@omega.js/client": "0.
|
|
157
|
+
"@omega.js/client": "0.53.0",
|
|
159
158
|
"@popperjs/core": "^2.11.8",
|
|
160
159
|
"@sentry/electron": "^7.13.0",
|
|
161
160
|
"chalk": "^5.6.2",
|