import path from 'path'; import * as fse from 'fs-extra'; export interface FileCacheInterface { get(key: string): Promise; set(key: string, value: unknown): Promise; remove(key: string): Promise; } export class FileCache implements FileCacheInterface { private readonly dirPath: string; private readonly keyPrefix: string; constructor({ dirPath, keyPrefix }: { dirPath: string; keyPrefix?: string }) { this.dirPath = dirPath; this.keyPrefix = keyPrefix ?? ''; } async get(key: string): Promise { const fileName = this.filePathKey(key); try { const exists = await fse.pathExists(fileName); if (!exists) { return; } return fse.readJson(fileName); } catch (error) { return; } } async set(key: string, value: unknown): Promise { const fileName = this.filePathKey(key); try { return fse.outputJson(fileName, value); } catch (error) { return; } } async remove(key: string): Promise { const fileName = this.filePathKey(key); try { return await fse.remove(fileName); } catch (error) { return; } } private filePathKey(key: string) { return path.join(this.dirPath, normalizePath(`${this.keyPrefix}${key}.json`)); } } /** * Normalizes path component by removing windows illegal characters */ function normalizePath(pathComponent: string) { return pathComponent.replace(/[:<>=?$!@+|]+/g, '-'); } /** * This no-op file cache is used to replace FileCache when Stackbit runs in Cloud. */ export class NoopFileCache implements FileCacheInterface { async get(): Promise { return; } async set(): Promise { return; } async remove(): Promise { return; } }