import { isRegisteredArtifactStack } from "./stacks.ts"; import type { ArtifactManifest, ArtifactRenderStatus, ArtifactStack, } from "./types.ts"; export interface CreateManifestInput { id: string; title: string; stack: ArtifactStack; entry: string; cwd: string; now?: Date; sessionFile?: string; sessionKey?: string; } export function createManifest(input: CreateManifestInput): ArtifactManifest { const timestamp = (input.now ?? new Date()).toISOString(); return { id: input.id, title: input.title, stack: input.stack, entry: input.entry, created: timestamp, updated: timestamp, cwd: input.cwd, ...(input.sessionFile ? { sessionFile: input.sessionFile } : {}), ...(input.sessionKey ? { sessionKey: input.sessionKey } : {}), }; } export function isArtifactManifest(value: unknown): value is ArtifactManifest { if (!value || typeof value !== "object") { return false; } const candidate = value as Record; return ( typeof candidate.id === "string" && typeof candidate.title === "string" && typeof candidate.stack === "string" && isRegisteredArtifactStack(candidate.stack) && typeof candidate.entry === "string" && typeof candidate.created === "string" && typeof candidate.updated === "string" && typeof candidate.cwd === "string" && (candidate.sessionFile === undefined || typeof candidate.sessionFile === "string") && (candidate.sessionKey === undefined || typeof candidate.sessionKey === "string") && (candidate.lastRender === undefined || isArtifactRenderStatus(candidate.lastRender)) ); } function isArtifactRenderStatus(value: unknown): value is ArtifactRenderStatus { if (!value || typeof value !== "object") { return false; } const candidate = value as Record; return ( typeof candidate.ok === "boolean" && typeof candidate.warnings === "number" && Number.isInteger(candidate.warnings) && candidate.warnings >= 0 && typeof candidate.errors === "number" && Number.isInteger(candidate.errors) && candidate.errors >= 0 && typeof candidate.rendered === "string" && optionalStringArray(candidate.warningCodes) && optionalStringArray(candidate.errorCodes) ); } function optionalStringArray(value: unknown): boolean { return ( value === undefined || (Array.isArray(value) && value.every((entry) => typeof entry === "string")) ); }