Files
kuber/lib/context.ts
T

57 lines
1.3 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;
}
export function createCachedGetter<T>(
_key: string,
fn: () => Promise<T>,
): () => Promise<T> {
let cached: Promise<T> | undefined;
return () => {
cached ??= fn().catch((error) => {
cached = undefined;
throw error;
});
return cached;
};
}