@omega.js/desktop 0.50.0 → 0.51.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 +1 -1
- package/dist/assets/css/tokens/_index.scss +1 -1
- package/dist/assets/themes/base/_includes/frontend/sections/account-section-header.html +4 -1
- package/dist/assets/themes/base/_includes/frontend/sections/footer.html +13 -6
- package/dist/assets/themes/base/_includes/frontend/sections/nav.html +10 -8
- package/dist/assets/themes/base/_includes/global/sections/account.html +3 -1
- package/dist/assets/themes/base/_includes/global/sections/app-sidebar.html +12 -8
- package/dist/assets/themes/base/_includes/global/sections/app-topbar.html +10 -6
- package/dist/assets/themes/base/_includes/global/sections/page-header.html +8 -4
- package/dist/assets/themes/base/_layouts/backend/pages/dashboard/index.html +24 -24
- package/dist/assets/themes/base/_layouts/frontend/pages/about.html +10 -10
- package/dist/assets/themes/base/_layouts/frontend/pages/account/index.html +35 -35
- package/dist/assets/themes/base/_layouts/frontend/pages/alternatives/index.html +4 -4
- package/dist/assets/themes/base/_layouts/frontend/pages/auth/signin.html +1 -1
- package/dist/assets/themes/base/_layouts/frontend/pages/auth/signup.html +4 -4
- package/dist/assets/themes/base/_layouts/frontend/pages/contact.html +3 -3
- package/dist/assets/themes/base/_layouts/frontend/pages/download.html +34 -33
- package/dist/assets/themes/base/_layouts/frontend/pages/extension/index.html +11 -11
- package/dist/assets/themes/base/_layouts/frontend/pages/legal/document.html +1 -1
- package/dist/assets/themes/base/_layouts/frontend/pages/status.html +1 -1
- package/dist/assets/themes/base/_layouts/frontend/pages/team/index.html +9 -7
- package/dist/assets/themes/base/_layouts/frontend/pages/team/member.html +5 -3
- package/dist/assets/themes/base/_sections/about/letter/section.html +1 -1
- package/dist/assets/themes/base/_sections/about/letter/section.json5 +4 -4
- package/dist/assets/themes/base/_sections/marketing/bento/section.html +1 -1
- package/dist/assets/themes/base/_sections/marketing/bento/section.json5 +15 -15
- package/dist/assets/themes/base/_sections/marketing/cta/section.json5 +1 -1
- package/dist/assets/themes/base/_sections/marketing/hero/section.html +6 -6
- package/dist/assets/themes/base/_sections/marketing/hero/section.json5 +10 -10
- package/dist/assets/themes/base/_sections/marketing/product-demo/section.html +1 -1
- package/dist/assets/themes/base/_sections/marketing/product-demo/section.json5 +2 -2
- package/dist/assets/themes/base/_sections/marketing/stats/section.html +1 -1
- package/dist/assets/themes/base/_sections/marketing/stats/section.json5 +5 -5
- package/dist/assets/themes/base/_sections/marketing/trusted-by/section.html +1 -1
- package/dist/assets/themes/base/_sections/marketing/trusted-by/section.json5 +2 -2
- package/dist/assets/themes/neobrutalism/_layouts/frontend/pages/index.html +10 -10
- package/dist/assets/themes/newsflash/_layouts/frontend/pages/index.html +10 -10
- package/dist/assets/themes/newsflash/_sections/marketing/desks/section.html +2 -2
- package/dist/assets/themes/newsflash/_sections/marketing/desks/section.json5 +4 -4
- package/dist/build.js +69 -28
- package/dist/cli-run.js +20 -13
- package/dist/cli.js +12 -7
- package/dist/commands/build.js +0 -2
- package/dist/commands/deploy.js +116 -44
- package/dist/commands/finalize-release.js +5 -4
- package/dist/commands/launch.js +12 -7
- package/dist/commands/lib/deploy-precheck.js +66 -34
- package/dist/commands/lib/ensure-target.js +71 -11
- package/dist/commands/package.js +0 -1
- package/dist/commands/publish.js +11 -4
- package/dist/commands/release.js +99 -252
- package/dist/commands/runner.js +42 -5
- package/dist/commands/sign-windows.js +46 -15
- package/dist/commands/test.js +4 -3
- package/dist/commands/validate-certs.js +291 -115
- package/dist/config/page-template.html +4 -0
- package/dist/defaults/.github/workflows/build.yml +144 -64
- package/dist/defaults/AGENTS.md +3 -2
- package/dist/defaults/_.gitignore +4 -2
- package/dist/defaults/config/certs/README.md +25 -45
- package/dist/defaults/config/omega.json5 +66 -32
- package/dist/defaults/hooks/deploy/pre.js +10 -0
- package/dist/defaults/src/assets/scss/main.scss +12 -2
- package/dist/defaults/src/integrations/tray/index.js +1 -1
- package/dist/gulp/main.js +13 -25
- package/dist/gulp/tasks/audit.js +18 -6
- package/dist/gulp/tasks/build-config.js +181 -60
- package/dist/gulp/tasks/bundle.js +108 -36
- package/dist/gulp/tasks/release.js +86 -4
- package/dist/gulp/tasks/sass.js +11 -0
- package/dist/hooks/lib/notarize-tools.js +137 -0
- package/dist/hooks/notarize-artifacts.js +57 -0
- package/dist/hooks/notarize.js +59 -8
- package/dist/lib/auth-persistence.js +25 -0
- package/dist/lib/client-bridge.js +11 -8
- package/dist/lib/deep-link.js +15 -8
- package/dist/lib/protocol.js +7 -1
- package/dist/lib/restart-manager/install.js +6 -3
- package/dist/lib/sign-helpers/auto-unlock.js +65 -27
- package/dist/lib/sign-helpers/console-lock.js +34 -0
- package/dist/lib/sign-helpers/exec-with-limit.js +68 -0
- package/dist/lib/sign-helpers/resolve-icons.js +6 -4
- package/dist/lib/tray.js +7 -6
- package/dist/main.js +16 -0
- package/dist/preload.js +8 -0
- package/dist/renderer.js +16 -4
- package/dist/runner/job-started.js +104 -0
- package/dist/test/fixtures/consumer-app/config/omega.json5 +7 -0
- package/dist/test/fixtures/consumer-app/package.json +1 -1
- package/dist/test/fixtures/consumer-app/src/assets/js/components/main/index.js +7 -1
- package/dist/test/harness/main-entry.js +2 -1
- package/dist/test/harness/renderer-preload.js +12 -3
- package/dist/test/runners/boot.js +101 -11
- package/dist/test/runners/electron.js +1 -1
- package/dist/test/suites/boot/consumer-app-boots.test.js +54 -0
- package/dist/test/suites/build/audit.test.js +45 -6
- package/dist/test/suites/build/auth-persistence-resolve.test.js +119 -0
- package/dist/test/suites/build/auto-unlock.test.js +105 -0
- package/dist/test/suites/build/boot-runner-timeout.test.js +253 -0
- package/dist/test/suites/build/brand-scss.test.js +106 -0
- package/dist/test/suites/build/build-config.test.js +146 -36
- package/dist/test/suites/build/build-json-bake.test.js +245 -0
- package/dist/test/suites/build/build-verbs.test.js +48 -15
- package/dist/test/suites/build/build-workflow-jobs.test.js +190 -0
- package/dist/test/suites/build/cli.test.js +32 -10
- package/dist/test/suites/build/config-schema.test.js +4 -4
- package/dist/test/suites/build/console-lock.test.js +51 -0
- package/dist/test/suites/build/defaults-scaffold.test.js +71 -2
- package/dist/test/suites/build/deploy-direct.test.js +241 -0
- package/dist/test/suites/build/deploy-dispatch.test.js +287 -0
- package/dist/test/suites/build/deploy-hook.test.js +169 -0
- package/dist/test/suites/build/ensure-target.test.js +14 -2
- package/dist/test/suites/build/env-delivery.test.js +19 -10
- package/dist/test/suites/build/env-watch.test.js +18 -7
- package/dist/test/suites/build/esm-only-dependency.test.js +127 -0
- package/dist/test/suites/build/exec-with-limit.test.js +53 -0
- package/dist/test/suites/build/finalize-release.test.js +2 -2
- package/dist/test/suites/build/get-config.test.js +120 -8
- package/dist/test/suites/build/github-utils.test.js +12 -6
- package/dist/test/suites/build/license-stamp.test.js +6 -4
- package/dist/test/suites/build/manager.test.js +88 -68
- package/dist/test/suites/build/manifest-deps.test.js +116 -0
- package/dist/test/suites/build/merge-line-files.test.js +27 -4
- package/dist/test/suites/build/notarize-artifacts.test.js +135 -0
- package/dist/test/suites/build/notarize-tools.test.js +38 -0
- package/dist/test/suites/build/notarize.test.js +207 -0
- package/dist/test/suites/build/release-pipeline.test.js +38 -60
- package/dist/test/suites/build/release-skipped-upload.test.js +107 -0
- package/dist/test/suites/build/resolve-icons.test.js +35 -35
- package/dist/test/suites/build/runner-job-guard.test.js +182 -0
- package/dist/test/suites/build/runner.test.js +25 -2
- package/dist/test/suites/build/sentry.test.js +8 -3
- package/dist/test/suites/build/setup-scripts.test.js +3 -0
- package/dist/test/suites/build/sign-windows.test.js +92 -8
- package/dist/test/suites/build/test-stealth.test.js +17 -11
- package/dist/test/suites/build/url-helpers.test.js +37 -17
- package/dist/test/suites/build/validate-certs.test.js +428 -55
- package/dist/test/suites/build/validate-config.test.js +3 -3
- package/dist/test/suites/main/auth-flow.test.js +12 -0
- package/dist/test/suites/main/auth-persistence.test.js +14 -17
- package/dist/test/suites/main/auto-updater.test.js +2 -2
- package/dist/test/suites/main/boot-sequence.test.js +1 -1
- package/dist/test/suites/main/client-bridge.integration.test.js +5 -82
- package/dist/test/suites/main/client-bridge.test.js +19 -6
- package/dist/test/suites/main/deep-link.test.js +54 -0
- package/dist/test/suites/main/startup-paths-and-ua.test.js +1 -1
- package/dist/test/suites/main/url-helpers.test.js +81 -72
- package/dist/test/suites/renderer/cross-context-helpers.test.js +19 -16
- package/dist/utils/build-pipeline.js +10 -10
- package/dist/utils/github.js +12 -51
- package/dist/utils/load-env.js +66 -0
- package/dist/utils/mode-helpers.js +43 -111
- package/dist/utils/platform.js +37 -0
- package/dist/utils/runner-env.js +2 -1
- package/dist/utils/runner-job-guard.js +149 -0
- package/dist/utils/ship-keys.js +52 -0
- package/dist/utils/test-stealth.js +5 -3
- package/dist/utils/url-helpers.js +33 -17
- package/dist/vendor/config/bundle-id.js +53 -0
- package/dist/vendor/config/client-config.js +141 -0
- package/dist/vendor/config/company.js +334 -15
- package/dist/vendor/config/dev-facts.js +48 -0
- package/dist/vendor/config/env-delivery.js +231 -9
- package/dist/vendor/config/env-retired.js +137 -0
- package/dist/vendor/config/env-rules.js +22 -3
- package/dist/vendor/config/env-schema.js +234 -117
- package/dist/vendor/config/env.js +55 -26
- package/dist/vendor/config/environment.js +189 -0
- package/dist/vendor/config/hooks.js +13 -11
- package/dist/vendor/config/index.js +121 -44
- package/dist/vendor/config/load.js +366 -115
- package/dist/vendor/config/merge.js +2 -2
- package/dist/vendor/config/order.js +3 -3
- package/dist/vendor/config/platforms.js +276 -0
- package/dist/vendor/config/repo.js +226 -104
- package/dist/vendor/config/retired-keys.js +232 -27
- package/dist/vendor/config/schema.js +525 -99
- package/dist/vendor/config/site-global.js +63 -53
- package/dist/vendor/config/targets.js +187 -0
- package/dist/vendor/config/validate.js +119 -59
- package/dist/vendor/devkit/argv.js +118 -0
- package/dist/vendor/devkit/attach-log-file.js +21 -13
- package/dist/vendor/devkit/brand-tokens.js +278 -0
- package/dist/vendor/devkit/brand-version.js +264 -0
- package/dist/vendor/devkit/build-json.js +91 -0
- package/dist/vendor/devkit/bundle.js +48 -0
- package/dist/vendor/devkit/certificate-expiry.js +108 -0
- package/dist/vendor/devkit/certs.js +16 -194
- package/dist/vendor/devkit/ci-workflows.js +124 -8
- package/dist/vendor/devkit/cli-router.js +3 -3
- package/dist/vendor/devkit/defaults-engine.js +69 -7
- package/dist/vendor/devkit/deploy-follow.js +297 -0
- package/dist/vendor/devkit/deploy-precheck.js +23 -8
- package/dist/vendor/devkit/deploy-record.js +11 -27
- package/dist/vendor/devkit/deploy-snapshot.js +661 -0
- package/dist/vendor/devkit/deploy.js +445 -75
- package/dist/vendor/devkit/git-auth.js +73 -0
- package/dist/vendor/devkit/git-remote.js +95 -0
- package/dist/vendor/devkit/github-repo.js +290 -0
- package/dist/vendor/devkit/local.js +47 -0
- package/dist/vendor/devkit/merge-line-files.js +23 -16
- package/dist/vendor/devkit/omega-bin.js +18 -3
- package/dist/vendor/devkit/pack-local.js +391 -0
- package/dist/vendor/devkit/preludes/index.js +120 -0
- package/dist/vendor/devkit/preludes/origin-heal.js +156 -0
- package/dist/vendor/devkit/service-account.js +43 -0
- package/dist/vendor/devkit/ship-plan.js +112 -0
- package/dist/vendor/devkit/signing-env.js +180 -0
- package/dist/vendor/devkit/signing-tree.js +92 -0
- package/dist/vendor/devkit/target-seams.js +142 -0
- package/dist/vendor/devkit/target-secrets.js +235 -50
- package/dist/vendor/devkit/test/esm-only-fixture.js +48 -0
- package/dist/vendor/devkit/test/fixtures/esm-only-package/browser.js +19 -0
- package/dist/vendor/devkit/test/fixtures/esm-only-package/index.js +20 -0
- package/dist/vendor/devkit/test/fixtures/esm-only-package/package.json +13 -0
- package/dist/vendor/monitoring/env.js +20 -10
- 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 +1 -1
- package/docs/auto-updater.md +5 -5
- package/docs/boot-sequence.md +1 -1
- package/docs/build-system.md +15 -7
- package/docs/client-bridge.md +9 -7
- package/docs/config-schema.md +4 -4
- package/docs/css.md +8 -2
- package/docs/deep-link.md +12 -4
- package/docs/environment-detection.md +32 -24
- package/docs/hooks.md +3 -1
- package/docs/icons.md +7 -7
- package/docs/index.md +61 -23
- package/docs/installer-options.md +24 -21
- package/docs/logging.md +5 -5
- package/docs/releasing.md +25 -17
- package/docs/runner.md +40 -5
- package/docs/shared/brands.md +12 -6
- package/docs/shared/breaking-changes.md +375 -21
- package/docs/shared/config.md +757 -199
- package/docs/shared/deploys.md +194 -91
- package/docs/shared/icons.md +18 -0
- package/docs/shared/local-dev.md +24 -6
- package/docs/shared/logging.md +9 -6
- package/docs/shared/monitoring.md +27 -13
- package/docs/shared/publishing.md +3 -3
- package/docs/shared/rulings.md +2 -2
- package/docs/shared/testing.md +1 -1
- package/docs/shared/theming.md +26 -1
- package/docs/shared/translation.md +49 -7
- package/docs/shared/updates.md +1 -1
- package/docs/signing.md +59 -33
- package/docs/test-framework.md +10 -5
- package/docs/themes.md +15 -1
- package/package.json +18 -12
- package/bin/omega-desktop +0 -2
- package/dist/commands/push-secrets.js +0 -141
- package/dist/test/suites/build/deliver-certs.test.js +0 -95
- package/dist/test/suites/build/derive-signing-env.test.js +0 -122
- package/dist/test/suites/build/push-secrets.test.js +0 -226
- package/dist/test/suites/build/resolve-signing-cert.test.js +0 -342
- package/dist/utils/deliver-certs.js +0 -69
- package/dist/utils/derive-signing-env.js +0 -56
- package/dist/utils/resolve-signing-cert.js +0 -175
- package/dist/vendor/config/desktop-artifacts.js +0 -110
- package/dist/vendor/config/instances.js +0 -208
- /package/dist/defaults/config/icons/{macos → mac}/dmg.png +0 -0
- /package/dist/defaults/config/icons/{macos → mac}/icon.png +0 -0
- /package/dist/defaults/config/icons/{macos → mac}/tray.png +0 -0
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Same walk as the config cascade (load.js owns it): a target inside a brand
|
|
7
7
|
* monorepo ({brand}/targets/{target}) layers the brand root's .env under its own,
|
|
8
|
-
* and a brand
|
|
9
|
-
*
|
|
8
|
+
* and a brand naming a company (`company: { id }`) layers that company's own
|
|
9
|
+
* `company/.env` underneath that (#677). Loading uses dotenv's no-override semantics: keys
|
|
10
10
|
* already in process.env (the shell) always win, and files apply
|
|
11
11
|
* innermost-first, so local beats brand beats company.
|
|
12
12
|
*
|
|
@@ -30,32 +30,40 @@ const fs = require('node:fs');
|
|
|
30
30
|
const path = require('node:path');
|
|
31
31
|
|
|
32
32
|
const { findBrandRoot } = require('./load.js');
|
|
33
|
-
const {
|
|
34
|
-
const { ENV_SCHEMA, envFileGroups } = require('./env-schema.js');
|
|
35
|
-
|
|
36
|
-
// The
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
// ([#586](https://github.com/Omega-JS-Stack/omega/issues/586)).
|
|
40
|
-
const ENV_ENVIRONMENTS = ['development', 'testing', 'production'];
|
|
33
|
+
const { resolveCompany } = require('./company.js');
|
|
34
|
+
const { ENV_SCHEMA, envFileGroups, envSchemaEntry } = require('./env-schema.js');
|
|
35
|
+
const { assertNoRetiredEnvKeys } = require('./env-retired.js');
|
|
36
|
+
// The one vocabulary lives with the one environment module (#817); this file
|
|
37
|
+
// re-exports it so the .env overlay names and the runtime answer stay one list.
|
|
38
|
+
const { ENV_ENVIRONMENTS } = require('./environment.js');
|
|
41
39
|
|
|
42
40
|
/**
|
|
43
|
-
* The
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
41
|
+
* The AMBIENT environment answer: what a lane resolves when nothing named one
|
|
42
|
+
* for it. It is the PRODUCER of the one input, never a second reader of it:
|
|
43
|
+
* `environment.js` owns the runtime answer (one input, `OMEGA_ENVIRONMENT`, no
|
|
44
|
+
* guessing), and this is the sniff a lane runs ONCE to decide what to set
|
|
45
|
+
* ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)). It is also the
|
|
46
|
+
* default for the two overlay selections below (`.env.<environment>` and
|
|
47
|
+
* `config/omega.<environment>.json5`), so a compose that was told nothing
|
|
48
|
+
* follows the same answer the runtime will give.
|
|
49
|
+
*
|
|
50
|
+
* An already-set `OMEGA_ENVIRONMENT` wins outright, so the producer and the
|
|
51
|
+
* reader can never disagree inside one process. Otherwise: testing wins, then
|
|
52
|
+
* production, else development.
|
|
48
53
|
*
|
|
49
54
|
* The final `else` is PRODUCTION on purpose: a deployed Cloud Function has no
|
|
50
55
|
* FUNCTIONS_EMULATOR and often no ENVIRONMENT var, so "no signal" IS the normal
|
|
51
56
|
* production state. Defaulting to development would make every deployed
|
|
52
|
-
* function skip real side effects (emails/analytics/webhooks).
|
|
53
|
-
* UJM/BXM, whose deployed artifacts always carry their signal.)
|
|
57
|
+
* function skip real side effects (emails/analytics/webhooks).
|
|
54
58
|
*
|
|
55
59
|
* @returns {'testing'|'production'|'development'} The environment.
|
|
56
60
|
*/
|
|
57
61
|
function envEnvironment() {
|
|
58
|
-
//
|
|
62
|
+
// The one input, when a lane already named it (#817).
|
|
63
|
+
if (ENV_ENVIRONMENTS.includes(process.env.OMEGA_ENVIRONMENT)) {
|
|
64
|
+
return process.env.OMEGA_ENVIRONMENT;
|
|
65
|
+
}
|
|
66
|
+
// Testing takes precedence, set by the test runner / emulator (OMEGA_TEST_MODE=true).
|
|
59
67
|
if (process.env.OMEGA_TEST_MODE === 'true') {
|
|
60
68
|
return 'testing';
|
|
61
69
|
}
|
|
@@ -104,14 +112,17 @@ function envLayerFiles(envPath, environment) {
|
|
|
104
112
|
function resolveEnvChain(startDir) {
|
|
105
113
|
const targetDir = path.resolve(startDir);
|
|
106
114
|
const brandRoot = findBrandRoot(targetDir);
|
|
107
|
-
// The
|
|
108
|
-
// targets/ walk above it), its own
|
|
109
|
-
|
|
115
|
+
// The company is named by the BRAND's config; when startDir IS a brand root
|
|
116
|
+
// (no targets/ walk above it), its own config names it. The layer is the
|
|
117
|
+
// company TREE's `.env`, named whether or not it exists: this resolves paths,
|
|
118
|
+
// and an `.env.<environment>` overlay (#586) derives from the base name, so a
|
|
119
|
+
// company that ships only an overlay still layers.
|
|
120
|
+
const company = resolveCompany(brandRoot || targetDir);
|
|
110
121
|
|
|
111
122
|
return {
|
|
112
123
|
local: path.join(targetDir, '.env'),
|
|
113
124
|
brand: brandRoot ? path.join(brandRoot, '.env') : null,
|
|
114
|
-
company:
|
|
125
|
+
company: company.dir ? path.join(company.dir, '.env') : null,
|
|
115
126
|
};
|
|
116
127
|
}
|
|
117
128
|
|
|
@@ -163,7 +174,7 @@ function loadEnvChain(envPaths) {
|
|
|
163
174
|
for (const envPath of envPaths) {
|
|
164
175
|
if (!envPath || !fs.existsSync(envPath)) continue;
|
|
165
176
|
|
|
166
|
-
const parsed =
|
|
177
|
+
const parsed = parseEnvFile(envPath);
|
|
167
178
|
for (const [key, value] of Object.entries(parsed)) {
|
|
168
179
|
if (value === '' || key in process.env) continue;
|
|
169
180
|
process.env[key] = value;
|
|
@@ -311,13 +322,22 @@ function reloadEnv(startDir, { target, environment = envEnvironment() } = {}) {
|
|
|
311
322
|
/**
|
|
312
323
|
* Parse one .env file into a plain map. Missing files read as empty.
|
|
313
324
|
*
|
|
325
|
+
* The ONE place a `.env` layer is read, so it is also where a RETIRED key is
|
|
326
|
+
* refused ([#893](https://github.com/Omega-JS-Stack/omega/issues/893)): there
|
|
327
|
+
* is no dual-read, so a line for a key that moved into config is a value
|
|
328
|
+
* nothing consults, and both readers below (the process cascade and the
|
|
329
|
+
* artifact composer) fail on it naming the move.
|
|
330
|
+
*
|
|
314
331
|
* @param {string|null} envPath
|
|
315
332
|
* @returns {Object<string, string>} Parsed key → value.
|
|
316
333
|
*/
|
|
317
334
|
function parseEnvFile(envPath) {
|
|
318
335
|
if (!envPath || !fs.existsSync(envPath)) return {};
|
|
319
336
|
|
|
320
|
-
|
|
337
|
+
const parsed = require('dotenv').parse(fs.readFileSync(envPath, 'utf8'));
|
|
338
|
+
assertNoRetiredEnvKeys(parsed, envPath);
|
|
339
|
+
|
|
340
|
+
return parsed;
|
|
321
341
|
}
|
|
322
342
|
|
|
323
343
|
/**
|
|
@@ -358,7 +378,11 @@ function deliveringEntry(key, target) {
|
|
|
358
378
|
* there is): a key rides down when some entry claims it — by name or by
|
|
359
379
|
* pattern — names this target, and sits in a file group. The TARGET layer
|
|
360
380
|
* passes through unfiltered: placing a key in the target's own .env IS the
|
|
361
|
-
* targeting.
|
|
381
|
+
* targeting. A key NO entry claims at all is the consumer's own
|
|
382
|
+
* ([#835](https://github.com/Omega-JS-Stack/omega/issues/835)) and rides down
|
|
383
|
+
* to every target: the schema never heard of it, so it names no target to be
|
|
384
|
+
* filtered by, and a consumer who wants one on a single target has that
|
|
385
|
+
* target's own .env. `deliverAs` renames on arrival in EVERY layer (the per-target GA4
|
|
362
386
|
* secrets), so a human writing the brand-level name in the target's own .env
|
|
363
387
|
* gets the one delivered key, overriding the brand's.
|
|
364
388
|
*
|
|
@@ -398,7 +422,12 @@ function composeTargetEnv({ targetDir, target, environment = envEnvironment() })
|
|
|
398
422
|
for (const { file, layer, filtered } of files) {
|
|
399
423
|
const claimed = {};
|
|
400
424
|
for (const [key, value] of Object.entries(parseEnvFile(file))) {
|
|
401
|
-
|
|
425
|
+
// The filter is on DECLARED keys: an entry that does not name this
|
|
426
|
+
// target keeps its key home. A key the schema knows nothing about is the
|
|
427
|
+
// CONSUMER's own (#835), has no target of its own to be judged by, and
|
|
428
|
+
// rides down to every target; a consumer who wants one on a single
|
|
429
|
+
// target puts it in that target's .env, which passes unfiltered anyway.
|
|
430
|
+
if (filtered && envSchemaEntry(key) && !deliveringEntry(key, target)) continue;
|
|
402
431
|
claimed[key] = value;
|
|
403
432
|
}
|
|
404
433
|
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* environment.js, the ONE environment module every OMEGA target answers from
|
|
3
|
+
* ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)).
|
|
4
|
+
*
|
|
5
|
+
* Four calls, one implementation, one call form everywhere: `getEnvironment()`
|
|
6
|
+
* plus `isDevelopment()` / `isProduction()` / `isTesting()`, mixed into a
|
|
7
|
+
* framework's Manager with `attachTo()`. @omega.js/backend, @omega.js/desktop,
|
|
8
|
+
* @omega.js/extension and @omega.js/web each carried their own copy of this
|
|
9
|
+
* logic, each with its own signal list and its own DEFAULT, and the copies
|
|
10
|
+
* disagreed: desktop answered `production` with no signal while the extension
|
|
11
|
+
* answered `development`, so a desktop dev boot baked itself as a production
|
|
12
|
+
* artifact.
|
|
13
|
+
*
|
|
14
|
+
* The fix is by construction, and it is the whole contract:
|
|
15
|
+
*
|
|
16
|
+
* ONE INPUT. On Node it is `process.env.OMEGA_ENVIRONMENT`. In a browser
|
|
17
|
+
* context (a desktop renderer, an extension view, a web page), which can read
|
|
18
|
+
* neither env nor files, it is `config.environment`, the build fact every
|
|
19
|
+
* surface already bakes into `OMEGA_BUILD_JSON.config`
|
|
20
|
+
* ([#896](https://github.com/Omega-JS-Stack/omega/issues/896)), reached as
|
|
21
|
+
* `this.config.environment` off the Manager the call is made on. Nothing else
|
|
22
|
+
* is consulted: no `app.isPackaged`, no `manifest.update_url`, no `NODE_ENV`,
|
|
23
|
+
* no terminal sniffing.
|
|
24
|
+
*
|
|
25
|
+
* NO DEFAULT. A context with no input does not guess a safe answer, it throws
|
|
26
|
+
* and names the variable. A guessed environment is how a dev build ships as
|
|
27
|
+
* production and how a production build talks to an emulator, and both of
|
|
28
|
+
* those failures are silent until a user finds them.
|
|
29
|
+
*
|
|
30
|
+
* Who SETS the one input is each target's own business, at the one place it
|
|
31
|
+
* already resolves its config, through `setEnvironment()` below (the only
|
|
32
|
+
* writer, so a fourth word can never reach the variable): the backend's boot
|
|
33
|
+
* takes the .env cascade's ambient answer, the desktop and extension build
|
|
34
|
+
* Managers take `production` under their build-mode flag and the ambient answer
|
|
35
|
+
* otherwise, and web's verbs name their own (`omega build` is production,
|
|
36
|
+
* `omega dev` is development).
|
|
37
|
+
*
|
|
38
|
+
* This module requires NOTHING. It is bundled into browser artifacts (the
|
|
39
|
+
* desktop renderer, every extension bundle) and vendored into
|
|
40
|
+
* @omega.js/client, so a single `node:fs` at the top would break all three.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
// The ONE environment vocabulary, and the home of it. Every `.env.<name>`
|
|
44
|
+
// overlay is suffixed with one of these, every `config/omega.<name>.json5`
|
|
45
|
+
// overlay is named with one of these, every framework's environment answer is
|
|
46
|
+
// one of these, and nothing anywhere spells a fourth
|
|
47
|
+
// ([#586](https://github.com/Omega-JS-Stack/omega/issues/586)).
|
|
48
|
+
const ENV_ENVIRONMENTS = ['development', 'testing', 'production'];
|
|
49
|
+
|
|
50
|
+
// The ONE input's name, spelled once so every error message and every writer
|
|
51
|
+
// reads it from here.
|
|
52
|
+
const ENVIRONMENT_VAR = 'OMEGA_ENVIRONMENT';
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The Node input: the environment variable, when this context has a `process`
|
|
56
|
+
* at all (a browser bundle does not).
|
|
57
|
+
* @returns {string|undefined} the raw value.
|
|
58
|
+
*/
|
|
59
|
+
function fromProcess() {
|
|
60
|
+
return typeof process !== 'undefined' && process.env
|
|
61
|
+
? process.env[ENVIRONMENT_VAR]
|
|
62
|
+
: undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The browser input: the build fact baked into `OMEGA_BUILD_JSON.config`,
|
|
67
|
+
* reached through the Manager the call was made on.
|
|
68
|
+
* @param {object} [context] - the `this` of the call.
|
|
69
|
+
* @returns {string|undefined} the raw value.
|
|
70
|
+
*/
|
|
71
|
+
function fromBakedConfig(context) {
|
|
72
|
+
return context && context.config ? context.config.environment : undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The running environment, from the one input.
|
|
77
|
+
*
|
|
78
|
+
* @this {object} [context] - a Manager carrying the baked `config`.
|
|
79
|
+
* @returns {'development'|'testing'|'production'} exactly one of the three.
|
|
80
|
+
* @throws {Error} when neither input names one of the three.
|
|
81
|
+
*/
|
|
82
|
+
function getEnvironment() {
|
|
83
|
+
const value = fromProcess() || fromBakedConfig(this);
|
|
84
|
+
|
|
85
|
+
if (!ENV_ENVIRONMENTS.includes(value)) {
|
|
86
|
+
// Loud by design: every lane sets the input, so reaching here is a broken
|
|
87
|
+
// lane, and any answer invented here would be wrong somewhere it matters.
|
|
88
|
+
throw new Error(`${ENVIRONMENT_VAR} is not set to one of ${ENV_ENVIRONMENTS.join(' | ')} (got ${value === undefined ? 'nothing' : JSON.stringify(value)}). On Node the lane that boots or builds this target sets it; in a browser context it is the baked OMEGA_BUILD_JSON.config.environment, which every OMEGA build writes.`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @this {object} [context] - a Manager carrying the baked `config`.
|
|
96
|
+
* @returns {boolean} true only in development (never in testing).
|
|
97
|
+
*/
|
|
98
|
+
function isDevelopment() {
|
|
99
|
+
return getEnvironment.call(this) === 'development';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @this {object} [context] - a Manager carrying the baked `config`.
|
|
104
|
+
* @returns {boolean} true only in production, a real positive check.
|
|
105
|
+
*/
|
|
106
|
+
function isProduction() {
|
|
107
|
+
return getEnvironment.call(this) === 'production';
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @this {object} [context] - a Manager carrying the baked `config`.
|
|
112
|
+
* @returns {boolean} true only while a test lane runs this process.
|
|
113
|
+
*/
|
|
114
|
+
function isTesting() {
|
|
115
|
+
return getEnvironment.call(this) === 'testing';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* The ONE writer of the one input, so every lane that names an environment
|
|
120
|
+
* spells it the same way and a fourth word is refused at the moment it is
|
|
121
|
+
* written rather than at the moment it is read.
|
|
122
|
+
*
|
|
123
|
+
* @param {string} value - one of the three names.
|
|
124
|
+
* @returns {string} the same value, so a caller can name it and pass it on.
|
|
125
|
+
* @throws {Error} when it is not one of the three.
|
|
126
|
+
*/
|
|
127
|
+
function setEnvironment(value) {
|
|
128
|
+
if (!ENV_ENVIRONMENTS.includes(value)) {
|
|
129
|
+
throw new Error(`${ENVIRONMENT_VAR} cannot be set to ${value === undefined ? 'nothing' : JSON.stringify(value)}: it is one of ${ENV_ENVIRONMENTS.join(' | ')}.`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
process.env[ENVIRONMENT_VAR] = value;
|
|
133
|
+
|
|
134
|
+
return value;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* The environment a NODE BUILD LANE is for, decided once for the two frameworks
|
|
139
|
+
* whose build Manager names it at load (@omega.js/desktop and
|
|
140
|
+
* @omega.js/extension, which carried byte-identical copies of this expression).
|
|
141
|
+
* Two rules, no sniffing:
|
|
142
|
+
*
|
|
143
|
+
* 1. The build-mode flag is the lane SAYING it produces a production artifact
|
|
144
|
+
* (`omega build` sets `OMEGA_BUILD_MODE`), and it wins over anything
|
|
145
|
+
* inherited, so a production build spawned from a test run still bakes
|
|
146
|
+
* production.
|
|
147
|
+
* 2. Otherwise a lane that already named one keeps it (the test runners spawn
|
|
148
|
+
* their children with `testing`), and a bare dev boot is `development`.
|
|
149
|
+
*
|
|
150
|
+
* It DECIDES; the caller writes it with `setEnvironment()`, which stays the one
|
|
151
|
+
* writer. This is the only default anywhere near this module, and it belongs to
|
|
152
|
+
* a build lane alone: a READER still gets no default at all.
|
|
153
|
+
*
|
|
154
|
+
* @param {boolean} buildMode - The lane's build-mode flag (`Manager.isBuildMode()`).
|
|
155
|
+
* @returns {'development'|'testing'|'production'} the word that lane is for.
|
|
156
|
+
*/
|
|
157
|
+
function buildLaneEnvironment(buildMode) {
|
|
158
|
+
return buildMode ? 'production' : (fromProcess() || 'development');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Mix the surface into a Manager constructor's prototype AND the constructor
|
|
163
|
+
* itself, so `Manager.isTesting()` works statically too. The idiom every
|
|
164
|
+
* framework already attaches with.
|
|
165
|
+
*
|
|
166
|
+
* @param {Function} Manager - the constructor to extend.
|
|
167
|
+
*/
|
|
168
|
+
function attachTo(Manager) {
|
|
169
|
+
Manager.prototype.getEnvironment = getEnvironment;
|
|
170
|
+
Manager.prototype.isDevelopment = isDevelopment;
|
|
171
|
+
Manager.prototype.isProduction = isProduction;
|
|
172
|
+
Manager.prototype.isTesting = isTesting;
|
|
173
|
+
Manager.getEnvironment = getEnvironment;
|
|
174
|
+
Manager.isDevelopment = isDevelopment;
|
|
175
|
+
Manager.isProduction = isProduction;
|
|
176
|
+
Manager.isTesting = isTesting;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
module.exports = {
|
|
180
|
+
ENV_ENVIRONMENTS,
|
|
181
|
+
ENVIRONMENT_VAR,
|
|
182
|
+
getEnvironment,
|
|
183
|
+
isDevelopment,
|
|
184
|
+
isProduction,
|
|
185
|
+
isTesting,
|
|
186
|
+
setEnvironment,
|
|
187
|
+
buildLaneEnvironment,
|
|
188
|
+
attachTo,
|
|
189
|
+
};
|
|
@@ -19,9 +19,11 @@
|
|
|
19
19
|
* add their own `config/hooks/` ignore line.
|
|
20
20
|
*
|
|
21
21
|
* Resolution walks the same hierarchy as the .env cascade: the brand root's
|
|
22
|
-
* own `config/hooks/` first, then the company
|
|
23
|
-
*
|
|
24
|
-
* a single brand can still override it.
|
|
22
|
+
* own `config/hooks/` first, then the company tree's (the parent brand's
|
|
23
|
+
* `company/config/hooks/`, resolved through company.js), so a company-wide hook
|
|
24
|
+
* covers every brand and a single brand can still override it. It is the ONE
|
|
25
|
+
* inheritance rule (#677) applied to one more relative path, and costs no code
|
|
26
|
+
* of its own. Hooks are plain CJS modules whose
|
|
25
27
|
* `module.exports` IS the hook function; call-site docs define each hook's
|
|
26
28
|
* signature and return contract.
|
|
27
29
|
*/
|
|
@@ -29,7 +31,7 @@
|
|
|
29
31
|
const fs = require('node:fs');
|
|
30
32
|
const path = require('node:path');
|
|
31
33
|
|
|
32
|
-
const {
|
|
34
|
+
const { resolveCompany } = require('./company.js');
|
|
33
35
|
|
|
34
36
|
// Hook points are code-owned kebab-case path constants ('account/password') —
|
|
35
37
|
// enforce the shape so a typo'd or traversal-shaped path fails loudly.
|
|
@@ -44,7 +46,7 @@ function hookFile(root, hookPath) {
|
|
|
44
46
|
|
|
45
47
|
/**
|
|
46
48
|
* Resolve a hook point to the file that defines it: the brand root's own
|
|
47
|
-
* `config/hooks/<hookPath>.js`, else the company
|
|
49
|
+
* `config/hooks/<hookPath>.js`, else the company tree's.
|
|
48
50
|
*
|
|
49
51
|
* @param {string} startRoot - Brand (or standalone-project) root
|
|
50
52
|
* @param {string} hookPath - Call-site-mirroring hook point, e.g. 'account/password'
|
|
@@ -55,13 +57,13 @@ function resolveHook(startRoot, hookPath) {
|
|
|
55
57
|
throw new Error(`Invalid hook path ${JSON.stringify(hookPath)} — kebab-case segments joined by '/', e.g. 'account/password'`);
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
if (
|
|
61
|
-
roots.push(companyRoot);
|
|
62
|
-
}
|
|
60
|
+
const brandRoot = path.resolve(startRoot);
|
|
61
|
+
const own = hookFile(brandRoot, hookPath);
|
|
62
|
+
if (fs.existsSync(own)) return own;
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
// One relative path, one rule: whatever the child lacks resolves from the
|
|
65
|
+
// company tree at the same place.
|
|
66
|
+
return resolveCompany(brandRoot).file(path.relative(brandRoot, own));
|
|
65
67
|
}
|
|
66
68
|
|
|
67
69
|
/**
|