@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/restart-manager.md
CHANGED
|
@@ -49,7 +49,7 @@ There is deliberately no quit endpoint — RM updates itself (below); nothing ex
|
|
|
49
49
|
|
|
50
50
|
1. **Boot** (step 12e): after `whenReady` + 15s (3s dev), `register()` runs the full flow — probe (`runtime.json` → pid alive via `process.kill(pid, 0)` (EPERM = alive) → `GET /v1/health` with protocolVersion match) → if RM isn't serving: `ensureInstalled()` + `ensureRunning()` (spawn detached, poll up to 15s) → `POST /v1/register` with **this process's pid**. Attempt budget: 3 per invocation. Never throws; failures land in `getStatus().lastError`.
|
|
51
51
|
2. **Heartbeat**: re-POST register every 60s (idempotent upsert on RM's side). Doubles as the keep-alive — a failed tick runs the full `register()` flow, which respawns (or reinstalls, cooldown-gated) RM.
|
|
52
|
-
3. **Graceful quit**: the first `before-quit` is prevented once, deregister flushes with a hard 1s cap, then `
|
|
52
|
+
3. **Graceful quit**: the first `before-quit` is prevented once, deregister flushes with a hard 1s cap, then `omega.quit({ force: true })` re-quits (all framework before-quit listeners are double-fire safe: main.js `_isQuitting`, appState sentinel, usage stamp). Exception: when the auto-updater has a staged install (`_allowQuit` + status `downloaded`) we never intercept `quitAndInstall`, deregister goes fire-and-forget and RM's grace window covers the race. RM-side safety net: a crash only counts after 2 consecutive dead ticks (~20s), so a slightly-late deregister always wins.
|
|
53
53
|
4. **Crash**: the pid dies with the registration still present → RM relaunches the app from its registered exe path (mac: `open` on the derived bundle). Never in dev — RM refuses to relaunch `environment !== 'production'` registrations (a dev exe path is the bare electron binary). Crash loops back off (3 relaunches / 10 min → RM gives up, visible in its dashboard).
|
|
54
54
|
|
|
55
55
|
## Silent install (smart existence first)
|
|
@@ -76,8 +76,8 @@ The update relaunch is safe by construction: RM's registrations are **storage-pe
|
|
|
76
76
|
|
|
77
77
|
## Bail conditions
|
|
78
78
|
|
|
79
|
-
- **`
|
|
80
|
-
- `
|
|
79
|
+
- **`omega.isTesting()`**: nothing fires on its own: no timers, no before-quit hook (a preventDefault would wedge the harness quit), and the root is isolated under the testing userData. Tests drive `register()`/`ensureInstalled()` explicitly against fixture servers; the network and spawn paths stay dead (`ensureInstalled` refuses network without `TEST_EXTENDED_MODE`, `ensureRunning` never spawns in testing).
|
|
80
|
+
- `omega.config.brand.id === 'restart-manager'`: RM doesn't manage itself.
|
|
81
81
|
- `config.restartManager.enabled === false` — explicit opt-out.
|
|
82
82
|
- Non-production without `OMEGA_RESTART_MANAGER_DEV=1` — dev noise guard.
|
|
83
83
|
|
|
@@ -96,11 +96,11 @@ Existing consumers with the old `{ enabled: true }` shape need zero changes.
|
|
|
96
96
|
## API
|
|
97
97
|
|
|
98
98
|
```js
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
99
|
+
omega.restartManager.register() // full ensure-installed→ensure-running→POST flow; never throws
|
|
100
|
+
omega.restartManager.unregister() // best-effort deregister (stops the heartbeat)
|
|
101
|
+
omega.restartManager.ensureInstalled() // smart-existence install; true when present
|
|
102
|
+
omega.restartManager.ensureRunning() // probe → spawn → poll; true when serving
|
|
103
|
+
omega.restartManager.getStatus() // { enabled, bailed, bailReason, root, installed,
|
|
104
104
|
// installedVersion, running, registered, port,
|
|
105
105
|
// pid, lastHeartbeatAt, lastError }
|
|
106
106
|
```
|
package/docs/runner.md
CHANGED
|
@@ -56,7 +56,7 @@ Then, in a normal (non-elevated) PowerShell:
|
|
|
56
56
|
|
|
57
57
|
Then the orgs: a checkbox of every org your token administers, in alphabetical order. Ticked by default are the orgs this box already answered for — the saved `OMEGA_RUNNER_ORGS`, else the orgs it actually registered, else NOTHING. A token that administers 35 orgs must never register 35 runners on one Enter. Ticking nothing is refused too — a runner registered against no org is not a runner. Off a TTY the walk asks nothing: `config` says so and stops (edit the file instead), `install` refuses only when a required key is missing, and a blank org list still means every org the token administers, because CI has no keyboard.
|
|
58
58
|
|
|
59
|
-
`start` is the exception, deliberately: it asks only for MISSING required keys, never the checkbox, and warns when the file's org list is not the one this install registered.
|
|
59
|
+
`start` is the exception, deliberately: it asks only for MISSING required keys, never the checkbox, and warns when the file's org list is not the one this install registered. On a bare box (nothing installed yet) `start` runs install itself, so there it is install's full walk, checkbox included.
|
|
60
60
|
|
|
61
61
|
Orgs in `OMEGA_RUNNER_ORGS` you do not administer are named in a warning and skipped.
|
|
62
62
|
|
|
@@ -64,13 +64,13 @@ Orgs in `OMEGA_RUNNER_ORGS` you do not administer are named in a warning and ski
|
|
|
64
64
|
|
|
65
65
|
```powershell
|
|
66
66
|
npx omega runner status # registered orgs, Startup shortcuts, live listeners, legacy leftovers
|
|
67
|
-
npx omega runner start #
|
|
67
|
+
npx omega runner start # the one command: install a bare box, else heal HOME and the job guard, refresh a stale actions/runner in place,
|
|
68
|
+
# register any admin org not served yet, then bring EVERY registered org up, detached (an org already alive is skipped)
|
|
68
69
|
npx omega runner restart # stop, wait for the listeners to go, then start
|
|
69
70
|
npx omega runner stop # kill every Runner.Listener.exe under the runner home
|
|
70
|
-
npx omega runner install #
|
|
71
|
+
npx omega runner install # the explicit clean rebuild: tears down first, so re-running is safe
|
|
71
72
|
npx omega runner config # the same full walk install runs — every key, current values as the defaults, plus the orgs
|
|
72
73
|
npx omega runner register-org <org># register one specific org
|
|
73
|
-
npx omega runner self-update # npm i -g @omega.js/desktop@latest
|
|
74
74
|
npx omega runner uninstall # remove everything, legacy services, tasks and the em-runner install included
|
|
75
75
|
npx omega runner monitor # tail the signing event log
|
|
76
76
|
```
|
|
@@ -79,13 +79,13 @@ Notes worth knowing before you use them:
|
|
|
79
79
|
|
|
80
80
|
- **`config` is `install`'s configuration step, alone.** Same walk, same defaults, same order — it just does not go on to register anything. A saved org your token no longer administers is named before the checkbox, since it cannot appear in it. Windows-only, and terminal-only (with nothing to ask with it stops and names the file). When the orgs you pick are not the ones this install registered, it says to re-run `install`.
|
|
81
81
|
- **Every subcommand tees its output to `<runner home>\logs\runner.log`**, and so does `npx omega sign-windows` — including inside a `windows-sign` job, which is exactly when the box's own record is wanted (the log lives in the runner home, never in a workspace, so the usual "no logs in CI" rule does not apply to it). `runner status` prints the path on its own line. It APPENDS, because more than one process writes it: `start` returns as soon as the runners are spawned, and every `sign-windows` those listeners go on to run adds to the same file. Each run stamps its own `# omega log` header; nothing rotates it, so delete the file when you want a clean one. `uninstall` keeps `.env` and `logs\`, since the log it is writing while it runs is the trail of that uninstall.
|
|
82
|
-
- **A refusal writes nothing.** Off Windows every subcommand but `
|
|
82
|
+
- **A refusal writes nothing.** Off Windows every subcommand but `monitor` stops at the platform check before the log file is opened, so running one on a Mac by accident leaves no `.gh-runners/` in the directory you were standing in.
|
|
83
83
|
- **The box verbs ignore the project's `.env` cascade.** `runner` and `sign-windows` read the shell and `<runner home>\.env`, nothing else, so running them from inside a brand folder can never hand a brand's `GH_TOKEN` to the box ([#337](https://github.com/Omega-JS-Stack/omega/issues/337)). Every other verb keeps the cascade.
|
|
84
|
-
- **`start` brings up EVERY registered org, detached.** It walks the Startup shortcuts in order and spawns one hidden runner per org, so the terminal comes straight back and nothing is lost by not watching it: the listener's output is the JSONL log `monitor` tails. Running it again is safe, which is the point of it: an org whose listener is already alive is named with its PID and skipped, never duplicated and never a refusal. Exit 0 when every org ends up online, 1 when a spawn failed. A listener sitting in session 0 is skipped too, but loudly: it is alive and will fail every job it picks up, so the line names the session and points at `restart`. Killing a listener is `stop`'s job, never a start's.
|
|
84
|
+
- **`start` brings up EVERY registered org, detached.** It walks the Startup shortcuts in order and spawns one hidden runner per org, so the terminal comes straight back and nothing is lost by not watching it: the listener's output is the JSONL log `monitor` tails. Running it again is safe, which is the point of it: an org whose listener is already alive is named with its PID and skipped, never duplicated and never a refusal. Exit 0 when every org ends up online, 1 when a spawn or a registration failed. A listener sitting in session 0 is skipped too, but loudly: it is alive and will fail every job it picks up, so the line names the session and points at `restart`. Killing a listener is `stop`'s job, never a start's.
|
|
85
85
|
- **`restart` is `stop` then `start`**, in that order, for the loop you would otherwise run by hand after a config change. It settles two things the two commands typed in sequence do not: the box config walk runs FIRST, so a box missing a required key is refused before anything is killed rather than left stopped, and each org's dir is polled (5 seconds) until no listener stands in it, because `taskkill` returns before the process is gone and a start that raced it would read the dying listener as "already running". A listener still standing after the wait is reported and that org is left alone, exit 1.
|
|
86
86
|
- **`stop` leaves the Startup shortcuts in place**, so a logout/login brings the runner back. For a permanent stop, run `uninstall`.
|
|
87
|
-
- **Every subcommand except `
|
|
88
|
-
- **A test process cannot touch a real box.** Every subcommand that changes the machine
|
|
87
|
+
- **Every subcommand except `monitor` refuses on non-Windows.** `OMEGA_RUNNER_FORCE=1` overrides it, for framework tests only.
|
|
88
|
+
- **A test process cannot touch a real box.** Every subcommand that changes the machine (`install`, `config`, `register-org`, `start`, `restart`, `stop`, `uninstall`) refuses, before the platform check and naming `OMEGA_TEST_RUNNER`, whenever the run is a test (`omega test` sets that variable; `OMEGA_TEST_MODE` counts too, the marker a sibling framework's runner or a consumer's own test script sets) and a home it could act on is not a scratch one, under a `.temp` directory or the OS temp dir. BOTH homes are checked, the passed one and the module-level `RUNNER_HOME`, because the box's `.env` was already read into the process from the latter when the command module was required; the refusal names whichever is real. The marker is read from the process environment only — an injected environment is a fixture for the config walk, never an answer to "am I a test". The Startup folder is the THIRD surface checked, because no home scopes it — `uninstall` sweeps every `omega-runner-*.cmd` in the folder whatever home it was given, and a case whose two homes were both scratch deleted the box's three real shortcuts. It has its own scratch seam, `OMEGA_RUNNER_STARTUP_DIR`, and a test run against the real folder refuses naming both. The surfaces that no path can redirect at all — the watcher service, the legacy logon tasks, the `actions.runner.*` services, and the legacy `em-runner` homes — are simply not swept under a test run; `uninstall` says so on one line instead. A test run also never kills a process whose ExecutablePath it cannot read: that path belongs to another account, and matching it scopes to no home at all, so `stop` and `uninstall` drop the clause instead of `taskkill /F`-ing a stranger's runner. And it never deregisters on its own: `deregisterOrgRunners` mints a real removal token and runs each org directory's `config.cmd`, neither of them home-scoped, so with a roster to remove a test run refuses, naming the seam, unless `exec` is injected and, while `GH_TOKEN` is set, `getRemoveToken` too. `start` and `restart` skip their org check the same way, on one line, unless both `_discoverOrgs` and `_registerOrg` are injected: registering acts on GitHub, never on a home. A framework suite that wants to drive these points `OMEGA_RUNNER_HOME` and `OMEGA_RUNNER_STARTUP_DIR` at scratches *before* the command module is required, since both are resolved once, at require time. `sign-windows` follows the same rule for its log: from a test run pointed at a real home it tees nowhere rather than write the box's own record. This exists because a suite once ran a real `install` on the box and registered 34 orgs.
|
|
89
89
|
- **`uninstall` deregisters on the GitHub side first, and keeps whatever did not come off.** It walks every `actions-runner-<org>\` directory under the runner home and runs that directory's own `config.cmd remove` before anything is deleted. If a removal exits non-zero — or `GH_TOKEN` is not set, so no removal token can be minted — that runner is still registered, so its directory SURVIVES the uninstall and the summary names the org. Re-running `uninstall` retries it. Belt and braces: `register-org` also deletes every org-side runner starting with this host's prefix before it registers a new one.
|
|
90
90
|
|
|
91
91
|
## Upgrading from the electron-manager runner
|
|
@@ -102,7 +102,9 @@ So the upgrade on the box is the ordinary one: `npx omega runner install` with `
|
|
|
102
102
|
|
|
103
103
|
## Adding a new org
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
No process watches for new orgs, but `start` checks every time it runs: `npx omega runner start` lists the orgs your `GH_TOKEN` administers, narrows them by `OMEGA_RUNNER_ORGS` when it is set, registers each one this box does not serve yet (Startup shortcut included), and brings it online with the rest. Orgs registered outside the list stay registered; `npx omega runner install` is the command that reshapes the box to the list exactly. An org check that cannot reach GitHub is one warn line, and `start` carries on and brings every registered org online.
|
|
106
|
+
|
|
107
|
+
To register one specific org alone:
|
|
106
108
|
|
|
107
109
|
```powershell
|
|
108
110
|
npx omega runner register-org <org-name>
|
|
@@ -280,7 +282,7 @@ The SafeNet driver sometimes detaches after a major OS update. Open the SafeNet
|
|
|
280
282
|
|
|
281
283
|
## Upgrading the actions/runner binary
|
|
282
284
|
|
|
283
|
-
`ACTIONS_RUNNER_VERSION` in `src/commands/runner.js` pins it. Bump the constant, ship
|
|
285
|
+
`ACTIONS_RUNNER_VERSION` in `src/commands/runner.js` pins it. Bump the constant, ship, then on the box run `npx omega runner start`. It sees that the version `config.json` recorded is not the pinned one, re-downloads `_template` in place, and copies it over each org dir whose listener is not running. `.runner`, `.credentials` and `.env` are not in the template, so every registration survives, and nothing is torn down. An org whose listener IS running has its binaries locked: it is skipped with one line naming `npx omega runner restart`, and the new version is recorded only once every org dir took it, so a `restart` (which stops first) finishes the job. `npx omega runner install` remains the clean rebuild when you want one.
|
|
284
286
|
|
|
285
287
|
## Related
|
|
286
288
|
|
package/docs/sentry.md
CHANGED
|
@@ -63,16 +63,16 @@ default set. Desktop's own `process.on('uncaughtException'|'unhandledRejection')
|
|
|
63
63
|
Same surface in main and renderer:
|
|
64
64
|
|
|
65
65
|
```js
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
omega.sentry.captureException(error, { extra: { ...context } })
|
|
67
|
+
omega.sentry.captureMessage('explicit log', 'info' | 'warning' | 'error')
|
|
68
|
+
omega.sentry.setUser({ id, email }) // or null to clear
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
In renderer (via preload bridge): `window.desktop.sentry` would expose the same surface — currently not wired (preload doesn't yet bridge sentry; renderer code can call `@sentry/electron/renderer` directly if it needs to).
|
|
72
72
|
|
|
73
73
|
## Auth attribution
|
|
74
74
|
|
|
75
|
-
When the user signs in via `client-bridge`, @omega.js/desktop automatically calls `
|
|
75
|
+
When the user signs in via `client-bridge`, @omega.js/desktop automatically calls `omega.sentry.setUser({ id, email })`. On sign-out, `setUser(null)` clears the context. So every error report is attributed to whoever was signed in at the time.
|
|
76
76
|
|
|
77
77
|
The user object is **normalized** before being sent — only `uid`/`id` is kept, and everything else (display name, photo URL, OAuth provider data, etc.) is stripped to avoid accidentally leaking PII.
|
|
78
78
|
|
package/docs/shared/analytics.md
CHANGED
|
@@ -534,7 +534,7 @@ name, birthday, gender, location and phone.
|
|
|
534
534
|
**One normalization table per provider, and no shared "close enough" normalizer.** The rules
|
|
535
535
|
genuinely differ key by key, and a value normalized by the wrong platform's rule is ACCEPTED
|
|
536
536
|
by the API and matched to nobody — the same silent nothing an unhashed value is. The server's
|
|
537
|
-
tables live in `packages/backend/src/
|
|
537
|
+
tables live in `packages/backend/src/omega/libraries/analytics/match-data.js`; the browser
|
|
538
538
|
half's shared rules (email, phone, external id) live in `@omega.js/analytics/identity` so both
|
|
539
539
|
halves of one person present identical keys.
|
|
540
540
|
|
package/docs/shared/brands.md
CHANGED
|
@@ -16,7 +16,7 @@ Fixture for the AUTOMATED corpus/e2e suites: offline, `demo-*` Firebase, determi
|
|
|
16
16
|
|
|
17
17
|
### `brands/playground-omega` — "OMEGA Playground", the standing live test brand
|
|
18
18
|
|
|
19
|
-
Renamed from omega-brand (Ian 2026-07-11, zero ambiguity). Born through the real wizard: id `playground` (shortened on 2026-09-10, [#808](https://github.com/Omega-JS-Stack/omega/issues/808), so the `<brand.id>-<role>` rule derives clean repo names off it), url playground.omegajs.dev, a SUBDOMAIN so derived surfaces never claim the real omegajs.dev. Its THREE repos all derive from that id, none of them typed ([#883](https://github.com/Omega-JS-Stack/omega/issues/883), all under the one `repo: { provider: 'github', org: 'Omega-JS-Stack' }` block): `playground-omega` (the
|
|
19
|
+
Renamed from omega-brand (Ian 2026-07-11, zero ambiguity). Born through the real wizard: id `playground` (shortened on 2026-09-10, [#808](https://github.com/Omega-JS-Stack/omega/issues/808), so the `<brand.id>-<role>` rule derives clean repo names off it), url playground.omegajs.dev, a SUBDOMAIN so derived surfaces never claim the real omegajs.dev. Its THREE repos all derive from that id, none of them typed ([#883](https://github.com/Omega-JS-Stack/omega/issues/883), all under the one `repo: { provider: 'github', org: 'Omega-JS-Stack' }` block): `playground-omega` (the PUBLIC source repo since 2026-09-24, so its Actions runs never count against the org storage allowance; the folder name here, whose `main` every `omega deploy` snapshots this folder onto, [docs/shared/deploys.md](deploys.md)), `playground-releases` (public: the desktop installers, the extension zips and the autoupdater feed), and `playground-web` (public: the BUILT site alone, one force-orphan commit on `gh-pages`, served by Pages at playground.omegajs.dev, which is what let the source repo stay private on a free org before it went public). The third, the private `playground-rehearsal` snapshot, retired with the rehearsal itself ([#872](https://github.com/Omega-JS-Stack/omega/issues/872)). Points at the real-but-throwaway Firebase project `omegajs-playground` (ITW-org-owned since 2026-07-11; sanctioned for live proofs: Blaze it, break it, delete it; it is TEST INFRASTRUCTURE, never production).
|
|
20
20
|
|
|
21
21
|
REBRANDED **OMEGA Playground** (Ian 2026-08-21, [#433](https://github.com/Omega-JS-Stack/omega/issues/433) — REVERSES the 2026-07-19 fiction ruling, whose invented brand read as a real product in the ad and analytics consoles). The doctrine now: the playground is openly the OMEGA test surface — "we can mess around here, nothing live actually matters" — so drift from the real omegajs.dev site reads as a demo doing its job, never as a broken copy. Infra identity unchanged (id, url, green accent, classy theme); name and voice are the only things that moved, and the catalog's display names stay placeholder demo copy. Cloud-side display names (the Meta pixel, the GA property + streams, the GCP project name) are the manager's follow-up.
|
|
22
22
|
|
|
@@ -26,6 +26,73 @@ gap tables, not this file. Converter TOOLING is
|
|
|
26
26
|
input, not its implementation. The legacy repos stay read-only reference
|
|
27
27
|
(AGENTS.md HARD RULE 1): nothing here asks you to change them.
|
|
28
28
|
|
|
29
|
+
## 2026-09-25: one runtime shape on every package ([#945](https://github.com/Omega-JS-Stack/omega/issues/945))
|
|
30
|
+
|
|
31
|
+
Every package's default export is ONE ready-made instance, `omega`, and a consumer never
|
|
32
|
+
writes `new`. `initialize(options)` returns that instance on every surface; on the async
|
|
33
|
+
surfaces `omega.ready` is the same promise, so a module that did not call it can still await
|
|
34
|
+
it. The class is exported by name (`Omega`) for tests only. Accessors are properties, never
|
|
35
|
+
zero-arg methods. `auth.user` is always a `User` from `@omega.js/account`: the stored account
|
|
36
|
+
document as own fields, the derived facts as getters, and a signed-out `User` (`authenticated`
|
|
37
|
+
false, `plan` basic) instead of null. The `@omega.js/manager` package, its `omega manage` verb
|
|
38
|
+
and its banners keep their names.
|
|
39
|
+
|
|
40
|
+
| Contract | Old form | New form | Manual migration step |
|
|
41
|
+
|---|---|---|---|
|
|
42
|
+
| Backend consumer entry (`src/index.js`) | `const Manager = (new (require('@omega.js/backend'))).init(exports, { … });` then `const { functions } = Manager.libraries;` | `const omega = require('@omega.js/backend');`, then `omega.initialize({ … });`, and `module.exports = omega.functions;` as the file's last line | Rewrite the two lines and add the export line. A function of your own joins the map before it: `omega.functions.items = omega.firebase.functions.region(omega.project.resourceZone).https.onRequest((req, res) => omega.routes.run('items', { req, res }));` |
|
|
43
|
+
| Desktop consumer entries (`src/main.js`, `src/preload.js`, each `src/assets/js/components/<view>/index.js`) | `new (require('@omega.js/desktop/main'))().initialize()`, or a `manager` instance destructured after `initialize()` | `const omega = require('@omega.js/desktop/main');` (or `/preload`, `/renderer`), then `omega.initialize().then(() => { const { logger, windows } = omega; })` | Rewrite each entry; every `manager.` becomes `omega.` |
|
|
44
|
+
| Extension contexts (`background`, `popup`, `sidepanel`, `options`, `page`, `content`, `offscreen`) | `import Manager from '@omega.js/extension/popup'; const manager = new Manager(); await manager.initialize();`, with the client read as `manager.omega` | `import omega from '@omega.js/extension/popup'; await omega.initialize();`: the instance IS the runtime, and the four page contexts carry the client's modules on it (`omega.auth`, `omega.storage`, `omega.bindings`) | Rewrite each context's entry and drop the `omega` destructure. The bare `@omega.js/extension` import is gone: import the context entry |
|
|
45
|
+
| Web service worker (`src/service-worker.js`) | `import Manager from '@omega.js/web/service-worker'; const manager = new Manager(); manager.initialize()` | `import omega from '@omega.js/web/service-worker'; omega.initialize()`; the framework file is `sw/omega.js` | Rewrite the three lines |
|
|
46
|
+
| Web page, layout, section and global modules | `export default ({ manager, options }) => { }`, and `import omega from '@omega.js/client'` for the client | `export default async ({ omega, options }) => { }`; a module that needs the instance outside that call imports `@omega.js/web/runtime` | Rename the argument, and repoint every `@omega.js/client` default import at `@omega.js/web/runtime` |
|
|
47
|
+
| A theme's `_theme.js` | A side-effect module: its initializers ran on import | `export default async ({ omega, options }) => { }`, which the host calls with the booted instance | Move the theme's initializers into the default export |
|
|
48
|
+
| Web page features | `omega.library().showExitPopup()` and the rest of the `omega.library()` / `omega._library` bag | Properties of the web instance: `omega.appearance`, `omega.shell`, `omega.motion`, `omega.exitPopup.show()` (`exitPopup` is null when the popup is off) | Rewrite each `omega.library()` read to the property |
|
|
49
|
+
| Client accessors | `omega.auth()`, `omega.utilities().escapeHTML(x)`, `omega.firestore()`, `omega.bindings()`, `omega.storage()`, `omega.dom()`, `omega.sentry()`, and the rest | `omega.auth`, `omega.utilities.escapeHTML(x)`, `omega.firestore`, `omega.bindings`, `omega.storage`, `omega.dom`, `omega.sentry` | Drop the `()` after every module name; a missed site throws `is not a function` |
|
|
50
|
+
| `@omega.js/client` default export | A live singleton, imported anywhere | The base class `Omega` and no instance: web, the extension page contexts and the desktop renderer each export the one instance | Import the instance from the host framework (`@omega.js/web/runtime`, the extension context, `@omega.js/desktop/renderer`), never from `@omega.js/client` |
|
|
51
|
+
| The signed-in user | `auth.getUser()` (the Firebase profile, or null), `auth.isAuthenticated()`, `auth.resolveSubscription(account)` | `auth.user`, a `User`: `authenticated`, `uid`, `email`, `plan`, `active`, `trialing`, `cancelling`, `everPaid`, the stored fields (`user.roles`, `user.subscription`), and `user.profile.{displayName,photoURL,emailVerified}` | Replace each call with the property. A `if (user)` check reads `user.authenticated`, since `auth.user` is never null |
|
|
52
|
+
| The auth listener state | `auth.listen((state) => …)` with `{ user, account, resolved, accountDenied }` | `{ user, denied }`: `user` is the one `User`, `denied` is true only when rules refused the account read. `auth.reload()` re-reads the account and resolves with the new state | Read `state.account.*` and `state.resolved.*` off `state.user`, and `state.accountDenied` as `state.denied` |
|
|
53
|
+
| Bindings | Three roots: `auth.user` (the Firebase profile), `auth.account.*` and `auth.resolved.*` | ONE root, `auth.user`: `auth.user.plan`, `auth.user.active`, `auth.user.roles.admin`, `auth.user.profile.displayName`, `auth.user.profile.photoURL`. `usage` stays its own root | Rewrite each `data-omega-bind`: `auth.account.x` and `auth.resolved.x` read `auth.user.x`, `auth.user.displayName` reads `auth.user.profile.displayName`, and `@show auth.user` reads `@show auth.user.authenticated` |
|
|
54
|
+
| `FormManager` | `new FormManager('#form', options)`, the class importing the singleton | `new FormManager(omega, '#form', options)` | Pass the instance first |
|
|
55
|
+
| Click triggers | `registerTrigger('name', handler)` from `@omega.js/client/modules/triggers.js` | `omega.triggers.register('name', handler)` | Rewrite each registration; the class stays `omega-<name>` |
|
|
56
|
+
| Extension auth page and messaging | `openAuthPage()`; `messenger.onMessage = (message, sender, sendResponse) => { }`; `messenger` absent in background and offscreen | `omega.auth.openPage()`; `messenger.onMessage(handler)`, which returns the unsubscribe; `messenger` on every context, and background's `omega.auth.user` built from the whole account document | Rewrite the call and every `onMessage` assignment |
|
|
57
|
+
| Desktop main auth | `manager.omega` (the client bridge): `getCurrentUser()`, `onAuthChange(fn)`, `getResolvedPlan()`, `getResolvedRoles()` | `omega.auth`: `.user` (a `User` built from the whole account document), `.listen(fn)`, `.signOut()`, `.getIdToken()`, `.handleToken()` | `getCurrentUser()` reads `omega.auth.user`, `onAuthChange` is `listen`, and the plan and roles read `omega.auth.user.plan` and `omega.auth.user.roles` |
|
|
58
|
+
| Desktop renderer | `manager.omega` for the client; `manager.storage` and `window.desktop.*` for the main process | The renderer instance extends the client (`omega.auth`, `omega.firestore`); everything that crosses to main is `omega.desktop.{ipc,storage,theme,fontawesome,autoUpdater,analytics,context,usage,remoteConfig}`. `omega.storage` is the page store; the app store is `omega.desktop.storage` | Read the client off the instance, and the app store as `omega.desktop.storage` |
|
|
59
|
+
| Desktop integrations (`src/integrations/<tray,menu,context-menu>/index.js`) | `module.exports = ({ manager, tray }) => { }` | `module.exports = ({ omega, tray }) => { }` (menu and context menu likewise) | Rename the argument |
|
|
60
|
+
| Desktop test harness | Boot `inspect` bodies received `{ manager, expect, … }`; the harness wrote `__EM_TEST__` lines on stdout | `{ omega, expect, … }`; the prefix is `__OMEGA_TEST__` | Rename the argument, and any grep of a run's stdout |
|
|
61
|
+
| Desktop logger export | `require('@omega.js/desktop/lib/logger')` | `require('@omega.js/desktop/build').logger(name)` at build time, `omega.logger` at runtime | Repoint the require |
|
|
62
|
+
| Build modules (`@omega.js/desktop/build`, `@omega.js/extension/build`) | `const Manager = new (require('@omega.js/extension/build')); Manager.getConfig();`; hook context `{ manager, projectRoot, mode }` | `const build = require('@omega.js/extension/build'); build.getConfig();` (no class, no `new`); hook context `{ build, projectRoot, mode }` | Rewrite each hook's require and its destructure |
|
|
63
|
+
| Backend route handler | `async ({ Manager, ctx, analytics, usage, user, settings, libraries, utilities }) => { }` | `async ({ ctx, omega, user, data, usage, analytics }) => { }`; everything in the list is also on `ctx` | Rename `settings` to `data`, `Manager` to `omega`; `libraries.admin` reads `omega.firebase.admin`, `utilities` reads `omega.utilities` |
|
|
64
|
+
| Backend event and cron handlers | Events `({ Manager, ctx, libraries, user, context, change, snapshot })`; cron `({ Manager, ctx, context, libraries })` | Events `({ ctx, omega, user, context, change, snapshot })`; cron `({ ctx, omega, context })` | Same renames as a route |
|
|
65
|
+
| Backend `ctx` | `RouteContext`: `ctx.Manager`, `ctx.getUser()`, `ctx.request.user`, `ctx.resolvedUser`, `ctx.settings`, `ctx.ref`, `ctx.constant.pastTime` | `Context`: `ctx.omega`, `ctx.user` (a `User`), `ctx.data`, `ctx.req` / `ctx.res`; request services built on first read: `ctx.usage`, `ctx.analytics`, `ctx.email`, `ctx.ai`, `ctx.metadata(doc)` | Rewrite each read. `ctx.constant.pastTime` has no replacement |
|
|
66
|
+
| Backend instance | `Manager.libraries.admin` / `.functions`, the factories (`Manager.User()`, `Manager.Usage()`, `Manager.Analytics()`, `Manager.Settings()`, `Manager.Utilities()`, `Manager.AI()`, `Manager.Email()`, `Manager.Metadata()`), `Manager.Middleware(req, res).run('items', options)` | `omega.firebase.admin` / `omega.firebase.functions` (the SDK; `omega.functions` is the exported map); the request services on `ctx` and the process services on `omega` (`omega.utilities`, `omega.email`, `omega.ai`, `omega.storage({ name })`); `omega.routes.run('items', { req, res }, options)` | A route never constructs a service: read it off `ctx` or `omega` |
|
|
67
|
+
| Backend events from a consumer's own trigger | `Manager.EventMiddleware(payload).run('users/on-create')` | `omega.events.run('users/on-create', payload)`: the dispatcher the framework's own triggers use; a relative name loads `<cwd>/events/<name>.js`, a leading `/` is verbatim | Rewrite each trigger: `.onCreate((user, context) => omega.events.run('users/on-create', { user, context }))` |
|
|
68
|
+
| Backend consumer routes | A consumer route rode `omega_api` at `/omega/<name>` and won over a framework route of the same name; `omega.run(name, req, res, options)` and `omega.runEvent(name, payload)` | `omega_api` and `/omega/*` serve only the framework's routes and the MCP endpoint. A consumer route is its own function, `omega.routes.run(name, { req, res }, options)` in the region `omega.project.resourceZone`, behind its own hosting rewrite at its own path (`/notes`); `omega.events.run(name, payload)` runs a trigger's handler. A consumer MCP tool's `path` is the path as served (`/notes`) | Give each route its own function and a `{ "source": "{/notes,/notes/**}", "function": "notes" }` rewrite after the `omega_api` one, repoint every caller from `/omega/<name>` to `/<name>`, prefix each consumer tool `path` with `/`, and rename `omega.run`/`omega.runEvent` |
|
|
69
|
+
| Backend `initialize()` options | `setupFunctionsIdentity`, and the test-runner switches `initialize`, `setupFunctions`, `setupServer`, `log` | `identity`; the switches are gone (`OMEGA_TEST_RUNNER` decides) | Rename `setupFunctionsIdentity`; delete the switches |
|
|
70
|
+
| Backend pipeline options | `setupSettings`, `includeNonSchemaSettings`, `parseMultipartFormData` | `validate`, `includeUnknown`, `parseMultipart` | Rename each option passed to `omega.routes.run()` |
|
|
71
|
+
| Config environment mixin | `attachTo(Manager)` / `attachEnvironment` from `@omega.js/config` | Each instance calls `getEnvironment()` and the three checks directly | Delete the mixin call |
|
|
72
|
+
| Removed outright (backend) | `functions/_legacy/` and the `setupFunctionsLegacy` option, `functions/wrappers/mailchimp/addToList.js`, `helpers/api-manager.js` (`ApiManager`), `helpers/roles.js` (`Roles`), `Manager.install()`, `Manager.debug()`, `self.interface`, `libraries.localDatabase` and `initializeLocalStorage`, `fetchStats`, `server-manager.js` | Gone | Delete every reference; `ctx.usage` covers what `ApiManager` counted |
|
|
73
|
+
| The `/backend-manager/*` URL alias | The router stripped the prefix, the edge worker forwarded it, and the `omega_api` hosting rewrite listed `/backend-manager` and `/backend-manager/**` | Gone: a call to the old prefix answers 404 | Repoint every caller at `/omega/*`, and drop the two sources from the brand's `firebase.json` rewrite |
|
|
74
|
+
| Removed outright (frontends) | Client `omega.library()` / `omega._library`; extension `openAuthPage()`, the root `.` export, the `attachTo` mixins; desktop `manager.omega`, `wmBridge`, `./lib/logger`, `__EM_TEST__` | Gone; each row above names its replacement | Rewrite per the rows above |
|
|
75
|
+
|
|
76
|
+
## 2026-09-25: one request-schema system ([#823](https://github.com/Omega-JS-Stack/omega/issues/823))
|
|
77
|
+
|
|
78
|
+
A route's schema file exports a function of the request and returns a plain field
|
|
79
|
+
declaration. ONE adapter turns that declaration into a zod schema and validates with it, so
|
|
80
|
+
zod is the only validator underneath and a schema stays a plain object until it runs: a split
|
|
81
|
+
on the plan, the query, the path or any other request fact is ordinary code
|
|
82
|
+
(`if (user.plan === 'pro') fields.limit.max = 200;`). Defaults still coerce and never reject.
|
|
83
|
+
The hand-rolled engine and the zod builder layer are both gone. The full vocabulary and the
|
|
84
|
+
split kinds: [schemas.md](../../packages/backend/docs/schemas.md).
|
|
85
|
+
|
|
86
|
+
| Contract | Old form | New form | Manual migration step |
|
|
87
|
+
|---|---|---|---|
|
|
88
|
+
| The schema function's argument | `({ ctx, user, data, method, headers, geolocation, client })` | `({ user, body, query, path, method, headers, geolocation })`: `user` is the caller's `User`, `body` and `query` are the raw parts (the route still receives their validated merge as `data`) | Read `data.x` as `body.x` or `query.x`, `user.subscription.product.id` as `user.plan`; a schema no longer reaches `ctx` or `client` |
|
|
89
|
+
| A field | `{ types: ['string'], default: '' }`, or a builder: `f.string({ default: '' })`, `f.number(…)`, `f.array(…)`, `f.passthrough(…)`, `f.multi(['string', 'number'], …)`, `f.any(…)` | `{ type: 'string', default: '' }`; `type` is one of `string number boolean array object any`, or a list of them | Rewrite each field; `f.passthrough` is `type: 'object'`, `f.multi(list)` is `type: list` |
|
|
90
|
+
| Nesting | A nested plain object, or `f.object({ … })` around the whole schema | The function returns the declaration itself; a nested object is `{ type: 'object', fields: { … } }`, array items are `of: { … }` | Return the map directly and wrap each nested group in `fields` |
|
|
91
|
+
| `required` | A boolean or a function (`required: () => isPremium`) | A boolean computed in the schema function (`required: isPremium`), never paired with `default` | Compute the condition before the declaration and assign the boolean |
|
|
92
|
+
| Path ids | A `default` computed from the request path, plus `min: 1` | `{ type: 'string', path: true }`, filled from the request path's trailing segments in declaration order | Replace the computed default with `path: true` |
|
|
93
|
+
| Field keys | `types`, `default`, `value`, `min`, `max`, `required`, `clean`, `sanitize`, `enum` | `type`, `default`, `value`, `min`, `max`, `required`, `clean`, `sanitize`, `enum`, plus `pattern` (a RegExp a sent value must match), `path`, `of` and `fields`; any other key throws, naming its dot-path | Rename `types` to `type`; nothing else to migrate |
|
|
94
|
+
| Removed | `helpers/schema-engine.js`, `helpers/schema-zod.js` and its `fields` builders, and a schema file exporting raw zod | Gone: `helpers/schema.js` is the one adapter | Delete the builder require from every schema file |
|
|
95
|
+
|
|
29
96
|
## 2026-09-14: the companion extension leaves `@omega.js/manager` ([#927](https://github.com/Omega-JS-Stack/omega/issues/927))
|
|
30
97
|
|
|
31
98
|
The companion extension lived at `@omega.js/manager`'s `extension/`, a whole extension
|
|
@@ -306,7 +373,7 @@ Full contract: [config.md](config.md#the-repo-block-and-the-repos-it-derives-883
|
|
|
306
373
|
| Classy gradient utilities | `.gradient-animated` (gradient shimmer) + `.gradient-grain` (noise overlay) on hero markup | `omega-dotgrid` — the masked dot backdrop v2 puts behind every hero — plus `data-omega-dotfield` where the animation was. Classy v2 ships zero gradients, so the old classes are silent no-ops | Codemod rule `gradient-utilities` converts both once ([#296](https://github.com/Omega-JS-Stack/omega/issues/296)); the pair on one element collapses to ONE `omega-dotgrid`. `.bg-gradient-*` names are NOT touched — v2 still neutralizes those to flat token paint |
|
|
307
374
|
| Sass entry | `@use 'ultimate-jekyll-manager' as * with (…)` in `src/assets/css/main.scss`; page CSS files `@use`-ing themselves | `@use 'omega:main' with (…)`; the self-`@use` lines are gone (every layer's page sheet already loads, [#624](https://github.com/Omega-JS-Stack/omega/issues/624)) | `omega migrate`'s consumer-assets pass rewrites both; by hand it is a one-line edit plus deleting the self-`@use` lines |
|
|
308
375
|
| JS entry | Seeded `src/assets/js/main.js` bootstrapping the manager | Deleted — core main + the boot runtime own it | `omega migrate` deletes an untouched seed and FLAGS a customized one; port custom logic into a page or section module |
|
|
309
|
-
| Client bootstrap | `import webManager from 'web-manager'`; `window.Manager` global | `import omega from '@omega.js/
|
|
376
|
+
| Client bootstrap | `import webManager from 'web-manager'`; `window.Manager` global | `import omega from '@omega.js/web/runtime'`, the web instance; no window global | Replace the import in every module and delete `window.Manager` references. The accessor and auth shapes are in [one runtime shape](#2026-09-25-one-runtime-shape-on-every-package-945) |
|
|
310
377
|
| Deploy | `npu sync --message='Deploy'` shell-out | `omega deploy` (plain git sync + `workflow_dispatch`, or the direct lane) | Replace the script; contract in [deploys.md](deploys.md) |
|
|
311
378
|
| Version maintenance | Setup-time `ensureManagerVersion()` + peer-dependency auto-install | The explicit `omega update` verb | Stop expecting self-updates; run `npx omega update` (`--apply` to install) — [updates.md](updates.md) |
|
|
312
379
|
| Charts | A page imported `chart.js` bare (it was a `@omega.js/web` dependency) and built its own `new Chart(canvas, config)` | `chart.js` is gone — the framework draws with TanStack Charts ([#772](https://github.com/Omega-JS-Stack/omega/issues/772)), reached ONLY through `__main_assets__/js/libs/charts.js` (`loadCharts`, `chartSlot`, `barChart`/`stackedBarChart`/`doughnutChart`/`lineChart`) | Replace the bare import and the hand-built config with the helpers, and the page's `<canvas>` with `chartSlot`'s markup (an SVG chart has no canvas). A page that genuinely needs the raw grammar imports `@tanstack/charts` bare instead — same framework-resolution rule, new name |
|
|
@@ -315,13 +382,13 @@ Full contract: [config.md](config.md#the-repo-block-and-the-repos-it-derives-883
|
|
|
315
382
|
|
|
316
383
|
| Contract | Old form | New form | Manual migration step |
|
|
317
384
|
|---|---|---|---|
|
|
318
|
-
| Package + init | `require('backend-manager')`; `Manager.init({ backendManagerConfigPath: 'backend-manager-config.json' })` | `require('@omega.js/backend')
|
|
385
|
+
| Package + init | `require('backend-manager')`; `Manager.init({ backendManagerConfigPath: 'backend-manager-config.json' })` | `const omega = require('@omega.js/backend');`, then `omega.initialize({ … });` and `module.exports = omega.functions;`; the config loader discovers the file, so there is no config-path option | Swap the dependency, rewrite the entry to that shape and delete the `backendManagerConfigPath` option. The handler and `ctx` shapes are in [one runtime shape](#2026-09-25-one-runtime-shape-on-every-package-945) |
|
|
319
386
|
| Config | `functions/backend-manager-config.json` | `functions/config/omega.json5` | Key-by-key table in [config.md](config.md#backend-manager-functionsbackend-manager-configjson--functionsconfigomegajson5--done-checkpoint-19) |
|
|
320
387
|
| Exported Cloud Functions | `bm_api`, `bm_signUpHandler`, `bm_createPost`, `bm_cronDaily`, … | `omega_api`, `omega_signUpHandler`, `omega_createPost`, `omega_cronDaily`, … | Deploy the new names, repoint every trigger/scheduler/webhook that names a function, then DELETE the orphaned `bm_*` functions from the Firebase project (a rename leaves the old ones running) |
|
|
321
|
-
| Hosting rewrite | `{ source: '/backend-manager/**', function: 'bm_api' }` | `{ source: '{/omega,/omega/**,/
|
|
388
|
+
| Hosting rewrite | `{ source: '/backend-manager/**', function: 'bm_api' }` | `{ source: '{/omega,/omega/**,/mcp,/mcp/**,/.well-known/oauth-protected-resource,/.well-known/oauth-authorization-server,/authorize,/token,/register}', function: 'omega_api' }` | The next verb's `ensureTarget()` writes it (and removes duplicates); by hand, replace the rewrite and keep it FIRST in the list |
|
|
322
389
|
| API dispatch | Command-based: `POST /backend-manager` with `{ command: 'user:sign-up', payload: {…} }` | REST: `POST /omega/user/sign-up` with the payload AS the body | Rewrite each caller: the command's `:` becomes a path segment, `payload` becomes the body. On the client, `omega.request('/omega/user/sign-up', { method: 'POST', body: {…} })` |
|
|
323
|
-
| URL prefix | `/backend-manager/*` | `/omega/*` (also `/omega_api/*` on the direct function URL) | Repoint every
|
|
324
|
-
| Per-request object | `BackendAssistant`; handler signature `module.exports = async ({ assistant, settings, analytics }) => …` | `
|
|
390
|
+
| URL prefix | `/backend-manager/*` | `/omega/*` (also `/omega_api/*` on the direct function URL) | Repoint every caller: the old prefix answers 404 |
|
|
391
|
+
| Per-request object | `BackendAssistant`; handler signature `module.exports = async ({ assistant, settings, analytics }) => …` | `Context` (`ctx`); handler signature `module.exports = async ({ ctx, omega, user, data, usage, analytics }) => …` | Rename the destructured argument and every `assistant.` call site (`ctx.respond`, `ctx.log`, `ctx.request`) in each custom route, event, and cron handler; `settings` is `data` |
|
|
325
392
|
| Environment | `BACKEND_MANAGER_KEY`, `BACKEND_MANAGER_WEBHOOK_KEY`, `BEM_TEST_RUNNER`, `BEM_HTTPS_PORT` | `OMEGA_ADMIN_KEY`, `OMEGA_WEBHOOK_KEY`, `OMEGA_TEST_RUNNER`, `OMEGA_HTTPS_PORT` | Rename in `.env`, in CI secrets, and in anything that reads them. Values carry over unchanged |
|
|
326
393
|
| AI provider keys | TWO names per provider: `BACKEND_MANAGER_OPENAI_API_KEY` (the company-wide fallback) beside a bare `OPENAI_API_KEY` (the brand's own), and the same pair for Anthropic. The provider preferred the bare one and fell back to the prefixed; `inferContact` read ONLY the prefixed one | ONE name per provider: `OPENAI_API_KEY`, `ANTHROPIC_API_KEY` ([#639](https://github.com/Omega-JS-Stack/omega/issues/639)). Every reader takes the bare name through the one env reader; the OMEGA-era `OMEGA_OPENAI_API_KEY` / `OMEGA_ANTHROPIC_API_KEY` twins are removed outright, with no dual-read | Rename `BACKEND_MANAGER_OPENAI_API_KEY` (or `OMEGA_OPENAI_API_KEY`) to `OPENAI_API_KEY` in `.env` and CI secrets, same for Anthropic, and delete the old rows. A key that served EVERY brand moves to the COMPANY `.env` under that same bare name — the cascade is the fallback, never a second key. An interactive `npx omega manage` asks for both once (the `ai` service) and writes them for you |
|
|
327
394
|
| CLI | `bm` / `bem` / `backend-manager` / `mgr` bins | `omega` / `omg` / `mgr` (one dispatcher; a backend's `functions/` dir resolves to the backend CLI) | Replace the bin name in npm scripts and workflows |
|
|
@@ -352,7 +419,7 @@ Full contract: [config.md](config.md#the-repo-block-and-the-repos-it-derives-883
|
|
|
352
419
|
| Config validation | EM's local validation util | The shared `@omega.js/config` schema, at boot and in the audit task | Nothing to move — but expect boot to report schema findings a legacy config silently carried, and fix them |
|
|
353
420
|
| Preload global | `contextBridge.exposeInMainWorld('em', …)` → `window.em` | `window.desktop` | Rename every `window.em.*` call in renderer code |
|
|
354
421
|
| Theme controls | `data-em-theme-set="system\|light\|dark"` | `data-omega-theme-set="system\|light\|dark"` | Rename the attribute in every view |
|
|
355
|
-
| Client bridge | `web-manager-bridge.js`; `manager.webManager` in renderer entries |
|
|
422
|
+
| Client bridge | `web-manager-bridge.js`; `manager.webManager` in renderer entries | The renderer instance extends `@omega.js/client` (`omega.auth`, `omega.firestore`); main reads the account as `omega.auth` | Rewrite every `webManager.` call to `omega.` on the instance; the desktop shapes are in [one runtime shape](#2026-09-25-one-runtime-shape-on-every-package-945) |
|
|
356
423
|
| Environment | `BACKEND_MANAGER_KEY` in the app's `.env` | `OMEGA_ADMIN_KEY`, resolved through the `.env` cascade (shell > local > brand root > company) | Rename the key; in a brand monorepo put the value at the brand root and leave the target's placeholder commented |
|
|
357
424
|
| Bundler overrides | `config.em.webpack.externals`: an array of extra module names the desktop webpack build marked `commonjs2` external | GONE ([#737](https://github.com/Omega-JS-Stack/omega/issues/737)): the bundler is esbuild and there is no consumer-facing override key. The externals set is the framework's native-module list plus what the consumer's own `package.json` declares from it | Delete the key. Nothing replaces it: ESM-only dependencies BUNDLE (a CommonJS bundle keeps `import.meta.url`, [#906](https://github.com/Omega-JS-Stack/omega/issues/906)), and native modules stay external through the framework's own list. A consumer with a genuinely native module the list does not name raises it upstream: the list lives in `src/gulp/tasks/bundle.js` (`nativeExternals`) and grows there, so every brand gets the fix |
|
|
358
425
|
| Gulp task name | `webpack` — `npm run gulp -- webpack`, and `[@omega.js/desktop:webpack]` in the logs | `bundle` — `npm run gulp -- bundle`, `[@omega.js/desktop:bundle]` ([#737](https://github.com/Omega-JS-Stack/omega/issues/737)) | Nothing for a normal consumer: the `build` / `package` / `publish` verbs are unchanged and nobody's npm scripts name the sub-task. Rename it in anything that invokes the gulp task directly, or greps `build.log` for the old tag |
|
|
@@ -367,7 +434,7 @@ Full contract: [config.md](config.md#the-repo-block-and-the-repos-it-derives-883
|
|
|
367
434
|
| CLI | `xm` / `bxm` / `ext` / `browser-extension-manager` / `mgr` bins | `omega` / `omg` / `mgr` | Replace the bin name in npm scripts and workflows |
|
|
368
435
|
| Config | `config/browser-extension-manager.json` | `config/omega.json5` (`targets.extension: {}` — key presence enables the target) | Key-by-key table in [config.md](config.md#browser-extension-manager-configbrowser-extension-managerjson--configomegajson5--done-checkpoint-20) |
|
|
369
436
|
| Analytics secret | `analytics.providers.google.secret` in the config file | `.env` → `GOOGLE_ANALYTICS_SECRET` (the loader hard-fails secret-shaped config keys) | Move the value to `.env`; the build snapshot bakes it exactly as before |
|
|
370
|
-
| Runtime singleton | `import webManager from 'web-manager'`; `manager.webManager` | `import omega from '@omega.js/
|
|
437
|
+
| Runtime singleton | `import webManager from 'web-manager'`; `manager.webManager` | `import omega from '@omega.js/extension/<context>'`: the context's instance carries the client's modules | Swap the import in every context (background, popup, options, sidepanel, content scripts) and read the client off `omega`; the extension shapes are in [one runtime shape](#2026-09-25-one-runtime-shape-on-every-package-945) |
|
|
371
438
|
| DOM bindings | `data-wm-bind` | `data-omega-bind` | Rename the attribute in every view |
|
|
372
439
|
| Cross-context messages | `{ command: 'bxm:syncAuth' }`, `{ command: 'bxm:signOut' }` | `{ command: 'omega:syncAuth' }`, `{ command: 'omega:signOut' }` | Rename in any custom `runtime.onMessage` handler or sender the extension ships |
|
|
373
440
|
| Bundler | webpack 5 + `babel-loader` + `@babel/preset-env`, with per-lane code splitting (`*.chunk.<hash>.js` plus `.LICENSE.txt` sidecars beside every bundle) | esbuild through @omega.js/devkit's `bundle()` wrapper ([#738](https://github.com/Omega-JS-Stack/omega/issues/738)). No consumer-facing bundler override key existed and none was added; there are no chunks and no license sidecars — every entry is ONE self-contained iife — and the syntax floor is esbuild's `target`, `chrome88, firefox91` (the MV3 minimums), not a browserslist guess | Nothing in a normal project: entry filenames (`assets/js/components/<name>.bundle.js`) are unchanged, and the manifest / views ask for the same paths. Two things to check: anything that referenced a chunk file BY NAME (nothing generated does), and any code that imported a package @omega.js/extension merely carries TRANSITIVELY — only the framework's DECLARED dependencies resolve from the framework now, so declare that package yourself or raise it upstream ([#87](https://github.com/Omega-JS-Stack/omega/issues/87)) |
|
|
@@ -378,11 +445,11 @@ Full contract: [config.md](config.md#the-repo-block-and-the-repos-it-derives-883
|
|
|
378
445
|
|
|
379
446
|
| Contract | Old form | New form | Manual migration step |
|
|
380
447
|
|---|---|---|---|
|
|
381
|
-
| Package + import | `import webManager from 'web-manager'` (npm `web-manager`) |
|
|
382
|
-
| Global | `window.Manager` / a page-attached `webManager` | No window global
|
|
448
|
+
| Package + import | `import webManager from 'web-manager'` (npm `web-manager`) | `@omega.js/client`, the browser base class `Omega`; each host framework exports the one instance | Swap the dependency and import the host's instance. The modules read as properties (`omega.auth`, `omega.firestore`, `omega.bindings`), and `initialize(configuration)` carries over: [one runtime shape](#2026-09-25-one-runtime-shape-on-every-package-945) |
|
|
449
|
+
| Global | `window.Manager` / a page-attached `webManager` | No window global: import the host framework's instance wherever it is needed | Delete the window assignments and the code that reads them |
|
|
383
450
|
| DOM bindings | `data-wm-bind` | `data-omega-bind` | Codemod rule `client-markup` (templates, consumer JS, and section `.json` descriptors alike) |
|
|
384
451
|
| Sign-out hook | `.auth-signout-btn` class, hardcoded in the auth module | The generic `omega-signout` click trigger (`registerTrigger('signout', …)` → class `omega-signout`) | Codemod rule `client-markup` renames the class everywhere it appears; custom behavior registers its own trigger instead of patching auth |
|
|
385
|
-
| Device module | `webManager.usage()` | `omega.device
|
|
452
|
+
| Device module | `webManager.usage()` | `omega.device` | Rename the call sites (`usage.js` became `device.js` verbatim) |
|
|
386
453
|
| Configuration payload | The site emitted a `web_manager` block into `window.Configuration` | The `client` section of `OMEGA_BUILD_JSON.config` (#894, the row above) | Config-side rename: see the UJM row and [config.md](config.md); nothing dual-reads the old key |
|
|
387
454
|
| Version-check manifest | The client probed `/build.json` then `/@output/build/build.json`, reading `data.timestamp` OR `data['npm-build'].timestamp` | One fetch of the site's `build.json` — mounted under the page's `data-omega-path-prefix` stamp on a site served from a URL path ([#364](https://github.com/Omega-JS-Stack/omega/issues/364)), `/build.json` at the domain root — and one read of `data.timestamp` (the omega web build emits exactly this) | Nothing to do on a migrated site. A site still serving the old path or the `npm-build` wrapper logs "No timestamp found in build.json" and never auto-reloads on a new deploy |
|
|
388
455
|
|
|
@@ -610,7 +677,7 @@ fallback would be the exact bug this removes.
|
|
|
610
677
|
| Contract | Old form | New form | Manual migration step |
|
|
611
678
|
|---|---|---|---|
|
|
612
679
|
| ASM group ids | `GROUPS` in `packages/backend/src/manager/libraries/email/constants.js` — seven literal ids compiled into the framework | `marketing.campaigns.providers.sendgrid.groups.<key>` in the brand's `config/omega.json5`, one integer per key (`orders`, `hello`, `account`, `marketing`, `security`, `newsletter`, `internal`) | **Per brand, once**: run `npx omega manage` (or `--service=campaigns`) — the campaigns service creates any group the account is missing and writes all seven ids into `config/omega.json5`. By hand: read the ids from SendGrid → Suppressions → Unsubscribe Groups and write the block yourself. The ensure matches by NAME, so on an account whose groups carry legacy-prefixed names ("BEM - Order Updates"), RENAME them to the canonical "OMEGA - " names FIRST (ids never change, so legacy sends keep working) — otherwise the ensure creates a duplicate set and unsubscribe state splits (this happened once on the shared account, repaired 2026-08-29). A brand on its own fresh account just gets its own groups. Until the block exists, every send throws instead of mailing under a foreign group |
|
|
613
|
-
| `prepare.resolveSender()` signature | `resolveSender({ sender, from, group }, brand, brandDomain)` | `resolveSender({ sender, from, group }, brand, brandDomain,
|
|
680
|
+
| `prepare.resolveSender()` signature | `resolveSender({ sender, from, group }, brand, brandDomain)` | `resolveSender({ sender, from, group }, brand, brandDomain, omega)`: the fourth argument carries the config the ids live in | Only affects code calling `prepare.js` directly: pass `omega` as the fourth argument. `group:` still accepts a raw numeric id AND now accepts a group KEY, which resolves through config |
|
|
614
681
|
|
|
615
682
|
## `brand.subdomains` becomes web targets ([#588](https://github.com/Omega-JS-Stack/omega/issues/588))
|
|
616
683
|
|
|
@@ -704,7 +771,7 @@ retry; its stale `usage/{uid}.oauth2` session clears with the daily clean.
|
|
|
704
771
|
| Config section | `oauth2: { <provider>: {…} }` | `connections: { <provider>: {…} }` — the per-provider block is byte-identical, with ONE change of meaning ([#793](https://github.com/Omega-JS-Stack/omega/issues/793)): a PACKAGED provider (google, discord, spotify, twitch, kick) is `enabled: false` in the framework defaults, so an entry that relied on "absent means enabled" is now off | Rename the key in `config/omega.json5`, and add `enabled: true` to each packaged provider's block that does not already carry it — a brand's OWN provider is unchanged (present unless `enabled: false`). A config still carrying `oauth2` is a retired-key error naming the move ([config.md](config.md#retired-keys-fail-loudly)) |
|
|
705
772
|
| Credentials | `OAUTH2_<PROVIDER>_CLIENT_ID` / `OAUTH2_<PROVIDER>_CLIENT_SECRET` | `CONNECTIONS_<PROVIDER>_CLIENT_ID` / `CONNECTIONS_<PROVIDER>_CLIENT_SECRET` | **Rename the pair by hand** in the brand `.env` (and every `.env.<environment>` overlay), and in the CI secrets any workflow injects them from. A layer still carrying the Google pair FAILS the load naming the new name ([#845](https://github.com/Omega-JS-Stack/omega/issues/845)): they are registered retired env names ([config.md](config.md#retired-env-keys-srcenv-retiredjs)), spelled out one provider at a time. For any other provider there is no check, and the env schema does not know the old name, so the provider reads an empty client id and its authorize leg 500s |
|
|
706
773
|
| Provider console redirect URI | `<websiteUrl>/oauth2` | `<websiteUrl>/connections/callback` | **Register the new URI at every provider** whose block the brand declares (Google Cloud console, Discord developer portal, Spotify dashboard, …). Add it BESIDE the old one, deploy, then remove the old one — a redirect URI is matched exactly, so a deploy ahead of the console edit breaks every link attempt |
|
|
707
|
-
| Brand provider module | `targets/backend/src/oauth2/<name>.js` | `targets/backend/src/connections/<name>.js` | Move the directory. The lane resolves `${
|
|
774
|
+
| Brand provider module | `targets/backend/src/oauth2/<name>.js` | `targets/backend/src/connections/<name>.js` | Move the directory. The lane resolves `${omega.cwd}/connections/` first and the package's own second, exactly as before |
|
|
708
775
|
| Website callback page | the `/oauth2` default page (`blueprint/auth/oauth2`) | `/connections/callback` (`blueprint/connections/callback`) | **Nothing for a brand that never overrode it.** A brand carrying its own copy moves it to the new path and layout name; `/connections` itself stays free for a future listing page |
|
|
709
776
|
| Provider module shape ([#793](https://github.com/Omega-JS-Stack/omega/issues/793)) | `verifyIdentity(tokenizeResult, Manager, ctx, uid)`, `buildAuthorizeUrl(context)`, `revokeToken(token, {…})`, `verifyConnection(refreshToken, {…})`, `authParams`, `urls.tokenize` + `urls.refresh` + `urls.status`, and a copy of the "already connected" query inside `verifyIdentity` | ONE context object for every step, called as a method on the module: `identity(context)` (required, → `{ id, … }`), `authorize`, `exchange`, `refresh`, `revoke`, `status`; `params` for extra authorize params; ONE `urls.token`; `urls.revoke` optional; `urls.status` deleted | **Per provider module, by hand** (switchboard's YouTube provider is the known one outside this repo): rename the six members, fold `urls.tokenize`/`urls.refresh` into `urls.token`, rename `authParams` → `params`, drop `urls.status`, read `tokenizeResult`/`Manager`/`ctx`/`uid`/`clientId` off the one `context` argument, and DELETE the uniqueness query — the route owns it now and matches on `identity.id`, so the step just answers the identity, with a string `id`. A module missing `identity()` or `urls.token` throws at load naming the file |
|
|
710
777
|
|
|
@@ -842,7 +909,6 @@ retires when its named condition is met, and never unilaterally.
|
|
|
842
909
|
|
|
843
910
|
| Compatibility | Who still speaks it | Retirement condition |
|
|
844
911
|
|---|---|---|
|
|
845
|
-
| The `/backend-manager/*` URL alias — the backend router's prefix strip and its Cloudflare edge-worker twin (`packages/manager/src/services/edge/workers/omega-api-proxy.js`) | In-the-wild clients of migrated brands: shipped apps, third-party integrations, and pages still calling the old path | Every known caller moved to `/omega/*` and the alias shows no traffic |
|
|
846
912
|
| `backendManagerKey` sent in outbound request bodies (`process.env.OMEGA_ADMIN_KEY` under the OLD field name) | Legacy-BEM parent deployments, the Ghostii API, and ITW's `wrapper` Cloud Function — all still reading that field | Each upstream migrates to the new stack and accepts the `omega-admin-key` header; fix per upstream, never unilaterally |
|
|
847
913
|
| The Ghostii flat-article response fallback | api.ghostii.ai, whose production backend runs legacy BEM and can return the flat field shape | Ghostii returns only the structured shape |
|
|
848
914
|
| The `gatherings/online` sign-out leg | Old somiibo / electron-manager desktop clients that still write that RTDB path | Those app versions are out of circulation |
|
package/docs/shared/config.md
CHANGED
|
@@ -338,8 +338,8 @@ targets: {
|
|
|
338
338
|
and runs locally on the emulator suite. Everything OMEGA does today.
|
|
339
339
|
- **`'custom'`** — the SAME backend (same routes, same schemas, same auth middleware, same
|
|
340
340
|
helpers, same `.env`) served by its Express app on `process.env.PORT`, for a container host
|
|
341
|
-
(Render & co). `
|
|
342
|
-
unchanged; an explicit `
|
|
341
|
+
(Render & co). `initialize()` reads the mode off this key, so a brand's `src/index.js` is
|
|
342
|
+
unchanged; an explicit `projectType` option still wins.
|
|
343
343
|
- **What custom mode removes is the Firebase LANE, not Firebase**: no Functions deploy, no
|
|
344
344
|
emulator, no emulator test run — those four verbs refuse loudly and name their replacement
|
|
345
345
|
([docs/backend/index.md](../backend/index.md)). `firebase-admin` still loads, so a custom
|
|
@@ -752,9 +752,8 @@ Who derives from it:
|
|
|
752
752
|
`src/environment.js` is the ONE environment module every OMEGA target answers
|
|
753
753
|
from ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)). Four calls,
|
|
754
754
|
one implementation, one call form everywhere: `getEnvironment()` plus
|
|
755
|
-
`isDevelopment()` / `isProduction()` / `isTesting()`,
|
|
756
|
-
|
|
757
|
-
`attachEnvironment`). It requires NOTHING, so it is bundled into browser
|
|
755
|
+
`isDevelopment()` / `isProduction()` / `isTesting()`, called directly by every
|
|
756
|
+
framework's `omega` instance and build module. It requires NOTHING, so it is bundled into browser
|
|
758
757
|
artifacts (the desktop renderer, every extension bundle) and vendored into
|
|
759
758
|
`@omega.js/client`, which reaches the same four through its own methods.
|
|
760
759
|
|
|
@@ -762,24 +761,21 @@ artifacts (the desktop renderer, every extension bundle) and vendored into
|
|
|
762
761
|
context, which can read neither env nor files, it is `config.environment`, the
|
|
763
762
|
build fact every surface already bakes into `OMEGA_BUILD_JSON.config`
|
|
764
763
|
([#896](https://github.com/Omega-JS-Stack/omega/issues/896)), reached as
|
|
765
|
-
`this.config.environment` off the
|
|
764
|
+
`this.config.environment` off the instance the call is made on. Nothing else is
|
|
766
765
|
consulted: no `app.isPackaged`, no `manifest.update_url`, no `NODE_ENV`, no
|
|
767
766
|
terminal sniffing.
|
|
768
767
|
|
|
769
|
-
**NO DEFAULT.** A context with no input throws and names the variable.
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
`development`, so a desktop `npm start` bundled itself as a production artifact.
|
|
773
|
-
@omega.js/client seeded `environment: 'production'` into its own config defaults,
|
|
774
|
-
and web's browser Manager defaulted to `development`.
|
|
768
|
+
**NO DEFAULT.** A context with no input throws and names the variable. A guessed
|
|
769
|
+
environment is how a dev build ships as production and how a production build talks
|
|
770
|
+
to an emulator, and both failures stay silent until a user finds them.
|
|
775
771
|
|
|
776
772
|
**`setEnvironment(value)` is the only writer**, so a fourth word can never reach
|
|
777
773
|
the variable. Who calls it, and with what:
|
|
778
774
|
|
|
779
775
|
| Lane | Names |
|
|
780
776
|
|---|---|
|
|
781
|
-
| `@omega.js/backend`'s boot (`
|
|
782
|
-
| `@omega.js/desktop` / `@omega.js/extension` `src/build.js`, at load | `buildLaneEnvironment(
|
|
777
|
+
| `@omega.js/backend`'s boot (`initialize()`, right after the `.env` cascade loads) | `envEnvironment()`, the AMBIENT answer (below) |
|
|
778
|
+
| `@omega.js/desktop` / `@omega.js/extension` `src/build.js`, at load | `buildLaneEnvironment(isBuildMode())`: `production` under `OMEGA_BUILD_MODE` (which WINS over an inherited value, so a production build spawned from a test run still bakes production), else an already-named value, else `development`. That rule is ONE exported helper beside `setEnvironment`, not a copy of the expression per framework, and those two build lanes are its only callers |
|
|
783
779
|
| `@omega.js/desktop`'s main process, at `initialize()` | the `environment` its baked config carries, for a packaged app that has no parent lane |
|
|
784
780
|
| `@omega.js/web`'s verbs | `production` for `omega build`, `development` for `omega dev`, `testing` for `omega test` |
|
|
785
781
|
| the desktop test runners, the extension `test` verb | `testing` |
|
|
@@ -828,7 +824,7 @@ byte-identical to the pre-N7 behavior (no bumping, no artifacts).
|
|
|
828
824
|
livereload 35729, cdp 9222). **This map is the ONLY source of those numbers**
|
|
829
825
|
([#834](https://github.com/Omega-JS-Stack/omega/issues/834)): @omega.js/client
|
|
830
826
|
carried four of them plus a classic dev origin, @omega.js/desktop's url-helpers
|
|
831
|
-
and
|
|
827
|
+
and the desktop auth lib three more, and @omega.js/extension's url-helpers and
|
|
832
828
|
background worker two, each as a last-resort fallback "for a build made with no
|
|
833
829
|
stack up". Every one of those is gone. The numbers reach a browser exactly one
|
|
834
830
|
way: each surface bakes the map into its build json with the classics as the
|
|
@@ -1352,7 +1348,7 @@ decision, declared once and made once, and it is DELIVERED one way:
|
|
|
1352
1348
|
rest are facts about the BUILD and never part of the client contract. `mode` is the same
|
|
1353
1349
|
THREE keys everywhere, `{ environment, build, publish }`: the build's verdict, whether it
|
|
1354
1350
|
was a build rather than a dev/watch run, and whether it publishes. A surface's own extra
|
|
1355
|
-
verdicts (desktop's `server`) stay inside that surface's
|
|
1351
|
+
verdicts (desktop's `server`) stay inside that surface's build module.
|
|
1356
1352
|
- **The delivery** is ONE FILE, `build.js` at the artifact's web root
|
|
1357
1353
|
([#743](https://github.com/Omega-JS-Stack/omega/issues/743), Ian 2026-09-12: "make it
|
|
1358
1354
|
same shape and consumption everywhere as much as possible"). Two plain statements, written
|
|
@@ -1367,7 +1363,7 @@ decision, declared once and made once, and it is DELIVERED one way:
|
|
|
1367
1363
|
Every HTML shell loads it with one script tag, FIRST (web's `core/_includes/core/head.html`
|
|
1368
1364
|
at `/build.js`, desktop's page template at `../../build.js`, the extension's at
|
|
1369
1365
|
`/build.js`), and every worker with one `importScripts('/build.js')` line (web's
|
|
1370
|
-
`sw/
|
|
1366
|
+
`sw/omega.js`, the extension's `background.js`). No bundle carries a copy: the esbuild
|
|
1371
1367
|
banners and defines the browser bundles grew are retired, and so is web's inline foot
|
|
1372
1368
|
script. The `dev` map is its own statement because `omega dev` REWRITES that one line per
|
|
1373
1369
|
request (#346), so a site built before the emulator came up still serves the map of the
|
|
@@ -1400,7 +1396,7 @@ always applies.
|
|
|
1400
1396
|
([#290](https://github.com/Omega-JS-Stack/omega/issues/290)). A brand target cannot require
|
|
1401
1397
|
this private package at runtime, so a framework that owns a derivation publishes its
|
|
1402
1398
|
ANSWER on the runtime config object the target already holds, under `resolved.*`: the
|
|
1403
|
-
backend's `
|
|
1399
|
+
backend's `omega.config.resolved.github` carries `{ owner, name, slug }`, the brand's
|
|
1404
1400
|
SOURCE repo as one finished value. The derivations themselves stay here (`src/repo.js`):
|
|
1405
1401
|
one implementation, called by the framework, so no brand re-implements the rules and
|
|
1406
1402
|
drifts from them. New derived values join a framework's `resolved` group as real brand
|
|
@@ -1433,6 +1429,13 @@ of any kind exists: a repo name that must differ is a brand id that must differ.
|
|
|
1433
1429
|
| Releases | `releasesRepo(config)` → `<repo.org>/<brand.id>-releases` | always public (the desktop updater polls it with no token) | every target's built artifacts: desktop installers, the extension's zips, tagged per target |
|
|
1434
1430
|
| Website, one per GitHub-hosted web target | `websiteRepo(config, name)` → `<repo.org>/<brand.id>-<target name>` | private only when the brand is private AND the org's plan allows Pages from a private repo, else public, and the manage walk says which | the BUILT site only, one force-orphan commit on `gh-pages`, served by Pages at the target's url |
|
|
1435
1431
|
|
|
1432
|
+
**`repoDrift(originSlug, config)`** is the one comparison of a checkout's `origin` with
|
|
1433
|
+
the source repo ([#934](https://github.com/Omega-JS-Stack/omega/issues/934)): the whole
|
|
1434
|
+
slug, case-insensitive, null when they agree or the config derives no source repo, else
|
|
1435
|
+
the line `origin is <slug> but config derives <derived>: fix repo.org in
|
|
1436
|
+
config/omega.json5 or move the repo`. The boot prelude prints it; `omega manage` and
|
|
1437
|
+
`omega deploy` refuse with it ([deploys.md](deploys.md#the-origin-gate-934)).
|
|
1438
|
+
|
|
1436
1439
|
**Visibility lives in the brand root's `package.json`**, never in omega.json5
|
|
1437
1440
|
(`brandVisibility(brandRoot)`): `private: true` or the field ABSENT is a private brand
|
|
1438
1441
|
(every brand monorepo is private by default, Ian 2026-09-11), and only a literal `false`
|
|
@@ -1821,8 +1824,8 @@ resolved config would fire on its own answer. The by-hand step, and the `parent`
|
|
|
1821
1824
|
| `parent` | RETIRED outright ([#677](https://github.com/Omega-JS-Stack/omega/issues/677)): a URL or `'self'` becomes **`company: { id }`**, and `parent: false` becomes **`company: { webhooks: false }`**. The key itself fails the load now, naming its new home |
|
|
1822
1825
|
|
|
1823
1826
|
Notes: @omega.js/backend's framework-defaults layer is `templates/config/omega.json5` resolved through
|
|
1824
|
-
the same loader and passed as `options.defaults`; `
|
|
1825
|
-
`backendManagerConfigPath` option
|
|
1827
|
+
the same loader and passed as `options.defaults`; `initialize()` takes no
|
|
1828
|
+
`backendManagerConfigPath` option (the loader discovers the file); boot warns on
|
|
1826
1829
|
schema findings, `npx omega test`'s target checks are the hard audit. The sandbox brand dogfoods the full
|
|
1827
1830
|
hierarchy: shared sections live in `brands/sandbox-brand/config/omega.json5` (brand level),
|
|
1828
1831
|
the backend target's local file carries only `targets.backend`.
|
|
@@ -1838,7 +1841,7 @@ the backend target's local file carries only `targets.backend`.
|
|
|
1838
1841
|
| `analytics.providers.google.secret` | **`.env` → `GOOGLE_ANALYTICS_SECRET`** (secrets never in omega.json5; loader hard-fails) |
|
|
1839
1842
|
| *(no extension-specific keys yet)* | `targets.extension: {}` — presence = enabled; extension-specific settings land here |
|
|
1840
1843
|
|
|
1841
|
-
Notes: `
|
|
1844
|
+
Notes: `build.getConfig()` (`require('@omega.js/extension/build')`) returns the RESOLVED config (missing file → `{}`; schema
|
|
1842
1845
|
findings warn once per process — BXM has no separate audit surface). The build snapshot
|
|
1843
1846
|
(`OMEGA_BUILD_JSON`, the artifact's one `build.js`) bakes `GOOGLE_ANALYTICS_SECRET` from the environment at
|
|
1844
1847
|
build time, same value flow as before. `bxm setup` scaffolds + merges `config/omega.json5`
|