Skip to Content
DocsBasicsEncoding & Decoding

Encoding & Decoding

Encoding (compile)

The compile function encodes a source object into Vein binary format using a schema.

import { compile } from "@stacknet/lode"; const vein: Uint8Array = compile(sourceObject, schema);

Algorithm

The encoder operates in two passes:

  1. Validation pass — iterate schema fields, check that required fields are present, resolve type tags, encode each value into a byte buffer
  2. Write pass — allocate a single ArrayBuffer of the exact total size, write the header and all field entries sequentially

Required Field Enforcement

If a required field is missing from the source object, compile throws:

Error: Required field "name" is missing

Optional fields (required: false) are silently omitted from the output if undefined or null.

Type Encoding

TypeEncoding
stringRaw UTF-8 bytes
bool0x01 (true) or 0x00 (false)
string[]count(2) + per item: len(2) + UTF-8 bytes
map<string,string>count(2) + per entry: klen(2) + key + vlen(2) + value

All multi-byte lengths are big-endian unsigned 16-bit integers.

Map keys are sorted lexicographically before encoding. This is not optional — it is how LODE guarantees determinism.


Decoding (decode)

The decode function reads Vein binary back into a plain JavaScript object.

import { decode } from "@stacknet/lode"; const obj: Record<string, any> = decode(vein, schema);

Validation

The decoder validates:

  1. Minimum length — at least 4 bytes (header size)
  2. Magic bytes — first two bytes must be 0x4C, 0x44 ("LD")
  3. Version — must match the schema version exactly
  4. Field bounds — each field’s declared length must not exceed remaining bytes
  5. Required fields — all required schema fields must be present in the decoded result

Forward Compatibility

If the decoder encounters a field ID that does not exist in the schema, it skips the field (advances the offset by the declared length) without error. This allows a v1 decoder to read payloads produced by a v2 encoder.

Error Cases

// Too short decode(new Uint8Array([0x4C]), schema); // → Error: Vein too short: expected at least 4 bytes // Wrong magic decode(new Uint8Array([0xFF, 0xFF, 1, 0]), schema); // → Error: Invalid magic: expected 0x4C44 ("LD"), got 0xffff // Version mismatch decode(v2Vein, v1Schema); // → Error: Version mismatch: vein is v2, schema is v1 // Truncated decode(truncatedVein, schema); // → Error: Field 3 declares length 100 but only 12 bytes remain

Round-Trip Example

import { compile, decode, loadLode } from "@stacknet/lode"; const schema = loadLode("model-layer-v1.lode"); const original = { name: "fast", isDefault: false, models: ["qwen3:8b"], defaultModel: "qwen3:8b", }; const vein = compile(original, schema); const decoded = decode(vein, schema); console.log(decoded); // { name: "fast", isDefault: false, models: ["qwen3:8b"], defaultModel: "qwen3:8b" }
Last updated on