Schema-Registry
Für größere Codebases mit vielen Event-Typen wird zu wissen,
was existiert, ein Problem. Jeder PersistentActor
deklariert seine Events; einige haben Adapter; Versionen leben
in den Adapter-Configs. Kein zentraler Katalog.
SchemaRegistry ist der optionale Katalog:
import { SchemaRegistry } from 'actor-ts';
export const registry = new SchemaRegistry() .add('Deposited', 2) .add('Withdrawn', 1) .add('AccountFrozen', 3) .add('AccountClosed', 1);Eine einfache typisierte Map von Event-Name → aktuelle Version. Verwende sie, um:
- Den aktuellen Stand jedes Schemas zu dokumentieren.
- Zu validieren, dass Adapter die richtige Version deklarieren.
- Tooling anzutreiben — Admin-Dashboards, Dev-Tools, die Journal-Inhalte zeigen.
Die meisten Projekte brauchen sie nicht. Greif danach, wenn du 10+ Event-Typen hast und dich dabei ertappst, manuell zu verfolgen, welche bei welcher Version ist.
Ein minimales Beispiel
Abschnitt betitelt „Ein minimales Beispiel“import { SchemaRegistry } from 'actor-ts';
// Geteiltes Modul — `schemas.ts`:export const registry = new SchemaRegistry() .add('Deposited', 2) .add('Withdrawn', 1) .add('Frozen', 3);
export type SchemaName = 'Deposited' | 'Withdrawn' | 'Frozen';Dann in Actors:
import { registry } from './schemas.js';
class Account extends PersistentActor<...> { override eventAdapter() { return new MigratingAdapter<DepositedEventV2>({ currentVersion: registry.versionOf('Deposited'), // → 2 chain: [...], }); }}Die currentVersion des Adapters und der Wert der Registry
müssen übereinstimmen. Zieh aus der Registry, um das zu
erzwingen.
Die API
Abschnitt betitelt „Die API“class SchemaRegistry { add(name: string, version: number): SchemaRegistry; versionOf(name: string): number; has(name: string): boolean; list(): Array<{ name: string; version: number }>;}add(name, version)— ein Schema registrieren. Gibt die Registry zum Verketten zurück.versionOf(name)— die aktuelle Version lesen. Wirft, wenn nicht registriert.has(name)— Existenz prüfen.list()— alles Registrierte aufzählen.
Immutable: add() gibt eine neue Registry zurück; das Original
wird nicht mutiert. Nützlich für Test-Scaffolding, wo du
frische Registries pro Test willst.
Validierung gegen Adapter
Abschnitt betitelt „Validierung gegen Adapter“import { SchemaRegistry, validateAdapter } from 'actor-ts';
// Während Tests / Startup:const adapter = new MigratingAdapter<EventV2>({ currentVersion: 2, chain: [...] });validateAdapter(adapter, registry, 'Deposited');// → wirft, wenn currentVersion(2) !== registry.versionOf('Deposited')Für Produktions-Code rufe validateAdapter beim System-Startup
als Sicherheitsnetz auf: wenn du die Version eines Adapters
hochziehst, aber vergisst, die Registry zu aktualisieren,
schlägt der Validate-Call laut fehl.
Tooling
Abschnitt betitelt „Tooling“Ein paar häufige Tooling-Formen, die von der Registry profitieren:
// Admin-Panel: jeden Event-Typ und seine aktuelle Version auflistenconst all = registry.list(); // → [{ name: 'Deposited', version: 2 }, ...]
// Dev-Skript: warnen, wenn ein Event im Journal eine Version hat,// die HÖHER ist als das, was die Registry kennt (ein Deploy-Issue)for await (const event of query.eventsByPersistenceId(...)) { const envelopeVersion = event.event._v; const expectedMax = registry.versionOf(event.event._t); if (envelopeVersion > expectedMax) { console.warn(`event ${event.event._t} has version ${envelopeVersion}, registry knows up to ${expectedMax}`); }}Wann du sie nicht brauchst
Abschnitt betitelt „Wann du sie nicht brauchst“Wie geht’s weiter
Abschnitt betitelt „Wie geht’s weiter“- Migration im Überblick — das größere Bild.
- DefaultAdapter — die typisierten Adapter, die die Registry konsumieren.
- MigratingAdapter — die verkettete Alternative.
- Envelope-Format —
die On-Disk-Form mit
_v/_t/_e.
Die SchemaRegistry-API-Referenz
deckt die vollständige Oberfläche ab.