Skip to content

Commit c7a8ae4

Browse files
committed
chore: use file modification time instead of explicit timestamp prop
1 parent bb8f44e commit c7a8ae4

3 files changed

Lines changed: 20 additions & 11 deletions

File tree

src/bin/check-latest-version.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ if (cachePath) {
2626
await fs.mkdir(path.dirname(cachePath), {recursive: true});
2727
await fs.writeFile(
2828
cachePath,
29-
JSON.stringify({version: data.version, timestamp: Date.now()}),
29+
JSON.stringify({version: data.version}),
3030
);
3131
}
3232
} catch {

src/utils/check-for-updates.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,24 @@ export async function checkForUpdates(message: string) {
2424
'latest.json',
2525
);
2626

27-
let cache: {version: string; timestamp: number} | undefined;
27+
let cachedVersion: string | undefined;
28+
let stats: {mtimeMs: number} | undefined;
2829
try {
30+
stats = await fs.stat(cachePath);
2931
const data = await fs.readFile(cachePath, 'utf8');
30-
cache = JSON.parse(data);
32+
cachedVersion = JSON.parse(data).version;
3133
} catch {
3234
// Ignore errors reading cache.
3335
}
3436

35-
if (cache && typeof cache.version === 'string' && cache.version !== VERSION) {
37+
if (cachedVersion && cachedVersion !== VERSION) {
3638
console.warn(
37-
`\nUpdate available: ${VERSION} -> ${cache.version}\n${message}\n`,
39+
`\nUpdate available: ${VERSION} -> ${cachedVersion}\n${message}\n`,
3840
);
3941
}
4042

4143
const now = Date.now();
42-
if (cache && now - cache.timestamp < 24 * 60 * 60 * 1000) {
44+
if (stats && now - stats.mtimeMs < 24 * 60 * 60 * 1000) {
4345
return;
4446
}
4547

tests/check-for-updates.test.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ describe('checkForUpdates', () => {
2222

2323
it('notifies if cache exists and version is different', async () => {
2424
sinon.stub(os, 'homedir').returns('/home/user');
25+
sinon.stub(fs, 'stat').resolves({mtimeMs: Date.now()} as any);
2526
sinon.stub(fs, 'readFile').callsFake(async filePath => {
2627
if (filePath.toString().includes('latest.json')) {
2728
return JSON.stringify({
2829
version: '99.9.9',
29-
timestamp: Date.now(),
3030
});
3131
}
3232
throw new Error(`File not found: ${filePath}`);
@@ -46,11 +46,11 @@ describe('checkForUpdates', () => {
4646

4747
it('does not spawn fetch process if cache is fresh', async () => {
4848
sinon.stub(os, 'homedir').returns('/home/user');
49+
sinon.stub(fs, 'stat').resolves({mtimeMs: Date.now()} as any);
4950
sinon.stub(fs, 'readFile').callsFake(async filePath => {
5051
if (filePath.toString().includes('latest.json')) {
5152
return JSON.stringify({
5253
version: VERSION,
53-
timestamp: Date.now(),
5454
});
5555
}
5656
throw new Error(`File not found: ${filePath}`);
@@ -64,11 +64,13 @@ describe('checkForUpdates', () => {
6464

6565
it('spawns detached process if cache is stale', async () => {
6666
sinon.stub(os, 'homedir').returns('/home/user');
67+
sinon.stub(fs, 'stat').resolves({
68+
mtimeMs: Date.now() - 25 * 60 * 60 * 1000, // 25 hours ago
69+
} as any);
6770
sinon.stub(fs, 'readFile').callsFake(async filePath => {
6871
if (filePath.toString().includes('latest.json')) {
6972
return JSON.stringify({
7073
version: VERSION,
71-
timestamp: Date.now() - 25 * 60 * 60 * 1000, // 25 hours ago
7274
});
7375
}
7476
throw new Error(`File not found: ${filePath}`);
@@ -83,14 +85,17 @@ describe('checkForUpdates', () => {
8385

8486
assert.ok(spawnStub.calledOnce);
8587
assert.strictEqual(spawnStub.firstCall.args[0], process.execPath);
86-
assert.ok(spawnStub.firstCall.args[1][0]?.includes('check-latest-version.js'));
88+
assert.ok(
89+
spawnStub.firstCall.args[1][0]?.includes('check-latest-version.js'),
90+
);
8791
assert.ok(spawnStub.firstCall.args[1][1]?.includes('latest.json'));
8892
assert.strictEqual(spawnStub.firstCall.args[2]?.detached, true);
8993
assert.ok(unrefSpy.calledOnce);
9094
});
9195

9296
it('spawns detached process if cache is missing', async () => {
9397
sinon.stub(os, 'homedir').returns('/home/user');
98+
sinon.stub(fs, 'stat').rejects(new Error('File not found'));
9499
sinon.stub(fs, 'readFile').callsFake(async filePath => {
95100
throw new Error(`File not found: ${filePath}`);
96101
});
@@ -104,7 +109,9 @@ describe('checkForUpdates', () => {
104109

105110
assert.ok(spawnStub.calledOnce);
106111
assert.strictEqual(spawnStub.firstCall.args[0], process.execPath);
107-
assert.ok(spawnStub.firstCall.args[1][0]?.includes('check-latest-version.js'));
112+
assert.ok(
113+
spawnStub.firstCall.args[1][0]?.includes('check-latest-version.js'),
114+
);
108115
assert.ok(spawnStub.firstCall.args[1][1]?.includes('latest.json'));
109116
assert.strictEqual(spawnStub.firstCall.args[2]?.detached, true);
110117
assert.ok(unrefSpy.calledOnce);

0 commit comments

Comments
 (0)