/** * `vault.exportBlobs()` — bulk blob extraction primitive. * * Async-iterable handle over every blob attached to records in a * vault, optionally filtered by collection allowlist and per-record * predicate. Emits tuples of `{ blobId, recordRef, bytes, meta }` so * the consumer can pipe into any sink (zip stream, S3 multipart, USB * copy, cold-storage tape) without pulling the whole export into * memory. * * ## Auth + audit * * - Capability check runs **once** at handle creation via * `Vault.assertCanExport('plaintext', 'blob')`. An operator whose * keyring lacks that bit fails before a single byte of ciphertext * is decrypted. * - Audit entry lands in `_export_audit` at handle creation: the * actor, start timestamp, target collections, predicate presence, * and batch mechanism. **No content hashes** — per the spec * non-correlation invariant. * * ## Abort + resume * * - `handle.abort()` flips the internal signal; the next iteration * boundary throws `AbortError`. Consumers already in `for await` * can catch and exit cleanly. * - Restart after a partial failure with `{ afterBlobId }` — the * iterator skips tuples up to (and including) that blob id before * yielding again. Combined with a blob-count ceiling it supports * idempotent batch re-runs. * * @module */ import type { Collection } from '../../kernel/collection.js'; export interface ExportBlobsOptions { /** * Collection allowlist. Omit to export blobs from every collection * the caller has read access to. */ readonly collections?: readonly string[]; /** * Per-record predicate. Called on the decrypted record BEFORE any * blob bytes are read for that record — returning false skips the * record and all its slots without touching their chunks. */ readonly where?: (record: unknown, context: { collection: string; id: string; }) => boolean; /** * Resume after a specific blob id. The iterator skips tuples up to * and including this id, then yields. Format of the id is the same * as `ExportedBlob.blobId` (the HMAC-keyed eTag). */ readonly afterBlobId?: string; /** * External abort signal. When fired, the next iterator tick throws * `ExportBlobsAbortedError`. Honored alongside `handle.abort()`. */ readonly signal?: AbortSignal; } export interface ExportedBlob { /** Opaque blob identifier — HMAC-keyed eTag, stable across vaults. */ readonly blobId: string; /** Where this blob came from in the vault. */ readonly recordRef: { readonly collection: string; readonly id: string; readonly slot: string; }; /** Decrypted plaintext bytes. */ readonly bytes: Uint8Array; /** Best-effort metadata (from the blob slot record). */ readonly meta: { readonly size: number; /** * User-visible filename stored on the slot. Often equal to the * slot name; differs when the caller supplied an explicit * `filename` to `BlobSet.put()`. */ readonly filename: string; readonly mimeType?: string; readonly createdAt?: string; }; } export interface ExportBlobsHandle extends AsyncIterable { /** Abort the export. Safe to call multiple times. */ abort(): void; /** True once `abort()` has fired or the external signal aborted. */ readonly aborted: boolean; } export declare class ExportBlobsAbortedError extends Error { constructor(reason: string); } export declare const EXPORT_AUDIT_COLLECTION = "_export_audit"; export interface ExportBlobsAuditEntry { readonly id: string; readonly mechanism: 'exportBlobs'; readonly actor: string; readonly startedAt: string; readonly collections: readonly string[] | null; readonly predicate: boolean; readonly afterBlobId: string | null; } /** * Build the handle. Factored out of `Vault.exportBlobs` so the * implementation can be unit-tested without going through the * compartment lifecycle. */ export declare function createExportBlobsHandle(actor: string, listAccessibleCollections: () => Promise, getCollection: (name: string) => Collection, writeAudit: (entry: ExportBlobsAuditEntry) => Promise, options: ExportBlobsOptions): ExportBlobsHandle;