/** Serialization Paseo itself produces. Verified byte-identical against the live config. */ export declare function serializeJson(value: unknown): string; export declare function hashBytes(bytes: string): string; /** Marker recorded when a target did not exist at preflight. */ export declare const ABSENT_IDENTITY = "absent"; export type PublishRefusal = { readonly reason: "parse-refusal"; readonly detail: string; } | { readonly reason: "format-drift"; readonly detail: string; } | { readonly reason: "cas-conflict"; readonly expected: string; readonly actual: string; }; export declare class PaseoPublishError extends Error { readonly refusal: PublishRefusal; readonly targetPath: string; constructor(targetPath: string, refusal: PublishRefusal); } export interface ReadTargetResult { readonly exists: boolean; /** Raw bytes as read, or `""` when absent. */ readonly raw: string; /** Hash of `raw`, or `ABSENT_IDENTITY` when absent. */ readonly identity: string; /** Parsed object; `{}` when absent. */ readonly parsed: Record; } /** * Read and validate a target without writing anything. * * Throws `PaseoPublishError` on unparseable JSON or on a formatting mismatch, * so callers never have to decide whether a file is safe to touch. */ export declare function readTarget(targetPath: string): Promise; export interface PublishPlan { /** Bytes that will be published. */ readonly nextRaw: string; /** Hash of `nextRaw` -- the expected post-publish identity, computable before any rename. */ readonly expectedIdentity: string; /** True when the mutation produced no change and publication can be skipped. */ readonly unchanged: boolean; } /** * Apply `mutate` to a validated read and compute the exact bytes to publish. * * Split out from {@link publishPlan} so the install saga can record the expected * post-publish identity in its durable intent BEFORE anything is written. */ export declare function planPublish(current: ReadTargetResult, mutate: (draft: Record) => void): PublishPlan; export interface PublishOptions { /** Identity the target must still carry at publication time. */ readonly expectedIdentity: string; /** Take a mode-0600 backup beside the original before replacing it. */ readonly backup: boolean; readonly now: Date; } export interface PublishResult { readonly published: boolean; readonly backupPath?: string; readonly identity: string; } /** * Publish `plan.nextRaw` to `targetPath` under a compare-and-swap on * `options.expectedIdentity`. * * The CAS is re-read immediately before the rename, which is the narrowest * window GJC can achieve. It does not defend against Paseo re-writing the file * later from its own stale in-memory copy -- Paseo exposes no lock or version * API, so that remains a documented residual risk detected by `--check`. */ export declare function publishPlan(targetPath: string, plan: PublishPlan, options: PublishOptions): Promise; /** Current on-disk identity, or {@link ABSENT_IDENTITY} when the file does not exist. */ export declare function currentIdentity(targetPath: string): Promise;