1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
import { FileStorage } from "@flystorage/file-storage";
import { LocalStorageAdapter } from "@flystorage/local-fs";
import fs from "fs/promises";
import { Log } from "../util/log";
import { App } from "../app";
import { AppPath } from "../app/path";
import { Bus } from "../bus";
import z from "zod/v4";
export namespace Storage {
const log = Log.create({ service: "storage" });
export const Event = {
Write: Bus.event(
"storage.write",
z.object({ key: z.string(), body: z.any() }),
),
};
const state = App.state("storage", async () => {
const app = await App.use();
const storageDir = AppPath.storage(app.root);
await fs.mkdir(storageDir, { recursive: true });
const storage = new FileStorage(new LocalStorageAdapter(storageDir));
log.info("created", { path: storageDir });
return {
storage,
};
});
function expose<T extends keyof FileStorage>(key: T) {
const fn = FileStorage.prototype[key];
return async (
...args: Parameters<typeof fn>
): Promise<ReturnType<typeof fn>> => {
const { storage } = await state();
const match = storage[key];
// @ts-ignore
return match.call(storage, ...args);
};
}
export const write = expose("write");
export const read = expose("read");
export const list = expose("list");
export const readToString = expose("readToString");
export async function readJSON<T>(key: string) {
const data = await readToString(key + ".json");
return JSON.parse(data) as T;
}
export async function writeJSON<T>(key: string, data: T) {
Bus.publish(Event.Write, { key, body: data });
const json = JSON.stringify(data);
await write(key + ".json", json);
}
}
|