@uniqbit/mate-core 0.15.0-canary.3 → 0.15.0-canary.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniqbit/mate-core",
3
- "version": "0.15.0-canary.3",
3
+ "version": "0.15.0-canary.6",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "src/",
package/src/cli/main.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { getActiveDistribution } from "../distribution";
2
2
  import {
3
+ enforceUpdateIfRequired,
3
4
  scheduleBackgroundCheck,
4
5
  showUpdateBannerIfAvailable,
5
6
  UpdateStateStore,
@@ -56,8 +57,15 @@ export async function main(argv = process.argv, deps: MainDeps = mainDeps): Prom
56
57
  command === "cap" && findPluginCliCommand(subcommand, rest[0]) !== undefined;
57
58
  if (!isPluginCommand) {
58
59
  const updateStore = new UpdateStateStore();
59
- await showUpdateBannerIfAvailable(updateStore);
60
60
  scheduleBackgroundCheck(updateStore);
61
+ if (
62
+ !isInstallRecoveryCommand(command, subcommand) &&
63
+ (await enforceUpdateIfRequired(updateStore))
64
+ ) {
65
+ process.exitCode = 1;
66
+ return;
67
+ }
68
+ await showUpdateBannerIfAvailable(updateStore);
61
69
  }
62
70
 
63
71
  if (!command || command === "help" || command === "--help" || command === "-h") {
@@ -1,10 +1,17 @@
1
1
  import type { PluginRegistry } from "./tools/setup/registry";
2
2
 
3
3
  export interface DistributionUpdateConfig {
4
- /** npm package whose versions are checked and installed by `mate update`. */
5
- packageName: string;
6
- /** npm registry used for update checks and downloads. */
7
- registry: string;
4
+ /** npm package whose versions are checked and installed by `mate update`. Defaults to `@uniqbit/<name>`. */
5
+ packageName?: string;
6
+ /** npm registry used for update checks and downloads. Defaults to public npm. */
7
+ registry?: string;
8
+ /**
9
+ * Refuse to run commands while a newer version is available, instead of
10
+ * only printing a banner. Install-recovery commands (`install`, `update`,
11
+ * `doctor`, `help`, `companion setup|link`) stay available so the user can
12
+ * actually upgrade.
13
+ */
14
+ enforce?: boolean;
8
15
  }
9
16
 
10
17
  /** Identity and version of the distribution assembled through `createMate`. */
@@ -13,7 +13,7 @@ interface UpdateState {
13
13
  latestVersion: string | null;
14
14
  }
15
15
 
16
- const TWELVE_HOURS_MS = 12 * 60 * 60 * 1000;
16
+ const SIX_HOURS_MS = 6 * 60 * 60 * 1000;
17
17
 
18
18
  export const updateCheckerDeps = {
19
19
  now: () => Date.now(),
@@ -34,11 +34,12 @@ export function getCurrentVersion(): string {
34
34
  return getActiveDistribution().config.version;
35
35
  }
36
36
 
37
- export function getUpdateConfig(): DistributionUpdateConfig {
37
+ export function getUpdateConfig(): Required<DistributionUpdateConfig> {
38
38
  const { name, update } = getActiveDistribution().config;
39
39
  return {
40
40
  packageName: update?.packageName ?? `@uniqbit/${name}`,
41
41
  registry: update?.registry ?? PUBLIC_NPM_REGISTRY,
42
+ enforce: update?.enforce ?? false,
42
43
  };
43
44
  }
44
45
 
@@ -69,6 +70,28 @@ export async function showUpdateBannerIfAvailable(store: UpdateStateStore): Prom
69
70
  }
70
71
  }
71
72
 
73
+ /**
74
+ * Distributions that set `update.enforce` refuse to run further commands while
75
+ * a cached newer version is available. Returns true when the current command
76
+ * must stop; state-load failures never block.
77
+ */
78
+ export async function enforceUpdateIfRequired(store: UpdateStateStore): Promise<boolean> {
79
+ if (!getUpdateConfig().enforce) return false;
80
+ try {
81
+ const state = await store.load();
82
+ if (!state.latestVersion) return false;
83
+ const current = getCurrentVersion();
84
+ if (!isNewer(state.latestVersion, current)) return false;
85
+ process.stderr.write(
86
+ `\n${frameworkConfig.name}: update required (${current} → ${state.latestVersion})\n`,
87
+ );
88
+ process.stderr.write(` Run \`${frameworkConfig.name} update\` before continuing.\n\n`);
89
+ return true;
90
+ } catch {
91
+ return false;
92
+ }
93
+ }
94
+
72
95
  export async function fetchLatestVersion(): Promise<string> {
73
96
  const { packageName, registry } = getUpdateConfig();
74
97
  return fetchPublicPackageVersion(packageName, registry);
@@ -79,7 +102,7 @@ export function scheduleBackgroundCheck(store: UpdateStateStore): void {
79
102
  try {
80
103
  const state = await store.load();
81
104
  const lastChecked = state.lastChecked ? new Date(state.lastChecked).getTime() : 0;
82
- if (updateCheckerDeps.now() - lastChecked < TWELVE_HOURS_MS) return;
105
+ if (updateCheckerDeps.now() - lastChecked < SIX_HOURS_MS) return;
83
106
  const latestVersion = await fetchLatestVersion();
84
107
  await store.save({ lastChecked: updateCheckerDeps.toIsoString(), latestVersion });
85
108
  } catch {