@omega.js/desktop 0.50.0 → 0.52.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 +2 -2
- 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 +176 -42
- 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 +146 -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 +635 -5
- 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 +125 -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 +249 -103
- 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 +425 -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 +505 -75
- package/dist/vendor/devkit/git-auth.js +73 -0
- package/dist/vendor/devkit/git-remote.js +172 -0
- package/dist/vendor/devkit/github-repo.js +290 -0
- package/dist/vendor/devkit/local.js +98 -3
- package/dist/vendor/devkit/lockfile.js +127 -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 +388 -0
- package/dist/vendor/devkit/preludes/index.js +120 -0
- package/dist/vendor/devkit/preludes/origin-heal.js +142 -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 +231 -57
- 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 +29 -19
- package/docs/runner.md +51 -14
- package/docs/shared/brands.md +12 -6
- package/docs/shared/breaking-changes.md +375 -21
- package/docs/shared/config.md +764 -199
- package/docs/shared/deploys.md +217 -91
- package/docs/shared/icons.md +18 -0
- package/docs/shared/local-dev.md +28 -8
- 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 +60 -34
- 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
|
@@ -9,10 +9,15 @@
|
|
|
9
9
|
* the ONE copy; each framework binds it with its own target string and nothing
|
|
10
10
|
* else.
|
|
11
11
|
*
|
|
12
|
-
* 1. DERIVE
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* 1. DERIVE: the KEY SET is @omega.js/config'sONE delivery primitive, read
|
|
13
|
+
* off the schema AND the composed values (`publishSecretKeys(target,
|
|
14
|
+
* { values })`): every entry whose `delivery` names the target, plus the
|
|
15
|
+
* `match` family members this brand actually configured
|
|
16
|
+
* ([#876](https://github.com/Omega-JS-Stack/omega/issues/876)) and the
|
|
17
|
+
* keys the schema does not know at all, a consumer's own
|
|
18
|
+
* ([#835](https://github.com/Omega-JS-Stack/omega/issues/835)). Still not
|
|
19
|
+
* "whatever the composed .env holds": a declared key this target does not
|
|
20
|
+
* deliver, and every `machineLocal` one, stay home.
|
|
16
21
|
* 2. COLLECT — the VALUES come from the target's COMPOSED env
|
|
17
22
|
* (`composeTargetEnv`, [#678](https://github.com/Omega-JS-Stack/omega/issues/678)):
|
|
18
23
|
* company ← brand ← target `.env`, the brand-side layers schema-filtered
|
|
@@ -23,10 +28,13 @@
|
|
|
23
28
|
* schema drops them from the delivered set itself.
|
|
24
29
|
* 3. GUARD — secrets belong to the repo whose Actions run the workflow, and
|
|
25
30
|
* the only acceptable proof of which repo that is, is the brand's own
|
|
26
|
-
* config (`repo.
|
|
31
|
+
* config (`repo.org`, the SOURCE repo). An inferred git remote is not proof: a
|
|
27
32
|
* target vendored into a framework/test monorepo, a cloned starter still
|
|
28
33
|
* pointing at the template author, or any fork would publish this brand's
|
|
29
|
-
* `.env` to a stranger's Actions.
|
|
34
|
+
* `.env` to a stranger's Actions. A checkout that could be the brand's own
|
|
35
|
+
* and whose origin names another repo REFUSES on `repoDrift`'s one line
|
|
36
|
+
* ([#934](https://github.com/Omega-JS-Stack/omega/issues/934)), the
|
|
37
|
+
* same refusal the deploy lane and the manage walk make.
|
|
30
38
|
* 4. PUBLISH — each collected key becomes a repo Actions secret via devkit's
|
|
31
39
|
* `gh` boundary (values on stdin, never logged).
|
|
32
40
|
*
|
|
@@ -34,20 +42,81 @@
|
|
|
34
42
|
* a skip — it throws the boundary's instructions (install, `gh auth login`, or
|
|
35
43
|
* `omega deploy --no-secrets`).
|
|
36
44
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
45
|
+
* A key the SCHEMA says this target's config requires (`required` /
|
|
46
|
+
* `requiredWhen`, @omega.js/config's env-rules) and the cascade resolves EMPTY
|
|
47
|
+
* stops the publish outright ([#891](https://github.com/Omega-JS-Stack/omega/issues/891)):
|
|
48
|
+
* the run that reads those secrets is the one that signs a release, and half a
|
|
49
|
+
* signing set on a runner is a green build nobody can install. Nothing is
|
|
50
|
+
* pushed on that path, so the fix and the re-run are one step, not a partial
|
|
51
|
+
* state to reason about. A key that is merely absent and NOT required gets one
|
|
52
|
+
* line naming it.
|
|
53
|
+
*
|
|
54
|
+
* There is no per-framework BIND any more
|
|
55
|
+
* ([#891](https://github.com/Omega-JS-Stack/omega/issues/891)): the four files
|
|
56
|
+
* that passed a target string and a seam were four places to forget a rule, and
|
|
57
|
+
* the standalone `omega push-secrets` verb they backed is gone with them. The
|
|
58
|
+
* seams live HERE, in one table keyed by target type, and every caller (each
|
|
59
|
+
* framework's deploy precheck, the manager's repo walk) makes the same call.
|
|
60
|
+
*
|
|
61
|
+
* desktop `resolveValue` base64-encodes a secret that names a FILE
|
|
62
|
+
* (#682: `CSC_LINK` points at a `.p12` and CI needs the bytes), and
|
|
63
|
+
* `deriveValues` fills the signing paths from the signing tree, by
|
|
64
|
+
* the ONE derivation the desktop env load runs
|
|
65
|
+
* (`@omega.js/devkit/signing-env`), so no operator pastes a path.
|
|
66
|
+
* backend `extraSecrets`: the deploy credential is a service-account FILE
|
|
67
|
+
* the cloud manage service mints (#872), so there is nothing in the
|
|
68
|
+
* cascade to compose it from and it arrives already valued.
|
|
69
|
+
* web, extension plain strings, no seam.
|
|
70
|
+
*
|
|
71
|
+
* `dryRun` ([#895](https://github.com/Omega-JS-Stack/omega/issues/895)) prints
|
|
72
|
+
* the key NAMES that would publish, the derived lines and any refusal, and
|
|
73
|
+
* sends nothing. The refusal still THROWS in a dry run: a plan that cannot be
|
|
74
|
+
* made is loud.
|
|
42
75
|
*/
|
|
43
|
-
const { composeTargetEnv } = require('../config/index.js');
|
|
76
|
+
const { composeTargetEnv, loadConfig, sourceRepo } = require('../config/index.js');
|
|
44
77
|
const { publishSecretKeys } = require('../config/env-delivery.js');
|
|
78
|
+
const { checkEnvRules } = require('../config/env-rules.js');
|
|
45
79
|
const { publishActionsSecrets } = require('./actions-secrets.js');
|
|
46
|
-
const {
|
|
80
|
+
const { assertOriginMatches } = require('./git-remote.js');
|
|
81
|
+
const { findBrandRoot } = require('./local.js');
|
|
82
|
+
const { targetSeams } = require('./target-seams.js');
|
|
47
83
|
|
|
48
84
|
/**
|
|
49
|
-
* The
|
|
50
|
-
*
|
|
85
|
+
* The target's COMPOSED env, with the bind's own derivations applied to it.
|
|
86
|
+
*
|
|
87
|
+
* PRODUCTION, named rather than sniffed: these values fuel the runner's release
|
|
88
|
+
* build, and the composer would otherwise default to whatever environment this
|
|
89
|
+
* shell happens to be
|
|
90
|
+
* ([#586](https://github.com/Omega-JS-Stack/omega/issues/586)): the same
|
|
91
|
+
* determinism the "FILES only, never the shell" rule above buys.
|
|
92
|
+
*
|
|
93
|
+
* Everything that reads the cascade reads it through HERE (the required-key
|
|
94
|
+
* check and the collection both), so a derived value is as real as a typed one
|
|
95
|
+
* to each of them ([#891](https://github.com/Omega-JS-Stack/omega/issues/891)).
|
|
96
|
+
*
|
|
97
|
+
* @param {object} options
|
|
98
|
+
* @param {string} options.targetDir - The target root.
|
|
99
|
+
* @param {string} options.target - Target name.
|
|
100
|
+
* @param {function} [options.deriveValues] - The derive seam (see collectTargetSecrets).
|
|
101
|
+
* @param {object} [options.logger] - `{ log, warn, error }`; each derivation prints one line.
|
|
102
|
+
* @returns {{ values: object, fixes: Object<string, string> }}
|
|
103
|
+
*/
|
|
104
|
+
function composeValues({ targetDir, target, deriveValues, logger }) {
|
|
105
|
+
const { values } = composeTargetEnv({ targetDir, target, environment: 'production' });
|
|
106
|
+
|
|
107
|
+
const { derived = [], fixes = {} } = (deriveValues ? deriveValues(values) : null) || {};
|
|
108
|
+
for (const { key, value } of derived) {
|
|
109
|
+
if (logger) logger.log(`${key} derived from ${value}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return { values, fixes };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The publishable secrets for a target: the delivery set the ONE primitive
|
|
117
|
+
* answers for it (schema names, family members, the consumer's own keys),
|
|
118
|
+
* valued from the same composed env the set is read off. An empty value never
|
|
119
|
+
* claims a key.
|
|
51
120
|
*
|
|
52
121
|
* @param {object} options
|
|
53
122
|
* @param {string} options.targetDir - The target root (its .env is the local layer).
|
|
@@ -56,20 +125,32 @@ const { resolveRepo } = require('./deploy.js');
|
|
|
56
125
|
* applied to each collected value before it travels (desktop base64-encodes
|
|
57
126
|
* its file-path signing secrets). A falsy return DROPS the key, exactly as an
|
|
58
127
|
* empty composed value does.
|
|
128
|
+
* @param {function} [options.deriveValues] - `(values) => { derived, fixes }`, the
|
|
129
|
+
* seam applied to the COMPOSED map before anything reads it: a bind may VALUE
|
|
130
|
+
* a key the cascade left empty (desktop derives its signing paths from the
|
|
131
|
+
* dispersed artifacts) and may name, per key it could NOT value, the fix line
|
|
132
|
+
* the refusal should carry. `derived` is `[{ key, value }]` (already written
|
|
133
|
+
* into the map); `fixes` is `key → sentence`.
|
|
59
134
|
* @returns {Object<string, string>} key → value, ready to publish.
|
|
60
135
|
*/
|
|
61
136
|
function collectTargetSecrets(options) {
|
|
62
|
-
const { targetDir, target,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// determinism the "FILES only, never the shell" rule above buys.
|
|
68
|
-
const { values } = composeTargetEnv({ targetDir, target, environment: 'production' });
|
|
137
|
+
const { targetDir, target, logger } = options;
|
|
138
|
+
const seams = targetSeams({ target, targetDir });
|
|
139
|
+
const resolveValue = 'resolveValue' in options ? options.resolveValue : seams.resolveValue;
|
|
140
|
+
const deriveValues = 'deriveValues' in options ? options.deriveValues : seams.deriveValues;
|
|
141
|
+
const { values } = composeValues({ targetDir, target, deriveValues, logger });
|
|
69
142
|
|
|
70
143
|
const secrets = {};
|
|
71
|
-
|
|
72
|
-
|
|
144
|
+
// The key set and the values come from ONE composition (#835, #876): a
|
|
145
|
+
// family member or a consumer's own key exists only in the composed map, so
|
|
146
|
+
// the set has to be read off the same map it is valued from.
|
|
147
|
+
for (const key of publishSecretKeys(target, { values })) {
|
|
148
|
+
if (!values[key]) {
|
|
149
|
+
// Never silence: a key with no value in the cascade is a key CI will not
|
|
150
|
+
// have. Whether that MATTERS is the schema's answer, below.
|
|
151
|
+
if (logger) logger.log(`No value for ${key} in the .env cascade: not published`);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
73
154
|
const value = resolveValue ? resolveValue(values[key], key) : values[key];
|
|
74
155
|
if (value) secrets[key] = value;
|
|
75
156
|
}
|
|
@@ -78,25 +159,63 @@ function collectTargetSecrets(options) {
|
|
|
78
159
|
}
|
|
79
160
|
|
|
80
161
|
/**
|
|
81
|
-
* The
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
162
|
+
* The keys this target's own config REQUIRES that the cascade cannot value.
|
|
163
|
+
*
|
|
164
|
+
* The rules are the schema's, evaluated by the ONE checker (#626) against the
|
|
165
|
+
* target's resolved config and its COMPOSED env, narrowed to the keys this
|
|
166
|
+
* publisher would send: a required key CI never reads is not the publish's
|
|
167
|
+
* business, and a rule nobody delivers cannot be fixed by pushing anything.
|
|
168
|
+
*
|
|
169
|
+
* The bind's derivations run FIRST (`deriveValues`), because a key the brand
|
|
170
|
+
* never typed but the dispersed files answer is not missing, and a key the
|
|
171
|
+
* derivation could not value carries that seam's own fix line
|
|
172
|
+
* ([#891](https://github.com/Omega-JS-Stack/omega/issues/891)).
|
|
85
173
|
*
|
|
86
174
|
* @param {object} options
|
|
87
175
|
* @param {string} options.targetDir - The target root.
|
|
88
|
-
* @param {string} options.target - Target name
|
|
89
|
-
* @
|
|
176
|
+
* @param {string} options.target - Target name.
|
|
177
|
+
* @param {function} [options.deriveValues] - The derive seam (see collectTargetSecrets).
|
|
178
|
+
* @returns {Array<{ key: string, rule: string, path: string|null, fix: string|null }>}
|
|
90
179
|
*/
|
|
91
|
-
function
|
|
180
|
+
function missingRequiredSecrets(options) {
|
|
181
|
+
const { targetDir, target } = options;
|
|
182
|
+
const deriveValues = 'deriveValues' in options
|
|
183
|
+
? options.deriveValues
|
|
184
|
+
: targetSeams({ target, targetDir }).deriveValues;
|
|
185
|
+
|
|
186
|
+
let config;
|
|
92
187
|
try {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
188
|
+
// PRODUCTION, the same environment `composeValues` composes for: the rules
|
|
189
|
+
// and the values have to be read off ONE config, or a developer machine's
|
|
190
|
+
// `config/omega.development.json5` decides whether a release publish
|
|
191
|
+
// refuses ([#895](https://github.com/Omega-JS-Stack/omega/issues/895)).
|
|
192
|
+
config = loadConfig(targetDir, target, { environment: 'production' }).config;
|
|
193
|
+
} catch (e) {
|
|
194
|
+
// No loadable config: there is no declaration to owe anything to.
|
|
195
|
+
return [];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const { values, fixes } = composeValues({ targetDir, target, deriveValues });
|
|
199
|
+
const delivered = new Set(publishSecretKeys(target, { values }));
|
|
96
200
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
201
|
+
return checkEnvRules(config, values, { target })
|
|
202
|
+
.filter((violation) => delivered.has(violation.key))
|
|
203
|
+
.map((violation) => ({ ...violation, fix: fixes[violation.key] || null }));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* The target's resolved PRODUCTION config, like every other read this publish
|
|
208
|
+
* makes (#895): the repo a release's secrets belong to is the one the
|
|
209
|
+
* production config names. Null when it doesn't load.
|
|
210
|
+
*
|
|
211
|
+
* @param {object} options
|
|
212
|
+
* @param {string} options.targetDir - The target root.
|
|
213
|
+
* @param {string} options.target - Target name ('web', 'extension', …).
|
|
214
|
+
* @returns {object|null}
|
|
215
|
+
*/
|
|
216
|
+
function productionConfig(options) {
|
|
217
|
+
try {
|
|
218
|
+
return loadConfig(options.targetDir, options.target, { environment: 'production' }).config || null;
|
|
100
219
|
} catch (e) {
|
|
101
220
|
return null;
|
|
102
221
|
}
|
|
@@ -111,16 +230,27 @@ function declaredBrandRepo(options) {
|
|
|
111
230
|
* @param {string} options.target - Target name ('web', 'extension', …).
|
|
112
231
|
* @param {object} options.logger - `{ log, warn, error }`.
|
|
113
232
|
* @param {object} [options.env] - Env map (default: process.env).
|
|
114
|
-
* @param {
|
|
233
|
+
* @param {boolean} [options.dryRun] - Print the plan (key NAMES, the derived
|
|
234
|
+
* lines, any refusal) and send nothing (#895).
|
|
235
|
+
* @param {function} [options.resolveValue] - Value seam override (tests).
|
|
236
|
+
* @param {function} [options.deriveValues] - Derive seam override (tests).
|
|
237
|
+
* @param {Object<string, string>} [options.extraSecrets] - Override for the
|
|
238
|
+
* target's already-valued keys, merged OVER the composed set (tests).
|
|
115
239
|
* @param {function} [options.execFn] - Injectable `gh` exec (tests).
|
|
116
|
-
* @
|
|
117
|
-
* @returns {{ skipped: string }|{ published: string[], failed: Array<object> }}
|
|
240
|
+
* @returns {{ skipped: string }|{ planned: string[] }|{ published: string[], failed: Array<object> }}
|
|
118
241
|
*/
|
|
119
242
|
function publishTargetSecrets(options) {
|
|
120
243
|
options = options || {};
|
|
121
|
-
const { targetDir, target, logger } = options;
|
|
244
|
+
const { targetDir, target, logger, dryRun } = options;
|
|
122
245
|
const env = options.env || process.env;
|
|
123
246
|
|
|
247
|
+
// The target type's own shape differences, in ONE table (#891). A caller
|
|
248
|
+
// passes a seam only to stub it.
|
|
249
|
+
const seams = targetSeams({ target, targetDir });
|
|
250
|
+
const resolveValue = 'resolveValue' in options ? options.resolveValue : seams.resolveValue;
|
|
251
|
+
const deriveValues = 'deriveValues' in options ? options.deriveValues : seams.deriveValues;
|
|
252
|
+
const extraSecrets = 'extraSecrets' in options ? options.extraSecrets : seams.extraSecrets;
|
|
253
|
+
|
|
124
254
|
// CI runs the generated workflow as its build/publish step — the secrets
|
|
125
255
|
// already exist there and the runner token can't write them.
|
|
126
256
|
if (env.GITHUB_ACTIONS === 'true' || env.CI === 'true') {
|
|
@@ -128,30 +258,74 @@ function publishTargetSecrets(options) {
|
|
|
128
258
|
return { skipped: 'ci' };
|
|
129
259
|
}
|
|
130
260
|
|
|
131
|
-
|
|
261
|
+
// The schema's set, plus the caller's own already-valued keys. An extra has
|
|
262
|
+
// no `.env` home to compose from (backend's deploy credential is a FILE the
|
|
263
|
+
// firebase service mints, #872), so it arrives valued and travels verbatim:
|
|
264
|
+
// `resolveValue` is the COMPOSED half's seam and would only mangle it. An
|
|
265
|
+
// empty extra claims no key, exactly as an empty composed value does.
|
|
266
|
+
// The config's OWN requirements first: a half set is never published (#891)
|
|
267
|
+
const missing = missingRequiredSecrets({ targetDir, target, deriveValues });
|
|
268
|
+
if (missing.length > 0) {
|
|
269
|
+
// ONE line shape per key, whatever answers it: `<KEY> (required by <path>):
|
|
270
|
+
// <the fix>`. A key a bind can DERIVE names the producer that delivers the
|
|
271
|
+
// file (`omega manage --service certificates`, then disperse) instead of
|
|
272
|
+
// asking for a path to paste; everything else names the .env to set.
|
|
273
|
+
const lines = missing.map(({ key, path, fix }) => {
|
|
274
|
+
const detail = fix || `set it in the ${target} target's .env or the brand's, then re-run.`;
|
|
275
|
+
|
|
276
|
+
return ` ${key}${path ? ` (required by ${path})` : ''}: ${detail}`;
|
|
277
|
+
});
|
|
278
|
+
throw new Error(
|
|
279
|
+
`${missing.length} secret(s) this brand's config requires are empty in the .env cascade (company/brand/target). `
|
|
280
|
+
+ `Nothing was published.\n${lines.join('\n')}`,
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const secrets = { ...collectTargetSecrets({ targetDir, target, resolveValue, deriveValues, logger }) };
|
|
285
|
+
for (const [key, value] of Object.entries(extraSecrets || {})) {
|
|
286
|
+
if (value) secrets[key] = value;
|
|
287
|
+
}
|
|
288
|
+
|
|
132
289
|
const keys = Object.keys(secrets);
|
|
133
290
|
if (!keys.length) {
|
|
134
291
|
logger.warn('Skipping secret publication — no keys composed for this target from the .env cascade (company/brand/target)');
|
|
135
292
|
return { skipped: 'no-secrets' };
|
|
136
293
|
}
|
|
137
294
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
repo
|
|
142
|
-
|
|
143
|
-
logger.warn(`Skipping secret publication — no GitHub remote here (${e.message})`);
|
|
144
|
-
return { skipped: 'no-remote' };
|
|
295
|
+
const config = productionConfig({ targetDir, target });
|
|
296
|
+
const source = config ? sourceRepo(config) : null;
|
|
297
|
+
if (!source) {
|
|
298
|
+
logger.warn('Skipping secret publication: this brand names no GitHub repo in config (repo.org). Set it, then re-run `omega deploy`.');
|
|
299
|
+
return { skipped: 'no-declared-repo' };
|
|
145
300
|
}
|
|
146
301
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
302
|
+
// The ONE origin gate the deploy lane and the manage walk use
|
|
303
|
+
// ([#934](https://github.com/Omega-JS-Stack/omega/issues/934)): the brand
|
|
304
|
+
// root's own origin (the local remote, which the boot prelude has already
|
|
305
|
+
// healed onto GitHub's redirect) must BE the derived source repo, or the
|
|
306
|
+
// publish REFUSES on the one drift line, because arming a repo that is not
|
|
307
|
+
// the derived one is the harm itself. No `.git` AT the brand root is nothing
|
|
308
|
+
// to compare: a NESTED brand's remote is the enclosing repo's by
|
|
309
|
+
// construction, and its deploy pushes to the derived repo regardless
|
|
310
|
+
// ([#872](https://github.com/Omega-JS-Stack/omega/issues/872)). A checkout
|
|
311
|
+
// with no GitHub origin (nobody pushed it yet, or it is hosted elsewhere) has
|
|
312
|
+
// no repo to arm, so it skips.
|
|
313
|
+
const origin = assertOriginMatches({ dir: findBrandRoot(targetDir), config });
|
|
314
|
+
if (origin.reason === 'no-origin' || origin.reason === 'foreign-remote') {
|
|
315
|
+
logger.warn(`Skipping secret publication: no GitHub remote here (${origin.reason})`);
|
|
316
|
+
return { skipped: 'no-remote' };
|
|
151
317
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
318
|
+
|
|
319
|
+
const repo = source.slug;
|
|
320
|
+
|
|
321
|
+
// The PLAN, and nothing else (#895): what the composition answered, by NAME.
|
|
322
|
+
// It runs after the refusal and the two guards above on purpose, so a dry run
|
|
323
|
+
// is a real preview of whether the deploy would publish at all: every one of
|
|
324
|
+
// them is a READ, and a plan naming keys the real run would skip is a promise
|
|
325
|
+
// the deploy cannot keep.
|
|
326
|
+
if (dryRun) {
|
|
327
|
+
logger.log(`DRY RUN, would publish ${keys.length} secret(s) for ${target}: ${keys.join(', ')}`);
|
|
328
|
+
return { planned: keys };
|
|
155
329
|
}
|
|
156
330
|
|
|
157
331
|
logger.log(`Publishing ${keys.length} secret(s) to ${repo}: ${keys.join(', ')}`);
|
|
@@ -162,4 +336,4 @@ function publishTargetSecrets(options) {
|
|
|
162
336
|
return result;
|
|
163
337
|
}
|
|
164
338
|
|
|
165
|
-
module.exports = { collectTargetSecrets,
|
|
339
|
+
module.exports = { collectTargetSecrets, missingRequiredSecrets, publishTargetSecrets };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE ESM-only dependency every OMEGA target proves its bundle lane against
|
|
3
|
+
* ([#906](https://github.com/Omega-JS-Stack/omega/issues/906)).
|
|
4
|
+
*
|
|
5
|
+
* `fixtures/esm-only-package/` is a real package (`"type": "module"`, no
|
|
6
|
+
* CommonJS build) with one entry per environment, chosen by export condition:
|
|
7
|
+
* the NODE entry opens a require of its own with
|
|
8
|
+
* `createRequire(import.meta.url)`, the shape that threw in a packaged desktop
|
|
9
|
+
* app, and the BROWSER entry touches no Node built-in. One package, so a target
|
|
10
|
+
* asks for it by its own name and gets the half its bundle is built for.
|
|
11
|
+
*
|
|
12
|
+
* It is INSTALLED rather than pointed at: `installEsmOnlyFixture(projectRoot)`
|
|
13
|
+
* copies it into the project's `node_modules`, which is where a bundler's normal
|
|
14
|
+
* resolution looks and the only shape that is the same in this monorepo and in a
|
|
15
|
+
* consumer running a framework's self-test off its packaged dist (desktop and
|
|
16
|
+
* extension carry the directory there through `omega.vendorAssets`).
|
|
17
|
+
*/
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const jetpack = require('fs-jetpack');
|
|
20
|
+
|
|
21
|
+
// The name a consumer entry imports, and what the fixture's two entries say
|
|
22
|
+
// about themselves. Exported because a test asserting the bundled copy ran must
|
|
23
|
+
// compare against the ONE spelling, not a retyped twin.
|
|
24
|
+
const FIXTURE_NAME = 'esm-only-fixture';
|
|
25
|
+
const FIXTURE_DIR = path.join(__dirname, 'fixtures', 'esm-only-package');
|
|
26
|
+
const NODE_MARKER = 'ESM_ONLY_FIXTURE_NODE';
|
|
27
|
+
const BROWSER_MARKER = 'ESM_ONLY_FIXTURE_BROWSER';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Install the fixture into a project, the way npm installs a dependency.
|
|
31
|
+
* @param {string} projectRoot - the project that will import it
|
|
32
|
+
* @returns {string} where it landed (`<projectRoot>/node_modules/esm-only-fixture`)
|
|
33
|
+
* @throws {Error} when the fixture is not where this module ships it: in a
|
|
34
|
+
* packaged framework that means the vendor step did not carry it, and a test
|
|
35
|
+
* that silently skipped the dependency would prove nothing
|
|
36
|
+
*/
|
|
37
|
+
function installEsmOnlyFixture(projectRoot) {
|
|
38
|
+
if (!jetpack.exists(FIXTURE_DIR)) {
|
|
39
|
+
throw new Error(`[devkit test] the ESM-only fixture is missing from ${FIXTURE_DIR}. A framework running this off its packaged dist needs the omega.vendorAssets entry that carries it`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const destination = path.join(projectRoot, 'node_modules', FIXTURE_NAME);
|
|
43
|
+
jetpack.copy(FIXTURE_DIR, destination, { overwrite: true });
|
|
44
|
+
|
|
45
|
+
return destination;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = { installEsmOnlyFixture, FIXTURE_NAME, FIXTURE_DIR, NODE_MARKER, BROWSER_MARKER };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// The BROWSER half of the fixture (the `browser` export condition), for the
|
|
2
|
+
// targets whose bundles are browser output: @omega.js/web's esm chunks and
|
|
3
|
+
// service worker, @omega.js/extension's iife bundles. It reaches for no Node
|
|
4
|
+
// built-in and no `import.meta` (esbuild rewrites `import.meta` in iife output
|
|
5
|
+
// too, and warns), because the thing a browser bundle has to prove is the other
|
|
6
|
+
// half of [#906](https://github.com/Omega-JS-Stack/omega/issues/906): an
|
|
7
|
+
// ESM-only package resolves, bundles and RUNS, with a real value on the other
|
|
8
|
+
// side.
|
|
9
|
+
export const flavor = 'browser';
|
|
10
|
+
export const marker = 'ESM_ONLY_FIXTURE_BROWSER';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A value the bundled copy has to compute at RUNTIME, so a test asserting it
|
|
14
|
+
* proves the module evaluated rather than proving its text survived.
|
|
15
|
+
* @returns {string} the fixture's own name for itself
|
|
16
|
+
*/
|
|
17
|
+
export function describeFixture() {
|
|
18
|
+
return `${marker}:${flavor}`;
|
|
19
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// The NODE half of the fixture (the `default` export condition): what an
|
|
2
|
+
// ESM-only dependency does the moment it needs a require of its own, which is
|
|
3
|
+
// the shape that broke a packaged desktop app
|
|
4
|
+
// ([#906](https://github.com/Omega-JS-Stack/omega/issues/906)). yargs-parser is
|
|
5
|
+
// the live case: `createRequire(import.meta.url)` with an `import.meta.url` of
|
|
6
|
+
// `undefined` throws ERR_INVALID_ARG_VALUE before a single line of app code
|
|
7
|
+
// runs.
|
|
8
|
+
//
|
|
9
|
+
// `viaRequire` requires a BUILT-IN rather than a file beside this one: a
|
|
10
|
+
// relative require resolves against the caller's own directory, which for a
|
|
11
|
+
// bundled copy is the bundle's, so a relative path would be testing where the
|
|
12
|
+
// output landed instead of whether the require works at all.
|
|
13
|
+
import { createRequire } from 'node:module';
|
|
14
|
+
|
|
15
|
+
const require = createRequire(import.meta.url);
|
|
16
|
+
|
|
17
|
+
export const flavor = 'node';
|
|
18
|
+
export const fileUrl = import.meta.url;
|
|
19
|
+
export const viaRequire = typeof require('node:path').join === 'function';
|
|
20
|
+
export const marker = 'ESM_ONLY_FIXTURE_NODE';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "esm-only-fixture",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "An ESM-only dependency, as every OMEGA target's bundle lane has to be able to carry one (#906)",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"browser": "./browser.js",
|
|
10
|
+
"default": "./index.js"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -8,20 +8,30 @@
|
|
|
8
8
|
* OMEGA_SENTRY_ENABLED=false kill switch — nothing reports, ever
|
|
9
9
|
* OMEGA_TEST_RUNNER a test run never pollutes a live project
|
|
10
10
|
* OMEGA_SENTRY_FORCE=true report from a non-production run (local proving)
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* the ONE environment the DEFAULT production signal, for hosts that
|
|
12
|
+
* pass no runtime one
|
|
13
13
|
*
|
|
14
|
-
* The production signal is the host's to supply
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* process
|
|
14
|
+
* The production signal is the host's to supply, and the DEFAULT is the one
|
|
15
|
+
* environment every OMEGA target answers from
|
|
16
|
+
* ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)):
|
|
17
|
+
* `@omega.js/config/environment`'s `isProduction()`, read off the host the gates
|
|
18
|
+
* were asked for (`process.env.OMEGA_ENVIRONMENT` on Node, the host's baked
|
|
19
|
+
* `config.environment` in a browser-ish context such as a renderer bundle).
|
|
20
|
+
* OMEGA_BUILD_MODE used to be that default, which made it a FIFTH production
|
|
21
|
+
* signal with its own opinion: a build-mode run of a development artifact
|
|
22
|
+
* reported as production, and a packaged production app whose lane did not
|
|
23
|
+
* carry the flag reported as development. @omega.js/backend still passes its
|
|
24
|
+
* own answer in (`Manager.isProduction()`), and a boolean a host supplies
|
|
25
|
+
* always wins.
|
|
19
26
|
*/
|
|
20
27
|
|
|
28
|
+
const { isProduction } = require('../config/environment.js');
|
|
29
|
+
|
|
21
30
|
/**
|
|
22
31
|
* Read the environment gates for core.resolveConfig().
|
|
23
|
-
* @param {object} [host] - the host's own signals
|
|
24
|
-
*
|
|
32
|
+
* @param {object} [host] - the host's own signals, and the context the one
|
|
33
|
+
* environment is read off (a Manager carrying the baked `config`)
|
|
34
|
+
* @param {boolean} [host.isProduction] - overrides the one environment's answer
|
|
25
35
|
* @param {boolean} [host.allowInDev] - the host's own dev opt-in (e.g. @omega.js/backend's `reportErrorsInDev`)
|
|
26
36
|
* @returns {{ killed: boolean, killedReason: string|null, isProduction: boolean, allowInDev: boolean }}
|
|
27
37
|
*/
|
|
@@ -41,7 +51,7 @@ function readGates(host) {
|
|
|
41
51
|
killedReason,
|
|
42
52
|
isProduction: typeof host.isProduction === 'boolean'
|
|
43
53
|
? host.isProduction
|
|
44
|
-
:
|
|
54
|
+
: isProduction.call(host),
|
|
45
55
|
allowInDev: !!host.allowInDev || env.OMEGA_SENTRY_FORCE === 'true',
|
|
46
56
|
};
|
|
47
57
|
}
|
|
@@ -30,7 +30,7 @@ const main = {
|
|
|
30
30
|
initialize(host) {
|
|
31
31
|
main._initialized = true;
|
|
32
32
|
|
|
33
|
-
const { shouldEnable, options, reason } = resolveConfig(host && host.config && host.config.monitoring, readGates());
|
|
33
|
+
const { shouldEnable, options, reason } = resolveConfig(host && host.config && host.config.monitoring, readGates(host));
|
|
34
34
|
main._options = options;
|
|
35
35
|
|
|
36
36
|
if (!shouldEnable) {
|
|
@@ -21,7 +21,7 @@ const preload = {
|
|
|
21
21
|
* @param {object} host - the desktop Manager: { config }
|
|
22
22
|
*/
|
|
23
23
|
initialize(host) {
|
|
24
|
-
const { shouldEnable, reason } = resolveConfig(host && host.config && host.config.monitoring, readGates());
|
|
24
|
+
const { shouldEnable, reason } = resolveConfig(host && host.config && host.config.monitoring, readGates(host));
|
|
25
25
|
preload._enabled = shouldEnable;
|
|
26
26
|
if (!shouldEnable) logger.log(`disabled — ${reason}`);
|
|
27
27
|
},
|
|
@@ -26,7 +26,7 @@ const renderer = {
|
|
|
26
26
|
initialize(host) {
|
|
27
27
|
renderer._initialized = true;
|
|
28
28
|
|
|
29
|
-
const { shouldEnable, options, reason } = resolveConfig(host && host.config && host.config.monitoring, readGates());
|
|
29
|
+
const { shouldEnable, options, reason } = resolveConfig(host && host.config && host.config.monitoring, readGates(host));
|
|
30
30
|
renderer._options = options;
|
|
31
31
|
|
|
32
32
|
if (!shouldEnable) {
|
package/docs/analytics.md
CHANGED
|
@@ -46,7 +46,7 @@ Mint the secret in GA4 Admin → Data Streams → your stream → **Measurement
|
|
|
46
46
|
|
|
47
47
|
### Production builds
|
|
48
48
|
|
|
49
|
-
The `bundle` task's esbuild `define` bakes `process.env.GOOGLE_ANALYTICS_SECRET` into the bundled main process at build time, so packaged apps don't need `.env` at runtime. The build runs with the secret set (CI does this via the GitHub Actions secret
|
|
49
|
+
The `bundle` task's esbuild `define` bakes `process.env.GOOGLE_ANALYTICS_SECRET` into the bundled main process at build time, so packaged apps don't need `.env` at runtime. The build runs with the secret set (CI does this via the GitHub Actions secret `omega deploy`'s precheck pushes).
|
|
50
50
|
|
|
51
51
|
## API
|
|
52
52
|
|
package/docs/auto-updater.md
CHANGED
|
@@ -110,13 +110,13 @@ Long enough that an actively-used app won't surprise-quit mid-task. Short enough
|
|
|
110
110
|
|
|
111
111
|
### Test mode behavior
|
|
112
112
|
|
|
113
|
-
When `manager.isTesting() === true` (
|
|
113
|
+
When `manager.isTesting() === true` (the one input: `OMEGA_ENVIRONMENT=testing`), the auto-updater swaps in test-friendly defaults so a real download → idle wait → install can complete in seconds instead of minutes:
|
|
114
114
|
|
|
115
115
|
- **Idle threshold**: `IDLE_INSTALL_THRESHOLD_MS_TESTING = 3000ms` (3 sec) instead of 15 min.
|
|
116
116
|
- **Both timers**: `IDLE_TICK_MS_TESTING = 500ms` replaces `feedCheckIntervalMs` and `idleEvalIntervalMs`.
|
|
117
117
|
- **`_promptToInstall` short-circuits** before invoking `dialog.showMessageBox`. The native dialog is modal + blocking + would pop a window the test process can't dismiss programmatically. In test mode the prompt logs `[testing] _promptToInstall(...) — skipped native dialog.` and returns. Tests that want to assert prompt behavior override `_promptToInstall` per-test (see `auto-updater.test.js`).
|
|
118
118
|
|
|
119
|
-
This lets the framework's own integration tests drive the full sequence (`OMEGA_DEV_UPDATE=available` → state machine → 500ms tick → 3s idle threshold elapses → stubbed `installNow` fires) in ~5s. Consumers running their own tests should
|
|
119
|
+
This lets the framework's own integration tests drive the full sequence (`OMEGA_DEV_UPDATE=available` → state machine → 500ms tick → 3s idle threshold elapses → stubbed `installNow` fires) in ~5s. Consumers running their own tests should name `OMEGA_ENVIRONMENT=testing` to inherit the same defaults.
|
|
120
120
|
|
|
121
121
|
## Menu integration
|
|
122
122
|
|
|
@@ -224,8 +224,8 @@ The submenu is dev-only (same gate as `view/developer/toggle-devtools`) and is a
|
|
|
224
224
|
|
|
225
225
|
```
|
|
226
226
|
provider: github
|
|
227
|
-
owner: <
|
|
228
|
-
repo:
|
|
227
|
+
owner: <repo.org>
|
|
228
|
+
repo: `${brand.id}-releases`
|
|
229
229
|
releaseType: release
|
|
230
230
|
```
|
|
231
231
|
|
|
@@ -233,7 +233,7 @@ So your private app repo and your public release repo are completely decoupled
|
|
|
233
233
|
|
|
234
234
|
## Failure modes
|
|
235
235
|
|
|
236
|
-
- **Update repo isn't public** → `electron-updater` gets 404 or 401 against a private repo. Fix: ensure the releases repo (`<
|
|
236
|
+
- **Update repo isn't public** → `electron-updater` gets 404 or 401 against a private repo. Fix: ensure the releases repo (`<repo.org>/<brand.id>-releases`) is public; `omega deploy`'s precheck creates it that way.
|
|
237
237
|
- **Token rotates / expires for `releases` repo** — `electron-updater` doesn't authenticate downloads (anonymous public reads). So tokens don't apply on the consumer side.
|
|
238
238
|
- **`app-update.yml` missing in the packaged app** → look at the build log for `electron-builder`'s "creating updates yml" line. If it's skipped, your `publish` block didn't materialize correctly into `dist/electron-builder.yml`.
|
|
239
239
|
- **`error` status with code `ERR_UPDATER_CHANNEL_FILE_NOT_FOUND`** → there's no `latest-mac.yml` (or `latest.yml` / `latest-linux.yml`) at the configured channel. Run a release first.
|
package/docs/boot-sequence.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
## Order
|
|
6
6
|
|
|
7
7
|
1. **`startup.applyEarly()`** — first thing, before `whenReady`. Calls `app.dock.hide()` for `mode: 'hidden'` (zero-bounce production via `LSUIElement` baked at build time).
|
|
8
|
-
1b. **userData path isolation** — appends an environment suffix to `app.getPath('userData')` so each environment's session data, logs, and `electron-store` files stay separate on the same machine: production untouched, development gets ` (Development)`, testing (`
|
|
8
|
+
1b. **userData path isolation** — appends an environment suffix to `app.getPath('userData')` so each environment's session data, logs, and `electron-store` files stay separate on the same machine: production untouched, development gets ` (Development)`, testing (`OMEGA_ENVIRONMENT=testing`) gets ` (Testing)`. The testing dir is **wiped at boot** so every test run starts from a clean slate (post-run state stays on disk for inspection until the next run; set `OMEGA_TEST_KEEP_USERDATA=1` to skip the wipe). **Must run before `storage.initialize()`** (which constructs `electron-store` against the path).
|
|
9
9
|
1c. **Global user-agent fallback** — sets `app.userAgentFallback` to a branded template via `node-powertools.template`. Default per-platform templates: `Mozilla/5.0 (... <platform-specific> ...) AppleWebKit/537.36 (KHTML, like Gecko) {brand.name}/{app.version} Chrome/{chrome} Safari/537.36`. Merge tags resolve from `{ brand: { name, id }, app: { version }, chrome, electron, node, platform, arch }`. Every BrowserWindow load + electron-updater fetch + node-fetch via the renderer carries the branded UA. Consumers can override post-init by re-setting `app.userAgentFallback` from their main.js.
|
|
10
10
|
2. **`app.on('before-quit')`** wired — sets `manager._isQuitting = true` so any quit path (Cmd+Q, role:'quit' menu, programmatic `app.quit()`, OS shutdown) bypasses the window-manager's hide-on-close trap.
|
|
11
11
|
3. **`ipc`** — typed channel bus online before any feature can register handlers.
|