@omega.js/desktop 0.52.0 → 0.54.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 +53 -48
- 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-run.js +4 -1
- package/dist/cli.js +3 -3
- package/dist/commands/build.js +2 -2
- package/dist/commands/cdp/capture.js +2 -2
- package/dist/commands/cdp/client.js +1 -1
- 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/cdp.js +1 -1
- package/dist/commands/clean.js +4 -5
- package/dist/commands/deploy.js +4 -4
- package/dist/commands/dev.js +25 -0
- package/dist/commands/finalize-release.js +4 -4
- package/dist/commands/launch.js +2 -2
- package/dist/commands/lib/deploy-precheck.js +3 -3
- package/dist/commands/lib/ensure-target.js +18 -23
- package/dist/commands/lib/migrate.js +17 -0
- package/dist/commands/logs.js +1 -1
- package/dist/commands/package.js +2 -2
- package/dist/commands/publish.js +2 -2
- package/dist/commands/release.js +4 -4
- package/dist/commands/runner.js +11 -11
- package/dist/commands/sign-windows.js +5 -5
- package/dist/commands/test.js +8 -8
- package/dist/commands/update.js +7 -6
- package/dist/commands/validate-certs.js +4 -4
- package/dist/commands/version.js +3 -3
- package/dist/defaults/.github/workflows/build.yml +18 -18
- package/dist/defaults/_.gitignore +0 -2
- package/dist/defaults/_mas/README.md +3 -3
- package/dist/defaults/config/certs/README.md +1 -1
- package/dist/defaults/config/omega.json5 +43 -43
- package/dist/defaults/docs/README.md +3 -3
- package/dist/defaults/gulpfile.js +1 -1
- package/dist/defaults/hooks/build/post.js +2 -2
- package/dist/defaults/hooks/build/pre.js +2 -2
- package/dist/defaults/hooks/deploy/pre.js +1 -1
- package/dist/defaults/hooks/notarize/post.js +2 -2
- package/dist/defaults/hooks/release/post.js +2 -2
- package/dist/defaults/hooks/release/pre.js +2 -2
- 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/assets/scss/pages/about.scss +1 -1
- package/dist/defaults/src/assets/scss/pages/main.scss +1 -1
- package/dist/defaults/src/assets/scss/pages/settings.scss +1 -1
- package/dist/defaults/src/integrations/context-menu/index.js +13 -13
- package/dist/defaults/src/integrations/menu/index.js +8 -8
- package/dist/defaults/src/integrations/tray/index.js +12 -12
- package/dist/defaults/src/main.js +5 -7
- package/dist/defaults/src/preload.js +4 -6
- package/dist/defaults/test/README.md +5 -5
- package/dist/defaults/test/_init.js +1 -1
- package/dist/gulp/main.js +9 -10
- package/dist/gulp/tasks/audit.js +11 -14
- 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 +29 -29
- package/dist/lib/restart-manager/install.js +1 -1
- package/dist/lib/restart-manager/protocol.js +1 -1
- 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 +399 -483
- package/dist/preload.js +236 -176
- package/dist/renderer.js +417 -391
- 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 +21 -8
- 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/build-workflow-jobs.test.js +2 -2
- package/dist/test/suites/build/cli.test.js +30 -2
- package/dist/test/suites/build/config-schema.test.js +5 -5
- package/dist/test/suites/build/defaults-em-dash.test.js +22 -0
- package/dist/test/suites/build/defaults-scaffold.test.js +21 -7
- package/dist/test/suites/build/deploy-direct.test.js +7 -5
- package/dist/test/suites/build/deploy-dispatch.test.js +2 -1
- package/dist/test/suites/build/deploy-hook.test.js +7 -5
- package/dist/test/suites/build/dev-verb.test.js +67 -0
- package/dist/test/suites/build/ensure-target.test.js +13 -5
- 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 +7 -7
- package/dist/test/suites/build/migrate.test.js +29 -0
- 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/project-scripts-deps.test.js +6 -10
- package/dist/test/suites/build/renderer-auth-bridge.test.js +211 -78
- package/dist/test/suites/build/runner-env-write.test.js +73 -0
- package/dist/test/suites/build/runner.test.js +11 -10
- package/dist/test/suites/build/sentry.test.js +2 -2
- package/dist/test/suites/build/setup-scripts.test.js +27 -0
- 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 +15 -4
- package/dist/test/suites/build/verb-logs.test.js +20 -0
- 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} +28 -8
- package/dist/test/utils/extended-mode-warning.js +1 -1
- package/dist/utils/boot-harness.js +56 -0
- package/dist/utils/build-pipeline.js +4 -4
- package/dist/utils/mode-helpers.js +2 -15
- package/dist/utils/runner-env.js +13 -28
- 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/company.js +46 -14
- package/dist/vendor/config/defaults.js +30 -7
- package/dist/vendor/config/edit.js +25 -3
- package/dist/vendor/config/env-delivery.js +1 -1
- package/dist/vendor/config/env-schema.js +3 -6
- package/dist/vendor/config/env.js +34 -22
- package/dist/vendor/config/environment.js +11 -30
- package/dist/vendor/config/index.js +21 -28
- package/dist/vendor/config/load.js +16 -9
- package/dist/vendor/config/platforms.js +1 -1
- package/dist/vendor/config/repo.js +10 -27
- package/dist/vendor/config/schema-client.js +64 -0
- package/dist/vendor/config/schema-cloud.js +38 -0
- package/dist/vendor/config/schema-manager.js +118 -0
- package/dist/vendor/config/schema-overrides.js +68 -0
- package/dist/vendor/config/schema.js +104 -160
- package/dist/vendor/config/site-global.js +2 -3
- package/dist/vendor/config/validate.js +97 -78
- package/dist/vendor/config/winback.js +1 -1
- package/dist/vendor/devkit/actions-secrets.js +1 -1
- package/dist/vendor/devkit/agents-md.js +233 -0
- package/dist/vendor/devkit/attach-log-file.js +16 -2
- package/dist/vendor/devkit/build-json.js +1 -1
- package/dist/vendor/devkit/ci-workflows.js +30 -30
- package/dist/vendor/devkit/cli-router.js +16 -11
- package/dist/vendor/devkit/defaults-engine.js +15 -51
- package/dist/vendor/devkit/deploy-snapshot.js +44 -9
- package/dist/vendor/devkit/env-lines.js +183 -0
- package/dist/vendor/devkit/local.js +64 -10
- package/dist/vendor/devkit/lockfile.js +32 -13
- package/dist/vendor/devkit/logger.js +7 -2
- package/dist/vendor/devkit/merge-line-files.js +219 -177
- package/dist/vendor/devkit/omega-bin.js +208 -111
- package/dist/vendor/devkit/preludes/docs-sync.js +52 -0
- package/dist/vendor/devkit/preludes/index.js +1 -0
- package/dist/vendor/devkit/target-picker.js +45 -0
- package/dist/vendor/devkit/test/dashed-files.js +37 -0
- package/dist/vendor/devkit/test/run-verb-under-tee.js +71 -0
- package/dist/vendor/devkit/test/runner-core.js +6 -6
- package/dist/vendor/devkit/update.js +15 -15
- package/dist/vendor/devkit/verb-scripts.js +40 -0
- package/dist/vendor/devkit/verbs.js +170 -0
- 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/package.json +19 -26
- package/dist/commands/install.js +0 -37
- package/dist/defaults/AGENTS.md +0 -110
- package/dist/defaults/CLAUDE.md +0 -1
- 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/dist/vendor/config/env-retired.js +0 -137
- package/dist/vendor/config/retired-keys.js +0 -635
- package/docs/analytics.md +0 -140
- package/docs/app-state.md +0 -92
- package/docs/audit.md +0 -69
- package/docs/auto-updater.md +0 -243
- package/docs/boot-sequence.md +0 -39
- package/docs/build-system.md +0 -169
- package/docs/cdp-debugging.md +0 -169
- package/docs/client-bridge.md +0 -269
- package/docs/common-mistakes.md +0 -21
- package/docs/config-schema.md +0 -120
- package/docs/context-menu.md +0 -112
- package/docs/context.md +0 -81
- package/docs/css.md +0 -90
- package/docs/deep-link.md +0 -186
- package/docs/environment-detection.md +0 -112
- package/docs/fontawesome.md +0 -107
- package/docs/hooks.md +0 -89
- package/docs/icons.md +0 -79
- package/docs/index.md +0 -317
- package/docs/installer-options.md +0 -165
- package/docs/ipc.md +0 -61
- package/docs/lib-modules.md +0 -53
- package/docs/logging.md +0 -229
- package/docs/menu.md +0 -160
- package/docs/releasing.md +0 -239
- package/docs/remote-config.md +0 -118
- package/docs/remote-scripts.md +0 -144
- package/docs/restart-manager.md +0 -144
- package/docs/runner.md +0 -290
- package/docs/sentry.md +0 -97
- package/docs/shared/agent-docs.md +0 -89
- package/docs/shared/analytics.md +0 -612
- package/docs/shared/brands.md +0 -57
- package/docs/shared/breaking-changes.md +0 -851
- package/docs/shared/config.md +0 -1952
- package/docs/shared/deploys.md +0 -341
- package/docs/shared/icons.md +0 -219
- package/docs/shared/local-dev.md +0 -167
- package/docs/shared/logging.md +0 -205
- package/docs/shared/monitoring.md +0 -167
- package/docs/shared/publishing.md +0 -187
- package/docs/shared/rulings.md +0 -34
- package/docs/shared/testing.md +0 -147
- package/docs/shared/theming.md +0 -629
- package/docs/shared/translation.md +0 -333
- package/docs/shared/updates.md +0 -61
- package/docs/signing.md +0 -293
- package/docs/startup.md +0 -142
- package/docs/storage.md +0 -59
- package/docs/templating.md +0 -101
- package/docs/test-boot-layer.md +0 -157
- package/docs/test-framework.md +0 -362
- package/docs/themes.md +0 -149
- package/docs/tooltips.md +0 -99
- package/docs/tray.md +0 -164
- package/docs/usage.md +0 -58
- package/docs/verts.md +0 -62
- package/docs/windows.md +0 -149
package/docs/build-system.md
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
# Build System
|
|
2
|
-
|
|
3
|
-
@omega.js/desktop's pipeline: **prepare-package** (framework only) → **gulp** (consumer) → **esbuild** (3 bundles) → **electron-builder** (packaging) → **strategy-pluggable signing**.
|
|
4
|
-
|
|
5
|
-
## prepare-package (framework-side)
|
|
6
|
-
|
|
7
|
-
Copies @omega.js/desktop's `src/` → `dist/` so consumers `require('@omega.js/desktop/main')` from the built output. Configured in @omega.js/desktop's `package.json`:
|
|
8
|
-
|
|
9
|
-
```jsonc
|
|
10
|
-
"preparePackage": {
|
|
11
|
-
"input": "./src",
|
|
12
|
-
"output": "./dist",
|
|
13
|
-
"type": "copy",
|
|
14
|
-
"replace": {},
|
|
15
|
-
"hooks": {}
|
|
16
|
-
}
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Run with `npm start` (watch) or `npm run prepare` (one-shot).
|
|
20
|
-
|
|
21
|
-
## Gulp (consumer-side)
|
|
22
|
-
|
|
23
|
-
Auto-loads tasks from `<@omega.js/desktop>/dist/gulp/tasks/*.js` via `<@omega.js/desktop>/dist/gulp/main.js`. Consumer's `package.json` points there:
|
|
24
|
-
|
|
25
|
-
```jsonc
|
|
26
|
-
"scripts": {
|
|
27
|
-
"gulp": "gulp --cwd ./ --gulpfile ./node_modules/@omega.js/desktop/dist/gulp/main.js"
|
|
28
|
-
}
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### Tasks
|
|
32
|
-
|
|
33
|
-
| Task | Status | Description |
|
|
34
|
-
|---|---|---|
|
|
35
|
-
| `defaults` | real | Copy `<@omega.js/desktop>/dist/defaults/*` into the consumer (skips existing files) |
|
|
36
|
-
| `distribute` | real | Stage consumer `src/` + @omega.js/desktop `dist/` into `.desktop-build/` |
|
|
37
|
-
| `bundle` | real | Three parallel bundles — main / preload / renderer, through @omega.js/devkit's `bundle()` wrapper. Named `webpack` until [#737](https://github.com/Omega-JS-Stack/omega/issues/737) |
|
|
38
|
-
| `sass` | real | SCSS → `dist/assets/css/*` |
|
|
39
|
-
| `html` | real | `src/views/**/index.html` → `dist/views/*` |
|
|
40
|
-
| `build-config` | real | Materialize `dist/electron-builder.yml` from source + mode-dependent injections (`LSUIElement` for hidden mode) |
|
|
41
|
-
| `package` | real | Run `electron-builder build --config dist/electron-builder.yml` (full DMG/zip/universal-mac, NSIS-win, deb+AppImage-linux) |
|
|
42
|
-
| `package-quick` | real | Quick-package for host platform/arch only — `--dir` mode, no DMG/zip/universal/notarize. ~30s vs ~3min for full `package`. Output: `release/<platform>-<arch>/<ProductName>.app` (or `.exe`-folder/linux-unpacked) — directly launchable. Used for smoke-testing packaged-mode behavior locally. `--quick` trims the electron-builder phase and NOTHING else: the build ahead of it is full and cold (#737). |
|
|
43
|
-
| `release` | real | `electron-builder build --publish always` |
|
|
44
|
-
| `audit` | real | Validate consumer config (required keys, valid enums, deep-link scheme format), ensure icon + entrypoints exist; in publish mode also requires an ADDRESSABLE releases repo (`repo.org` + `brand.id`) + `electron-builder.yml`. Throws with a numbered list of every problem found |
|
|
45
|
-
| `serve` | real | Spawns `electron .` against the build output, websocket on `OMEGA_LIVERELOAD_PORT` |
|
|
46
|
-
|
|
47
|
-
### Composition
|
|
48
|
-
|
|
49
|
-
```js
|
|
50
|
-
// `build` produces bundles only (dist/main.bundle.js, etc.) — no installer.
|
|
51
|
-
exports.build = series(
|
|
52
|
-
exports['hook:build:pre'],
|
|
53
|
-
exports.defaults,
|
|
54
|
-
exports.distribute,
|
|
55
|
-
parallel(exports.sass, exports.bundle, exports.html),
|
|
56
|
-
exports.audit,
|
|
57
|
-
exports['build-config'],
|
|
58
|
-
exports['hook:build:post'],
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
// `packageBuild` = build + electron-builder (full DMG/zip/universal). Slow (~3min on mac).
|
|
62
|
-
exports.packageBuild = series(exports.build, exports.package);
|
|
63
|
-
|
|
64
|
-
// `packageQuick` = build + electron-builder --dir for host platform/arch only.
|
|
65
|
-
// Fast (~20-30s) — smoke-testing only.
|
|
66
|
-
exports.packageQuick = series(exports.build, exports['package-quick']);
|
|
67
|
-
|
|
68
|
-
// `publish` = build + sign + notarize + GH Release upload (to the brand's ONE
|
|
69
|
-
// public releases repo, under versionless names).
|
|
70
|
-
exports.publish = series(
|
|
71
|
-
exports.build,
|
|
72
|
-
exports['hook:release:pre'],
|
|
73
|
-
exports.release,
|
|
74
|
-
exports['hook:release:post'],
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
exports.default = series(exports.build, exports.serve);
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## esbuild — three bundles
|
|
81
|
-
|
|
82
|
-
All bundled in production for source protection. `app.asar` alone is not obfuscation (anyone can `npx asar extract` it) — minification and name mangling are what protect framework + app source.
|
|
83
|
-
|
|
84
|
-
Every bundle goes through @omega.js/devkit's ONE `bundle()` wrapper ([docs/devkit/index.md](../../../docs/devkit/index.md)), which composes the shared parts: the framework-deps resolve hook (#87), the production `@dev-only` strip (#18), the minify/sourcemap rules by mode, and one timing line per build. `src/gulp/tasks/bundle.js` holds only what is desktop's own.
|
|
85
|
-
|
|
86
|
-
| Bundle | Entry | Output | Platform / format | Externals |
|
|
87
|
-
|---|---|---|---|---|
|
|
88
|
-
| `main` | `src/main.js` | `dist/main.bundle.js` | `node` / `cjs` | electron + node builtins + native modules from consumer's `package.json` |
|
|
89
|
-
| `preload` | `src/preload.js` | `dist/preload.bundle.js` | `node` / `cjs` | electron — `platform: 'node'` already leaves every built-in external, same as main, so electron is the only name worth stating |
|
|
90
|
-
| `renderer` | `src/assets/js/components/<view>/index.js` | `dist/assets/js/components/<view>.bundle.js` | `browser` / `iife` | none — Node built-ins resolve to an empty module (see below) |
|
|
91
|
-
|
|
92
|
-
### Syntax floor — the pinned Electron answers it
|
|
93
|
-
|
|
94
|
-
webpack encoded the runtime as `target: 'electron-main' | 'electron-preload' | 'web'`. esbuild splits it into `platform` (above) and `target` (the syntax floor), and the floor is READ from the Electron binary the consumer pinned: [src/utils/electron-targets.js](../src/utils/electron-targets.js) runs it once per build with `ELECTRON_RUN_AS_NODE` (no window, no focus) and takes `process.versions.node` → `node<version>` for main/preload and `process.versions.chrome` → `chrome<major>` for the renderer. The binary is resolved from the FRAMEWORK's module context — the same lookup `build-config` pins `electronVersion` with, so the bundles compile for the Electron that will actually run them. A binary that can't be run (a CI job with `ELECTRON_SKIP_BINARY_DOWNLOAD`) warns and drops the floor; it never invents a version.
|
|
95
|
-
|
|
96
|
-
### Node built-ins in the renderer
|
|
97
|
-
|
|
98
|
-
The renderer runs with `contextIsolation: true` — a browser-like environment with no Node globals — but libraries bundled through @omega.js/client still IMPORT `fs`, `path`, `crypto` and friends on code paths their browser builds never take. webpack answered with `resolve.fallback: { fs: false, … }`; esbuild has no such option, so the same list is a resolve hook onto one empty CommonJS module (`RENDERER_EMPTY_MODULES` in the task). `electron` is on the list too: a renderer that reached the real module would be a security hole, not a missing polyfill.
|
|
99
|
-
|
|
100
|
-
### OMEGA_BUILD_JSON: a define for Node, one file for the browser
|
|
101
|
-
|
|
102
|
-
The wrapper is the ONE shape every OMEGA browser surface carries, `{ config, package, mode, license, builtAt }` ([#894](https://github.com/Omega-JS-Stack/omega/issues/894)), with `mode` the same three keys everywhere (`{ environment, build, publish }`; desktop's own `server` verdict stays inside `Manager.getMode()`). Two blobs come out of one composition, off one set of build facts:
|
|
103
|
-
|
|
104
|
-
- `composeBuildJson()` → main and preload, as an esbuild `define` (the bare identifier becomes the literal at compile time) plus a `banner` that assigns it to `globalThis`. Its `config` is the WHOLE resolved config, because the main process boots from it in a packaged app, and both bundles are Node rather than a public surface. `process.env.NODE_ENV` is defined the same way: webpack derived it from its `mode`, esbuild has no modes, so the build states it.
|
|
105
|
-
- `composeClientBuildJson()` → the renderer, written ONCE as `dist/build.js` through `@omega.js/devkit/build-json` ([#743](https://github.com/Omega-JS-Stack/omega/issues/743)). Its `config` is `clientConfig(resolved)` from `@omega.js/config`, the browser-safe subset every OMEGA browser surface carries: a renderer is readable from DevTools, so the GCP account facts, the signing certificates and the account admins stay out of it. The page template loads the file with `<script src="../../build.js">` as the view's FIRST script, ahead of the view bundle (`dist/views/<view>/` → `dist/`, resolved inside a packaged asar exactly as the bundle tag beside it is), and the renderer bundle carries no define and no banner of its own.
|
|
106
|
-
|
|
107
|
-
The build facts ride on both: `runtime: 'electron'` ([#896](https://github.com/Omega-JS-Stack/omega/issues/896), the fact @omega.js/client cannot sniff from inside a renderer), `environment`, `version`, `buildTime`, `target`, and the resolved `dev` map on non-production builds.
|
|
108
|
-
|
|
109
|
-
Pinned by `src/test/suites/build/build-json-bake.test.js`.
|
|
110
|
-
|
|
111
|
-
## electron-builder
|
|
112
|
-
|
|
113
|
-
@omega.js/desktop **generates** `dist/electron-builder.yml` from `config/omega.json5` + @omega.js/desktop defaults — the consumer never ships an `electron-builder.yml`. `gulp/build-config` does the materialization, applying:
|
|
114
|
-
|
|
115
|
-
- App metadata: `appId`, `productName`, `copyright` (with `{YEAR}` token expansion to the current year)
|
|
116
|
-
- App-level cross-platform fields: `category` mapping, `languages`, `darkModeSupport`
|
|
117
|
-
- Per-target (per-platform) installer config from `targets.{mac,win,linux}`:
|
|
118
|
-
- **mac**: arch (default `universal`), MAS stubs (not implemented)
|
|
119
|
-
- **win**: arch (default `x64`+`ia32`), NSIS oneClick + shortcuts
|
|
120
|
-
- **linux**: arch, optional snap publishing
|
|
121
|
-
- Target lists derived from the `platforms` declaration and versionless `artifactName` templates from `@omega.js/config`'s `platforms.js`: the ONE format table the website's direct-download URLs read too, so `/releases/latest/download/<asset>` never changes. The asset table + the whole release contract: [releasing.md](releasing.md#versionless-assets-and-direct-download-links)
|
|
122
|
-
- Mode-dependent injections like `mac.extendInfo.LSUIElement: true` when `startup.mode === 'hidden'` (zero-bounce production launches — see [startup.md](startup.md))
|
|
123
|
-
- `electronVersion` pinned from the INSTALLED electron (resolved via the framework's module context — electron-builder refuses semver ranges and can't see a workspace-hoisted electron from the target dir)
|
|
124
|
-
- Generated entitlements + resolved icons + materialized publish + afterSign hook. The publish block is CONFIG-ONLY and fully derived ([#883](https://github.com/Omega-JS-Stack/omega/issues/883)): `<brand.id>-releases` under `repo.org`, through @omega.js/config's `releasesRepo`. No git-remote discovery and no typed repo name (a brand-monorepo target's remote is the repo it is nested in; electron-builder's update-info step crashes on a null publish config, so this isn't cosmetic)
|
|
125
|
-
- Optional passthrough: `fileAssociations`, `protocols`
|
|
126
|
-
- The `files` list: everything under the target root except source maps, `.env` files, `logs/`, and the scratch and state dirs `.omega/`, `.claude/`, `.temp/`, `.cache/`, `.gh-runners/` and `test/` ([#866](https://github.com/Omega-JS-Stack/omega/issues/866): the boot runner stages `.omega/test-app` with symlinks into the target, and the packager followed them). `src/` ships, because the runtime reads `src/integrations/*` from the app root; `config/` (the build resources dir) and `release/` are excluded by electron-builder itself
|
|
127
|
-
|
|
128
|
-
The full per-target reference (every config knob, default value, and what it produces in YAML) lives in **[installer-options.md](installer-options.md)**.
|
|
129
|
-
|
|
130
|
-
`gulp/package` and `gulp/package-quick` both point electron-builder at the generated `dist/electron-builder.yml`. Consumer overrides via `config.electronBuilder.*` are merged on top of the generated config — see [installer-options.md § Raw `electronBuilder` overrides](installer-options.md#raw-electronbuilder-overrides-escape-hatch) for the escape hatch.
|
|
131
|
-
|
|
132
|
-
## Build modes
|
|
133
|
-
|
|
134
|
-
Environment variables (set in-process by the `omega build` / `omega package` / `omega publish` verbs — the consumer's npm scripts are thin `npx omega` aliases):
|
|
135
|
-
|
|
136
|
-
| Var | Effect |
|
|
137
|
-
|---|---|
|
|
138
|
-
| `OMEGA_BUILD_MODE=true` | Production bundles (minified, name-mangled, no sourcemaps, `@dev-only` blocks stripped) |
|
|
139
|
-
| `OMEGA_BUILD_OUTPUT=<path>` | The boot-test seam: redirect the gulp BUILD output away from `<project>/dist` (absolute, or relative to the project root). Resolved by [src/utils/dist-root.js](../src/utils/dist-root.js), which every build task's output path goes through — but `omega clean` and the generated `electron-builder.yml` stay project-relative, so this is NOT a general relocation switch; packaging under it is unsupported. Used by the boot-test runner so a test build never collides with the `npm start` watcher's `dist/` ([test-boot-layer.md](test-boot-layer.md#isolated-build-output)) |
|
|
140
|
-
| `OMEGA_IS_PUBLISH=true` | electron-builder runs with `--publish always` |
|
|
141
|
-
| `OMEGA_IS_SERVER=true` | Running in CI |
|
|
142
|
-
|
|
143
|
-
## Windows code signing
|
|
144
|
-
|
|
145
|
-
Strategy-pluggable via `platforms.windows.signing.strategy` in `config/omega.json5`:
|
|
146
|
-
|
|
147
|
-
| Strategy | Where signing runs | When to use |
|
|
148
|
-
|---|---|---|
|
|
149
|
-
| `self-hosted` | Self-hosted GH Actions runner with USB EV token plugged in | Default for @omega.js/desktop v1 — physical EV token desktop |
|
|
150
|
-
| `cloud` | `windows-latest` runner shells out to a cloud signing CLI (Azure Trusted Signing / SSL.com / DigiCert KeyLocker) | Future migration target |
|
|
151
|
-
| `local` | Developer's Windows machine after CI uploads unsigned artifact | Fallback when no runner is available |
|
|
152
|
-
|
|
153
|
-
The `gulp/build-config` task and `electron-builder.yml`'s `win.sign` hook both honor `platforms.windows.signing.strategy` so the same code path drives all three. Provider modules live in `src/lib/sign-providers/{ev,azure,sslcom,digicert}.js` (Pass 3).
|
|
154
|
-
|
|
155
|
-
## GitHub Actions
|
|
156
|
-
|
|
157
|
-
`.github/workflows/build.yml` (in `src/defaults/`) runs a 3-OS matrix: macOS / Linux / Windows. Windows job uploads unsigned; a separate `windows-sign` job runs on the strategy-appropriate runner and attaches signed artifacts to the release.
|
|
158
|
-
|
|
159
|
-
Env vars set globally:
|
|
160
|
-
|
|
161
|
-
```yaml
|
|
162
|
-
NODE_VERSION: '22'
|
|
163
|
-
OMEGA_BUILD_MODE: 'true'
|
|
164
|
-
OMEGA_IS_PUBLISH: 'true'
|
|
165
|
-
OMEGA_IS_SERVER: 'true'
|
|
166
|
-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
Concurrency group: `${{ github.ref }}` with `cancel-in-progress`.
|
package/docs/cdp-debugging.md
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
# CDP Debugging (Claude ↔ Electron)
|
|
2
|
-
|
|
3
|
-
@omega.js/desktop's `serve` task forwards all `--` CLI flags to the Electron child process. This enables Chrome DevTools Protocol (CDP) debugging, which lets Claude (or any CDP client) interact with the running Electron app — take screenshots, click elements, type text, evaluate JS, read console logs, inspect network requests, etc.
|
|
4
|
-
|
|
5
|
-
Two ways to use it: **the built-in `npx omega cdp` toolkit** (below — zero setup, multi-target, knows @omega.js/desktop's conventions) and the `chrome-devtools-electron` MCP (further down — richer single-page interaction: click/fill/network/traces).
|
|
6
|
-
|
|
7
|
-
## Launching with CDP
|
|
8
|
-
|
|
9
|
-
Two equivalent ways:
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
# Env var (recommended)
|
|
13
|
-
OMEGA_CDP_PORT=9222 npm start
|
|
14
|
-
|
|
15
|
-
# CLI flag
|
|
16
|
-
npm start -- --remote-debugging-port=9222
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Both add `--remote-debugging-port=9222` to the Electron spawn args. The env var takes precedence if both are set; a CLI flag already present won't be duplicated.
|
|
20
|
-
|
|
21
|
-
Verify CDP is live:
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
curl -s http://localhost:9222/json
|
|
25
|
-
# Returns JSON array of page targets (one per BrowserWindow)
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## The `mgr cdp` toolkit
|
|
29
|
-
|
|
30
|
-
Zero-dependency subcommands for driving the running dev app — see, act, and run the no-watch iterate loop. All read `OMEGA_CDP_PORT` (default 9222), or take `--port <n>` (which wins).
|
|
31
|
-
|
|
32
|
-
**Pinning a port in an npm script? Use `--port`, never `cross-env`.** `npx cross-env OMEGA_CDP_PORT=… npx omega cdp eval … "window.desktop.ipc.invoke('my:channel')"` STRIPS the inner quotes from the expression before it reaches V8 (`invoke(my:channel)` → `SyntaxError: missing ) after argument list`). `npx omega cdp eval … "…" --port <n>` keeps the expression intact.
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
npx omega cdp status # running? targets, window rect, theme
|
|
36
|
-
npx omega cdp eval <match> '<expr>' # evaluate JS in any webContents
|
|
37
|
-
npx omega cdp shot <match> <out.png> # ONE renderer's own pixels
|
|
38
|
-
npx omega cdp capture <out.png> # the COMPOSITED window (macOS)
|
|
39
|
-
npx omega cdp theme <dark|light|system> # flip the live theme (manager.theme)
|
|
40
|
-
npx omega cdp relaunch # quit → npm start → wait for boot
|
|
41
|
-
npx omega cdp quit # quit + wait for the process tree to drain
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
### The multi-target model
|
|
45
|
-
|
|
46
|
-
An @omega.js/desktop app is one window but potentially MANY webContents (every BrowserWindow + every `WebContentsView` is its own CDP page target). Every subcommand takes a **URL-substring matcher** instead of a "current page": the main window's document is always `/views/main/` (@omega.js/desktop's templating convention); other views match by their own URLs. `status` lists what's live.
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
npx omega cdp eval "/views/main/" 'document.title'
|
|
50
|
-
npx omega cdp eval "example.com" 'getComputedStyle(document.body).backgroundColor'
|
|
51
|
-
npx omega cdp eval "/views/main/" "window.desktop.ipc.invoke('my-app:some-channel')" # the real IPC surface
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Promises are awaited, results print as JSON, and expressions run with a user gesture (focus()/clipboard-ish APIs behave like real input).
|
|
55
|
-
|
|
56
|
-
### shot vs capture — the compositing discriminator
|
|
57
|
-
|
|
58
|
-
`shot` asks ONE renderer for its own surface; `capture` photographs the window the OS composited (the BrowserWindow document + every WebContentsView stacked). They answer different questions:
|
|
59
|
-
|
|
60
|
-
- Styling wrong in one view? → `shot` that target.
|
|
61
|
-
- Layering/transparency/z-order wrong? → `capture`; if `shot` looks right but `capture` doesn't, the bug is in compositing, not your CSS.
|
|
62
|
-
|
|
63
|
-
Caveats:
|
|
64
|
-
- `shot` needs a VISIBLE surface — a hidden view (`setVisible(false)`, a background view) produces no compositor frames and the capture times out. Show/select it first.
|
|
65
|
-
- `capture` raises the app and region-captures its rect — anything overlaying that region still wins. For an occlusion-proof image: `--find-window-id` (slow Swift path; JXA's CoreGraphics bridge segfaults) → `capture <out.png> --window-id <id>` (the ID is stable per window lifetime — cache it).
|
|
66
|
-
- **Color profiles:** macOS embeds the MONITOR's ICC profile in screenshot PNGs; many viewers (including image previews in tooling) misrender it dramatically — an opaque dark panel can read near-white. `capture` converts every file to sRGB via `sips`, so it's portable. Hand-rolled screencaptures should do the same: `sips -m "/System/Library/ColorSync/Profiles/sRGB Profile.icc" shot.png --out shot.png`.
|
|
67
|
-
- `capture`, `relaunch`, and `quit` are macOS-only (screencapture / sips / osascript). `status`/`eval`/`shot`/`theme` are cross-platform.
|
|
68
|
-
|
|
69
|
-
### relaunch / quit — the iterate loop
|
|
70
|
-
|
|
71
|
-
@omega.js/desktop dev has **no watch** (`npm start` builds once, then runs) — every `src/` edit needs quit → rebuild → boot. `relaunch` is that loop in one command: it quits the app (real quit — `before-quit` handlers run), waits for the **full process tree to drain** (port-down alone is NOT that signal — the npm-start chain takes a few more seconds, and a test run started inside that window gets contaminated with flaky boot suites), spawns a detached `npm start` with `OMEGA_CDP_PORT`, and waits for the boot signal. `quit` is the first half alone — safe to run `npx omega test` the moment it returns. **Never run tests while the app is going down** (a test run started before the process tree drains gets contaminated) — boot tests build into their own `.omega/test-app/` output since #110, so `dist/` itself no longer collides.
|
|
72
|
-
|
|
73
|
-
The boot signal defaults to the main window's document target. Apps whose boot completes later than first paint override it in `config/omega.json5`:
|
|
74
|
-
|
|
75
|
-
```json5
|
|
76
|
-
cdp: {
|
|
77
|
-
readySignal: 'my-app://overlay', // URL substring of the target that appears LAST in boot
|
|
78
|
-
}
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
The packaged-app process name (for quit/raise/window-id matching) comes from config too: `app.productName` (derived from `brand.name`); dev builds run under "Electron".
|
|
82
|
-
|
|
83
|
-
## Driving a regular Chrome (not the app)
|
|
84
|
-
|
|
85
|
-
Sometimes the thing to drive is a regular **Chrome** — the marketing site, a web flow, an OAuth page — not the Electron app.
|
|
86
|
-
|
|
87
|
-
> Mirrored across the five sister frameworks (UJM / @omega.js/backend / BXM / @omega.js/desktop / @omega.js/client) — same core section, framework-flavored. Edit all five together.
|
|
88
|
-
|
|
89
|
-
Browser work runs through the **`chrome-devtools` MCP** (via mcp-router). There is NO launch procedure anymore — no ports, no profile dirs, no curl checks:
|
|
90
|
-
|
|
91
|
-
- **Just call the tools** — `new_page`, `navigate_page`, `take_screenshot`, `click`, `fill`, `evaluate_script`, `list_console_messages`, `list_network_requests`. The browser auto-launches on the first call.
|
|
92
|
-
- **Each Claude session gets its OWN private Chrome** (`--isolated`): temp profile, CDP over an internal pipe. Parallel sessions cannot see or touch each other's pages — open and close pages freely, the whole browser is yours.
|
|
93
|
-
- **It dies with the session.** No orphans, no cleanup, nothing to kill.
|
|
94
|
-
- **Ephemeral profile** — cookies/logins do NOT persist between sessions. If a flow needs auth, log in during the task.
|
|
95
|
-
- **Self-signed HTTPS is pre-accepted** (`--acceptInsecureCerts` in the upstream) — dev servers load without certificate interstitials.
|
|
96
|
-
- **NEVER quit/kill Chrome by app name** (`killall "Google Chrome"`, osascript) — that's the user's personal browser, not yours.
|
|
97
|
-
|
|
98
|
-
Humans: the agent's Chrome window is visible — you can watch it drive. Full reference: `~/.claude/mcp-server/servers/chrome-devtools/CLAUDE.md`.
|
|
99
|
-
|
|
100
|
-
@omega.js/desktop specifics:
|
|
101
|
-
|
|
102
|
-
- **The Electron app stays attach-by-port** — that's the whole rest of this doc (`mgr cdp` per invocation, or the `chrome-devtools-electron` MCP below). Port convention: **9222** = the Electron app. The isolated `chrome-devtools` browser has nothing to do with the app.
|
|
103
|
-
- **Navigating to a brand's UJM dev site (the local marketing site)?** **`https://localhost:4000` — NEVER the LAN IP** (`https://192.168.x.x:...`). Port 4000 by default, increments to 4001+ when multiple sites run; exact port in `.temp/_config_browsersync.yml` at the root of the WEBSITE project (the UJM consumer — e.g. `<brand>-website/.temp/_config_browsersync.yml`, NOT this app repo).
|
|
104
|
-
|
|
105
|
-
## What CDP exposes
|
|
106
|
-
|
|
107
|
-
- **Renderer processes only** — one "page" target per BrowserWindow. Main process is NOT exposed (use `--inspect=9229` for that, which is a separate V8 inspector protocol).
|
|
108
|
-
- Each BrowserWindow appears as a separate page target. MCP tools with `list_pages`/`select_page` can switch between them.
|
|
109
|
-
- Chromium silently ignores flags it doesn't recognize, so gulp's own flags (`--cwd`, `--gulpfile`) pass through harmlessly.
|
|
110
|
-
|
|
111
|
-
## MCP setup (Claude ↔ Electron)
|
|
112
|
-
|
|
113
|
-
A `chrome-devtools-electron` MCP upstream is configured at `~/.claude/mcp-server/servers/chrome-devtools-electron/config.json`. It reads `OMEGA_CDP_PORT` from the environment at spawn time (defaults to 9222), so the same upstream works for any Electron app — just set the env var **BEFORE launching `claude`** (it's expanded once, when the session's router spawns the upstream; mid-session changes do nothing).
|
|
114
|
-
|
|
115
|
-
```json
|
|
116
|
-
{
|
|
117
|
-
"enabled": true,
|
|
118
|
-
"command": "sh",
|
|
119
|
-
"args": ["-c", "exec /Users/ian/.nvm/default-bin/npx -y chrome-devtools-mcp@latest --browserUrl=http://127.0.0.1:${OMEGA_CDP_PORT:-9222} --usage-statistics=false"]
|
|
120
|
-
}
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
This runs alongside the regular `chrome-devtools` upstream (which launches its own per-session isolated browser — no env vars, no ports). Tools are namespaced:
|
|
124
|
-
- `chrome-devtools__take_screenshot` → the session's own Chrome browser
|
|
125
|
-
- `chrome-devtools-electron__take_screenshot` → the running Electron app
|
|
126
|
-
|
|
127
|
-
Multiple Claude sessions can debug different apps simultaneously — each terminal sets its own `OMEGA_CDP_PORT`. See `~/.claude/mcp-server/README.md`.
|
|
128
|
-
|
|
129
|
-
### Available MCP tools (29)
|
|
130
|
-
|
|
131
|
-
Screenshots, click, fill, type, hover, drag, evaluate JS, list/read console messages, list/inspect network requests, navigate, resize, keyboard input, accessibility snapshots, Lighthouse audits, performance traces, heap snapshots, dialog handling.
|
|
132
|
-
|
|
133
|
-
### Session setup
|
|
134
|
-
|
|
135
|
-
If the upstream was added/enabled after a Claude session started, its tools won't appear until next session. To enable mid-session:
|
|
136
|
-
|
|
137
|
-
```
|
|
138
|
-
# From shell
|
|
139
|
-
mcp enable chrome-devtools-electron
|
|
140
|
-
|
|
141
|
-
# From inside Claude (if upstream is enabled on disk but not in session)
|
|
142
|
-
router__enable_upstream { name: "chrome-devtools-electron" }
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
## Port conventions
|
|
146
|
-
|
|
147
|
-
| Port | Protocol | Usage |
|
|
148
|
-
|------|----------|-------|
|
|
149
|
-
| 9222 | CDP (HTTP + WebSocket) | Electron renderer debugging (standard CDP port) |
|
|
150
|
-
| 9229 | V8 Inspector | Node.js / Electron main process debugging (`--inspect`) |
|
|
151
|
-
|
|
152
|
-
Use 9222 for `--remote-debugging-port` (industry standard). Avoid 9229 — that's the Node.js inspector port and a different protocol.
|
|
153
|
-
|
|
154
|
-
## Security
|
|
155
|
-
|
|
156
|
-
CDP gives full control of the renderer — any local process can connect and read/modify anything. **Never ship with `--remote-debugging-port` baked in.** It's dev-only, gated behind `OMEGA_CDP_PORT` which is never set in production.
|
|
157
|
-
|
|
158
|
-
## How it works
|
|
159
|
-
|
|
160
|
-
`src/gulp/tasks/serve.js` collects extra args in two ways:
|
|
161
|
-
|
|
162
|
-
1. **CLI flags**: `process.argv.slice(2).filter(arg => arg.startsWith('--'))` — forwards all `--` flags from the gulp process to Electron
|
|
163
|
-
2. **`OMEGA_CDP_PORT` env var**: if set and no `--remote-debugging-port` is already in the args, appends `--remote-debugging-port=${OMEGA_CDP_PORT}`
|
|
164
|
-
|
|
165
|
-
The args are passed to `spawn(electronBin, ['.', ...extraArgs])`. The main process boot log shows the received argv:
|
|
166
|
-
|
|
167
|
-
```
|
|
168
|
-
[info] (main) Initializing @omega.js/desktop (main)... argv=[".","--remote-debugging-port=9222"]
|
|
169
|
-
```
|
package/docs/client-bridge.md
DELETED
|
@@ -1,269 +0,0 @@
|
|
|
1
|
-
# Client Bridge — Auth State Sync
|
|
2
|
-
|
|
3
|
-
@omega.js/desktop keeps Firebase auth state in sync across all processes (main + every renderer window). The pattern mirrors BXM's background/foreground architecture: **main is the source of truth**, renderers reflect.
|
|
4
|
-
|
|
5
|
-
## Why this exists
|
|
6
|
-
|
|
7
|
-
In Electron, you can't just initialize Firebase in the renderer and forget about it:
|
|
8
|
-
|
|
9
|
-
- Multiple renderer windows would each have their own Firebase instance with no coordination.
|
|
10
|
-
- Main-process code (tray, menu, deep-link routes) needs to know who's signed in.
|
|
11
|
-
- A deep-link auth-token (`myapp://auth/token?token=...`) arrives in main, but the user's UI lives in the renderer — somebody has to bridge them.
|
|
12
|
-
|
|
13
|
-
The bridge handles all three.
|
|
14
|
-
|
|
15
|
-
## How it works
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
19
|
-
│ MAIN (client-bridge.js) │
|
|
20
|
-
│ - Owns Firebase Auth instance ("omega-auth" app) │
|
|
21
|
-
│ - Source of truth for auth state │
|
|
22
|
-
│ - Listens for desktop:auth:* IPC from renderers │
|
|
23
|
-
│ - Broadcasts desktop:auth:* IPC to all renderers on changes │
|
|
24
|
-
└─────────────────────────────────────────────────────────────┘
|
|
25
|
-
▲ │ broadcasts
|
|
26
|
-
│ sync-request ▼
|
|
27
|
-
┌──────────────────────────┐ ┌──────────────────────────┐
|
|
28
|
-
│ RENDERER (window 1) │ │ RENDERER (window 2) │
|
|
29
|
-
│ @omega.js/client + Firebase │ │ @omega.js/client + Firebase │
|
|
30
|
-
└──────────────────────────┘ └──────────────────────────┘
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### Auth flow: deep-link → all processes signed in
|
|
34
|
-
|
|
35
|
-
**Consumers never collect credentials.** There is no login form to build — call `manager.openAuthFlow()` (documented in `lib/auth-flow.js`), which opens the brand website's sign-in page in the user's browser and receives the result through the deep link below.
|
|
36
|
-
|
|
37
|
-
1. User signs in on the website. Web-manager generates a custom token. Website opens `myapp://auth/token?token=XYZ` (deep link).
|
|
38
|
-
2. @omega.js/desktop's deep-link `auth/token` built-in fires `manager.omega.handleAuthToken(token)`.
|
|
39
|
-
3. Main calls `signInWithCustomToken(auth, token)` against its own Firebase Auth → main is now signed in.
|
|
40
|
-
4. Main broadcasts `desktop:auth:sign-in-with-token` IPC with the same token to all renderer windows.
|
|
41
|
-
5. Each renderer receives the broadcast, calls `omega.auth().signInWithCustomToken(token)` against its own (@omega.js/client-managed) Firebase Auth → all renderers signed in with the same user.
|
|
42
|
-
6. Tokens are NOT stored — they expire in 1 hour. Auth state persists via Firebase's built-in IndexedDB persistence.
|
|
43
|
-
|
|
44
|
-
### Auth flow: renderer load → sync with main
|
|
45
|
-
|
|
46
|
-
When a renderer window opens (cold or warm), it asks main for the current state:
|
|
47
|
-
|
|
48
|
-
1. Renderer sends `desktop:auth:sync-request` IPC with its current UID (or null).
|
|
49
|
-
2. Main compares with its own UID:
|
|
50
|
-
- **Same UID** → no sync needed, returns `{ needsSync: false }`.
|
|
51
|
-
- **Main signed out, renderer signed in** → returns `{ needsSync: true, signOut: true }`. Renderer signs out.
|
|
52
|
-
- **Main signed in, renderer not (or different user)** → main fetches a fresh custom token from `POST ${apiUrl}/omega/user/token` (responds `{ token }`) and returns `{ needsSync: true, customToken, user }`. Renderer signs in with that token.
|
|
53
|
-
|
|
54
|
-
### Sign-out flow
|
|
55
|
-
|
|
56
|
-
Any renderer (or main code) calls `manager.omega.signOut()`:
|
|
57
|
-
|
|
58
|
-
1. Main signs out its own Firebase.
|
|
59
|
-
2. Main broadcasts `desktop:auth:sign-out` IPC to all renderers.
|
|
60
|
-
3. Each renderer signs out its own Firebase.
|
|
61
|
-
|
|
62
|
-
## Public API
|
|
63
|
-
|
|
64
|
-
### Main process (`manager.omega`)
|
|
65
|
-
|
|
66
|
-
```js
|
|
67
|
-
// Sign in via a custom token (called automatically by the auth/token deep-link route).
|
|
68
|
-
await manager.omega.handleAuthToken(token);
|
|
69
|
-
|
|
70
|
-
// Read the currently signed-in user (snapshot, no sensitive fields).
|
|
71
|
-
manager.omega.getCurrentUser();
|
|
72
|
-
// → { uid, email, displayName, photoURL, emailVerified } | null
|
|
73
|
-
|
|
74
|
-
// Fresh Firebase ID token for calling authenticated backend routes from main
|
|
75
|
-
// (send as `Authorization: Bearer <token>`). null when signed out.
|
|
76
|
-
await manager.omega.getIdToken();
|
|
77
|
-
|
|
78
|
-
// Subscribe to auth state changes (e.g. to refresh tray/menu items).
|
|
79
|
-
const off = manager.omega.onAuthChange((user) => {
|
|
80
|
-
manager.tray.refresh();
|
|
81
|
-
manager.menu.refresh();
|
|
82
|
-
});
|
|
83
|
-
off(); // unsubscribe
|
|
84
|
-
|
|
85
|
-
// Sign out from any process.
|
|
86
|
-
await manager.omega.signOut();
|
|
87
|
-
|
|
88
|
-
// The renderer-resolved subscription — THE main-side plan source. Renderers run
|
|
89
|
-
// @omega.js/client's full auth cycle (Firestore account fetch → resolveSubscription)
|
|
90
|
-
// and push the result to main (desktop:auth:account-resolved, uid-guarded); main can't
|
|
91
|
-
// run Firestore itself. null until a renderer has resolved.
|
|
92
|
-
manager.omega.getResolvedPlan();
|
|
93
|
-
// → { plan, active, trialing, cancelling } | null
|
|
94
|
-
manager.omega.getResolvedRoles();
|
|
95
|
-
// → { admin, betaTester, ... } | null
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
### Renderer process (the @omega.js/desktop Manager you `initialize()`)
|
|
99
|
-
|
|
100
|
-
```js
|
|
101
|
-
// Read the user from main (always returns main's authoritative state).
|
|
102
|
-
const user = await renderer.getMainUser();
|
|
103
|
-
|
|
104
|
-
// Sign out (goes through main; broadcasts to all other renderers).
|
|
105
|
-
await renderer.signOut();
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
The renderer's `Manager.initialize()` automatically:
|
|
109
|
-
- Boots @omega.js/client (so renderer-side Firebase is available).
|
|
110
|
-
- Wires the auth bridge (`desktop:auth:sync-request` on load + listens for broadcasts).
|
|
111
|
-
- Runs @omega.js/client's **full auth cycle** (`auth().listen()`): waits for auth to settle,
|
|
112
|
-
fetches the Firestore account, resolves the subscription, and auto-populates the
|
|
113
|
-
**`data-omega-bind` bindings** — so @omega.js/desktop app views can use UJM/BXM-style reactive HTML
|
|
114
|
-
(`@show auth.user`, `@text auth.account.plan.id`, `@show auth.account.plan.id === 'premium'`,
|
|
115
|
-
see @omega.js/client's docs/bindings.md). Each settle pushes `{ resolved, roles }` to main
|
|
116
|
-
(`desktop:auth:account-resolved`) and re-offers it whenever main announces a state change,
|
|
117
|
-
so a renderer that resolved before main signed in still delivers.
|
|
118
|
-
|
|
119
|
-
You don't write any of this — it just works.
|
|
120
|
-
|
|
121
|
-
## Session persistence (main)
|
|
122
|
-
|
|
123
|
-
Renderers persist their Firebase sessions in IndexedDB for free (browser contexts).
|
|
124
|
-
Main is Node — Firebase defaults to in-memory there — so @omega.js/desktop plugs in its own vault:
|
|
125
|
-
**`lib/auth-persistence.js`**, a PLUGGABLE strategy behind a custom Firebase
|
|
126
|
-
`Persistence` (the `getReactNativePersistence()` shape).
|
|
127
|
-
|
|
128
|
-
- **`safeStorage`** (default) — values encrypted via Electron `safeStorage` (macOS
|
|
129
|
-
Keychain / Windows DPAPI / kwallet-gnome) before touching disk
|
|
130
|
-
(`{userData}/omega-auth-session.json` holds base64 ciphertext only). This is the same
|
|
131
|
-
os_crypt machinery Chromium uses for its cookie jar — stronger than browser
|
|
132
|
-
IndexedDB/localStorage, which are plaintext LevelDB on disk.
|
|
133
|
-
- **`none`** — explicit opt-out (in-memory, pre-1.12 behavior).
|
|
134
|
-
- **Custom** — `require('@omega.js/desktop/lib/auth-persistence').register(name, { available, getItem, setItem, removeItem })` before `initialize()`, then select it via config.
|
|
135
|
-
|
|
136
|
-
```jsonc
|
|
137
|
-
{
|
|
138
|
-
"omega": {
|
|
139
|
-
"authPersistence": "safeStorage" // 'safeStorage' (default) | 'none' | custom name
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
A TEST RUN is always `none`, whatever this config says, on the main and boot layers
|
|
145
|
-
alike: the harness never signs a real user in, so it never asks the OS keychain
|
|
146
|
-
([#907](https://github.com/Omega-JS-Stack/omega/issues/907), the mechanics in
|
|
147
|
-
[test-framework.md](test-framework.md)).
|
|
148
|
-
|
|
149
|
-
Storage only — distribution across processes stays the IPC sync protocol above.
|
|
150
|
-
The session restores at boot (offline included: no network round trip), so a restart
|
|
151
|
-
keeps the user signed in; renderers then re-resolve the account and re-push the plan.
|
|
152
|
-
|
|
153
|
-
## Config
|
|
154
|
-
|
|
155
|
-
```jsonc
|
|
156
|
-
{
|
|
157
|
-
"cloud": {
|
|
158
|
-
"provider": "firebase",
|
|
159
|
-
"config": {
|
|
160
|
-
"apiKey": "...",
|
|
161
|
-
"authDomain": "myapp.com",
|
|
162
|
-
"projectId": "myapp",
|
|
163
|
-
// ... etc.
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
If `cloud.config` is empty/missing, the bridge logs a warning and runs in no-op mode (everything returns harmless defaults).
|
|
170
|
-
|
|
171
|
-
## Firebase (bundled)
|
|
172
|
-
|
|
173
|
-
Firebase is **bundled from @omega.js/desktop's module context** (@omega.js/client owns it in @omega.js/desktop's dependency tree) — the same treatment `json5` gets in main. It was previously runtime-resolved, which silently failed in every symlinked dev app (see CHANGELOG 1.11.1).
|
|
174
|
-
|
|
175
|
-
If you're building a no-auth Electron app, just leave `cloud.config` empty — the bridge is a clean no-op.
|
|
176
|
-
|
|
177
|
-
In a TESTING run (`OMEGA_ENVIRONMENT=testing`) the bridge connects its auth instance to the local auth emulator, on the port it reads in three steps: `OMEGA_AUTH_PORT` when the CLI that booted the stack published one, then the `dev.ports.auth` value the bundle baked into `OMEGA_BUILD_JSON` (a packaged main process has no parent env, [#745](https://github.com/Omega-JS-Stack/omega/issues/745)), then the classic `9099`. Same chain `getApiUrl()` walks ([environment-detection.md](environment-detection.md)) and the same move it makes when it maps testing to localhost, and the same one @omega.js/extension's background worker makes for its emulator runs; development and production are untouched.
|
|
178
|
-
|
|
179
|
-
## Common patterns
|
|
180
|
-
|
|
181
|
-
### Refresh tray when auth state changes
|
|
182
|
-
|
|
183
|
-
```js
|
|
184
|
-
// In src/tray/index.js or wherever you have access to manager:
|
|
185
|
-
manager.omega.onAuthChange((user) => {
|
|
186
|
-
manager.tray.refresh(); // re-evaluates dynamic labels
|
|
187
|
-
});
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
```js
|
|
191
|
-
// In src/tray/index.js:
|
|
192
|
-
tray.item({
|
|
193
|
-
label: () => {
|
|
194
|
-
const user = manager.omega.getCurrentUser();
|
|
195
|
-
return user ? `Signed in as ${user.email}` : 'Sign in';
|
|
196
|
-
},
|
|
197
|
-
click: () => {
|
|
198
|
-
if (manager.omega.getCurrentUser()) {
|
|
199
|
-
manager.omega.signOut();
|
|
200
|
-
} else {
|
|
201
|
-
require('electron').shell.openExternal(`${manager.config.brand.url}/sign-in?desktop=true`);
|
|
202
|
-
}
|
|
203
|
-
},
|
|
204
|
-
});
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
### Gate a deep-link route on auth
|
|
208
|
-
|
|
209
|
-
```js
|
|
210
|
-
manager.deepLink.on('user/profile/:id', (ctx) => {
|
|
211
|
-
if (!manager.omega.getCurrentUser()) {
|
|
212
|
-
require('electron').shell.openExternal(`${manager.config.brand.url}/sign-in?return=profile/${ctx.params.id}`);
|
|
213
|
-
ctx.handled = true;
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
manager.windows.show('main');
|
|
217
|
-
manager.windows.get('main').webContents.send('navigate', { to: `/profile/${ctx.params.id}` });
|
|
218
|
-
});
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
### Sign-out button in a renderer
|
|
222
|
-
|
|
223
|
-
```html
|
|
224
|
-
<button id="signout">Sign out</button>
|
|
225
|
-
<script>
|
|
226
|
-
document.getElementById('signout').addEventListener('click', async () => {
|
|
227
|
-
await renderer.signOut(); // goes through main, propagates everywhere
|
|
228
|
-
});
|
|
229
|
-
</script>
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
## IPC channels
|
|
233
|
-
|
|
234
|
-
| Channel | Direction | Payload | Description |
|
|
235
|
-
|---|---|---|---|
|
|
236
|
-
| `desktop:auth:sync-request` | renderer → main | `{ contextUid }` | "I'm at this UID, are we in sync?" |
|
|
237
|
-
| `desktop:auth:sign-out` | renderer → main | (none) | "Sign me (and everyone) out." |
|
|
238
|
-
| `desktop:auth:get-user` | renderer → main | (none) | Read main's current user. |
|
|
239
|
-
| `desktop:auth:sign-in-with-token` | main → all renderers | `{ token }` | "Sign in with this custom token now." |
|
|
240
|
-
| `desktop:auth:sign-out` | main → all renderers | `{}` | "Sign out now." |
|
|
241
|
-
| `desktop:auth:state-changed` | main → all renderers | `{ uid, email, ... } \| null` | Auth state changed (informational). |
|
|
242
|
-
|
|
243
|
-
## Testing
|
|
244
|
-
|
|
245
|
-
### Unit tests (always run)
|
|
246
|
-
|
|
247
|
-
`client-bridge.test.js` covers the dispatch logic, IPC handler shape, sync-request comparison, and the `auth/token` deep-link integration — all without hitting Firebase.
|
|
248
|
-
|
|
249
|
-
### The real-surface e2e lane (monorepo root)
|
|
250
|
-
|
|
251
|
-
`npm run test:e2e-desktop` ([scripts/e2e-desktop-auth.js](../../../scripts/e2e-desktop-auth.js)) boots a real Electron app against the backend emulator and delivers `<brand.id>://auth/token` from a SECOND instance — the OS-forwarded argv path — then asserts main AND the renderer both land on the emulator user. Offline; it is the lane that proves this whole chain end to end.
|
|
252
|
-
|
|
253
|
-
### Extended tests (skip without the opt-in)
|
|
254
|
-
|
|
255
|
-
`client-bridge.integration.test.js` talks to REAL Firebase, so it is gated behind extended mode (the cross-framework `TEST_EXTENDED_MODE` opt-in; see [test-framework.md](test-framework.md#extended-vs-normal-mode)):
|
|
256
|
-
|
|
257
|
-
```bash
|
|
258
|
-
npx omega test --extended # or: TEST_EXTENDED_MODE=true npx omega test
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
It asks for NO credential of its own ([#819](https://github.com/Omega-JS-Stack/omega/issues/819), Ian 2026-09-13): the service-account path and the test uid it used to mint a custom token from are retired env keys now. The SIGN-IN proof belongs to [#904](https://github.com/Omega-JS-Stack/omega/issues/904), which signs desktop in as a persona the backend emulator seeds, the same mechanism web and the extension use. Without the opt-in the suite skips cleanly with a reason, so CI stays green.
|
|
262
|
-
|
|
263
|
-
## Implementation notes
|
|
264
|
-
|
|
265
|
-
- Firebase app name in main is `omega-auth` (avoids clashes if a consumer's main code also wants its own Firebase instance).
|
|
266
|
-
- The bridge does NOT persist user info to @omega.js/desktop storage — Firebase's IndexedDB persistence handles session restoration. Matches BXM.
|
|
267
|
-
- Custom tokens are NEVER stored. Renderers receive them once via broadcast, sign in, discard. Fresh tokens are minted on demand from `POST /omega/user/token` via @omega.js/client's shared request layer (`createRequest` from `@omega.js/client/modules/request.js`) — same code path as the extension background's token sync.
|
|
268
|
-
- `manager.getApiUrl()` returns the dev or prod URL, so the bridge automatically hits the right backend. Available across all four Manager contexts (main / renderer / preload / build) via the shared `src/utils/url-helpers.js` module — same code path everywhere. See the Cross-context helpers section of the framework guide ([docs/desktop/index.md](../../../docs/desktop/index.md)).
|
|
269
|
-
- All sensitive Firebase user fields (`stsTokenManager`, `providerData`, etc.) are stripped before sending over IPC. Only `{uid, email, displayName, photoURL, emailVerified}` cross the bridge.
|
package/docs/common-mistakes.md
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# Common Mistakes to Avoid
|
|
2
|
-
|
|
3
|
-
1. **Auto-creating windows in main.js** — @omega.js/desktop does NOT auto-create windows. The consumer's main.js must call `manager.windows.create('main', { show: !startup.isLaunchHidden() })` inside `manager.initialize().then()`. Always create `main` — even in hidden launches, with `show: false` — so the activate/second-instance handlers can surface UI on user re-launch.
|
|
4
|
-
2. **Putting JS logic in config** — Trays / menus / context-menus are file-based (`src/integrations/<name>/index.js`). Click handlers, dynamic labels, conditional visibility — all live in the JS file. Don't try to express them in `omega.json5`.
|
|
5
|
-
3. **Shipping `<slot>@2x.png` files** — Ship ONE file at the native (@2x) size; @omega.js/desktop downscales the @1x sibling. Bundled defaults work the same way. See [icons.md](icons.md).
|
|
6
|
-
4. **Naming the macOS tray icon source `trayTemplate.png`** — The input filename is `tray.png` (matches Windows/Linux). @omega.js/desktop owns the `Template` magic when writing to dist.
|
|
7
|
-
5. **Reading `process.cwd()` from packaged-app runtime code** — It's `/` in packaged apps. Use `require('./utils/app-root.js')()` (tries `app.getAppPath()` first, falls back for tests/non-Electron contexts).
|
|
8
|
-
6. **Setting `enabled: true` to turn on sentry/analytics** — Wrong convention. Set the credentials (`monitoring.providers.sentry.dsn = '...'`, `analytics.providers.google.id = '...'`); presence enables. Same for `cloud.config`.
|
|
9
|
-
7. **Defining cross-context helpers on individual Manager prototypes** — Use `attachTo(Manager)` in `src/utils/<topic>-helpers.js` so main/renderer/preload/build all share the same code path.
|
|
10
|
-
8. **Trying to share a Manager instance across processes** — Each process has its own. They communicate via IPC (`manager.ipc.invoke/handle`).
|
|
11
|
-
9. **Calling `shell.openExternal(url)` directly with a dynamic URL** — Gate through `require('./utils/sanitize-url.js')` first (returns `''` for non-http(s) protocols). Any dynamic URL must have its protocol filtered before navigation.
|
|
12
|
-
10. **Hand-editing `dist/electron-builder.yml` or `dist/config/entitlements.mac.plist`** — Both are generated by `gulp/build-config` from `config/omega.json5` + @omega.js/desktop defaults. Edit the source config; the YAML/plist regenerate every build.
|
|
13
|
-
11. **Forgetting that "build" failed but the .app launched anyway** — `ELECTRON_RUN_AS_NODE=1` makes Electron silently run as Node: `app` is undefined, no BrowserWindow, no window appears. The CLI boundary strips this var; if you see weird "nothing happens" launches in dev, check whether your shell has it set.
|
|
14
|
-
12. **Hard-coding `EM_*` env vars in source** — Use `manager.isDevelopment()`, `manager.isProduction()`, `manager.isTesting()`, `manager.getEnvironment()` instead. See [environment-detection.md](environment-detection.md).
|
|
15
|
-
13. **Installing @omega.js/desktop's dependencies as direct consumer deps** — Consumer projects must NOT `npm install firebase`, `fs-jetpack`, `@omega.js/client`, or any other @omega.js/desktop/@omega.js/client transitive dep. The bundler re-resolves every name @omega.js/desktop DECLARES from the framework's own installation (`@omega.js/devkit/bundle`'s framework-deps hook). If a dependency isn't resolving, the fix is in @omega.js/desktop's `package.json` or its bundle task — not the consumer's `package.json`. Mirrors BXM and UJM.
|
|
16
|
-
14. **Touching Firebase directly in consumer code** — Firebase is owned by @omega.js/client. Consumer code NEVER does `require('firebase')` or `import('firebase/app')`. In renderers use `require('@omega.js/client')` → `omega.auth()`, `omega.firestore()`. In main process, use `manager.omega` (the @omega.js/desktop bridge). Same rule in BXM and UJM.
|
|
17
|
-
15. **Forgetting `await` on `windows.create()`** — It's async and returns a Promise, not a BrowserWindow. Passing the Promise to code that calls `win.on(...)` silently fails with "is not a function".
|
|
18
|
-
16. **Using raw `import()` for ESM-only deps** — Use `importESM(specifier)` from `utils/import-esm.js`. It tries the consumer's `node_modules/` first, then falls back to @omega.js/desktop's own copy. This means consumers don't need to install @omega.js/desktop's transitive ESM deps (they're resolved from @omega.js/desktop's `node_modules/` automatically). A dep import the bundler cannot inline (a variable specifier) only resolves from the consumer — if the dep isn't installed there, it fails silently.
|
|
19
|
-
17. **Touching `process` in code shared with renderers** — With `contextIsolation: true` and `nodeIntegration: false` (the defaults), `process` does not exist in renderers — `process.platform` in a shared util throws a `ReferenceError`, it does not return `undefined`. Branch platform/env logic in main (or the preload) and hand the RESULT to the renderer (IPC, preload-exposed value, or a data attribute) — never share a util that dereferences `process` across contexts.
|
|
20
|
-
18. **Expecting `target="_blank"` to work in a `file://` renderer** — Anchors with `target="_blank"` silently do nothing; there is no browser to open. External links go through `shell.openExternal` (gated per mistake 9) — wire a click handler or use the framework's external-link binding rather than a bare anchor.
|
|
21
|
-
19. **Registering the brand-scheme handler on the default session only** — `protocol.handle('<brand.id>', handler)` covers ONLY the default session. Sessions from `session.fromPartition(...)` do NOT inherit it, and Electron auto-opens external protocols: a `brand://` load in a partitioned webContents is classified by Chromium as an EXTERNAL protocol and handed to the OS — macOS Launch Services then launches whatever installed app owns the scheme (an old production copy of YOUR app, mid-run). Silent in dev until it isn't. If your app uses partitions, register the same handler on every partition you vend, idempotently — e.g. a session-manager whose `getElectronSession()` does `ses.protocol.handle(scheme, handler)` guarded by a `WeakSet`. There is no Electron API to read a registered handler back, so this cannot be automated after the fact; register through one owned code path. (Candidate future @omega.js/desktop API: opt-in `manager.protocol.handle(handler)` that applies the handler to the default session + every `session-created` — see TODO.md.) The TEST harness already contains this class of escape during `mgr test` (stub brand handler + `openExternal` denied — see [test-framework.md](test-framework.md)), but that protects tests only, not your packaged app.
|