Storage
Semantic estate storage for snapshots, SQL blobs, and state manifests
What Storage Does
- Publish immutable estate artifacts -
estate.json, snapshots, SQL blobs, and state manifests - List and read by content hash - filenames are not proof
- Refuse path-level get/put/delete - parsers, not drivers, admit trusted values
Available Writers
| Writer | Storage | Best For |
|---|---|---|
| Filesystem | Local files | Development, CI/CD, version control |
ObjectStoreEstateStorage |
Strongly consistent object store with conditional create | Shared remote estates |
MemoryEstateStorage |
Process memory | Tests and storage conformance fixtures |
Semantic Interface
Storage is a reader/writer of content-addressed objects, not a path store:
interface MigrationStorageReader {
readEstate(): Promise<Uint8Array | null>;
listStates(): Promise<readonly string[]>;
listSnapshots(): Promise<readonly string[]>;
listSql(): Promise<readonly string[]>;
readState(id: string): Promise<Uint8Array | null>;
readSnapshot(hash: string): Promise<Uint8Array | null>;
readSql(hash: string): Promise<Uint8Array | null>;
}
interface MigrationStorageWriter extends MigrationStorageReader {
publishEstate(bytes: Uint8Array): Promise<PublishResult>;
publishSnapshot(hash: string, bytes: Uint8Array): Promise<PublishResult>;
publishSql(hash: string, bytes: Uint8Array): Promise<PublishResult>;
publishState(id: string, bytes: Uint8Array): Promise<PublishResult>;
}
interface PublishResult {
outcome: "created" | "identical";
}
Reader inventories and reads must be strongly consistent. Writer publication is conditional create: publishing identical bytes at the same identity is idempotent, while different bytes at that identity are corruption. The state manifest is published last and is the only visibility boundary for a new state.
Eventually consistent or last-writer-wins storage cannot implement the writer contract directly. It needs an external single-writer or conditional publication owner. Workers KV is therefore refused as a writable estate; strongly consistent object storage with conditional writes can be used.
Custom writable storage should run the exported
createStorageConformanceSuite() against a fresh writer. The suite proves
idempotent identical publication, corruption refusal, committed-manifest
inventory, and immutable estate publication. It does not upgrade a storage
service whose consistency or conditional-write contract is weaker than the
interface promises.
Directory Structure
The filesystem writer uses this estate layout:
migrations/
├── estate.json
├── snapshots/
│ └── <snapshot-hash>.json
├── sql/
│ └── <sql-hash>.sql
└── states/
└── <state-id>.json
Use a writer with createMigrationClient:
import { createFsStorageWriter, createMigrationClient } from "viborm/migrations";
const migrations = createMigrationClient(client, {
storage: createFsStorageWriter("./migrations"),
});