import { randomUUID } from "node:crypto"; import { constants } from "node:fs"; import { open as openFile, rename as renameFile, rm as removeFile, } from "node:fs/promises"; import path from "node:path"; import type { z } from "zod"; export type ValidatedJsonArtifactInput = Readonly<{ path: string; schema: z.ZodType; value: unknown; }>; export function serializeValidatedJsonArtifact( input: ValidatedJsonArtifactInput, ): Buffer { const parsed = input.schema.parse(input.value); const serialized = JSON.stringify(parsed, null, 2); if (serialized === undefined) { throw new TypeError("Validated JSON artifact is not serializable"); } return Buffer.from(`${serialized}\n`, "utf8"); } export type ValidatedJsonArtifactFileSystem = Readonly<{ open: (path: string, flags: number, mode: number) => Promise<{ writeFile(data: string, encoding: "utf8"): Promise; sync(): Promise; close(): Promise; }>; openDirectory: (path: string) => Promise<{ sync(): Promise; close(): Promise; }>; rename: (source: string, destination: string) => Promise; rm: (path: string, options: Readonly<{ force: true }>) => Promise; }>; type ValidatedJsonArtifactWriterDependencies = Readonly<{ createNonce?: () => string; fileSystem?: ValidatedJsonArtifactFileSystem; }>; const defaultFileSystem: ValidatedJsonArtifactFileSystem = Object.freeze({ open: async (target, flags, mode) => openFile(target, flags, mode), openDirectory: async (target) => openFile(target, constants.O_RDONLY), rename: async (source, destination) => renameFile(source, destination), rm: async (target, options) => removeFile(target, options), }); function hasErrorCode(error: unknown, code: string): boolean { return ( typeof error === "object" && error !== null && "code" in error && error.code === code ); } /** * Builds a writer whose only publish operation is an atomic sibling rename. * Dependency injection is limited to the file-system boundary so failure * ownership can be verified without exposing a caller-selected cleanup path. */ export function createValidatedJsonArtifactWriter( dependencies: ValidatedJsonArtifactWriterDependencies = {}, ) { const createNonce = dependencies.createNonce ?? randomUUID; const fileSystem = dependencies.fileSystem ?? defaultFileSystem; return async function writeArtifact( input: ValidatedJsonArtifactInput, ): Promise { const serialized = serializeValidatedJsonArtifact(input); const temporaryPath = path.join( path.dirname(input.path), `.${path.basename(input.path)}.${createNonce()}.tmp`, ); let ownsTemporaryFile = false; try { const handle = await fileSystem.open( temporaryPath, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600, ); ownsTemporaryFile = true; let writeFailed = false; let writeFailure: unknown; try { await handle.writeFile(serialized.toString("utf8"), "utf8"); await handle.sync(); } catch (error) { writeFailed = true; writeFailure = error; } let closeFailed = false; let closeFailure: unknown; try { await handle.close(); } catch (error) { closeFailed = true; closeFailure = error; } if (writeFailed) throw writeFailure; if (closeFailed) throw closeFailure; await fileSystem.rename(temporaryPath, input.path); ownsTemporaryFile = false; const directoryHandle = await fileSystem.openDirectory( path.dirname(input.path), ); try { try { await directoryHandle.sync(); } catch (error) { if (!hasErrorCode(error, "EINVAL") && !hasErrorCode(error, "ENOTSUP")) { throw error; } } } finally { await directoryHandle.close(); } } catch (error) { if (ownsTemporaryFile) { try { await fileSystem.rm(temporaryPath, { force: true }); } catch { // Preserve the publishing failure; cleanup is confined to our nonce. } } throw error; } }; } export const writeValidatedJsonArtifact = createValidatedJsonArtifactWriter();