3.5 KiB
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
addVersionfor new entries andlatestSchema/latestVersionaccessors. - Per-version migration registration via
addMigration<U extends BitPackerSchema>with aMigrationFunction<T, U>. - Bit-packer-aware: pack/unpack methods that select the schema by version number and route through an injectable
BitPacker. - Bulk reconstruction from
SchemaRegistrystorage rows.
Usage: Basic Example
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
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<T extends BitPackerSchema = BitPackerSchema>
constructor(schema: T, options: VersionedSchemaOptions)addVersion(schema: BitPackerSchema, description?: string): number— appends; returns new version number.addMigration<U extends BitPackerSchema>(from: number, to: number, fn: MigrationFunction): voidgetSchema(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: BitPackerSchemaget 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
_bitPackerdefaults to a freshBitPacker()instance; tests inject a stub to verify pack/unpack are routed through the injectable, not module-scope state. MigrationFunctionsignatures are intentionallyany → anybecause migration functions transform between heterogeneous data shapes; theT → Ugeneric threading is encouraged but not enforced at runtime.addVersionappends in monotonic order. There is no insertion or rewriting — historical versions are immutable so packed data on disk stays decodable.