import { type SnapshotCommitInput, type SnapshotCommitResult, type SnapshotHydrateResult, type SnapshotProbe, type VersionedSnapshotStore } from "./snapshot-protocol.js"; declare const DEFAULT_SESSION_STATE_DIR: string; declare const DEFAULT_FILESYSTEM_STORE_DIR: string; /** Windows can briefly retain directory handles after recursive removal. */ export declare function renameDirectoryWithRetry(source: string, destination: string): Promise; export interface SessionMetadata { sessionId: string; dehydratedAt: string; worker: string; /** Compressed (stored) tar size in bytes. */ sizeBytes: number; /** Uncompressed tar-stream size in bytes (feeds the compression-ratio stat). */ rawSizeBytes?: number; /** Compression codec of the stored tar; absent = legacy gzip. */ codec?: SnapshotCodec; reason?: string; iteration?: number; [key: string]: unknown; } /** * `epoch` scopes every operation to one snapshot key family (see the epoch * key-scoping contract in snapshot-protocol.ts): absent/0 is the legacy * layout every pre-regen session keeps forever; >= 1 addresses that epoch's * own chain. The legacy (non-versioned) write paths only ever run for * epoch 0 — epoch chains are versioned-only and go through the * {@link VersionedSnapshotStore} methods. */ export interface SessionStateStore { dehydrate(sessionId: string, meta?: Record, epoch?: number): Promise; hydrate(sessionId: string, epoch?: number): Promise; checkpoint(sessionId: string, epoch?: number): Promise; getSnapshotSizeBytes(sessionId: string, epoch?: number): Promise; exists(sessionId: string, epoch?: number): Promise; /** With epoch >= 1 removes ONLY that epoch's chain; absent/0 removes the legacy family. */ delete(sessionId: string, epoch?: number): Promise; /** Remove the legacy family AND every epoch chain (real session deletion). */ deleteAllEpochs(sessionId: string): Promise; } export type ArtifactEncoding = "utf-8" | "base64"; export type ArtifactSource = "agent" | "user" | "system" | "file" | "copy"; export interface ArtifactMetadata { filename: string; sizeBytes: number; contentType: string; isBinary: boolean; uploadedAt: string; source: ArtifactSource; /** SHA-256 (hex) of the stored bytes. Absent only on legacy artifacts written before digests. */ sha256?: string; /** How the bytes arrived when source is "file" or "copy" (origin path / artifact ref). */ sourceDetail?: string; /** Pinned artifacts survive session cleanup (deleteArtifacts skips them by default). */ pinned?: boolean; } export interface ArtifactUploadOptions { encoding?: ArtifactEncoding; source?: ArtifactSource; sourceDetail?: string; pinned?: boolean; } export interface ArtifactDownloadResult extends ArtifactMetadata { body: Buffer; } export declare const TEXT_ARTIFACT_MAX_BYTES = 1048576; export declare function normalizeArtifactContentType(contentType?: string | null): string; export declare function isBinaryArtifactContentType(contentType?: string | null): boolean; export declare function getBinaryArtifactMaxBytes(): number; export declare function resolveArtifactUpload(content: string | Buffer, contentType?: string, opts?: ArtifactUploadOptions): Promise<{ body: Buffer; metadata: Omit; }>; export declare function getFileArtifactMaxBytes(): number; /** * Resolve metadata for a data-plane upload from a local file: size gate, * streamed SHA-256, and content-type sniffing from the head bytes. The * body is never buffered whole — stores stream the file themselves. */ export declare function resolveArtifactFileUpload(filePath: string, contentType?: string, opts?: ArtifactUploadOptions): Promise<{ metadata: Omit; }>; export type SnapshotCodec = "gzip" | "brotli"; export declare const DEFAULT_SNAPSHOT_CODEC: SnapshotCodec; /** Resolve the codec from a stored marker/metadata value; default gzip (legacy). */ export declare function resolveSnapshotCodec(value: unknown): SnapshotCodec; /** Filesystem epoch-chain tar: `S.e.v.tar.br`. */ export declare function epochVersionedTarFileName(sessionId: string, epoch: number, version: number): string; /** Filesystem epoch-chain meta: `S.e.meta.json` (worker-local only). */ export declare function epochMetaFileName(sessionId: string, epoch: number): string; /** * Fail-closed parse of an epoch-scoped snapshot object name. Epoch deletion * paths (`delete` with epoch, `deleteAllEpochs`) may remove ONLY names this * accepts — anything else under the `${sessionId}.e` prefix is logged and * left alone, so deletion can never touch a shape the stores did not write. */ export declare function parseEpochSnapshotName(sessionId: string, name: string): { epoch: number; version?: number; kind: "tar" | "meta"; } | null; declare function buildMetadata(tarPath: string, sessionId: string, meta?: Record): SessionMetadata; /** * Tar the session dir, compress with `codec`, and write to `tarPath`. * Returns `rawSizeBytes` (the uncompressed tar-stream length — a free * by-product of the pipeline, and the right "uncompressed snapshot size" * for compression-ratio stats) and the codec used. * * Excludes: live `inuse..lock` (scoped to a dead SDK process), and the * lifecycle-protocol marker + sentinel (the marker describes the dir * relative to the store; the sentinel is a local dirty flag). The * `.ps-turn-commit.json` file IS included so already-committed recovery can * read the turn result out of the tar. */ declare function archiveSessionDir(sessionStateDir: string, sessionId: string, tarPath: string, codec?: SnapshotCodec): Promise<{ rawSizeBytes: number; codec: SnapshotCodec; }>; declare function extractSessionArchive(sessionStateDir: string, tarPath: string, codec?: SnapshotCodec): Promise; /** * Backwards-compatible wrapper kept for callers that historically expected an * async, polling readiness check. Today this is a single-shot probe; the * arguments other than `sessionStateDir` and `sessionId` are accepted but * ignored, intentionally — see {@link checkSessionSnapshot} for rationale. */ declare function waitForSessionSnapshot(sessionStateDir: string, sessionId: string, _timeoutMs?: number, _pollMs?: number, _stablePolls?: number): Promise<{ ready: boolean; missing: string[]; }>; export declare class FilesystemSessionStore implements SessionStateStore, VersionedSnapshotStore { private storeDir; private sessionStateDir; constructor(storeDir?: string, sessionStateDir?: string); private tarPath; private metaPath; private casLockDir; private withCasLock; private readStoredMeta; /** Codec of the currently stored snapshot (default gzip for legacy). */ private storedCodec; /** The tar the current meta points at: version-named or the legacy path. */ private currentTarPath; private probeUnlocked; probeSnapshot(sessionId: string, epoch?: number): Promise; commitSnapshot(sessionId: string, input: SnapshotCommitInput, epoch?: number): Promise; hydrateSnapshot(sessionId: string, epoch?: number): Promise; /** * True when the store holds a VERSIONED snapshot for this session. The * legacy write paths below must never clobber one: the versioned chain * is CAS-protected truth that another worker may have advanced, and an * unconditional legacy overwrite would both destroy the version * metadata and potentially roll the content back (review findings: * unfenced-legacy-write class). */ private hasVersionedSnapshot; dehydrate(sessionId: string, meta?: Record, epoch?: number): Promise; hydrate(sessionId: string, epoch?: number): Promise; checkpoint(sessionId: string, epoch?: number): Promise; getSnapshotSizeBytes(sessionId: string, epoch?: number): Promise; exists(sessionId: string, epoch?: number): Promise; delete(sessionId: string, epoch?: number): Promise; deleteAllEpochs(sessionId: string): Promise; /** * Unlink epoch-chain objects (tars + meta), optionally narrowed to one * epoch. Enumerates the `${sessionId}.e` prefix and removes ONLY names * the fail-closed parser accepts; anything else is logged and left * alone. Enumeration (not meta-directed deletion) also collects orphan * version tars left by a crash between tar rename and meta rename. */ private deleteEpochObjects; } /** * Interface for artifact (file) storage. * Implemented by both SessionBlobStore (Azure Blob) and FilesystemArtifactStore (local disk). */ export interface ArtifactStore { uploadArtifact(sessionId: string, filename: string, content: string | Buffer, contentType?: string, opts?: ArtifactUploadOptions): Promise; /** Data-plane write: stream a local file into the store without buffering the whole body. */ uploadArtifactFromFile(sessionId: string, filename: string, filePath: string, contentType?: string, opts?: ArtifactUploadOptions): Promise; /** Data-plane copy between sessions; bytes never leave the store process. */ copyArtifact(fromSessionId: string, fromFilename: string, toSessionId: string, toFilename?: string, opts?: ArtifactUploadOptions): Promise; downloadArtifact(sessionId: string, filename: string): Promise; downloadArtifactText(sessionId: string, filename: string): Promise; statArtifact(sessionId: string, filename: string): Promise; listArtifacts(sessionId: string): Promise; setArtifactPinned(sessionId: string, filename: string, pinned: boolean): Promise; deleteArtifact(sessionId: string, filename: string): Promise; artifactExists(sessionId: string, filename: string): Promise; } declare const DEFAULT_ARTIFACT_DIR: string; /** * Filesystem-based artifact store for local mode (no Azure Blob). * Stores artifacts as plain files under `//`. * @internal */ export declare class FilesystemArtifactStore implements ArtifactStore { private artifactDir; constructor(artifactDir?: string); private safePath; private metadataPath; private writeFileAtomic; private readStoredMetadata; private buildMetadata; uploadArtifact(sessionId: string, filename: string, content: string | Buffer, contentType?: string, opts?: ArtifactUploadOptions): Promise; downloadArtifact(sessionId: string, filename: string): Promise; downloadArtifactText(sessionId: string, filename: string): Promise; listArtifacts(sessionId: string): Promise; deleteArtifact(sessionId: string, filename: string): Promise; artifactExists(sessionId: string, filename: string): Promise; statArtifact(sessionId: string, filename: string): Promise; uploadArtifactFromFile(sessionId: string, filename: string, filePath: string, contentType?: string, opts?: ArtifactUploadOptions): Promise; copyArtifact(fromSessionId: string, fromFilename: string, toSessionId: string, toFilename?: string, opts?: ArtifactUploadOptions): Promise; setArtifactPinned(sessionId: string, filename: string, pinned: boolean): Promise; } export { DEFAULT_ARTIFACT_DIR, DEFAULT_FILESYSTEM_STORE_DIR, DEFAULT_SESSION_STATE_DIR, archiveSessionDir, buildMetadata, extractSessionArchive, waitForSessionSnapshot, }; //# sourceMappingURL=session-store.d.ts.map