# VersionedSchema _(no submodules)_ ## Purpose `VersionedSchema` is the working unit for evolving a `BitPackerSchema` over time without breaking previously-packed data. A single `VersionedSchema` instance keeps an ordered list of `SchemaVersion` rows (each pairing a version number with a `BitPackerSchema` and an optional description), plus a list of `SchemaMigration` rows that describe how to transform data between adjacent versions. Production code constructs versioned schemas in two ways: directly via the constructor when authoring a new schema lineage, or via `SchemaRegistry.getVersionedSchema(namespace, name)` when reconstructing one from storage. It is the contract the migration engine, the registry, and the runtime pack/unpack path all consult. ## Features - Ordered version list with `addVersion` for new entries and `latestSchema` / `latestVersion` accessors. - Per-version migration registration via `addMigration` with a `MigrationFunction`. - Bit-packer-aware: pack/unpack methods that select the schema by version number and route through an injectable `BitPacker`. - Bulk reconstruction from `SchemaRegistry` storage rows. ## Usage: Basic Example ```ts import { VersionedSchema } from "@suaveplan/bitpacker-schema"; const player = new VersionedSchema({ name: "-16", health: 255 }, { name: "player" }); player.addVersion({ name: "-16", health: 255, mana: 255 }, "added mana"); const latest = player.latestSchema; ``` ## Usage: Advanced Example ```ts import { VersionedSchema } from "@suaveplan/bitpacker-schema"; const player = new VersionedSchema( { name: "-16", health: 255 }, { name: "player", namespace: "game" } ); player.addVersion({ name: "-16", health: 255, mana: 255 }); player.addMigration(1, 2, (data) => ({ ...data, mana: 100 })); // Pack v1 data, then transparently migrate up. const packed = player.pack({ name: "Hero", health: 200 }, 1); const v2Data = player.unpackAndMigrate(packed, 1, 2); ``` ## API Reference ### `class VersionedSchema` - `constructor(schema: T, options: VersionedSchemaOptions)` - `addVersion(schema: BitPackerSchema, description?: string): number` — appends; returns new version number. - `addMigration(from: number, to: number, fn: MigrationFunction): void` - `getSchema(version: number): BitPackerSchema` — throws if version not found. - `pack(data, version): Uint8Array` / `unpack(data, version): unknown` — pack/unpack at a specific version. - `get versions: readonly SchemaVersion[]` - `get latestSchema: BitPackerSchema` - `get latestVersion: number` ### `interface SchemaVersion` `{ version: number; schema: BitPackerSchema; description?: string; createdAt?: Date }` ### `interface VersionedSchemaOptions` `{ name: string; namespace?: string; description?: string; autoMigrate?: boolean; includeVersion?: boolean; bitPacker?: BitPacker }` ## Implementation Notes - The internal `_bitPacker` defaults to a fresh `BitPacker()` instance; tests inject a stub to verify pack/unpack are routed through the injectable, not module-scope state. - `MigrationFunction` signatures are intentionally `any → any` because migration functions transform between heterogeneous data shapes; the `T → U` generic threading is encouraged but not enforced at runtime. - `addVersion` appends in monotonic order. There is no insertion or rewriting — historical versions are immutable so packed data on disk stays decodable.