Files
skills/docs/foundation/bitpacker/bitpacker-schema/src/versioning/versioning.md
2026-05-29 08:20:56 +01:00

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 addVersion for new entries and latestSchema / latestVersion accessors.
  • Per-version migration registration via addMigration<U extends BitPackerSchema> with a MigrationFunction<T, U>.
  • 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

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): 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.