@verevoir/storage
v1.1.0
Published
Database-agnostic storage adapter with Postgres reference implementation
Readme
@verevoir/storage
A database-agnostic persistence layer for Verevoir content. Provides an abstract StorageAdapter interface and two implementations: an in-memory adapter for development/testing and a Postgres adapter using JSONB.
What It Does
- Defines a
StorageAdapterinterface for CRUD + listing of content documents - Ships a
MemoryAdapterfor tests and local development (zero dependencies) - Ships a
PostgresAdapterbacked by a single JSONB table (depends onpg) - Stores metadata (id, block type, timestamps) as proper columns; content payload as JSONB
- Does not validate data — validation is the schema engine's job
Install
npm install @verevoir/storageQuick Example
In-Memory (development/testing)
import { MemoryAdapter } from '@verevoir/storage';
const storage = new MemoryAdapter();
await storage.connect();
const doc = await storage.create('hero', { title: 'Hello', featured: true });
const fetched = await storage.get(doc.id);
const heroes = await storage.list('hero');
await storage.disconnect();Postgres
import { PostgresAdapter } from '@verevoir/storage';
const storage = new PostgresAdapter({
connectionString: 'postgres://user:pass@localhost:5432/mydb',
});
await storage.connect();
await storage.migrate(); // creates documents table
const doc = await storage.create('hero', { title: 'Hello' });
await storage.disconnect();StorageAdapter Interface
interface StorageAdapter {
connect(): Promise<void>;
disconnect(): Promise<void>;
migrate(): Promise<void>;
create(blockType: string, data: Record<string, unknown>): Promise<Document>;
get(id: string): Promise<Document | null>;
update(id: string, data: Record<string, unknown>): Promise<Document>;
delete(id: string): Promise<void>;
list(blockType: string): Promise<Document[]>;
}Document Type
interface Document<T = Record<string, unknown>> {
id: string;
blockType: string;
data: T;
createdAt: Date;
updatedAt: Date;
}Architecture
| File | Responsibility |
| ---------------------------- | ----------------------------------------------------- |
| src/types.ts | Document and StorageAdapter interface definitions |
| src/memory.ts | In-memory adapter using a Map |
| src/postgres/adapter.ts | Postgres adapter using pg |
| src/postgres/migrations.ts | Table creation SQL |
| src/index.ts | Public API exports |
Design Decisions
- The adapter does not validate data. Validation belongs to the schema engine. The adapter persists whatever it receives.
- Postgres stores content in a single
documentstable with a JSONBdatacolumn. Metadata columns (id,block_type,created_at,updated_at) are proper typed columns for indexing and querying. - The in-memory adapter matches the same interface, making it a drop-in replacement for tests.
Documentation
- Building a Storage Adapter — implementing the StorageAdapter interface
- Getting Started — content model, storage, and editor in five minutes
- Integration Guide — connecting content models, storage, editor, and more
Development
npm install # Install dependencies
make build # Compile TypeScript
make test # Run test suite (needs Docker for Postgres integration tests)
make lint # Check formatting