55 lines
1.8 KiB
TypeScript
55 lines
1.8 KiB
TypeScript
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
import { existsSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
|
|
export interface Cache {
|
|
get(key: string): Promise<Uint8Array | undefined>;
|
|
put(key: string, value: Uint8Array, options?: { ttl?: number }): Promise<void>;
|
|
delete(key: string): Promise<void>;
|
|
}
|
|
|
|
export interface CloudflareCacheLike {
|
|
match(request: Request): Promise<Response | undefined>;
|
|
put(request: Request, response: Response): Promise<void>;
|
|
delete(request: Request): Promise<boolean>;
|
|
}
|
|
|
|
function cacheKey(key: string): string {
|
|
return encodeURIComponent(key);
|
|
}
|
|
|
|
export function filesystemCache(dir: string): Cache {
|
|
return {
|
|
async get(key) {
|
|
const path = join(dir, cacheKey(key));
|
|
if (!existsSync(path)) return undefined;
|
|
return new Uint8Array(await readFile(path));
|
|
},
|
|
async put(key, value) {
|
|
await mkdir(dir, { recursive: true });
|
|
const path = join(dir, cacheKey(key));
|
|
const staged = `${path}.next`;
|
|
await writeFile(staged, value);
|
|
await rename(staged, path);
|
|
},
|
|
async delete(key) {
|
|
const path = join(dir, cacheKey(key));
|
|
if (existsSync(path)) await rename(path, `${path}.deleted`);
|
|
},
|
|
};
|
|
}
|
|
|
|
export function cloudflareCache(cache: CloudflareCacheLike, origin = "https://muddle.cache"): Cache {
|
|
const request = (key: string) => new Request(new URL(`/${encodeURIComponent(key)}`, origin).toString());
|
|
return {
|
|
async get(key) {
|
|
const response = await cache.match(request(key));
|
|
return response ? new Uint8Array(await response.arrayBuffer()) : undefined;
|
|
},
|
|
async put(key, value, options) {
|
|
const headers = options?.ttl ? { "cache-control": `max-age=${options.ttl}` } : undefined;
|
|
await cache.put(request(key), new Response(value, { headers }));
|
|
},
|
|
async delete(key) { await cache.delete(request(key)); },
|
|
};
|
|
}
|