@omega.js/desktop 0.52.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 +17 -12
- 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 +11 -11
- 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/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/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 +2 -2
- 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 +8 -11
- package/dist/vendor/config/load.js +1 -2
- package/dist/vendor/config/platforms.js +1 -1
- 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/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/local.js +2 -0
- package/dist/vendor/devkit/merge-line-files.js +2 -3
- 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 +38 -27
- 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/remote-config.md +9 -9
- package/docs/remote-scripts.md +12 -12
- package/docs/restart-manager.md +8 -8
- package/docs/sentry.md +4 -4
- package/docs/shared/analytics.md +1 -1
- package/docs/shared/breaking-changes.md +79 -13
- package/docs/shared/config.md +17 -21
- 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/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/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
|
|
|
@@ -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
|
|
@@ -1828,8 +1824,8 @@ resolved config would fire on its own answer. The by-hand step, and the `parent`
|
|
|
1828
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 |
|
|
1829
1825
|
|
|
1830
1826
|
Notes: @omega.js/backend's framework-defaults layer is `templates/config/omega.json5` resolved through
|
|
1831
|
-
the same loader and passed as `options.defaults`; `
|
|
1832
|
-
`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
|
|
1833
1829
|
schema findings, `npx omega test`'s target checks are the hard audit. The sandbox brand dogfoods the full
|
|
1834
1830
|
hierarchy: shared sections live in `brands/sandbox-brand/config/omega.json5` (brand level),
|
|
1835
1831
|
the backend target's local file carries only `targets.backend`.
|
|
@@ -1845,7 +1841,7 @@ the backend target's local file carries only `targets.backend`.
|
|
|
1845
1841
|
| `analytics.providers.google.secret` | **`.env` → `GOOGLE_ANALYTICS_SECRET`** (secrets never in omega.json5; loader hard-fails) |
|
|
1846
1842
|
| *(no extension-specific keys yet)* | `targets.extension: {}` — presence = enabled; extension-specific settings land here |
|
|
1847
1843
|
|
|
1848
|
-
Notes: `
|
|
1844
|
+
Notes: `build.getConfig()` (`require('@omega.js/extension/build')`) returns the RESOLVED config (missing file → `{}`; schema
|
|
1849
1845
|
findings warn once per process — BXM has no separate audit surface). The build snapshot
|
|
1850
1846
|
(`OMEGA_BUILD_JSON`, the artifact's one `build.js`) bakes `GOOGLE_ANALYTICS_SECRET` from the environment at
|
|
1851
1847
|
build time, same value flow as before. `bxm setup` scaffolds + merges `config/omega.json5`
|
package/docs/shared/logging.md
CHANGED
|
@@ -67,7 +67,7 @@ headers included, so it never rides a request carrying ANY credential header —
|
|
|
67
67
|
the line ([#130](https://github.com/Omega-JS-Stack/omega/issues/130)). The module
|
|
68
68
|
segment is the invocation's function name, which the context already knows
|
|
69
69
|
(`options.functionName || FUNCTION_TARGET`). Home:
|
|
70
|
-
`packages/backend/src/
|
|
70
|
+
`packages/backend/src/omega/context/logging.js`. A shared backend module
|
|
71
71
|
that logs outside a ctx carries its own file identity.
|
|
72
72
|
|
|
73
73
|
### Markers and exemptions
|
|
@@ -18,7 +18,7 @@ supplies only what it alone can know.
|
|
|
18
18
|
scripts, ad and chat widgets, and whatever browser extension a visitor installed. None of it is
|
|
19
19
|
ours to answer for, so a browser event reports only when an `@omega.js` bundle is on its stack.
|
|
20
20
|
- **Capture lives at SEAMS**, never in scattered try/catch: process hooks, the route error handler
|
|
21
|
-
(`
|
|
21
|
+
(`ctx.report()`), the event-trigger catch, the SDK's own global handlers.
|
|
22
22
|
- **PII is scrubbed by default.** The uid rides (it is the join key to the account); the email is
|
|
23
23
|
OFF unless a config explicitly opts in.
|
|
24
24
|
- **Everything is OFF when the DSN is unset** — and when it is off, the SDK is never `require()`d
|
|
@@ -88,7 +88,7 @@ target answers from ([#817](https://github.com/Omega-JS-Stack/omega/issues/817))
|
|
|
88
88
|
context such as a renderer bundle). `OMEGA_BUILD_MODE` used to be that default, which made it a
|
|
89
89
|
FIFTH production signal with an opinion of its own: a build-mode run of a development artifact
|
|
90
90
|
reported as production, and a packaged production app whose lane did not carry the flag reported as
|
|
91
|
-
development. @omega.js/backend still passes its own answer in (`
|
|
91
|
+
development. @omega.js/backend still passes its own answer in (`omega.isProduction()`, env-derived
|
|
92
92
|
and stable for the life of the process), alongside its own `reportErrorsInDev` option, and a boolean
|
|
93
93
|
a host supplies always wins. A context that names no environment at all throws by name, the same way
|
|
94
94
|
every other read of the one environment does.
|
|
@@ -119,8 +119,8 @@ by hand. Nothing tags a build stamp by design.
|
|
|
119
119
|
|
|
120
120
|
| Surface | Seam |
|
|
121
121
|
|---|---|
|
|
122
|
-
| Backend routes | `
|
|
123
|
-
| Backend event triggers | `
|
|
122
|
+
| Backend routes | `ctx.report()`: 5xx captures automatically, 4xx never ([backend guide](../backend/index.md)) |
|
|
123
|
+
| Backend event triggers | `omega/events.js`: a handler that throws, or a handler file that will not load, goes through the SAME `report()` door. A deliberate block (an `HttpsError`, or an explicit numeric 4xx code) is the trigger's 4xx and never captures; a string `.code` (`ENOENT`, `messaging/invalid-token`) is a system error, not a block, and reports. |
|
|
124
124
|
| Backend payment webhooks | the REFUSAL family's shared seam (`acknowledgeRefusal()` in `events/firestore/payments-webhooks/on-write.js`) captures ONE `warning` per refused event, tagged with the reason and the provider. A refusal is a decision, not a fault, so it never reports as an exception; a processed event reports nothing; and only IDS ride — the refusal stamp's own fields plus the event's ([#550](https://github.com/Omega-JS-Stack/omega/issues/550)). |
|
|
125
125
|
| Desktop main | `@sentry/electron/main`'s own `OnUncaughtException` + `onUnhandledRejection` integrations. Desktop's process handlers log to `runtime.log` and are ADDITIVE — never a second capture. |
|
|
126
126
|
| Desktop renderer | the SDK's window `error` / `unhandledrejection` handlers |
|
|
@@ -134,7 +134,7 @@ configured URL fragments. Default: `/assets/js/`, which is where both @omega.js/
|
|
|
134
134
|
|
|
135
135
|
An event with **no matching frame is dropped**, and that includes an event with no frames at all — a
|
|
136
136
|
cross-origin `Script error.` is exactly the third-party noise this exists to kill. Deliberate
|
|
137
|
-
`omega.sentry
|
|
137
|
+
`omega.sentry.captureException(…)` calls are unaffected: they are thrown from page bundles, which
|
|
138
138
|
ARE our bundles. The corollary: a deliberate capture must pass an Error CONSTRUCTED in framework
|
|
139
139
|
code — hand it a frameless one (a bare cross-browser `fetch` TypeError, say, which some engines
|
|
140
140
|
raise with no usable stack) and the filter drops it, by design.
|
package/docs/shared/testing.md
CHANGED
|
@@ -32,7 +32,7 @@ Layer names inside a suite are platform-native on purpose: desktop's `main`/`ren
|
|
|
32
32
|
| 2a — Sandbox e2e | The **cross-stack e2e** (headless Chromium → website → backend: signup/signin/subscribe/cancel/refund/data-request/delete lifecycle, plus the four chart types drawn as real SVG marks). It runs the consumer-brand lane file below directly (the root lane calls `node test/e2e/run.js`, not the brand-root `omega test` walk): `brands/sandbox-brand/test/e2e/run.js` on the devkit harness, driving a REAL `@omega.js/web` page served by the REAL `omega dev` against the emulator with its seeded personas, every port allocator-bumped ([#775](https://github.com/Omega-JS-Stack/omega/issues/775)) | `npm run test:e2e` at the root | Every checkpoint; `OMEGA_SKIP_E2E=1` to skip |
|
|
33
33
|
| 2b — Verts company-mode e2e | The **cross-brand verts (house-ads) proof** (OMEGA Playground's backend emulator serves seeded `verts` inventory — HTML unit / scoring / 204 / fail-closed redirect / whitelist scoping — and The Daily Build consumes as `source: 'company'`: real `@omega.js/config` compose → real `@omega.js/client` resolution → the consumer-built URL fetched against the parent stack) | `npm run test:verts` at the root | Every checkpoint touching the verts chain; `OMEGA_SKIP_E2E=1` to skip |
|
|
34
34
|
| 2c — Extension auth e2e | The **extension ↔ backend auth boundary in a REAL Chrome** ([scripts/e2e-extension-auth.js](../../scripts/e2e-extension-auth.js)): the playground's extension app builds as a TESTING build, headless Chrome loads it unpacked, the brand-site `?authToken=` tab drives the background SW's real sign-in, and the popup context's `omega:syncAuth` message makes the SW fetch a fresh custom token from the emulator — the uid round trip asserted INSIDE the extension. Offline by construction (host-resolver rules NXDOMAIN everything but the local stack). It FOLLOWS a bumped port like every other lane ([#744](https://github.com/Omega-JS-Stack/omega/issues/744)): the emulator boots FIRST and the extension builds second, so the bundle task bakes the live ports into `OMEGA_BUILD_JSON`'s `config.dev.ports` — the only channel a browser context has — and the lane reads the bake back out of the packaged service worker's own bundle and asserts the baked hosting/auth pair equals the resolved map before Chrome ever starts | `npm run test:e2e-extension` at the root | Every checkpoint touching extension auth, the SW build config, or the `/user/token` wire; `OMEGA_SKIP_E2E=1` to skip, and no puppeteer Chrome → SKIPPED (exit 0, reason printed) |
|
|
35
|
-
| 2d — Desktop auth e2e | The **desktop ↔ backend auth boundary in a REAL Electron app** ([scripts/e2e-desktop-auth.js](../../scripts/e2e-desktop-auth.js)): a consumer app staged from @omega.js/desktop's bundled fixture is built and booted by the real boot runner, then a SECOND Electron instance launches carrying `<brand.id>://auth/token?authToken=…` — the OS single-instance lock forwards that argv to the running app, whose real `second-instance` → deep-link →
|
|
35
|
+
| 2d — Desktop auth e2e | The **desktop ↔ backend auth boundary in a REAL Electron app** ([scripts/e2e-desktop-auth.js](../../scripts/e2e-desktop-auth.js)): a consumer app staged from @omega.js/desktop's bundled fixture is built and booted by the real boot runner, then a SECOND Electron instance launches carrying `<brand.id>://auth/token?authToken=…` — the OS single-instance lock forwards that argv to the running app, whose real `second-instance` → deep-link → desktop auth lib chain signs it in. Both sides of the process boundary are asserted: main's client-bridge on the emulator user, and the renderer's own @omega.js/client Firebase on the same uid (it learned only through the real `desktop:auth:sign-in-with-token` broadcast). Offline by construction — a testing run connects main's auth to the emulator and the staged config points the renderer's client at the same ports | `npm run test:e2e-desktop` at the root | Every checkpoint touching desktop auth, the deep-link routes, or the `/user/token` wire; `OMEGA_SKIP_E2E=1` to skip, and no electron binary (or no built @omega.js/desktop `dist/`) → SKIPPED (exit 0, reason printed) |
|
|
36
36
|
| 2e — User flows e2e (real browser) | The **CRUCIAL user flows through the actual UI** ([scripts/e2e-flows.js](../../scripts/e2e-flows.js)): headless Chromium against the playground's full emulator suite (seeded personas) plus the REAL `omega dev` — the auth-emulator proxy the provider redirect leg needs lives only there. Five areas — four per spec item of [#155](https://github.com/Omega-JS-Stack/omega/issues/155), plus the billing journeys of [#209](https://github.com/Omega-JS-Stack/omega/issues/209): **auth** (the Google picker's real redirect leg on /signup and again with `authReturnUrl`, `?authSignout=true` + the account page's kick-out, the empty-return loud failure, and the password FORMS — /signin, /signup, /reset), **checkout** (bound state, armed payment buttons, a `_dev_cardProvider=test` payment landing on /payment/confirmation with its order), **verts** (an unfilled slot laddering no-fill → promo, the card content-sized under its slot ceiling, the UTM set on the promo link and the click forwarded out of the frame), **account** (a signed-in policy page rendering the persona's account state from the emulator), **billing journeys** (one paid lifecycle per DEDICATED seeded persona — upgrade, cancel, a declined renewal, a trial converting — each verdict read off the RENDERED account page; the two end states no UI can reach post a hand-built test webhook at the backend exactly as a provider would). **Hard precondition**: `OMEGA_WEBHOOK_KEY` must be in the playground backend's `.env` cascade — the webhook route authenticates on it, and the lane throws `OMEGA_WEBHOOK_KEY is missing from the playground backend's .env cascade` at startup rather than running a crippled pass. Owns its stack: it HOLDS every classic port so both children bump onto fresh ones, so it never disturbs a live dev boot | `npm run test:flows` at the root | Every checkpoint touching auth pages, checkout, the vert ladder, the account page, or the billing lifecycle; `OMEGA_SKIP_E2E=1` to skip, and no puppeteer Chrome → SKIPPED (exit 0, reason printed) |
|
|
37
37
|
| 2.5 — Wizard journey (outside-monorepo consumer) | The FULL consumer story in a temp brand born OUTSIDE the monorepo: real onboard wizard (flags) → `i local` tree link → `omega dev` boot + branded-homepage probe → headless creds-scrubbed manage (update must build every target) | `npm run test:journey` at the root (also the tail of root `npm test`) | The full sequence, and any change to onboard/linking/boot plumbing |
|
|
38
38
|
| 3 — Playground (live rehearsal) | The 24-service manage pipeline against REAL cloud (Firebase, Cloudflare, SendGrid, …) | `npm run pipeline` in `brands/playground-omega` | SPARINGLY — Ian-authorized (real infra, real cost) |
|
|
@@ -50,7 +50,7 @@ Layer names inside a suite are platform-native on purpose: desktop's `main`/`ren
|
|
|
50
50
|
|
|
51
51
|
**Port isolation cuts two ways.** Every lane FOLLOWS a bumped port — including the extension lane, which builds after the boot so the resolved map is baked into the artifact the SW reads ([#744](https://github.com/Omega-JS-Stack/omega/issues/744)); the user-flows lane REFUSES the classics outright — it binds every classic port on all three addresses (127.0.0.1, ::1, wildcard: Node's SO_REUSEADDR means one bind is not enough) for the whole run, so the emulator CLI and `omega dev` both bump onto fresh ports and a developer's live stack is untouched. A classic port that is already busy is somebody else's: the hold simply fails and the allocator bumps around it as always. The website port is allocated by the LANE and handed to both children as `OMEGA_WEBSITE_PORT`, because the backend builds checkout confirmation URLs from it and boots first.
|
|
52
52
|
|
|
53
|
-
**The auth lanes divide by SURFACE.** `npm run test:auth` ([scripts/e2e-auth-token.js](../../scripts/e2e-auth-token.js)) is the fast WIRE-CONTRACT lane: the desktop
|
|
53
|
+
**The auth lanes divide by SURFACE.** `npm run test:auth` ([scripts/e2e-auth-token.js](../../scripts/e2e-auth-token.js)) is the fast WIRE-CONTRACT lane: the desktop auth lib required in-process from node against the emulator, proving the custom-token round trip in seconds. Tiers 2c and 2d are the REAL-SURFACE proofs of the same chain — the extension's background SW inside actual Chrome, and the desktop app inside actual Electron with a real OS-delivered deep link. A change to the token wire runs the fast lane; a change to how either app RECEIVES it runs its real-surface lane.
|
|
54
54
|
|
|
55
55
|
**Every lane leaves a log.** A lane tees its full output — its own lines plus every child command's — to `.temp/logs/<lane>.log` (`test:packages` → `.temp/logs/test-packages.log`), and each e2e runner writes per-step verdicts to `.temp/<lane>/steps.log` beside its environment logs, so `grep '^FAIL' .temp/*/steps.log` names the failing step even after a lane was killed. Truncated per run; read them instead of re-running a lane to see what it said ([logging.md](logging.md)).
|
|
56
56
|
|
package/docs/shared/theming.md
CHANGED
|
@@ -466,7 +466,7 @@ Resilience rules (load-bearing):
|
|
|
466
466
|
that must beat the big bundle belongs there (brand custom hero animations,
|
|
467
467
|
[#441](https://github.com/Omega-JS-Stack/omega/issues/441), ride the same
|
|
468
468
|
engine and get the same early start) — weighed against that budget. It must
|
|
469
|
-
never import `@omega.js/client`: the
|
|
469
|
+
never import `@omega.js/client`: the runtime import drags the whole client into
|
|
470
470
|
the bundle and rebuilds the very problem it exists to solve. The motion
|
|
471
471
|
module's subpath is standalone by design, and `core/js/core/motion.js` adopts
|
|
472
472
|
the running instance rather than starting a second one.
|
|
@@ -98,7 +98,7 @@ pinned by `packages/manager/test/workspace-translation-sdk.test.js`).
|
|
|
98
98
|
only fail the same way — the playground's ship-the-docs page came back
|
|
99
99
|
25-for-26 on all six attempts, in both languages, and shipped untranslated.
|
|
100
100
|
A single string that still will not come back whole throws, and the caller
|
|
101
|
-
|
|
101
|
+
ships that page-language pair untranslated (never half-translated).
|
|
102
102
|
- Original leading/trailing whitespace is re-applied to every translation.
|
|
103
103
|
- Rules baked into the system prompt: preserve HTML/URLs/placeholders
|
|
104
104
|
(`$1`, `{name}`, `{{ value }}`), never translate the brand name.
|
|
@@ -133,12 +133,20 @@ pages, inside the package ([below](#framework-shipped-default-page-translations-
|
|
|
133
133
|
strings come from the committed cache instantly, cold strings translate live
|
|
134
134
|
through the provider — a build ships the COMPLETE translated site whenever
|
|
135
135
|
the provider delivers, and a warm cache means zero provider calls. A provider
|
|
136
|
-
FAILURE
|
|
137
|
-
the language (the build still exits 0): no half-translated copy ever ships
|
|
136
|
+
FAILURE ships that page-language pair UNTRANSLATED, warning loudly with the page
|
|
137
|
+
and the language (the build still exits 0): no half-translated copy ever ships
|
|
138
138
|
behind full language chrome.
|
|
139
|
-
`omega build --cached-only`
|
|
140
|
-
|
|
141
|
-
|
|
139
|
+
`omega build --cached-only` ships cold page-language pairs UNTRANSLATED instead
|
|
140
|
+
(the warning lists them) for provider-free builds; `omega translate` fills them.
|
|
141
|
+
An untranslated pair still lands the SOURCE page at its translated path
|
|
142
|
+
(`dist/{lang}/...`, `{lang}.html` for the home) with its links rewritten into
|
|
143
|
+
the language, because every produced copy links there and a missing file is a
|
|
144
|
+
dead link that fails `omega test`'s link check and ships with `omega deploy`
|
|
145
|
+
([#953](https://github.com/Omega-JS-Stack/omega/issues/953)). It is never
|
|
146
|
+
ADVERTISED: its `<html lang dir>` and `og:locale` name the source language its
|
|
147
|
+
text is in, its canonical and `og:url` stay the source page's (it duplicates
|
|
148
|
+
that page), no hreflang alternate names it (on it or on the original), and the
|
|
149
|
+
sitemap does not list it.
|
|
142
150
|
`omega translate` still runs the live pass standalone against an existing
|
|
143
151
|
dist/ and exits 1 on failures. `OMEGA_TRANSLATE_ONLY=<route>` limits any of
|
|
144
152
|
these to one page (canary/debug).
|
|
@@ -148,7 +156,7 @@ Per page × language: text nodes/`<title>`/meta/attribute copy translate
|
|
|
148
156
|
(RTL-aware), canonical + `og:url` + `og:locale` localized, internal links
|
|
149
157
|
rewritten to `/{lang}/...`, and hreflang + `og:locale:alternate` tags
|
|
150
158
|
stitched into BOTH the copy and the original — naming only the languages
|
|
151
|
-
actually PRODUCED for that page (a pair
|
|
159
|
+
actually PRODUCED for that page (a pair left untranslated, cold or failed, is never
|
|
152
160
|
advertised, on the copies as on the originals), so hreflang never lies.
|
|
153
161
|
`og:locale` carries Open Graph's `language_TERRITORY` form (`en_US`,
|
|
154
162
|
`es_ES`) from the devkit language SSOT's locale map — on translated copies
|
|
@@ -281,8 +289,8 @@ as its own `<url>`, and each entry of a translated set — source and copies
|
|
|
281
289
|
alike — carries the full `xhtml:link rel="alternate"` list (`x-default` at the
|
|
282
290
|
source language) plus the source entry's `lastmod`/`changefreq`/`priority`.
|
|
283
291
|
Entries stay in loc byte order. The language-prefixed entries are owned by that
|
|
284
|
-
pass: each run drops them all and re-emits only what it produced, so
|
|
285
|
-
or failed
|
|
292
|
+
pass: each run drops them all and re-emits only what it produced, so an
|
|
293
|
+
untranslated pair (cold or failed) is listed nowhere.
|
|
286
294
|
|
|
287
295
|
The visitor-facing **language switcher** is the footer dropup in the shared
|
|
288
296
|
base footer include (`_includes/frontend/sections/footer.html`, the base layer
|
|
@@ -322,7 +330,8 @@ list in `gulp/config/locales.js` is gone (only the CWS `limits` remain there).
|
|
|
322
330
|
language SSOT, settings reader (fake `send`).
|
|
323
331
|
- web `test/translate.test.js` — handcrafted dist through the real pipeline:
|
|
324
332
|
copies/chrome/links/exclusions/alternates/cache/override/only-filter, the
|
|
325
|
-
produced-languages-only alternates, and the
|
|
333
|
+
produced-languages-only alternates, and the untranslated-copy fallback
|
|
334
|
+
(cold and failed pairs land unadvertised, no language link dangles).
|
|
326
335
|
- web `test/language-switcher.test.js` — the switcher's DOM read (x-default
|
|
327
336
|
dropped, duplicates collapsed, current marked, escaping) and the built footer
|
|
328
337
|
mount in classy and newsflash.
|