Files
kuber/lib/context.ts
T

56 lines
1.4 KiB
TypeScript

import { AsyncLocalStorage } from "node:async_hooks";
import type { ComposeSpecification } from "../schema/docker.d";
import { getProject, throwWhen } from "./shared";
import { readCompose, resolveComposeFile } from "./yaml";
type AppContext = {
project: string;
cwd: string;
path(): Promise<string | undefined>;
compose(): Promise<ComposeSpecification>;
};
const appContext = new AsyncLocalStorage<AppContext>();
export function provideContext<T>(fn: () => T): T {
const cwd = process.cwd();
const path = createCachedGetter("composeFile", () => resolveComposeFile(cwd));
return appContext.run(
{
project: getProject(),
cwd,
path,
compose: createCachedGetter("compose", () =>
path()
.then(
throwWhen(
(path): path is undefined => path === undefined,
"Compose file cannot be found",
),
)
.then(readCompose),
),
},
fn,
);
}
export function ctx() {
const store = appContext.getStore();
if (!store) throw new Error("Not in context!");
return store;
}
const cache: Record<string, unknown> = {};
export function createCachedGetter<T>(
key: string,
fn: () => Promise<T>,
): () => Promise<T> {
return async () => {
if (key in cache) return cache[key] as T;
const result = await fn();
cache[key] = result;
return result;
};
}