release(v4.3.0): browser persistence via @shade/storage-indexeddb

Ship an official IndexedDB-backed StorageProvider so browser-based Shade
consumers persist identity, prekeys, sessions, retired identities,
peer-verification state and stream-resume rows across tab refresh and
browser restart. Closes the gap that forced browser apps onto
storage:"memory" (regenerated identity each load, orphaned device
records server-side).

- New package @shade/storage-indexeddb (4.3.0): full StorageProvider
  conformance, schema v1, idb-backed; bumpPeerIdentityVersion is wrapped
  in a single readwrite IDB transaction (atomic, vs SQLite's
  read-then-upsert race).
- @shade/sdk resolveStorage() accepts { type: 'indexeddb', dbName? } via
  dynamic import (lazy, optional dep — same pattern as
  @shade/storage-postgres). Named StorageSpec type now reused by
  ResolvedConfig.
- Tests: 16 new tests in shade-storage-indexeddb (StorageProvider
  surface + peer-verifications + full E2EE conversation surviving a
  simulated tab reload). Run on fake-indexeddb.
- Lockstep version bump 4.2.1 → 4.3.0 across all 25 packages.
- Publish scripts updated to include the new package.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-05 17:35:02 +02:00
parent b77b7e771c
commit f5f42fe557
37 changed files with 1167 additions and 54 deletions

View File

@@ -17,11 +17,12 @@ export interface ShadeConfig {
* - "memory" — in-memory only (lost on restart, good for tests)
* - "sqlite:/path/to/file.db" — SQLite backend
* - { type: 'postgres', url: 'postgres://...' } — PostgreSQL backend
* - { type: 'indexeddb', dbName?: 'my-app' } — browser IndexedDB
* - An explicit StorageProvider instance
*
* Default: "memory"
*/
storage?: string | StorageProvider | { type: 'postgres'; url: string };
storage?: StorageSpec;
/**
* Your address on the prekey server (e.g. "alice@example.com" or "device:abc123").
@@ -96,9 +97,16 @@ export interface ShadeKTConfig {
witnessMaxStored?: number;
}
/** Acceptable shapes for `ShadeConfig.storage`. */
export type StorageSpec =
| string
| StorageProvider
| { type: 'postgres'; url: string }
| { type: 'indexeddb'; dbName?: string };
export interface ResolvedConfig {
prekeyServer: string;
storage: string | StorageProvider | { type: 'postgres'; url: string };
storage: StorageSpec;
address?: string | undefined;
autoReplenish: { min: number; target: number; intervalMs: number } | false;
autoRotate: false | '1d' | '7d' | '30d' | '90d';