Luigit
repositories / pi-ext

pi-ext

bugabingas pi extensions

owned by admin

extensions/web/store.ts

Raw
import { createHash, randomUUID } from "node:crypto";
import { mkdir, writeFile } from "node:fs/promises";
import { homedir } from "node:os";
import path from "node:path";

export interface StateDirOptions {
	platform?: NodeJS.Platform;
	env?: NodeJS.ProcessEnv;
	home?: string;
}

export interface SavedJsonResult {
	namespace: string;
	responseId: string;
	fullOutputPath: string;
	byteLength: number;
}

export function platformStateDir(
	platform: NodeJS.Platform = process.platform,
	env: NodeJS.ProcessEnv = process.env,
	home = homedir(),
): string {
	const paths = platform === "win32" ? path.win32 : path.posix;
	// Treat XDG_STATE_HOME as an explicit override for hermetic tests/CI,
	// even on platforms where it is not the native convention.
	if (env.XDG_STATE_HOME) return paths.join(env.XDG_STATE_HOME, "pi");
	if (platform === "win32")
		return paths.join(
			env.LOCALAPPDATA ?? paths.join(home, "AppData", "Local"),
			"pi",
		);
	if (platform === "darwin")
		return paths.join(home, "Library", "Application Support", "pi");
	return paths.join(home, ".local", "state", "pi");
}

export function projectStoreDir(
	namespace: string,
	cwd: string,
	options: StateDirOptions = {},
): string {
	const paths = pathModule(options.platform);
	return paths.join(
		platformStateDir(options.platform, options.env, options.home),
		namespace,
		hash(cwd),
	);
}

export async function saveJsonResult(
	namespace: string,
	cwd: string,
	value: unknown,
	options: StateDirOptions = {},
): Promise<SavedJsonResult> {
	const responseId = randomUUID();
	const paths = pathModule(options.platform);
	const dir = paths.join(projectStoreDir(namespace, cwd, options), "results");
	await mkdir(dir, { recursive: true, mode: 0o700 });
	const fullOutputPath = paths.join(dir, `${responseId}.json`);
	const body = `${JSON.stringify(value, null, 2)}\n`;
	await writeFile(fullOutputPath, body, { mode: 0o600 });
	return {
		namespace,
		responseId,
		fullOutputPath,
		byteLength: Buffer.byteLength(body),
	};
}

function pathModule(platform: NodeJS.Platform = process.platform) {
	return platform === "win32" ? path.win32 : path.posix;
}

function hash(input: string): string {
	return createHash("sha256").update(input).digest("hex");
}