@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.
Files changed (161) hide show
  1. package/README.md +38 -38
  2. package/dist/cli-run.js +4 -1
  3. package/dist/cli.js +2 -2
  4. package/dist/commands/cdp/client.js +1 -1
  5. package/dist/commands/cdp.js +1 -1
  6. package/dist/commands/clean.js +2 -3
  7. package/dist/commands/dev.js +25 -0
  8. package/dist/commands/lib/ensure-target.js +12 -17
  9. package/dist/commands/lib/migrate.js +17 -0
  10. package/dist/commands/logs.js +1 -1
  11. package/dist/commands/release.js +1 -1
  12. package/dist/commands/test.js +4 -4
  13. package/dist/commands/update.js +5 -4
  14. package/dist/defaults/.github/workflows/build.yml +18 -18
  15. package/dist/defaults/_.gitignore +0 -2
  16. package/dist/defaults/_mas/README.md +3 -3
  17. package/dist/defaults/config/certs/README.md +1 -1
  18. package/dist/defaults/config/omega.json5 +36 -36
  19. package/dist/defaults/docs/README.md +3 -3
  20. package/dist/defaults/gulpfile.js +1 -1
  21. package/dist/defaults/hooks/build/post.js +1 -1
  22. package/dist/defaults/hooks/build/pre.js +1 -1
  23. package/dist/defaults/hooks/notarize/post.js +2 -2
  24. package/dist/defaults/hooks/release/post.js +1 -1
  25. package/dist/defaults/hooks/release/pre.js +1 -1
  26. package/dist/defaults/src/assets/scss/pages/about.scss +1 -1
  27. package/dist/defaults/src/assets/scss/pages/main.scss +1 -1
  28. package/dist/defaults/src/assets/scss/pages/settings.scss +1 -1
  29. package/dist/defaults/src/integrations/context-menu/index.js +11 -11
  30. package/dist/defaults/src/integrations/menu/index.js +5 -5
  31. package/dist/defaults/src/integrations/tray/index.js +9 -9
  32. package/dist/defaults/src/main.js +2 -2
  33. package/dist/defaults/src/preload.js +1 -1
  34. package/dist/defaults/test/README.md +3 -3
  35. package/dist/defaults/test/_init.js +1 -1
  36. package/dist/gulp/tasks/audit.js +5 -8
  37. package/dist/lib/restart-manager/index.js +1 -1
  38. package/dist/lib/restart-manager/install.js +1 -1
  39. package/dist/lib/restart-manager/protocol.js +1 -1
  40. package/dist/main.js +4 -3
  41. package/dist/preload.js +1 -1
  42. package/dist/test/suites/build/audit.test.js +20 -7
  43. package/dist/test/suites/build/build-workflow-jobs.test.js +2 -2
  44. package/dist/test/suites/build/cli.test.js +28 -0
  45. package/dist/test/suites/build/defaults-em-dash.test.js +22 -0
  46. package/dist/test/suites/build/defaults-scaffold.test.js +19 -5
  47. package/dist/test/suites/build/deploy-direct.test.js +7 -5
  48. package/dist/test/suites/build/deploy-dispatch.test.js +2 -1
  49. package/dist/test/suites/build/deploy-hook.test.js +4 -2
  50. package/dist/test/suites/build/dev-verb.test.js +67 -0
  51. package/dist/test/suites/build/ensure-target.test.js +11 -3
  52. package/dist/test/suites/build/merge-line-files.test.js +6 -6
  53. package/dist/test/suites/build/migrate.test.js +29 -0
  54. package/dist/test/suites/build/project-scripts-deps.test.js +6 -10
  55. package/dist/test/suites/build/runner-env-write.test.js +73 -0
  56. package/dist/test/suites/build/runner.test.js +9 -8
  57. package/dist/test/suites/build/setup-scripts.test.js +27 -0
  58. package/dist/test/suites/build/validate-config.test.js +13 -2
  59. package/dist/test/suites/build/verb-logs.test.js +20 -0
  60. package/dist/test/suites/renderer/window-desktop-surface.test.js +1 -1
  61. package/dist/utils/build-pipeline.js +4 -4
  62. package/dist/utils/runner-env.js +13 -28
  63. package/dist/vendor/config/company.js +46 -14
  64. package/dist/vendor/config/defaults.js +30 -7
  65. package/dist/vendor/config/edit.js +25 -3
  66. package/dist/vendor/config/env-delivery.js +1 -1
  67. package/dist/vendor/config/env-schema.js +3 -6
  68. package/dist/vendor/config/env.js +34 -22
  69. package/dist/vendor/config/index.js +13 -17
  70. package/dist/vendor/config/load.js +15 -7
  71. package/dist/vendor/config/repo.js +10 -27
  72. package/dist/vendor/config/schema-client.js +64 -0
  73. package/dist/vendor/config/schema-cloud.js +38 -0
  74. package/dist/vendor/config/schema-manager.js +118 -0
  75. package/dist/vendor/config/schema-overrides.js +68 -0
  76. package/dist/vendor/config/schema.js +99 -152
  77. package/dist/vendor/config/validate.js +97 -77
  78. package/dist/vendor/devkit/agents-md.js +233 -0
  79. package/dist/vendor/devkit/attach-log-file.js +15 -1
  80. package/dist/vendor/devkit/ci-workflows.js +30 -30
  81. package/dist/vendor/devkit/cli-router.js +13 -7
  82. package/dist/vendor/devkit/defaults-engine.js +9 -43
  83. package/dist/vendor/devkit/deploy-snapshot.js +44 -9
  84. package/dist/vendor/devkit/env-lines.js +183 -0
  85. package/dist/vendor/devkit/local.js +62 -10
  86. package/dist/vendor/devkit/lockfile.js +32 -13
  87. package/dist/vendor/devkit/logger.js +7 -2
  88. package/dist/vendor/devkit/merge-line-files.js +219 -176
  89. package/dist/vendor/devkit/omega-bin.js +208 -111
  90. package/dist/vendor/devkit/preludes/docs-sync.js +52 -0
  91. package/dist/vendor/devkit/preludes/index.js +1 -0
  92. package/dist/vendor/devkit/target-picker.js +45 -0
  93. package/dist/vendor/devkit/test/dashed-files.js +37 -0
  94. package/dist/vendor/devkit/test/run-verb-under-tee.js +71 -0
  95. package/dist/vendor/devkit/update.js +15 -15
  96. package/dist/vendor/devkit/verb-scripts.js +40 -0
  97. package/dist/vendor/devkit/verbs.js +170 -0
  98. package/package.json +18 -24
  99. package/dist/commands/install.js +0 -37
  100. package/dist/defaults/AGENTS.md +0 -119
  101. package/dist/defaults/CLAUDE.md +0 -1
  102. package/dist/vendor/config/env-retired.js +0 -137
  103. package/dist/vendor/config/retired-keys.js +0 -635
  104. package/docs/analytics.md +0 -140
  105. package/docs/app-state.md +0 -92
  106. package/docs/audit.md +0 -69
  107. package/docs/auth.md +0 -284
  108. package/docs/auto-updater.md +0 -243
  109. package/docs/boot-sequence.md +0 -44
  110. package/docs/build-system.md +0 -169
  111. package/docs/cdp-debugging.md +0 -169
  112. package/docs/common-mistakes.md +0 -21
  113. package/docs/config-schema.md +0 -120
  114. package/docs/context-menu.md +0 -112
  115. package/docs/context.md +0 -81
  116. package/docs/css.md +0 -84
  117. package/docs/deep-link.md +0 -186
  118. package/docs/environment-detection.md +0 -112
  119. package/docs/fontawesome.md +0 -109
  120. package/docs/hooks.md +0 -89
  121. package/docs/icons.md +0 -79
  122. package/docs/index.md +0 -328
  123. package/docs/installer-options.md +0 -165
  124. package/docs/ipc.md +0 -61
  125. package/docs/lib-modules.md +0 -53
  126. package/docs/logging.md +0 -227
  127. package/docs/menu.md +0 -160
  128. package/docs/releasing.md +0 -239
  129. package/docs/remote-config.md +0 -118
  130. package/docs/remote-scripts.md +0 -144
  131. package/docs/restart-manager.md +0 -144
  132. package/docs/runner.md +0 -290
  133. package/docs/sentry.md +0 -97
  134. package/docs/shared/agent-docs.md +0 -89
  135. package/docs/shared/analytics.md +0 -612
  136. package/docs/shared/brands.md +0 -57
  137. package/docs/shared/breaking-changes.md +0 -917
  138. package/docs/shared/config.md +0 -1948
  139. package/docs/shared/deploys.md +0 -341
  140. package/docs/shared/icons.md +0 -219
  141. package/docs/shared/local-dev.md +0 -167
  142. package/docs/shared/logging.md +0 -205
  143. package/docs/shared/monitoring.md +0 -167
  144. package/docs/shared/publishing.md +0 -187
  145. package/docs/shared/rulings.md +0 -34
  146. package/docs/shared/testing.md +0 -147
  147. package/docs/shared/theming.md +0 -629
  148. package/docs/shared/translation.md +0 -342
  149. package/docs/shared/updates.md +0 -61
  150. package/docs/signing.md +0 -293
  151. package/docs/startup.md +0 -142
  152. package/docs/storage.md +0 -59
  153. package/docs/templating.md +0 -101
  154. package/docs/test-boot-layer.md +0 -157
  155. package/docs/test-framework.md +0 -362
  156. package/docs/themes.md +0 -149
  157. package/docs/tooltips.md +0 -99
  158. package/docs/tray.md +0 -164
  159. package/docs/usage.md +0 -58
  160. package/docs/verts.md +0 -62
  161. 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.
@@ -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.