forked from heygen-com/hyperframes
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathupdateCheck.ts
More file actions
122 lines (105 loc) · 3.66 KB
/
Copy pathupdateCheck.ts
File metadata and controls
122 lines (105 loc) · 3.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import { compareVersions } from "compare-versions";
import { readConfig, writeConfig } from "../telemetry/config.js";
import { VERSION } from "../version.js";
import { isDevMode } from "./env.js";
const NPM_REGISTRY_URL = "https://registry.npmjs.org/hyperframes/latest";
const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
const FETCH_TIMEOUT_MS = 3000;
/** Returns true if `a` is newer than `b` per semver (handles alpha, beta, rc). */
function isNewerSemver(a: string, b: string): boolean {
try {
return compareVersions(a, b) > 0;
} catch {
return a !== b;
}
}
export interface UpdateCheckResult {
current: string;
latest: string;
updateAvailable: boolean;
}
export interface UpdateMeta {
version: string;
latestVersion?: string;
updateAvailable: boolean;
}
/**
* Check npm registry for the latest version. Uses a 24h cache to avoid
* hitting the registry on every invocation.
*
* @param force - Skip cache and fetch fresh data
*/
export async function checkForUpdate(force?: boolean): Promise<UpdateCheckResult> {
const config = readConfig();
const now = Date.now();
if (!force && config.lastUpdateCheck && config.latestVersion) {
const lastCheck = new Date(config.lastUpdateCheck).getTime();
if (now - lastCheck < CHECK_INTERVAL_MS) {
return {
current: VERSION,
latest: config.latestVersion,
updateAvailable: isNewerSemver(config.latestVersion, VERSION),
};
}
}
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
const res = await fetch(NPM_REGISTRY_URL, {
signal: controller.signal,
headers: { Connection: "close" },
});
clearTimeout(timeout);
if (!res.ok) return fallbackResult(config.latestVersion);
const data = (await res.json()) as { version?: string };
const latest = data.version ?? VERSION;
config.lastUpdateCheck = new Date().toISOString();
config.latestVersion = latest;
writeConfig(config);
return { current: VERSION, latest, updateAvailable: isNewerSemver(latest, VERSION) };
} catch {
return fallbackResult(config.latestVersion);
}
}
function fallbackResult(cachedLatest?: string): UpdateCheckResult {
return {
current: VERSION,
latest: cachedLatest ?? VERSION,
updateAvailable: cachedLatest ? isNewerSemver(cachedLatest, VERSION) : false,
};
}
/**
* Synchronous read from cache — for _meta envelope on --json commands.
* Never fetches. Returns what the last background check found.
*/
export function getUpdateMeta(): UpdateMeta {
const config = readConfig();
return {
version: VERSION,
latestVersion: config.latestVersion,
updateAvailable: config.latestVersion ? isNewerSemver(config.latestVersion, VERSION) : false,
};
}
/**
* Wrap a JSON payload with the _meta version envelope.
* Use this in all --json command outputs for consistent agent-friendly metadata.
*/
export function withMeta<T extends object>(data: T): T & { _meta: UpdateMeta } {
return { ...data, _meta: getUpdateMeta() };
}
/**
* Print update notice to stderr if a newer version is available.
* Skipped in CI, non-TTY, dev mode, or when HYPERFRAMES_NO_UPDATE_CHECK is set.
*/
export function printUpdateNotice(): void {
if (isDevMode()) return;
if (process.env["CI"] === "true" || process.env["CI"] === "1") return;
if (!process.stderr.isTTY) return;
if (process.env["HYPERFRAMES_NO_UPDATE_CHECK"] === "1") return;
const meta = getUpdateMeta();
if (!meta.updateAvailable || !meta.latestVersion) return;
process.stderr.write(
`\n Update available: ${meta.version} \u2192 ${meta.latestVersion}\n` +
` Run: npx hyperframes@latest\n\n`,
);
}