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

@@ -5,6 +5,59 @@ All notable changes to Shade are documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [4.3.0] — 2026-05-05 — Browser persistence via `@shade/storage-indexeddb`
Browser-based Shade consumers had no path to session persistence: the only
storage option that worked outside Node was `"memory"`, so the identity
keypair regenerated on every page load and `device:${registrationId}`
churned to a fresh address each refresh. Building a `StorageProvider`
in consumer-land meant 25+ method re-implementations per app and no
shared conformance surface.
`4.3.0` ships an official IndexedDB adapter alongside SQLite and Postgres
so any browser-based Shade SDK consumer (dashboards, contact-list apps,
browser-extension messengers) gets persistent identity, prekeys, sessions,
retired identities, peer-verification state and stream-resume rows for
free, surviving tab refresh and browser restart.
### Added
#### `@shade/storage-indexeddb` (new package)
- `IndexedDBStorage.create({ dbName? })` — async open of an IDB
database (one object store per `StorageProvider` category) with
schema version 1. `dbName` defaults to `"shade"`; consumers that
run multiple Shade-backed apps on the same origin pass distinct
names (`"my-app-shade"`) so the IDB inspector groups them sensibly.
- Full `StorageProvider` conformance: identity, signed/one-time prekeys,
sessions, trusted identities, retired identities (with prune by
`retiredAt`), stream-state save/get/list/prune, peer verifications,
and the per-peer identity-version counter.
- `bumpPeerIdentityVersion` is wrapped in a single IDB `readwrite`
transaction — atomic read-modify-write, closing the race window the
SQLite adapter currently has on parallel `acceptIdentityChange`
calls. (SQL adapters will be brought in line in a follow-up.)
- Implementation dependency: `idb` (Jake Archibald's typed wrapper).
Tests run against `fake-indexeddb` for parity with the SQLite test
layout.
#### `@shade/sdk`
- `resolveStorage()` accepts a fourth spec form:
`{ type: 'indexeddb', dbName?: string }`. Resolution goes through
a dynamic import so Node-only consumers don't pull a browser-only
adapter into their bundle (same pattern as `@shade/storage-postgres`).
- `ShadeConfig['storage']` now exports a named `StorageSpec` type
reused by `ResolvedConfig`, replacing the duplicated inline union.
### Tests
- `packages/shade-storage-indexeddb/tests/indexeddb-storage.test.ts`
full StorageProvider surface (identity, prekeys, sessions, trust,
retired identities, persistence across close+reopen) plus an end-to-end
`ShadeSessionManager` conversation that survives a simulated tab
reload mid-session.
- `packages/shade-storage-indexeddb/tests/peer-verifications.test.ts`
CRUD round-trip, upsert-on-duplicate, identity-version increment
invariants, persistence across reopen.
## [4.2.1] — 2026-05-04 — Concurrent-ratchet desync under pull-mode drainer
A consumer running `shade.files.httpClient(server, { outboundQueueUrl, ... })`