Files
Shade/packages/shade-observer
Sterister f5f42fe557 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>
2026-05-05 17:35:02 +02:00
..

@shade/observer

Live observability backend for Shade — exposes a snapshot endpoint, an SSE event stream, and serves the bundled dashboard SPA.

Install

bun add @shade/observer @shade/server @shade/core

Usage

import { createObserver } from '@shade/observer';
import { ShadeEventEmitter, ShadeSessionManager } from '@shade/core';
import { PrekeyServerEvents, createPrekeyServer } from '@shade/server';

// 1. Create event emitters
const clientEvents = new ShadeEventEmitter();
const serverEvents = new PrekeyServerEvents();

// 2. Wire them into your session manager and prekey server
const manager = new ShadeSessionManager(crypto, storage, { events: clientEvents });
const prekeyServer = createPrekeyServer({ crypto, events: serverEvents });

// 3. Create the observer
const observer = createObserver({
  token: process.env.SHADE_OBSERVER_TOKEN!,
  clientEvents,
  serverEvents,
});

// 4. Mount or serve standalone
import { Hono } from 'hono';
const app = new Hono();
app.route('/shade-observer', observer);

Bun.serve({ port: 3900, fetch: app.fetch });

After this, visit http://localhost:3900/shade-observer/dashboard/ and enter your bearer token to see the dashboard.

Endpoints

Method Path Auth Description
GET /api/state Bearer Current snapshot (identity, sessions, prekeys, server stats)
GET /api/events Bearer (or ?token=) SSE stream of live events
GET /dashboard/ None Bundled web UI
GET /health None Liveness check

Configuration

Env var Required Description
SHADE_OBSERVER_TOKEN Yes Bearer token (min 16 chars). Refuses to start if shorter.

The token is checked with constant-time comparison.

Security notes

  • Event payloads contain NO key material, plaintext, or signatures — only structural facts (counters, addresses, short hashes for display).
  • The observer is intended for internal/debugging use. Put it behind a reverse proxy and authenticate access.
  • The dashboard stores the bearer token in localStorage for convenience. Don't load the dashboard on shared computers.