import fs from "fs/promises" import { AppPath } from "./path" import { Log } from "../util/log" import { Context } from "../util/context" export namespace App { const log = Log.create({ service: "app" }) export type Info = Awaited> const ctx = Context.create("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("created", { path: dataDir }) const services = new Map< any, { state: any shutdown?: (input: any) => Promise } >() const result = { get services() { return services }, get root() { return input.directory }, } return result } export function state( key: any, init: (app: Info) => State, shutdown?: (state: Awaited) => Promise, ) { 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 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 }) } }