@intlayer/chokidar
Version:
Uses chokidar to scan and build Intlayer declaration files into dictionaries based on Intlayer configuration.
93 lines (91 loc) • 2.79 kB
JavaScript
import { mkdir, readFile, stat, unlink, writeFile } from "node:fs/promises";
import { dirname } from "node:path";
import packageJson from "@intlayer/core/package.json" with { type: "json" };
//#region src/utils/runOnce.ts
const DEFAULT_RUN_ONCE_OPTIONS = { cacheTimeoutMs: 60 * 1e3 };
const writeSentinelFile = async (sentinelFilePath, currentTimestamp) => {
const data = {
version: packageJson.version,
timestamp: currentTimestamp
};
try {
await mkdir(dirname(sentinelFilePath), { recursive: true });
await writeFile(sentinelFilePath, JSON.stringify(data), { flag: "wx" });
} catch (err) {
if (err.code === "EEXIST") return;
if (err.code === "ENOENT") try {
await mkdir(dirname(sentinelFilePath), { recursive: true });
await writeFile(sentinelFilePath, JSON.stringify(data), { flag: "wx" });
return;
} catch (retryErr) {
if (retryErr.code === "EEXIST") return;
}
throw err;
}
};
/**
* Ensures a callback function runs only once within a specified time window across multiple processes.
* Uses a sentinel file to coordinate execution and prevent duplicate work.
*
* @param sentinelFilePath - Path to the sentinel file used for coordination
* @param callback - The function to execute (should be async)
* @param options - The options for the runOnce function
*
* @example
* ```typescript
* await runPrepareIntlayerOnce(
* '/tmp/intlayer-sentinel',
* async () => {
* // Your initialization logic here
* await prepareIntlayer();
* },
* 30 * 1000 // 30 seconds cache
* );
* ```
*
* @throws {Error} When there are unexpected filesystem errors
*/
const runOnce = async (sentinelFilePath, callback, options) => {
const { onIsCached, cacheTimeoutMs, forceRun } = {
...DEFAULT_RUN_ONCE_OPTIONS,
...options ?? {}
};
const currentTimestamp = Date.now();
try {
const sentinelAge = currentTimestamp - (await stat(sentinelFilePath)).mtime.getTime();
let shouldRebuild = Boolean(forceRun) || sentinelAge > cacheTimeoutMs;
if (!shouldRebuild) try {
const raw = await readFile(sentinelFilePath, "utf8");
let cachedVersion;
try {
cachedVersion = JSON.parse(raw).version;
} catch {
cachedVersion = void 0;
}
if (!cachedVersion || cachedVersion !== packageJson.version) shouldRebuild = true;
} catch {
shouldRebuild = true;
}
if (shouldRebuild) try {
await unlink(sentinelFilePath);
} catch {}
else {
await onIsCached?.();
return;
}
} catch (err) {
if (err.code === "ENOENT") {} else throw err;
}
await writeSentinelFile(sentinelFilePath, currentTimestamp);
try {
await callback();
await writeSentinelFile(sentinelFilePath, currentTimestamp);
} catch {
try {
await unlink(sentinelFilePath);
} catch {}
}
};
//#endregion
export { runOnce };
//# sourceMappingURL=runOnce.mjs.map