mikser-io 11.14.0 → 11.14.1
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 +1 -1
- package/src/instance.js +41 -8
package/package.json
CHANGED
package/src/instance.js
CHANGED
|
@@ -31,7 +31,8 @@ import { createHash } from 'node:crypto'
|
|
|
31
31
|
import { tmpdir } from 'node:os'
|
|
32
32
|
import path from 'node:path'
|
|
33
33
|
import { existsSync, unlinkSync } from 'node:fs'
|
|
34
|
-
import { chmod } from 'node:fs/promises'
|
|
34
|
+
import { chmod, stat } from 'node:fs/promises'
|
|
35
|
+
import { checksum } from './utils/index.js'
|
|
35
36
|
|
|
36
37
|
import runtime from './runtime.js'
|
|
37
38
|
import { onLoaded } from './lifecycle.js'
|
|
@@ -288,23 +289,55 @@ function configMismatch(theirs) {
|
|
|
288
289
|
// configCoverage lists every local module the config graph pulled in, so a
|
|
289
290
|
// stat over that list catches an edit to an imported module — which a
|
|
290
291
|
// client-side checksum of the entry file would miss entirely.
|
|
292
|
+
// Has a config file CHANGED since this instance started?
|
|
293
|
+
//
|
|
294
|
+
// Content, not mtime. A `git rebase`, `git checkout` or `rsync` rewrites a
|
|
295
|
+
// file with byte-identical content and a new mtime, and the instance then
|
|
296
|
+
// refused every forwarded command — "this instance's config changed on disk
|
|
297
|
+
// since it started" — while `git diff HEAD` reported nothing. Twice in one
|
|
298
|
+
// afternoon on one machine.
|
|
299
|
+
//
|
|
300
|
+
// On production the cost is not a restart. The config checksum is what the
|
|
301
|
+
// cache is stamped with, so a config the engine believes has moved buys a
|
|
302
|
+
// full cold re-derive of every asset, which is how a no-op rebase turns into
|
|
303
|
+
// twenty minutes of ffmpeg.
|
|
304
|
+
//
|
|
305
|
+
// mtime is kept as a PRE-FILTER, not as the answer: it is a stat against a
|
|
306
|
+
// read, and in the ordinary case nothing has moved and nothing is read. Only
|
|
307
|
+
// a file whose mtime shifted gets hashed, and only a file whose CONTENT
|
|
308
|
+
// shifted is reported. A file rewritten identically has its stamp refreshed
|
|
309
|
+
// so the next check is cheap again.
|
|
310
|
+
async function configFingerprint(file) {
|
|
311
|
+
try {
|
|
312
|
+
return { mtime: (await stat(file)).mtimeMs, hash: await checksum(file) }
|
|
313
|
+
} catch {
|
|
314
|
+
// Deleted, or unreadable. A stable sentinel, so a file that is still
|
|
315
|
+
// missing on the next check does not read as having changed again.
|
|
316
|
+
return { mtime: 0, hash: null }
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
291
320
|
export async function configStale() {
|
|
292
321
|
const covered = runtime.options.configCoverage?.files ?? []
|
|
293
322
|
if (!covered.length) return null
|
|
294
|
-
const { stat } = await import('node:fs/promises')
|
|
295
323
|
const stamps = runtime.options.configStamps
|
|
296
324
|
if (!stamps) {
|
|
297
325
|
// First call: record, do not judge. Nothing to compare against yet.
|
|
298
326
|
runtime.options.configStamps = Object.fromEntries(
|
|
299
|
-
await Promise.all(covered.map(async (file) =>
|
|
300
|
-
try { return [file, (await stat(file)).mtimeMs] } catch { return [file, 0] }
|
|
301
|
-
})))
|
|
327
|
+
await Promise.all(covered.map(async (file) => [file, await configFingerprint(file)])))
|
|
302
328
|
return null
|
|
303
329
|
}
|
|
304
330
|
for (const file of covered) {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
if (
|
|
331
|
+
const was = stamps[file]
|
|
332
|
+
const now = await configFingerprint(file)
|
|
333
|
+
if (was?.mtime === now.mtime) continue // nothing touched it
|
|
334
|
+
if (was?.hash === now.hash) {
|
|
335
|
+
// Touched and identical — a checkout, a rebase, a sync. Not a
|
|
336
|
+
// change, and re-stamped so this file is a stat again next time.
|
|
337
|
+
stamps[file] = now
|
|
338
|
+
continue
|
|
339
|
+
}
|
|
340
|
+
return file
|
|
308
341
|
}
|
|
309
342
|
return null
|
|
310
343
|
}
|