import { type DeviceArtifactKind, type DeviceCapabilityId } from './device-capability-contract.js'; import { type DevicePolicySource } from './device-policy-source.js'; /** Index row for one retained capture. */ export interface DeviceCaptureArtifact { readonly id: string; readonly nodeId: string; readonly capabilityId: DeviceCapabilityId; readonly kind: DeviceArtifactKind; readonly mediaType: string; readonly fileName: string; readonly byteLength: number; /** Digest written with the record; re-checked on every read and every sweep. */ readonly sha256: string; readonly capturedAt: number; readonly expiresAt: number; readonly workId?: string | undefined; readonly reason?: string | undefined; } export type DeviceArtifactRemovalReason = 'expired' | 'file-missing' | 'content-mismatch' | 'orphan-file' | 'malformed' | 'count-cap'; export interface DeviceArtifactRemoval { readonly artifactId: string; readonly nodeId: string; readonly capabilityId: string; readonly fileName: string; readonly reason: DeviceArtifactRemovalReason; readonly removedAt: number; readonly byteLength: number; } export interface DeviceArtifactSweepReport { readonly sweptAt: number; readonly removed: readonly DeviceArtifactRemoval[]; readonly retained: number; readonly bytesReclaimed: number; } export interface DeviceArtifactPolicy { /** Age TTL for a capture. Default 24h per the owner ruling. */ readonly retentionMs: number; /** Count cap; oldest captures past the cap are reaped even inside the TTL. */ readonly maxArtifacts: number; } export declare const DEFAULT_DEVICE_ARTIFACT_POLICY: DeviceArtifactPolicy; export interface DeviceCaptureStoreOptions { /** * Fixed retention and cap, or a resolver read at every use so a live settings * change applies without a restart (see device-policy-source.ts). */ readonly policy?: DevicePolicySource | undefined; readonly now?: (() => number) | undefined; } /** Read outcome: either verified bytes, or an honest reason they are gone. */ export type DeviceArtifactReadResult = { readonly ok: true; readonly artifact: DeviceCaptureArtifact; readonly bytes: Uint8Array; } | { readonly ok: false; readonly reason: 'not-found' | 'expired' | 'file-missing' | 'content-mismatch'; }; /** Retained captures: bytes under `directory`, index beside them. */ export declare class DeviceCaptureArtifactStore { private readonly directory; private readonly index; private readonly resolvePolicy; private readonly now; private writeChain; constructor(directory: string, options?: DeviceCaptureStoreOptions); /** Retention and cap in force right now (re-read when given a resolver). */ getPolicy(): DeviceArtifactPolicy; getDirectory(): string; private readWithDrops; private mutate; /** Live (unexpired) capture records, newest first. */ list(nodeId?: string): Promise; /** * Retain bytes from a capture. * * The bytes are written FIRST and the index row second, so a crash between * the two leaves an orphan file (reaped as 'orphan-file') rather than an * index row pointing at nothing that a later read would trust. */ retain(input: { readonly nodeId: string; readonly capabilityId: DeviceCapabilityId; readonly kind: DeviceArtifactKind; readonly mediaType: string; readonly bytes: Uint8Array; readonly workId?: string | undefined; readonly reason?: string | undefined; readonly ttlMs?: number | undefined; }): Promise; /** Absolute path of a retained capture's bytes. */ pathFor(artifact: DeviceCaptureArtifact): string; /** * Read a capture back, re-hashing the bytes before returning them. A record * that no longer matches its digest is reaped on the spot rather than served. */ read(artifactId: string): Promise; /** * One housekeeping pass over records AND bytes. Idempotent and concurrency * safe: it recomputes every removal from what it just read, and deleting an * already-deleted file is tolerated. */ sweep(): Promise; } //# sourceMappingURL=device-capture-artifacts.d.ts.map