Files
skills/docs/persistence/storage/storage/README.md
2026-05-29 08:20:56 +01:00

10 KiB

@suaveplan/storage - Enterprise key-value storage abstractions: AbstractStorage (StorageLike + streaming + hooks + OTel), MemoryStorage (TTL, zero-copy streams), NamespacedStorage, StorageFactory with module-augmentation provider registry, structured STORAGE.* errors.

Summary

Enterprise key-value storage abstractions for Suaveplan. Provides AbstractStorage (implementing StorageLike), MemoryStorage with TTL and zero-copy streaming, NamespacedStorage with scoped operations, and StorageFactory with a module-augmentation provider registry.

Documentation tree

  • abstract — (no submodules) - namespace — NamespacedStorage wraps any `Abstract…
    • abstract — (no submodules) - namespace — NamespacedStorage wraps any `Abstract…
    • namespace — NamespacedStorage wraps any AbstractStorage instance and prefixes all key operations with a caller-supplied namespa…
  • errors — (no submodules)
  • factory — (no submodules)
  • memory — (no submodules)
  • types — (no submodules)
    • schemas — Provides Zod schemas for every value-type in @suaveplan/storage that crosses a runtime boundary — factory configurati…
    • types — (no submodules)
- namespace — `NamespacedStorage` wraps any `Abstract…
  • abstract — (no submodules)- namespace — NamespacedStorage wraps any `Abstract…

  • namespace — NamespacedStorage wraps any AbstractStorage instance and prefixes all key operations with a caller-supplied namespa…

  • errors — (no submodules)- errors — (no submodules)- factory — (no submodules)- factory — (no submodules)- memory — (no submodules)- memory — (no submodules)- types — (no submodules)- schemas — Provides Zod schemas for every value-type in @suaveplan/storage that crosses a runtime boundary — factory configurati…

    • types — (no submodules)- namespace — NamespacedStorage wraps any `Abstract…
  • abstract — (no submodules)- namespace — NamespacedStorage wraps any `Abstract…

  • namespace — NamespacedStorage wraps any AbstractStorage instance and prefixes all key operations with a caller-supplied namespa…

  • errors — (no submodules)- errors — (no submodules)- factory — (no submodules)- factory — (no submodules)- memory — (no submodules)- memory — (no submodules)- types — (no submodules)- schemas — Provides Zod schemas for every value-type in @suaveplan/storage that crosses a runtime boundary — factory configurati…

    • types — (no submodules)- namespace — NamespacedStorage wraps any `Abstract…
  • abstract — (no submodules)- namespace — NamespacedStorage wraps any `Abstract…

  • namespace — NamespacedStorage wraps any AbstractStorage instance and prefixes all key operations with a caller-supplied namespa…

  • errors — (no submodules)- errors — (no submodules)- factory — (no submodules)- factory — (no submodules)- memory — (no submodules)- memory — (no submodules)- types — (no submodules)- schemas — Provides Zod schemas for every value-type in @suaveplan/storage that crosses a runtime boundary — factory configurati…

    • types — (no submodules)- abstract — (no submodules)- namespace — NamespacedStorage wraps any AbstractStorage instance and prefixes all key operations with a caller-supplied namespa…
  • errors — (no submodules) - errors — (no submodules)- factory — (no submodules) - factory — (no submodules)- memory — (no submodules) - memory — (no submodules)- types — (no submodules) - schemas — Provides Zod schemas for every value-type in @suaveplan/storage that crosses a runtime boundary — factory configurati…

    • types — (no submodules)

Installation

bun add @suaveplan/storage

Quick Start

import { MemoryStorage } from '@suaveplan/storage/memory';

const store = new MemoryStorage();
const enc = new TextEncoder();

await store.set('user:1', enc.encode('{"name":"Alice"}'));
const buf = await store.get('user:1');
console.log(new TextDecoder().decode(buf!)); // {"name":"Alice"}

// TTL — expires after 5 seconds
await store.set('session:xyz', enc.encode('token'), { ttl: 5000 });

store.destroy(); // stop background cleanup timer

Streaming

import { MemoryStorage } from '@suaveplan/storage/memory';

const store = new MemoryStorage();

// Write via WritableStream
const ws = store.createWriteStream('blob');
const writer = ws.getWriter();
await writer.write(new Uint8Array([1, 2, 3]));
await writer.write(new Uint8Array([4, 5, 6]));
await writer.close(); // flushes to storage

// Read via ReadableStream
const rs = store.createReadStream('blob');
const reader = rs.getReader();
const { value } = await reader.read(); // Uint8Array([1, 2, 3, 4, 5, 6])

// Byte-range read
const slice = await store.getPartial('blob', 2, 3); // bytes [2, 5)

Namespaces

import { MemoryStorage } from '@suaveplan/storage/memory';

const store = new MemoryStorage();
const users = store.namespace('user');
const sessions = store.namespace('session');

await users.set('alice', new Uint8Array([1]));
await sessions.set('alice', new Uint8Array([2]));

// No cross-namespace leakage
await sessions.get('alice'); // Uint8Array([2])
await users.get('alice');    // Uint8Array([1])

// clear() is scoped
await users.clear(); // removes only user:* keys
await sessions.get('alice'); // still Uint8Array([2])

Factory / Custom Provider

import { StorageFactory } from '@suaveplan/storage/factory';
import { AbstractStorage } from '@suaveplan/storage/abstract';

// Register a custom provider
class RedisStorage extends AbstractStorage { /* ... */ }
StorageFactory.register('redis', RedisStorage);

// Module augmentation for full type safety
declare module '@suaveplan/storage/factory' {
  interface StorageProviderRegistry { redis: RedisStorage; }
}

const store = StorageFactory.create({ type: 'redis' });

Error Handling

import {
  StorageNotFoundError,
  StorageQuotaError,
  StorageInvalidKeyError,
  STORAGE_CODES,
} from '@suaveplan/storage/errors';

try {
  await store.set('../escape', new Uint8Array([1]));
} catch (err) {
  if (err instanceof StorageInvalidKeyError) {
    console.error(err.code);  // STORAGE.INVALID_KEY
    console.error(err.key);   // "../escape"
  }
}

// Quota
store.setMaxValueSize(100);
try {
  await store.set('big', new Uint8Array(200));
} catch (err) {
  if (err instanceof StorageQuotaError) { /* handle */ }
}

Module Docs

Dependencies

Dependency Purpose
@suaveplan/error SuaveplanError base class, defineCodes, wire format
@suaveplan/types StorageLike, EventBusLike interfaces
@suaveplan/events Default EventBus for lifecycle events
@opentelemetry/api storage.ops counter, storage.op.duration_ms histogram
zod Schema validation for config and options
tslib TypeScript runtime helpers