import { ManifestStore, TableName } from "../storage.mjs"; interface R2ObjectMetadata { etag: string; } interface R2ObjectBody extends R2ObjectMetadata { text: () => Promise; } interface R2ListResult { objects: Array<{ key: string; }>; truncated: boolean; cursor?: string; } interface R2ConditionalPutOptions { /** * Workers-binding-style precondition. `etagMatches` rejects with `null` * return on mismatch; `etagDoesNotMatch: '*'` rejects if the key exists. */ onlyIf?: { etagMatches?: string; etagDoesNotMatch?: string; }; } /** * Minimal Cloudflare R2 binding shape needed for the manifest CAS loop. * Structurally compatible with Cloudflare's `R2Bucket` Workers API. */ interface R2ManifestBucketLike { get: (key: string) => Promise; put: (key: string, bytes: string | Uint8Array, options?: R2ConditionalPutOptions) => Promise; list: (options?: { prefix?: string; cursor?: string; limit?: number; }) => Promise; /** * Bulk delete. Required by {@link ManifestStore.purgeTenant}. Cloudflare's * `R2Bucket.delete` accepts a single key or a string[] batch; both shapes * work here. */ delete: (keys: string | string[]) => Promise; } /** * CAS lifecycle events emitted by the manifest store. Consumers wire these * into metrics (prom-client, console.table, the contention harness) to * measure rejection rate and latency under real R2 load. */ type R2ManifestEvent = { kind: 'cas-attempt'; siteId: string; table: TableName; attempt: number; } | { kind: 'cas-rejected'; siteId: string; table: TableName; attempt: number; } | { kind: 'cas-committed'; siteId: string; table: TableName; attempts: number; }; interface CreateR2ManifestStoreOptions { bucket: R2ManifestBucketLike; /** Tenant scope. All shard keys are prefixed `u_/manifest/...`. */ userId: string; /** Override the snapshot version-id generator. Defaults to `${ts}-${random}`. */ newSnapshotId?: () => string; now?: () => number; /** Maximum CAS retries before giving up. Defaults to 8. */ maxRetries?: number; /** * Optional telemetry hook. Fired synchronously from the CAS loop on each * attempt, rejection, and successful commit. Must not throw; exceptions * propagate and will fail the mutation. */ onEvent?: (event: R2ManifestEvent) => void; } declare function createR2ManifestStore(opts: CreateR2ManifestStoreOptions): ManifestStore; export { CreateR2ManifestStoreOptions, R2ManifestBucketLike, R2ManifestEvent, createR2ManifestStore };