@omega.js/desktop 0.53.0 → 0.54.1
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 +38 -38
- package/dist/cli-run.js +4 -1
- package/dist/cli.js +2 -2
- package/dist/commands/cdp/client.js +1 -1
- package/dist/commands/cdp.js +1 -1
- package/dist/commands/clean.js +2 -3
- package/dist/commands/dev.js +25 -0
- package/dist/commands/lib/ensure-target.js +12 -17
- package/dist/commands/lib/migrate.js +17 -0
- package/dist/commands/logs.js +1 -1
- package/dist/commands/release.js +1 -1
- package/dist/commands/test.js +4 -4
- package/dist/commands/update.js +5 -4
- package/dist/defaults/.github/workflows/build.yml +18 -18
- package/dist/defaults/_.gitignore +0 -2
- package/dist/defaults/_mas/README.md +3 -3
- package/dist/defaults/config/certs/README.md +1 -1
- package/dist/defaults/config/omega.json5 +36 -36
- package/dist/defaults/docs/README.md +3 -3
- package/dist/defaults/gulpfile.js +1 -1
- package/dist/defaults/hooks/build/post.js +1 -1
- package/dist/defaults/hooks/build/pre.js +1 -1
- package/dist/defaults/hooks/notarize/post.js +2 -2
- package/dist/defaults/hooks/release/post.js +1 -1
- package/dist/defaults/hooks/release/pre.js +1 -1
- package/dist/defaults/src/assets/scss/pages/about.scss +1 -1
- package/dist/defaults/src/assets/scss/pages/main.scss +1 -1
- package/dist/defaults/src/assets/scss/pages/settings.scss +1 -1
- package/dist/defaults/src/integrations/context-menu/index.js +11 -11
- package/dist/defaults/src/integrations/menu/index.js +5 -5
- package/dist/defaults/src/integrations/tray/index.js +9 -9
- package/dist/defaults/src/main.js +2 -2
- package/dist/defaults/src/preload.js +1 -1
- package/dist/defaults/test/README.md +3 -3
- package/dist/defaults/test/_init.js +1 -1
- package/dist/gulp/tasks/audit.js +5 -8
- package/dist/lib/restart-manager/index.js +1 -1
- package/dist/lib/restart-manager/install.js +1 -1
- package/dist/lib/restart-manager/protocol.js +1 -1
- package/dist/main.js +4 -3
- package/dist/preload.js +1 -1
- package/dist/test/suites/build/audit.test.js +20 -7
- package/dist/test/suites/build/build-workflow-jobs.test.js +2 -2
- package/dist/test/suites/build/cli.test.js +28 -0
- package/dist/test/suites/build/defaults-em-dash.test.js +22 -0
- package/dist/test/suites/build/defaults-scaffold.test.js +19 -5
- package/dist/test/suites/build/deploy-direct.test.js +7 -5
- package/dist/test/suites/build/deploy-dispatch.test.js +2 -1
- package/dist/test/suites/build/deploy-hook.test.js +4 -2
- package/dist/test/suites/build/dev-verb.test.js +67 -0
- package/dist/test/suites/build/ensure-target.test.js +11 -3
- package/dist/test/suites/build/merge-line-files.test.js +6 -6
- package/dist/test/suites/build/migrate.test.js +29 -0
- package/dist/test/suites/build/project-scripts-deps.test.js +6 -10
- package/dist/test/suites/build/runner-env-write.test.js +73 -0
- package/dist/test/suites/build/runner.test.js +9 -8
- package/dist/test/suites/build/setup-scripts.test.js +27 -0
- package/dist/test/suites/build/validate-config.test.js +13 -2
- package/dist/test/suites/build/verb-logs.test.js +20 -0
- package/dist/test/suites/renderer/window-desktop-surface.test.js +1 -1
- package/dist/utils/build-pipeline.js +4 -4
- package/dist/utils/runner-env.js +13 -28
- package/dist/vendor/config/company.js +46 -14
- package/dist/vendor/config/defaults.js +30 -7
- package/dist/vendor/config/edit.js +25 -3
- package/dist/vendor/config/env-delivery.js +1 -1
- package/dist/vendor/config/env-schema.js +3 -6
- package/dist/vendor/config/env.js +34 -22
- package/dist/vendor/config/index.js +13 -17
- package/dist/vendor/config/load.js +15 -7
- package/dist/vendor/config/repo.js +10 -27
- package/dist/vendor/config/schema-client.js +64 -0
- package/dist/vendor/config/schema-cloud.js +38 -0
- package/dist/vendor/config/schema-manager.js +118 -0
- package/dist/vendor/config/schema-overrides.js +68 -0
- package/dist/vendor/config/schema.js +99 -152
- package/dist/vendor/config/validate.js +97 -77
- package/dist/vendor/devkit/agents-md.js +233 -0
- package/dist/vendor/devkit/attach-log-file.js +15 -1
- package/dist/vendor/devkit/ci-workflows.js +30 -30
- package/dist/vendor/devkit/cli-router.js +13 -7
- package/dist/vendor/devkit/defaults-engine.js +9 -43
- package/dist/vendor/devkit/deploy-snapshot.js +44 -9
- package/dist/vendor/devkit/env-lines.js +183 -0
- package/dist/vendor/devkit/local.js +62 -10
- package/dist/vendor/devkit/lockfile.js +32 -13
- package/dist/vendor/devkit/logger.js +7 -2
- package/dist/vendor/devkit/merge-line-files.js +219 -176
- package/dist/vendor/devkit/omega-bin.js +208 -111
- package/dist/vendor/devkit/preludes/docs-sync.js +52 -0
- package/dist/vendor/devkit/preludes/index.js +1 -0
- package/dist/vendor/devkit/target-picker.js +45 -0
- package/dist/vendor/devkit/test/dashed-files.js +37 -0
- package/dist/vendor/devkit/test/run-verb-under-tee.js +71 -0
- package/dist/vendor/devkit/update.js +15 -15
- package/dist/vendor/devkit/verb-scripts.js +40 -0
- package/dist/vendor/devkit/verbs.js +170 -0
- package/package.json +18 -24
- package/dist/commands/install.js +0 -37
- package/dist/defaults/AGENTS.md +0 -119
- package/dist/defaults/CLAUDE.md +0 -1
- package/dist/vendor/config/env-retired.js +0 -137
- package/dist/vendor/config/retired-keys.js +0 -635
- package/docs/analytics.md +0 -140
- package/docs/app-state.md +0 -92
- package/docs/audit.md +0 -69
- package/docs/auth.md +0 -284
- package/docs/auto-updater.md +0 -243
- package/docs/boot-sequence.md +0 -44
- package/docs/build-system.md +0 -169
- package/docs/cdp-debugging.md +0 -169
- package/docs/common-mistakes.md +0 -21
- package/docs/config-schema.md +0 -120
- package/docs/context-menu.md +0 -112
- package/docs/context.md +0 -81
- package/docs/css.md +0 -84
- package/docs/deep-link.md +0 -186
- package/docs/environment-detection.md +0 -112
- package/docs/fontawesome.md +0 -109
- package/docs/hooks.md +0 -89
- package/docs/icons.md +0 -79
- package/docs/index.md +0 -328
- package/docs/installer-options.md +0 -165
- package/docs/ipc.md +0 -61
- package/docs/lib-modules.md +0 -53
- package/docs/logging.md +0 -227
- package/docs/menu.md +0 -160
- package/docs/releasing.md +0 -239
- package/docs/remote-config.md +0 -118
- package/docs/remote-scripts.md +0 -144
- package/docs/restart-manager.md +0 -144
- package/docs/runner.md +0 -290
- package/docs/sentry.md +0 -97
- package/docs/shared/agent-docs.md +0 -89
- package/docs/shared/analytics.md +0 -612
- package/docs/shared/brands.md +0 -57
- package/docs/shared/breaking-changes.md +0 -917
- package/docs/shared/config.md +0 -1948
- package/docs/shared/deploys.md +0 -341
- package/docs/shared/icons.md +0 -219
- package/docs/shared/local-dev.md +0 -167
- package/docs/shared/logging.md +0 -205
- package/docs/shared/monitoring.md +0 -167
- package/docs/shared/publishing.md +0 -187
- package/docs/shared/rulings.md +0 -34
- package/docs/shared/testing.md +0 -147
- package/docs/shared/theming.md +0 -629
- package/docs/shared/translation.md +0 -342
- package/docs/shared/updates.md +0 -61
- package/docs/signing.md +0 -293
- package/docs/startup.md +0 -142
- package/docs/storage.md +0 -59
- package/docs/templating.md +0 -101
- package/docs/test-boot-layer.md +0 -157
- package/docs/test-framework.md +0 -362
- package/docs/themes.md +0 -149
- package/docs/tooltips.md +0 -99
- package/docs/tray.md +0 -164
- package/docs/usage.md +0 -58
- package/docs/verts.md +0 -62
- package/docs/windows.md +0 -149
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
# Environment Detection
|
|
2
|
-
|
|
3
|
-
`getEnvironment()` returns exactly ONE of three mutually-exclusive, exhaustive values:
|
|
4
|
-
|
|
5
|
-
```javascript
|
|
6
|
-
omega.getEnvironment() // 'development' | 'testing' | 'production'
|
|
7
|
-
|
|
8
|
-
omega.isDevelopment() // true ONLY in development
|
|
9
|
-
omega.isTesting() // true ONLY in testing
|
|
10
|
-
omega.isProduction() // true ONLY in production
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
**ONE input, and no default** ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)). `getEnvironment()` reads the `OMEGA_ENVIRONMENT` variable in Node, and the baked `OMEGA_BUILD_JSON.config.environment` in a renderer (which has no `process.env`). Nothing else is consulted: the `app.isPackaged`, `config.em.environment`, `OMEGA_BUILD_MODE` and `NODE_ENV` sniffs are gone, and a context with neither input **throws**, naming the variable. The old default here was `production`, so a plain `npm start` bundled itself as a production artifact while @omega.js/extension's copy of the same function answered `development` from the same inputs.
|
|
14
|
-
|
|
15
|
-
**One implementation, shared with every sibling framework.** The four calls are `@omega.js/config`'s [environment.js](../../config/src/environment.js), the module @omega.js/extension, @omega.js/web, @omega.js/backend and @omega.js/client all answer from. @omega.js/desktop has four entry points (main / renderer / preload / build); [src/utils/mode-helpers.js](../src/utils/mode-helpers.js) re-exports the shared four beside desktop's own `getVersion()`. The build module exports them as plain functions, and every process's `omega` carries them as methods.
|
|
16
|
-
|
|
17
|
-
```javascript
|
|
18
|
-
omega.getEnvironment() // same answer in main / renderer / preload
|
|
19
|
-
require('@omega.js/desktop/build').isTesting() // the build module, for build-time scripts
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
**Who sets the input.** [src/build.js](../src/build.js) names it at LOAD, from the lane: `OMEGA_BUILD_MODE` (which `omega build` / `package` / `publish` / `release` and the boot runner's staged build all set) is `production` and WINS over an inherited value, so a production build spawned from a test run still bakes production; otherwise a lane that already named one keeps it (the test runners spawn their children naming `testing`), and a bare dev boot is `development`. The electron app that lane spawns inherits the variable. A PACKAGED app has no parent lane, so [src/main.js](../src/main.js) names it from the word the build baked into the artifact: that is a FALLBACK for the context with no input, never an override ([#925](https://github.com/Omega-JS-Stack/omega/issues/925)). A process that already carries `OMEGA_ENVIRONMENT` keeps it, which is why a test lane that boots a production artifact still answers `testing` inside it.
|
|
23
|
-
|
|
24
|
-
**The renderer gets the running word too.** A page has no `process`, so its `omega` reads input 2, the baked `config.environment`, which is the word the BUILD was for. Those agree everywhere except a lane that boots a production artifact, so the preload (a Node context, it has the variable) exposes it on `window.desktop.environment` and [src/renderer.js](../src/renderer.js) applies it over the baked word at `initialize()`. Same precedence, one context removed: the running environment first, the bake second. No second signal exists.
|
|
25
|
-
|
|
26
|
-
**The three checks are mutually exclusive**: exactly one is true. `isDevelopment()` is **false** during testing, and `isProduction()` is a real positive check (it is NOT `!isDevelopment()`).
|
|
27
|
-
|
|
28
|
-
## Available helpers
|
|
29
|
-
|
|
30
|
-
| Helper | Returns |
|
|
31
|
-
|---|---|
|
|
32
|
-
| `getEnvironment()` | `'development' \| 'testing' \| 'production'`: the one reader of the one input; throws when it is absent. |
|
|
33
|
-
| `isDevelopment()` | `true` ONLY in development, and NOT testing. Derives from `getEnvironment()`. |
|
|
34
|
-
| `isTesting()` | `true` ONLY in testing. Derives from `getEnvironment()`. |
|
|
35
|
-
| `isProduction()` | `true` ONLY in production. A **real positive check**, NOT `!isDevelopment()`. |
|
|
36
|
-
|
|
37
|
-
## Gating side effects — use the INTENTIONAL check
|
|
38
|
-
|
|
39
|
-
Because there are three environments, never gate a side effect on a two-value assumption. State what you mean:
|
|
40
|
-
|
|
41
|
-
```javascript
|
|
42
|
-
// Production-only (skip OS side effects / real telemetry in dev AND testing):
|
|
43
|
-
if (isProduction()) { /* do the real thing */ }
|
|
44
|
-
if (!isProduction()) { /* skip / use the safe local behavior */ }
|
|
45
|
-
|
|
46
|
-
// Local-or-test (anything that should run in BOTH dev and testing):
|
|
47
|
-
if (isDevelopment() || isTesting()) { /* localhost URL, isolate userData, suppress login items */ }
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
**Avoid** `if (!isDevelopment())` or `if (env !== 'development')` to gate production behavior — those wrongly include `testing` as production and leak real side effects (login items, telemetry, auto-update) during test runs. This is the bug class that motivated the 3-value model. (A genuinely dev-only feature like live-reload is the exception: `env !== 'development'` correctly skips it in both testing and production.)
|
|
51
|
-
|
|
52
|
-
## URL helpers
|
|
53
|
-
|
|
54
|
-
```javascript
|
|
55
|
-
omega.getApiUrl() // the app's API URL: the SSOT for calling the backend
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
`getApiUrl()` / `getFunctionsUrl()` / `getWebsiteUrl()` resolve to **local** URLs (from the baked dev map, whose floor is the classic hosting / functions / website numbers) in development OR testing, and to production (`https://api.<brand.url host>` etc.) otherwise. They route through `this.getEnvironment()`, so they're correct everywhere without an argument: call them directly. Pass an explicit `env` arg (`getApiUrl('production')`) only to force a specific environment regardless of the current one, rarely needed, and mainly used by tests to pin a specific environment's mapping.
|
|
59
|
-
|
|
60
|
-
`getAuthUrl()` builds the **sign-in URL that round-trips an auth token back to the app**: `<site>/signin?authReturnUrl=<site>/token?authReturnUrl=<brand.id>://auth/token`, where `<site>` is `getWebsiteUrl()` (same env split). The website's `/signin` page logs the user in (or bounces straight through if already signed in), its `/token` page mints a Firebase custom token via the backend, and the final redirect (`?authToken=<token>`, the ONE shape) deep-links the token into the app's built-in `auth/token` route → `omega.auth.handleToken()` → `signInWithCustomToken`. Use it for EVERY "Sign in" affordance an app exposes; never link the bare `/signin` page, which strands the login in the browser. Requires `brand.id` (the deep-link scheme) in config; throws when missing. The optional second arg `getAuthUrl(env, returnUrl)` overrides the chain's final hop: that's how `lib/auth-flow.js` swaps in its dev loopback return.
|
|
61
|
-
|
|
62
|
-
**Apps should launch the flow through `omega.openAuthFlow()` (main process), not by opening `getAuthUrl()` themselves**: production opens `getAuthUrl()` externally as-is (the OS routes the custom scheme back), while dev/test, where the scheme is NOT OS-registered (protocol.js registers only in production, and macOS can't runtime-register schemes missing from the bundle's Info.plist), swap the final hop for a one-shot, nonce-checked loopback HTTP listener (RFC 8252 §7.3) that feeds the token into the SAME deep-link pipeline. Sign-in always happens in the user's REAL default browser (their existing session/SSO), never an embedded window. Requires @omega.js/client ≥ 4.3.4 on the website (`isValidRedirectUrl` accepts loopback hosts while the SITE runs in dev). See [src/lib/auth-flow.js](../src/lib/auth-flow.js).
|
|
63
|
-
|
|
64
|
-
All three local helpers resolve from whichever channel the process has: the `OMEGA_*_PORT` env vars (the CLI that booted the stack publishes them), then the `dev` map the bundle baked into `OMEGA_BUILD_JSON` (a packaged main process has no parent env, so a bumped emulator port reaches it only this way, [#745](https://github.com/Omega-JS-Stack/omega/issues/745)). There is no third step: the classic numbers used to be hand-typed under them, and they are gone ([#834](https://github.com/Omega-JS-Stack/omega/issues/834)).
|
|
65
|
-
|
|
66
|
-
| Helper | Env channel | Baked channel | Neither |
|
|
67
|
-
|---|---|---|---|
|
|
68
|
-
| `getApiUrl()` | `OMEGA_HTTPS_PORT`, else `OMEGA_HOSTING_PORT` | `dev.ports.https`, else `dev.ports.hosting` | throws |
|
|
69
|
-
| `getFunctionsUrl()` | `OMEGA_FUNCTIONS_PORT` | `dev.ports.functions` | throws |
|
|
70
|
-
| `getWebsiteUrl()` | `OMEGA_WEBSITE_PORT`, composed as `https://localhost:<port>` | `dev.origin` (the whole origin) first, else `dev.ports.website` | throws |
|
|
71
|
-
|
|
72
|
-
The classics still reach these helpers, from the ONE place they are defined: the bundle task bakes `CLASSIC_PORTS` and `CLASSIC_DEV_ORIGIN` (`@omega.js/config`) as the FLOOR of the `dev` map, with the live stack's resolved numbers over them, so a dev artifact always carries a complete map. A read that finds none names the fact it wanted and the build step that writes it. A production build bakes no `dev` at all, which is correct: a packaged app has no local stack to reach.
|
|
73
|
-
|
|
74
|
-
The first two rows are port chains: each cell names a port, and the helper builds the URL around it. The website row is an ORIGIN chain ([#747](https://github.com/Omega-JS-Stack/omega/issues/747)): the baked `dev.origin` the live website published carries scheme, host AND port, so it is the complete fact and outranks the port cell; only when it is absent does a port compose an origin, over **https**, because `omega dev` fronts its public port with the mkcert proxy by default and a port number alone can never say the scheme. Whenever the website published an origin, that is the same answer `@omega.js/client`'s `getDevWebsiteOrigin()` gives every other surface ([#262](https://github.com/Omega-JS-Stack/omega/issues/262)), and `getAuthUrl()` inherits it by construction.
|
|
75
|
-
|
|
76
|
-
A resolved `OMEGA_HTTPS_PORT` (or a baked `dev.ports.https`) means `omega serve`'s mkcert proxy is up, so the api URL is https. That is the same chain @omega.js/extension's `getApiUrl()` walks, and the same one `omega.auth` uses for the auth emulator port (`OMEGA_AUTH_PORT` → `dev.ports.auth` → throw, [auth.md](auth.md)).
|
|
77
|
-
|
|
78
|
-
Resolving local in test mode is required because tests hit the local emulator — without it, the app (and tests calling `getApiUrl()`) would leak to the live production server.
|
|
79
|
-
|
|
80
|
-
> The URL helpers live in [src/utils/url-helpers.js](../src/utils/url-helpers.js) as plain functions of the instance (`getApiUrl(omega, environment)`), reading its `getEnvironment()`; each process class calls them from its own methods.
|
|
81
|
-
|
|
82
|
-
## Where they live
|
|
83
|
-
|
|
84
|
-
Source: [src/utils/mode-helpers.js](../src/utils/mode-helpers.js) for `getEnvironment()` + `is*()` + `getVersion()`; [src/utils/url-helpers.js](../src/utils/url-helpers.js) for the URL builders. Both modules export plain functions. [build.js](../src/build.js) exports the mode helpers as they are; the three process classes, [main.js](../src/main.js) (the methods mixed in from [lib/_environment-mixin.js](../src/lib/_environment-mixin.js)), [preload.js](../src/preload.js) and [renderer.js](../src/renderer.js), call them from their own methods (the renderer takes the environment four and `getApiUrl()` / `getFunctionsUrl()` from @omega.js/client's base class it extends).
|
|
85
|
-
|
|
86
|
-
## How detection works
|
|
87
|
-
|
|
88
|
-
`getEnvironment()` reads ONE input, and there is no precedence ladder under it
|
|
89
|
-
([#817](https://github.com/Omega-JS-Stack/omega/issues/817)):
|
|
90
|
-
|
|
91
|
-
1. **`process.env.OMEGA_ENVIRONMENT`**, wherever this context has a `process` (main, preload, build-time Node).
|
|
92
|
-
2. **The baked `config.environment`** off the `omega` the call is made on, for a renderer, which has none. It is the build fact every OMEGA surface spells the same way ([#896](https://github.com/Omega-JS-Stack/omega/issues/896)). The preload hands the running word across to the renderer when the two differ, so this step answers the artifact's own build only when no lane named one ([#925](https://github.com/Omega-JS-Stack/omega/issues/925)).
|
|
93
|
-
3. **Neither** is a loud error naming `OMEGA_ENVIRONMENT`. There is no default, because the four framework copies this replaced each had one and they disagreed.
|
|
94
|
-
|
|
95
|
-
The lanes above supply that input, and the whole table of who names what lives in
|
|
96
|
-
[docs/shared/config.md](../../../docs/shared/config.md).
|
|
97
|
-
|
|
98
|
-
## Adding a new helper
|
|
99
|
-
|
|
100
|
-
Write the function in a `src/utils/<topic>-helpers.js` module, export it from [build.js](../src/build.js), and call it from a method on each process class that needs it. Don't define a helper's logic inside one process class: that path leads to duplicated semantics. For anything environment-derived, derive from `getEnvironment()` rather than reading `process.env` / `app.*` directly, so there is one source of truth and no chance of drift.
|
|
101
|
-
|
|
102
|
-
## Why this matters
|
|
103
|
-
|
|
104
|
-
**One signal, used everywhere.** The test runners spawn their children naming `OMEGA_ENVIRONMENT=testing`; every piece of code that calls `isTesting()` (framework or consumer) then sees `true`, no need to invent a per-module env var.
|
|
105
|
-
|
|
106
|
-
**Sub-modules check the same signal.** When framework code (an auto-update poll, a restart-manager registration) needs to skip side effects in tests, it checks `isTesting()` — the same answer the consumer's own code gets. No drift.
|
|
107
|
-
|
|
108
|
-
**`is*()` can never disagree with `getEnvironment()`.** Because the checks derive from the single resolver instead of reading raw signals, there is exactly one definition of "what environment is this," and a wrong-but-confident gate is structurally impossible. Since #817 that holds ACROSS frameworks too: the resolver is one shared module, so @omega.js/desktop and @omega.js/extension can no longer answer differently from the same inputs.
|
|
109
|
-
|
|
110
|
-
## See also
|
|
111
|
-
|
|
112
|
-
- [test-framework.md](test-framework.md): `OMEGA_ENVIRONMENT=testing` is named automatically by the test runners; extended mode (`--extended` / `TEST_EXTENDED_MODE`) gates real external APIs.
|
package/docs/fontawesome.md
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
# FontAwesome
|
|
2
|
-
|
|
3
|
-
@omega.js/desktop serves the **brand's best available Font Awesome set** —
|
|
4
|
-
Pro when the brand supplies one (see below), otherwise the **Free set**
|
|
5
|
-
(solid + regular + brands, SVG) straight from its
|
|
6
|
-
`@fortawesome/fontawesome-free` npm dependency — every consumer gets 2,600+
|
|
7
|
-
icons with **zero setup**, fully offline, no icon font, no CDN, and nothing
|
|
8
|
-
vendored inside the framework package.
|
|
9
|
-
|
|
10
|
-
```html
|
|
11
|
-
<button class="btn btn-primary">
|
|
12
|
-
<i class="fa-solid fa-rocket me-2"></i>Launch
|
|
13
|
-
</button>
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
That's it. Any `<i>` element carrying `fa-*` classes — in static HTML or
|
|
17
|
-
inserted dynamically at any time — gets the real SVG injected inline by the
|
|
18
|
-
renderer bootstrap. No `initialize()` options, no imports.
|
|
19
|
-
|
|
20
|
-
## One icon mechanism, every surface (C4 cp108)
|
|
21
|
-
|
|
22
|
-
Icon SEMANTICS — valid names/styles, candidate lookup order (requested style,
|
|
23
|
-
then the brands fallback), the injected root attributes, and alias mapping —
|
|
24
|
-
live in **`@omega.js/client/modules/icon-core.js`**, the SAME module
|
|
25
|
-
@omega.js/web's build-time inlining pass uses. Desktop and web can never
|
|
26
|
-
drift on how an icon name resolves or what the served SVG looks like.
|
|
27
|
-
|
|
28
|
-
## How it works
|
|
29
|
-
|
|
30
|
-
- **Assets** — resolved through the root chain (cp111), best-first:
|
|
31
|
-
`OMEGA_FONTAWESOME_ROOT` download dir → `@fortawesome/fontawesome-pro`
|
|
32
|
-
when the brand installed it → `@fortawesome/fontawesome-free` (a declared
|
|
33
|
-
runtime dependency, always last so a partial brand set never loses icons
|
|
34
|
-
the free set has). Each root holds `svgs/<style>/*.svg` plus
|
|
35
|
-
`metadata/icon-families.json` for aliases (`search` → `magnifying-glass`).
|
|
36
|
-
Declared dependencies ride into packaged apps automatically (fs reads
|
|
37
|
-
through the asar transparently).
|
|
38
|
-
- **Main lib** (`lib/fontawesome.js`): `omega.fontawesome.get(name, style)`
|
|
39
|
-
resolves an icon to its SVG string (`null` for unknown names — never
|
|
40
|
-
throws). Lookups are slug-sanitized via icon-core (the IPC channel can
|
|
41
|
-
never read outside the icon directories) and cached per app run. Serves
|
|
42
|
-
renderers over `desktop:fontawesome:get`.
|
|
43
|
-
- **Preload bridge** — `window.desktop.fontawesome.get(name, style)` →
|
|
44
|
-
`Promise<svg | null>`.
|
|
45
|
-
- **Renderer auto-render** (`renderer.js _wireFontAwesome`) — a thin
|
|
46
|
-
wrapper over **@omega.js/client's shared `icon-renderer`** (C4 cp112, the
|
|
47
|
-
same module web pages run): scan + MutationObserver for insertions AND
|
|
48
|
-
class changes (`el.className = 'fa-solid fa-stop'` re-renders in place;
|
|
49
|
-
dropping the classes clears the SVG), FA's family × weight class parsing
|
|
50
|
-
(`fa-sharp fa-light` → `sharp-light`; Pro markup without a Pro set stays
|
|
51
|
-
empty — never a wrong-style fallback), caching, and the
|
|
52
|
-
`data-omega-fa="<style>/<name>"` marker. Desktop supplies only the
|
|
53
|
-
transport: IPC to main's icon server.
|
|
54
|
-
The SVG is injected as a child of the `<i>`, sized `1em`/`currentColor` — it
|
|
55
|
-
inherits text color and scales with font-size (bump it via `font-size` or a
|
|
56
|
-
`fs-*` utility). Served SVGs also carry `overflow="visible"` (FA-kit parity:
|
|
57
|
-
`.svg-inline--fa { overflow: visible }`) — FA 7 glyphs may draw OUTSIDE
|
|
58
|
-
their viewBox (fa-lock's shackle peaks at y=-32 in a `0 0 384 512` box) and
|
|
59
|
-
the SVG-root default of `overflow: hidden` clips them flat.
|
|
60
|
-
|
|
61
|
-
## Minimal surfaces
|
|
62
|
-
|
|
63
|
-
The auto-render is wired by `initialize()`. A renderer that deliberately skips
|
|
64
|
-
`initialize()` (e.g. a lightweight popover overlay with no auth) can enable JUST
|
|
65
|
-
the icon pipeline on the same instance:
|
|
66
|
-
|
|
67
|
-
```js
|
|
68
|
-
import omega from '@omega.js/desktop/renderer';
|
|
69
|
-
|
|
70
|
-
omega.enableFontAwesome();
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
## Supplying Font Awesome Pro (C4 cp111)
|
|
74
|
-
|
|
75
|
-
Pro is brand-supplied, never redistributed by the framework. The two
|
|
76
|
-
routes (FA npm token, or an `OMEGA_FONTAWESOME_ROOT` download dir), the
|
|
77
|
-
chain semantics, and the style/family model are documented once at the
|
|
78
|
-
repo hub: **[docs/shared/icons.md](../../../docs/shared/icons.md)**. Desktop-specific
|
|
79
|
-
note: a packaged brand target declares `@fortawesome/fontawesome-pro` as its
|
|
80
|
-
own **prod dependency** so the set ships inside the asar.
|
|
81
|
-
|
|
82
|
-
## Notes
|
|
83
|
-
|
|
84
|
-
- **The icon CSS is not desktop's.** The box, the size scale and the
|
|
85
|
-
`fa-spin`/`fa-bounce`/`fa-beat` utilities ride ONE sheet vendored from
|
|
86
|
-
@omega.js/web at prepare (see [css.md](css.md#icon-presentation)). Fix icon
|
|
87
|
-
presentation there, never here.
|
|
88
|
-
- **Unknown names render nothing** — the `<i>` stays empty (marked
|
|
89
|
-
`data-omega-fa`). If you need a fallback, resolve through
|
|
90
|
-
`window.desktop.fontawesome.get()` and swap yourself.
|
|
91
|
-
- **Free set = solid + regular + brands.** Pro styles (light/duotone/sharp)
|
|
92
|
-
need a supplied Pro set (above); otherwise
|
|
93
|
-
`omega.fontawesome.get(name, 'duotone')` returns `null`.
|
|
94
|
-
- **Updating the set** — bump the `@fortawesome/fontawesome-free` dependency
|
|
95
|
-
(or reinstall/refresh the brand's Pro supply).
|
|
96
|
-
|
|
97
|
-
## Testing
|
|
98
|
-
|
|
99
|
-
- `src/test/suites/main/fontawesome.test.js` — resolution, aliases (via the
|
|
100
|
-
metadata map), sanitization (traversal attempts), caching, IPC round-trip,
|
|
101
|
-
the `overflow="visible"` serve attribute, and the cp111 root chain
|
|
102
|
-
(`OMEGA_FONTAWESOME_ROOT` wins, free set falls through for icons and
|
|
103
|
-
metadata the brand set lacks).
|
|
104
|
-
- `src/test/suites/renderer/fontawesome.test.js` — the real-DOM proof of
|
|
105
|
-
the SHARED icon-renderer: inserted `<i>` elements get SVGs on the live
|
|
106
|
-
DOM, class changes re-render in place and class removal clears (cp112),
|
|
107
|
-
modifier classes are never mistaken for names, Pro family/weight classes
|
|
108
|
-
compose (Pro-adaptive assertions), unknown names stay empty, injected
|
|
109
|
-
SVGs compute `overflow: visible` (out-of-viewBox glyphs must not clip).
|
package/docs/hooks.md
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
# Lifecycle Hooks
|
|
2
|
-
|
|
3
|
-
Consumers can inject custom logic at well-defined points without forking @omega.js/desktop's gulp tasks. All hooks are **purely additive extension points** — @omega.js/desktop's core logic always runs first, the hook is called after (or before, depending on the lifecycle point), and a hook throwing only logs a warning, never breaks the build.
|
|
4
|
-
|
|
5
|
-
## How hooks work
|
|
6
|
-
|
|
7
|
-
1. @omega.js/desktop scaffolds empty hook files into `<consumer>/hooks/**/*.js` on every verb (`ensureTarget()`).
|
|
8
|
-
2. At each lifecycle point, @omega.js/desktop checks for the file. If it exists, @omega.js/desktop loads + invokes it. If not, no-op.
|
|
9
|
-
3. The hook signature is `async (ctx) => { ... }`, with `ctx` the ONE hook-argument shape every OMEGA framework passes, `{ build, projectRoot, mode }`: `build` is the build module (`require('@omega.js/desktop/build')`, one plain object of functions: `getConfig()`, `getPackage()`, `getRootPath()`, ...). Whatever it returns is awaited but ignored.
|
|
10
|
-
4. **Failure semantics:**
|
|
11
|
-
- File missing entirely → logged informationally (`hook "<name>" not present at ... — skipping.`), build continues.
|
|
12
|
-
- File exists but fails to load (syntax error, etc.) → **throws**, build fails.
|
|
13
|
-
- File exists but doesn't export a function → **throws**, build fails.
|
|
14
|
-
- File loads + invokes the function and the function throws → **throws**, build fails.
|
|
15
|
-
|
|
16
|
-
In other words: a hook that doesn't exist is fine (you'll see one log line), but a hook that's broken in any way fails loudly. You should never silently ship a malformed hook to production.
|
|
17
|
-
|
|
18
|
-
## Hooks reference
|
|
19
|
-
|
|
20
|
-
| Hook file | When it runs | `ctx` shape |
|
|
21
|
-
|---|---|---|
|
|
22
|
-
| `hooks/build/pre.js` | Before the build pipeline runs (`defaults` → `distribute` → `bundle` ...) | `{ build, projectRoot, mode }` |
|
|
23
|
-
| `hooks/build/post.js` | After the build pipeline finishes, before `electron-builder` packages anything | `{ build, projectRoot, mode }` |
|
|
24
|
-
| `hooks/release/pre.js` | Before `electron-builder build --publish always` | `{ build, projectRoot, mode }` |
|
|
25
|
-
| `hooks/release/post.js` | After the release publishes | `{ build, projectRoot, mode }` |
|
|
26
|
-
| `hooks/deploy/pre.js` | Inside `omega deploy`, after the local scaffold and before the network precheck, on both lanes (the dispatch and `--direct`); a dry run skips it, because a hook may act on the world ([#900](https://github.com/Omega-JS-Stack/omega/issues/900): the playground's prunes its release family down to the newest, so two releases stay live; the VERSION comes from `omega bump` at the brand root, [#869](https://github.com/Omega-JS-Stack/omega/issues/869), never from a hook) | `{ build, projectRoot, mode: 'production' }` |
|
|
27
|
-
| `hooks/notarize/post.js` | After @omega.js/desktop's built-in macOS notarization completes (extension only — @omega.js/desktop's notarize is the real entrypoint) | electron-builder afterSign context |
|
|
28
|
-
|
|
29
|
-
`mode` is `'production'` when `OMEGA_BUILD_MODE=true`, else `'development'`. A deploy hook always reads `'production'`: the verb runs outside a build, and what it is about to publish is a release.
|
|
30
|
-
|
|
31
|
-
## Why this design
|
|
32
|
-
|
|
33
|
-
- **Notarize specifically:** the consumer's `hooks/notarize/post.js` is **never** the electron-builder afterSign entrypoint. @omega.js/desktop's `gulp/build-config` injects `afterSign:` pointing at @omega.js/desktop's real notarize implementation (resolved via `require.resolve('@omega.js/desktop/hooks/notarize')`). @omega.js/desktop's real notarize calls into the consumer's `hooks/notarize/post.js` as a final post-step. So the consumer can never accidentally break notarization by editing the file — the file can be empty, malformed, or missing entirely and the app still notarizes correctly.
|
|
34
|
-
- **Why no `hooks/notarize/pre.js`?** electron-builder's `afterSign` hook is the only signing-related extension point we control. Anything that would belong in a "pre-notarize" step belongs either in `hooks/release/pre.js` (whole-release-level prep, runs before the gulp release task), or in electron-builder's own `afterPack` / `afterAllArtifactBuild` configuration (per-artifact mutation). If you have a real use case that doesn't fit either, file an issue.
|
|
35
|
-
- **Build/release hooks:** standard before/after lifecycle pattern, the same `ctx` @omega.js/extension hands its hooks.
|
|
36
|
-
|
|
37
|
-
## Examples
|
|
38
|
-
|
|
39
|
-
### Slack notification on release
|
|
40
|
-
|
|
41
|
-
```js
|
|
42
|
-
// hooks/release/post.js
|
|
43
|
-
module.exports = async ({ build, projectRoot }) => {
|
|
44
|
-
const pkg = require(`${projectRoot}/package.json`);
|
|
45
|
-
const url = process.env.SLACK_WEBHOOK_URL;
|
|
46
|
-
if (!url) return;
|
|
47
|
-
await fetch(url, {
|
|
48
|
-
method: 'POST',
|
|
49
|
-
headers: { 'content-type': 'application/json' },
|
|
50
|
-
body: JSON.stringify({ text: `🚀 ${pkg.name} v${pkg.version} released` }),
|
|
51
|
-
});
|
|
52
|
-
};
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Generate changelog before build
|
|
56
|
-
|
|
57
|
-
```js
|
|
58
|
-
// hooks/build/pre.js
|
|
59
|
-
const { execSync } = require('child_process');
|
|
60
|
-
const fs = require('fs');
|
|
61
|
-
const path = require('path');
|
|
62
|
-
|
|
63
|
-
module.exports = async ({ projectRoot }) => {
|
|
64
|
-
const log = execSync('git log --oneline -n 20', { cwd: projectRoot });
|
|
65
|
-
fs.writeFileSync(path.join(projectRoot, 'CHANGELOG_LATEST.txt'), log);
|
|
66
|
-
};
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### Custom post-notarize archive
|
|
70
|
-
|
|
71
|
-
```js
|
|
72
|
-
// hooks/notarize/post.js
|
|
73
|
-
const fs = require('fs');
|
|
74
|
-
const path = require('path');
|
|
75
|
-
|
|
76
|
-
module.exports = async (context) => {
|
|
77
|
-
const { appOutDir, packager } = context;
|
|
78
|
-
const appName = packager.appInfo.productFilename;
|
|
79
|
-
const appPath = path.join(appOutDir, `${appName}.app`);
|
|
80
|
-
// e.g. archive a copy somewhere off the build path
|
|
81
|
-
fs.cpSync(appPath, `/tmp/omega-archive/${appName}-${Date.now()}.app`, { recursive: true });
|
|
82
|
-
};
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Tests
|
|
86
|
-
|
|
87
|
-
- `src/test/suites/build/run-consumer-hook.test.js` — silent skip, invocation with args, error swallowing.
|
|
88
|
-
- `src/test/suites/build/deploy-hook.test.js`: `omega deploy` runs `hooks/deploy/pre.js` after the scaffold and before the precheck; a dry run skips it.
|
|
89
|
-
- `src/test/suites/build/build-config.test.js` — `injectAfterSign` always points at @omega.js/desktop's notarize.
|
package/docs/icons.md
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# Icons
|
|
2
|
-
|
|
3
|
-
Convention-only. No config block — drop PNGs at known paths and @omega.js/desktop finds them.
|
|
4
|
-
|
|
5
|
-
## Layout
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
config/icons/
|
|
9
|
-
global/ ← used by any platform with no platform-specific override
|
|
10
|
-
icon.png
|
|
11
|
-
tray.png
|
|
12
|
-
mac/ ← macOS overrides (beats global)
|
|
13
|
-
icon.png
|
|
14
|
-
tray.png ← 32×32 native; @omega.js/desktop renames to trayTemplate.png in dist
|
|
15
|
-
dmg.png ← 1080×760 DMG installer background
|
|
16
|
-
windows/ ← Windows overrides
|
|
17
|
-
icon.png
|
|
18
|
-
tray.png ← optional; falls back to icon.png
|
|
19
|
-
linux/ ← Linux overrides
|
|
20
|
-
icon.png
|
|
21
|
-
tray.png
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Resolution chain (per slot, per platform)
|
|
25
|
-
|
|
26
|
-
Most specific wins:
|
|
27
|
-
|
|
28
|
-
1. `<projectRoot>/config/icons/<platform>/<file>` — platform-specific override
|
|
29
|
-
2. `<projectRoot>/config/icons/global/<file>` — universal fallback shared by all platforms
|
|
30
|
-
3. `<projectRoot>/config/icons/windows/<file>` — Linux-only extra step (legacy compat — Linux apps historically reuse Windows assets)
|
|
31
|
-
4. `<@omega.js/desktop>/dist/config/icons/<platform>/<file>` — @omega.js/desktop bundled default
|
|
32
|
-
5. `<@omega.js/desktop>/dist/config/icons/windows/<file>` — Linux-only extra step at the bundled level
|
|
33
|
-
|
|
34
|
-
Inside the runtime tray lookup (`lib/tray.js`), tray-slot misses fall back to the app icon (`icon.png`) instead of returning null.
|
|
35
|
-
|
|
36
|
-
## Sizes — ship @2x native only
|
|
37
|
-
|
|
38
|
-
Retina slots (macOS tray, macOS dmg) take ONE source file at the native (@2x) size. @omega.js/desktop downscales the @1x sibling at build time via `sharp` and writes both into `dist/`. Consumers never ship `<name>@2x.png` files.
|
|
39
|
-
|
|
40
|
-
| Slot | Native size | @omega.js/desktop emits |
|
|
41
|
-
|---|---|---|
|
|
42
|
-
| `mac/tray.png` | 32×32 | `trayTemplate.png` (16×16) + `trayTemplate@2x.png` (32×32) |
|
|
43
|
-
| `mac/dmg.png` | 1080×760 | `dmg.png` (540×380) + `dmg@2x.png` (1080×760) |
|
|
44
|
-
| `mac/icon.png` | 1024×1024 | `icon.png` (unchanged; electron-builder converts to `.icns`) |
|
|
45
|
-
| `windows/icon.png` | 1024×1024 | `icon.png` (unchanged; electron-builder converts to `.ico`) |
|
|
46
|
-
| `linux/icon.png` | 1024×1024 | `icon.png` (unchanged) |
|
|
47
|
-
|
|
48
|
-
## Why `trayTemplate.png` on disk
|
|
49
|
-
|
|
50
|
-
macOS reads the literal filename of the tray icon and treats any `*Template.png` as a "template image" — pure-black with alpha, automatically inverted in dark mode. Consumers ship `tray.png` (clearer naming, matches Windows/Linux); @omega.js/desktop owns the `Template` suffix when writing to `dist/`.
|
|
51
|
-
|
|
52
|
-
If you set a custom path via `tray.icon(path)` in your `src/integrations/tray/index.js`, YOU are responsible for the runtime filename containing `Template` — @omega.js/desktop only owns the convention path.
|
|
53
|
-
|
|
54
|
-
## Two common scenarios
|
|
55
|
-
|
|
56
|
-
**One icon for everything:**
|
|
57
|
-
|
|
58
|
-
```
|
|
59
|
-
config/icons/global/icon.png # mac + win + linux
|
|
60
|
-
config/icons/global/tray.png # mac + win + linux
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
**Mac-specific + shared Win/Linux:**
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
config/icons/global/icon.png # win + linux use this
|
|
67
|
-
config/icons/mac/icon.png # mac override
|
|
68
|
-
config/icons/mac/tray.png # mac-specific tray (will become trayTemplate.png in dist)
|
|
69
|
-
config/icons/mac/dmg.png # mac-only by definition
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Source files
|
|
73
|
-
|
|
74
|
-
- `src/lib/sign-helpers/resolve-icons.js` — the resolver itself; called from `gulp/build-config.js`.
|
|
75
|
-
- `src/lib/tray.js#_defaultIconPath` — runtime tray lookup (same convention waterfall, but checks `dist/` first since the build already resolved).
|
|
76
|
-
|
|
77
|
-
## Bundled defaults
|
|
78
|
-
|
|
79
|
-
@omega.js/desktop ships its own `icon.png`, `tray.png`, `dmg.png` for each platform in `<@omega.js/desktop>/src/defaults/config/icons/<platform>/`. These are the final fallback when neither the consumer nor a global file provides anything — so a freshly scaffolded project produces a buildable app with the generic @omega.js/desktop icon out of the box.
|