Files
tf_code/js/src/app/index.ts
Dax Raad b840a40759 sync
2025-05-26 21:44:55 -04:00

87 lines
2.0 KiB
TypeScript

import fs from "node:fs/promises";
import { AppPath } from "./path";
import { Log } from "../util/log";
import { Context } from "../util/context";
import { Config } from "./config";
export namespace App {
const log = Log.create({ service: "app" });
export type Info = Awaited<ReturnType<typeof create>>;
const ctx = Context.create<Info>("app");
async function create(input: { directory: string }) {
const dataDir = AppPath.data(input.directory);
await fs.mkdir(dataDir, { recursive: true });
await Log.file(input.directory);
log.info("creating");
const config = await Config.load(input.directory);
log.info("created", { path: dataDir });
const services = new Map<
any,
{
state: any;
shutdown?: (input: any) => Promise<void>;
}
>();
const result = {
get services() {
return services;
},
get config() {
return config;
},
get root() {
return input.directory;
},
};
return result;
}
export function state<State>(
key: any,
init: (app: Info) => State,
shutdown?: (state: Awaited<State>) => Promise<void>,
) {
return () => {
const app = ctx.use();
const services = app.services;
if (!services.has(key)) {
log.info("registering service", { name: key });
services.set(key, {
state: init(app),
shutdown: shutdown,
});
}
return services.get(key)?.state as State;
};
}
export async function use() {
return ctx.use();
}
export async function provide<T extends (app: Info) => any>(
input: { directory: string },
cb: T,
) {
const app = await create(input);
return ctx.provide(app, async () => {
const result = await cb(app);
for (const [key, entry] of app.services.entries()) {
log.info("shutdown", { name: key });
await entry.shutdown?.(await entry.state);
}
return result;
});
}
}