@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
|
@@ -261,6 +261,33 @@ function relativeSpecPath(fromDir, target) {
|
|
|
261
261
|
return path.relative(fs.realpathSync(fromDir), fs.realpathSync(target)).split(path.sep).join('/');
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Regenerate the install root's OWN lockfile after a flip (#938): inside the
|
|
266
|
+
* omega monorepo the tree install climbs to the monorepo root and writes that
|
|
267
|
+
* lockfile, so the brand's would stay stale. Loaded here rather than at the top:
|
|
268
|
+
* this module runs at every CLI boot (freshnessBoot), and the lockfile read
|
|
269
|
+
* pulls in @omega.js/config, which the boot has no use for.
|
|
270
|
+
* @param {string} installRoot - The brand root (or standalone target).
|
|
271
|
+
* @param {object} [logger] - Logger with log (silent when omitted).
|
|
272
|
+
* @returns {Promise<void>}
|
|
273
|
+
*/
|
|
274
|
+
function regenerateBrandLockfile(installRoot, logger) {
|
|
275
|
+
const { regenerateLockfile } = require('./lockfile.js');
|
|
276
|
+
return regenerateLockfile({ root: installRoot, log: logger ? (line) => logger.log(line) : undefined });
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Whether the install root's lockfile is missing or disagrees with its
|
|
281
|
+
* manifests' @omega.js registry specs: the deploy gate's own read (#938).
|
|
282
|
+
* @param {string} installRoot - The brand root (or standalone target).
|
|
283
|
+
* @returns {boolean}
|
|
284
|
+
*/
|
|
285
|
+
function brandLockfileStale(installRoot) {
|
|
286
|
+
const { brandLockfileDrift } = require('./brand-version.js');
|
|
287
|
+
const { lock, drift } = brandLockfileDrift({ root: installRoot });
|
|
288
|
+
return !lock || drift.length > 0;
|
|
289
|
+
}
|
|
290
|
+
|
|
264
291
|
/**
|
|
265
292
|
* file:-install a brand's @omega.js dependencies from the local monorepo.
|
|
266
293
|
*
|
|
@@ -275,7 +302,8 @@ function relativeSpecPath(fromDir, target) {
|
|
|
275
302
|
* targets degenerate to themselves.
|
|
276
303
|
*
|
|
277
304
|
* Idempotent: dependencies already resolving to the monorepo copy are
|
|
278
|
-
* skipped, and when nothing needs linking no install runs.
|
|
305
|
+
* skipped, and when nothing needs linking no install runs. An install is
|
|
306
|
+
* followed by the brand's OWN lockfile regeneration (#938).
|
|
279
307
|
* @param {object} options
|
|
280
308
|
* @param {string} options.dir - Target directory to link from (any target in the brand).
|
|
281
309
|
* @param {string} options.monorepoRoot - Monorepo root path.
|
|
@@ -347,6 +375,11 @@ async function linkLocalPackages(options) {
|
|
|
347
375
|
logger && logger.warn(`install failed — restored ${manifestBackups.size} manifest(s) to their pre-link specs`);
|
|
348
376
|
throw error;
|
|
349
377
|
}
|
|
378
|
+
|
|
379
|
+
// Outside the rollback: the install succeeded, so the manifests and the
|
|
380
|
+
// tree already agree, and restoring the manifests now would split them.
|
|
381
|
+
// A failed regeneration puts the lock back itself and throws as what it is.
|
|
382
|
+
await regenerateBrandLockfile(installRoot, logger);
|
|
350
383
|
}
|
|
351
384
|
|
|
352
385
|
return actions;
|
|
@@ -364,7 +397,9 @@ async function linkLocalPackages(options) {
|
|
|
364
397
|
* @omega.js/client in one brand. An explicit `range` still wins verbatim — the
|
|
365
398
|
* caller owns that string. Idempotent: registry-spec'd entries are untouched;
|
|
366
399
|
* nothing to flip → no install. Same transactional manifest restore as the
|
|
367
|
-
* linker when the install fails.
|
|
400
|
+
* linker when the install fails. Either way the brand's OWN lockfile ends up
|
|
401
|
+
* agreeing with the manifests (#938): regenerated after the install, and
|
|
402
|
+
* regenerated alone when nothing flipped but the lock still disagrees.
|
|
368
403
|
* @param {object} options
|
|
369
404
|
* @param {string} options.dir - Any directory inside the brand.
|
|
370
405
|
* @param {object} [options.logger] - Logger with log/warn (silent when omitted).
|
|
@@ -416,7 +451,11 @@ async function restoreRegistrySpecs(options) {
|
|
|
416
451
|
}
|
|
417
452
|
}
|
|
418
453
|
|
|
419
|
-
if (
|
|
454
|
+
if (dryRun) {
|
|
455
|
+
return actions;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (installNeeded) {
|
|
420
459
|
try {
|
|
421
460
|
await safeInstall('npm install', { log: true, config: { cwd: installRoot } });
|
|
422
461
|
} catch (error) {
|
|
@@ -426,6 +465,15 @@ async function restoreRegistrySpecs(options) {
|
|
|
426
465
|
logger && logger.warn(`install failed — restored ${manifestBackups.size} manifest(s) to their file: specs`);
|
|
427
466
|
throw error;
|
|
428
467
|
}
|
|
468
|
+
|
|
469
|
+
// Outside the rollback, as in linkLocalPackages: the flipped manifests and
|
|
470
|
+
// the installed tree agree, so only the lock is left to heal.
|
|
471
|
+
await regenerateBrandLockfile(installRoot, logger);
|
|
472
|
+
} else if (brandLockfileStale(installRoot)) {
|
|
473
|
+
// Nothing to flip, but the lock still disagrees (the specs were flipped
|
|
474
|
+
// before the lock was ever regenerated): this verb is the fix the deploy's
|
|
475
|
+
// lockfile gate names, so it heals the lock here too (#938).
|
|
476
|
+
await regenerateBrandLockfile(installRoot, logger);
|
|
429
477
|
}
|
|
430
478
|
|
|
431
479
|
return actions;
|
|
@@ -1548,6 +1596,34 @@ function healFailedMessage(result) {
|
|
|
1548
1596
|
].join('\n');
|
|
1549
1597
|
}
|
|
1550
1598
|
|
|
1599
|
+
/**
|
|
1600
|
+
* Leave the #350 prepare gate wired on a package this process just prepared
|
|
1601
|
+
* ([#870](https://github.com/Omega-JS-Stack/omega/issues/870)). prepare-package
|
|
1602
|
+
* rewrites `scripts.prepare` to its own UNGUARDED string on the way through, and
|
|
1603
|
+
* a heal that left it there hands a consumer install the door back. The prepare
|
|
1604
|
+
* script restores it in a `finally`, so this is the net for the case a finally
|
|
1605
|
+
* cannot reach: a prepare killed outright, or one that never ran the gate at all.
|
|
1606
|
+
* The guard is loaded from the devkit BESIDE the prepared package, the same hop
|
|
1607
|
+
* the gated script's own relative require makes, and its path is built at runtime
|
|
1608
|
+
* rather than written as a literal specifier, because devkit's vendored copies
|
|
1609
|
+
* carry `src/` only and a relative require of `tools/` would send the vendor walk
|
|
1610
|
+
* outside the module root.
|
|
1611
|
+
* @param {object} options
|
|
1612
|
+
* @param {string} options.monorepoRoot - The monorepo containing the package.
|
|
1613
|
+
* @param {string} options.packageDir - The package that was prepared.
|
|
1614
|
+
* @returns {boolean} Whether the manifest holds the gate now (true when the
|
|
1615
|
+
* checkout carries no guard to enforce).
|
|
1616
|
+
*/
|
|
1617
|
+
function keepPrepareGuarded(options) {
|
|
1618
|
+
const { monorepoRoot, packageDir } = options;
|
|
1619
|
+
const guardPath = path.join(monorepoRoot, 'packages', 'devkit', 'tools', 'prepare-guard.js');
|
|
1620
|
+
if (!fs.existsSync(guardPath)) {
|
|
1621
|
+
return true;
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
return require(guardPath).ensureGuarded({ packageDir }).guarded;
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1551
1627
|
/**
|
|
1552
1628
|
* Check that a locally-linked framework's dist is at least as new as its src —
|
|
1553
1629
|
* reporting or rebuilding it when a src edit landed without a prepare, so
|
|
@@ -1661,6 +1737,10 @@ function ensureFreshLocalDist(options) {
|
|
|
1661
1737
|
stdio: 'inherit',
|
|
1662
1738
|
shell: process.platform === 'win32',
|
|
1663
1739
|
});
|
|
1740
|
+
|
|
1741
|
+
// Whatever that prepare did, it does not get to leave the gate off (#870)
|
|
1742
|
+
const guarded = inMonorepo ? keepPrepareGuarded({ monorepoRoot, packageDir: realDir }) : true;
|
|
1743
|
+
|
|
1664
1744
|
if (result.status !== 0) {
|
|
1665
1745
|
const failure = `npm run prepare exited ${result.status === null ? String(result.error && result.error.message || 'spawn error') : result.status}`;
|
|
1666
1746
|
if (inMonorepo) {
|
|
@@ -1671,6 +1751,21 @@ function ensureFreshLocalDist(options) {
|
|
|
1671
1751
|
console.warn(`omega: rebuild failed (${failure} in ${realDir}) — continuing on the stale dist`);
|
|
1672
1752
|
return { status: 'rebuild-failed', packageName, dir: realDir };
|
|
1673
1753
|
}
|
|
1754
|
+
|
|
1755
|
+
// A prepare that ended with the gate off hands a consumer install the #350
|
|
1756
|
+
// door back, so a heal that could not put it back is a FAILED heal like any
|
|
1757
|
+
// other: the boot stops on it rather than running on an ungated package.
|
|
1758
|
+
if (!guarded) {
|
|
1759
|
+
return {
|
|
1760
|
+
status: 'heal-failed',
|
|
1761
|
+
packageName,
|
|
1762
|
+
dir: realDir,
|
|
1763
|
+
reason,
|
|
1764
|
+
failure: 'npm run prepare left scripts.prepare off the #350 gate',
|
|
1765
|
+
monorepoRoot,
|
|
1766
|
+
};
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1674
1769
|
return { status: 'rebuilt', by: 'self', packageName, dir: realDir };
|
|
1675
1770
|
});
|
|
1676
1771
|
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lockfile: regenerate an install root's OWN package-lock.json
|
|
3
|
+
* ([#938](https://github.com/Omega-JS-Stack/omega/issues/938)).
|
|
4
|
+
*
|
|
5
|
+
* ONE helper for its three callers: the pack step (`pack-local`, the staged
|
|
6
|
+
* shape), `omega i local` (`linkLocalPackages`) and `omega i live`
|
|
7
|
+
* (`restoreRegistrySpecs`).
|
|
8
|
+
*
|
|
9
|
+
* Two things a plain `npm install` gets wrong here, and this answers both:
|
|
10
|
+
* - `--prefix` makes npm treat `root` as the install root. Without it, npm in
|
|
11
|
+
* a directory that is itself a WORKSPACE of an outer root (every in-repo
|
|
12
|
+
* brand, under the omega monorepo's `brands/*`) climbs to that outer root
|
|
13
|
+
* and writes ITS lockfile, leaving the brand's own untouched.
|
|
14
|
+
* - npm KEEPS a locked link whose target's version satisfies a registry spec,
|
|
15
|
+
* so a lock from the local era (`link: true` into a checkout already at the
|
|
16
|
+
* published number) would survive the flip. Every @omega.js entry the
|
|
17
|
+
* deploy gate would refuse (`brandLockfileDrift`) is dropped first, with its
|
|
18
|
+
* link target, so npm resolves those afresh and keeps every other pin.
|
|
19
|
+
* - npm also honors a STALE path entry, a folder the lock names that is no
|
|
20
|
+
* longer on disk (a renamed target), and re-creates whatever link its
|
|
21
|
+
* dependencies declare. Those entries go first, with everything under them
|
|
22
|
+
* and every `node_modules/` link pointing into them.
|
|
23
|
+
*
|
|
24
|
+
* Transactional: a failed npm run writes the lock back byte for byte.
|
|
25
|
+
*/
|
|
26
|
+
const fs = require('fs');
|
|
27
|
+
const path = require('path');
|
|
28
|
+
const jetpack = require('fs-jetpack');
|
|
29
|
+
|
|
30
|
+
const { safeInstall } = require('./safe-install.js');
|
|
31
|
+
const { brandLockfileDrift, staleLockPaths } = require('./brand-version.js');
|
|
32
|
+
|
|
33
|
+
/** A path equal to base, or nested beneath it. */
|
|
34
|
+
const under = (value, base) => value === base || value.startsWith(`${base}/`);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Drop every stale path entry (`staleLockPaths`), everything nested under it,
|
|
38
|
+
* and every `node_modules/` entry whose `resolved` points into it.
|
|
39
|
+
*
|
|
40
|
+
* @param {object} lock - The parsed lock (mutated).
|
|
41
|
+
* @param {string} root - The install root the keys are relative to.
|
|
42
|
+
* @returns {string[]} The stale paths dropped (the outermost of each tree).
|
|
43
|
+
*/
|
|
44
|
+
function dropStalePaths(lock, root) {
|
|
45
|
+
const stale = staleLockPaths({ root, packages: lock.packages });
|
|
46
|
+
const outermost = stale.filter((key) => !stale.some((other) => other !== key && under(key, other)));
|
|
47
|
+
|
|
48
|
+
for (const [key, entry] of Object.entries(lock.packages)) {
|
|
49
|
+
const pointsInto = entry && typeof entry.resolved === 'string' && outermost.some((base) => under(entry.resolved, base));
|
|
50
|
+
if (outermost.some((base) => under(key, base)) || pointsInto) delete lock.packages[key];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return outermost;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Drop every lock entry `drift` names, plus a dropped link's target entry and
|
|
58
|
+
* everything nested under it (the checkout's own dependencies).
|
|
59
|
+
*
|
|
60
|
+
* @param {object} lock - The parsed lock (mutated).
|
|
61
|
+
* @param {Array<{ key: string|null, entry: object|undefined }>} drift - What the gate refused.
|
|
62
|
+
* @returns {string[]} The names whose entries were dropped.
|
|
63
|
+
*/
|
|
64
|
+
function dropDrift(lock, drift) {
|
|
65
|
+
const dropped = [];
|
|
66
|
+
|
|
67
|
+
for (const { name, key, entry } of drift) {
|
|
68
|
+
// An absent entry has nothing to drop (npm adds it from the manifest), and
|
|
69
|
+
// one inside a stale path is already gone with it.
|
|
70
|
+
if (!key || !lock.packages[key]) continue;
|
|
71
|
+
|
|
72
|
+
delete lock.packages[key];
|
|
73
|
+
dropped.push(name);
|
|
74
|
+
|
|
75
|
+
if (entry.link && entry.resolved) {
|
|
76
|
+
for (const other of Object.keys(lock.packages)) {
|
|
77
|
+
if (under(other, entry.resolved)) delete lock.packages[other];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return dropped;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Regenerate `root`'s package-lock.json from its manifests, lock-only: no
|
|
87
|
+
* scripts, no node_modules writes.
|
|
88
|
+
*
|
|
89
|
+
* @param {object} options
|
|
90
|
+
* @param {string} options.root - The install root whose lock is regenerated.
|
|
91
|
+
* @param {function} [options.log] - Line sink (silent when omitted).
|
|
92
|
+
* @returns {Promise<void>}
|
|
93
|
+
*/
|
|
94
|
+
async function regenerateLockfile({ root, log }) {
|
|
95
|
+
const { lockPath, lock, drift } = brandLockfileDrift({ root });
|
|
96
|
+
const original = lock ? jetpack.read(lockPath) : null;
|
|
97
|
+
|
|
98
|
+
if (lock && lock.packages) {
|
|
99
|
+
const pruned = dropStalePaths(lock, root);
|
|
100
|
+
const dropped = dropDrift(lock, drift);
|
|
101
|
+
|
|
102
|
+
if (pruned.length || dropped.length) {
|
|
103
|
+
jetpack.write(lockPath, `${JSON.stringify(lock, null, 2)}\n`);
|
|
104
|
+
}
|
|
105
|
+
if (log && pruned.length) log(`Pruned the lock entries of folders no longer on disk (${pruned.join(', ')}) so npm stops honoring what they declare`);
|
|
106
|
+
if (log && dropped.length) log(`Dropped the stale lock entries of ${dropped.join(', ')} so npm resolves them from the manifests`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (log) log(`Regenerating ${path.basename(root)}/package-lock.json...`);
|
|
110
|
+
|
|
111
|
+
// The REAL path: npm writes a link's `resolved` relative to the physical
|
|
112
|
+
// directory, so a prefix spelled through an alias (macOS /var for
|
|
113
|
+
// /private/var, a symlinked brand dir) reads those paths from the wrong place.
|
|
114
|
+
const prefix = fs.realpathSync(root);
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
await safeInstall(
|
|
118
|
+
`npm install --package-lock-only --ignore-scripts --no-audit --no-fund --prefix "${prefix}"`,
|
|
119
|
+
{ log: false, config: { cwd: prefix } },
|
|
120
|
+
);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
if (original !== null) jetpack.write(lockPath, original);
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
module.exports = { regenerateLockfile };
|
|
@@ -23,8 +23,16 @@
|
|
|
23
23
|
// - The Default section is replaced with the new framework's defaults.
|
|
24
24
|
// - Keys that already had values (in either Default or Custom) keep those values
|
|
25
25
|
// in the same section they were in.
|
|
26
|
-
// -
|
|
27
|
-
//
|
|
26
|
+
// - The Default section is COMPLETELY managed ([#926](https://github.com/Omega-JS-Stack/omega/issues/926)):
|
|
27
|
+
// a line the new framework block no longer carries LEAVES the consumer, so a
|
|
28
|
+
// rule the framework retires or rewrites actually takes effect everywhere. A
|
|
29
|
+
// retired framework line and a line a user typed inside the framework block
|
|
30
|
+
// cannot be told apart, and the block header already says it is overwritten on
|
|
31
|
+
// every setup, so `.gitignore` and `AGENTS.md` drop it. Lines a user owns
|
|
32
|
+
// belong under the Custom marker, which stays verbatim.
|
|
33
|
+
// - .env is the one exception: a retired key holding a NON-EMPTY value migrates
|
|
34
|
+
// to the Custom section (that value is data, not a rule), while an empty
|
|
35
|
+
// retired key (`KEY=` / `KEY=""`) drops like any other retired line.
|
|
28
36
|
// - .env values are normalized to **double-quoted** form on every merge:
|
|
29
37
|
// KEY=raw-value → KEY="raw-value"
|
|
30
38
|
// KEY="already-quoted" → KEY="already-quoted" (left alone)
|
|
@@ -110,24 +118,23 @@ function mergeLineBasedFiles(existingContent, newContent, fileName) {
|
|
|
110
118
|
}
|
|
111
119
|
}
|
|
112
120
|
|
|
113
|
-
//
|
|
114
|
-
//
|
|
121
|
+
// Anything in the existing Default section the new framework block no longer
|
|
122
|
+
// carries. The block is COMPLETELY managed (#926), so it DROPS: a retired
|
|
123
|
+
// framework line and a line the user typed into the framework block cannot be
|
|
124
|
+
// told apart, and the block header already says it is overwritten on every
|
|
125
|
+
// setup. The one exception is an .env key holding a real value, which is the
|
|
126
|
+
// user's DATA rather than a rule, so it migrates down to Custom; an empty one
|
|
127
|
+
// drops with the rest. .gitignore and AGENTS.md migrate nothing.
|
|
115
128
|
const migratedToCustom = [];
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
|
|
129
|
+
if (isEnvFile) {
|
|
130
|
+
for (const line of existingDefault) {
|
|
131
|
+
const trimmed = line.trim();
|
|
132
|
+
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
119
133
|
|
|
120
|
-
if (isEnvFile) {
|
|
121
134
|
const key = trimmed.split('=')[0].trim();
|
|
122
|
-
if (key && !newDefaultKeys.has(key) && !existingCustomKeys.has(key)) {
|
|
135
|
+
if (key && !newDefaultKeys.has(key) && !existingCustomKeys.has(key) && !envValueIsEmpty(trimmed)) {
|
|
123
136
|
migratedToCustom.push(normalizeEnvLine(line));
|
|
124
137
|
}
|
|
125
|
-
} else {
|
|
126
|
-
// .gitignore: line not in new defaults → migrate.
|
|
127
|
-
const inNew = newLines.some((nl) => nl.trim() === trimmed);
|
|
128
|
-
if (!inNew) {
|
|
129
|
-
migratedToCustom.push(line);
|
|
130
|
-
}
|
|
131
138
|
}
|
|
132
139
|
}
|
|
133
140
|
|
|
@@ -186,7 +193,7 @@ function normalizeEnvLine(line) {
|
|
|
186
193
|
if (eqIdx < 0) return line; // no `=` — not a KEY=VALUE line
|
|
187
194
|
|
|
188
195
|
const key = trimmed.slice(0, eqIdx).trim();
|
|
189
|
-
|
|
196
|
+
const value = trimmed.slice(eqIdx + 1);
|
|
190
197
|
|
|
191
198
|
// Strip trailing whitespace + inline comment-after-value (rare; we only strip a # that follows a space).
|
|
192
199
|
// We do NOT strip # inside quoted values. Detect that by checking if value starts with a quote.
|
|
@@ -253,9 +253,10 @@ async function run({ hostName, hostRun, argv = process.argv.slice(2) }) {
|
|
|
253
253
|
const target = findTarget(process.cwd());
|
|
254
254
|
|
|
255
255
|
// No context — the bootstrap case (a verb run in a fresh directory has
|
|
256
|
-
// no framework dep yet, by definition). Run the
|
|
257
|
-
//
|
|
258
|
-
//
|
|
256
|
+
// no framework dep yet, by definition). Run the INSTALLED @omega.js/manager
|
|
257
|
+
// when one resolves, else the HOST framework's CLI exactly like the
|
|
258
|
+
// pre-dispatcher bins did, and say which one so a hoist-winner at a brand
|
|
259
|
+
// root is never a silent mystery.
|
|
259
260
|
if (!target) {
|
|
260
261
|
// …but ONLY for a verb that cannot write. The fallback hands a mutating verb
|
|
261
262
|
// to whichever framework won npm's bin link, and that verb scaffolds its own
|
|
@@ -279,6 +280,20 @@ async function run({ hostName, hostRun, argv = process.argv.slice(2) }) {
|
|
|
279
280
|
process.exit(1);
|
|
280
281
|
}
|
|
281
282
|
|
|
283
|
+
// The manager wins a contextless run whenever the install carries one: the
|
|
284
|
+
// verbs that survive the refusal above are the ones that run where no
|
|
285
|
+
// target exists yet (onboard, create, new), and those are the manager's own.
|
|
286
|
+
// Without this, a fresh brand-template clone that installed ONLY
|
|
287
|
+
// @omega.js/manager still ran the backend, because the manager DEPENDS on
|
|
288
|
+
// the backend and npm's arbitrary hoist winner linked the backend's bin:
|
|
289
|
+
// `npx omega onboard` answered `Unknown command`
|
|
290
|
+
// ([#908](https://github.com/Omega-JS-Stack/omega/issues/908)).
|
|
291
|
+
const manager = tryResolveCli(MANAGER, process.cwd());
|
|
292
|
+
if (manager.cliPath) {
|
|
293
|
+
console.error(`omega: no target context found from ${process.cwd()}: running ${MANAGER}`);
|
|
294
|
+
return require(manager.cliPath).run();
|
|
295
|
+
}
|
|
296
|
+
|
|
282
297
|
console.error(`omega: no target context found from ${process.cwd()} — running ${hostName}`);
|
|
283
298
|
return hostRun();
|
|
284
299
|
}
|