# storage-adapter / persister _(no submodules)_ ## Purpose Bridges `@suaveplan/storage` `AbstractStorage` onto the queue's `ChunkPersister` contract. Persistence enables resuming an interrupted transfer: every received chunk is written through to a key-value backend (IndexedDB in browsers, file-backed stores on the server) keyed by `file::chunk:` so a fresh queue with the same `fileId` can hydrate via `loadAllChunks`. ## Features - Deterministic key layout (`chunkStorageKey`, `chunkStoragePrefix`). - Persists chunk bytes alongside the metadata via the storage backend's optional `metadata` slot. - Loads a single chunk or lists every persisted chunk id for the configured `fileId`, in ascending order. - Structural `ChunkStorageLike` view so tests can substitute a Map. ## Usage: Basic ```ts import { MemoryStorage } from "@suaveplan/storage"; import { StorageChunkPersister } from "@suaveplan/streams-chunk-queue"; const storage = new MemoryStorage(); const persister = new StorageChunkPersister({ storage, fileId: 12345n }); ``` ## Usage: Advanced ```ts import { IndexedDBStorage } from "@suaveplan/storage"; const storage = await IndexedDBStorage.open("downloads", "chunks"); const persister = new StorageChunkPersister({ storage, fileId: 12345n, }); const queue = new StreamingChunkQueue({ fileId: 12345n, totalChunks: 100n, persister, }); await queue.loadAllChunks(); ``` ## API Reference ### `chunkStorageKey(fileId, chunkId)` → `string` `file::chunk:`. ### `chunkStoragePrefix(fileId)` → `string` `file::chunk:`. ### `ChunkPersister` ```ts interface ChunkPersister { persist(chunk: StoredChunk): Promise; load(chunkId: bigint): Promise; listChunkIds(): Promise; } ``` ### `StorageChunkPersister` ```ts new StorageChunkPersister({ storage, fileId }); ``` Implements `ChunkPersister` over any `ChunkStorageLike`. `listChunkIds` filters by prefix, parses the trailing segment as `bigint`, and sorts ascending — the ordering means `StreamingChunkQueue.loadAllChunks` ingests in the canonical chunk order. ## Implementation Notes `BigInt` is converted to `string` before being stored in storage metadata so the JSON wire form is portable. The persister does NOT attempt to delete entries — chunks are durable until the consumer explicitly clears the underlying storage. Keys with an empty trailing segment (`file:7:chunk:`) are silently dropped from `listChunkIds` because they cannot be parsed as a bigint.