Schema
A LODE schema is a JSON document that defines the structure of an encodable object. Every schema must have "schema": "lode" as its discriminator.
Structure
{
"schema": "lode",
"version": <number>,
"name": "<string>",
"fields": [
{
"id": <1-255>,
"name": "<string>",
"type": "<type>",
"required": <boolean>
}
]
}Top-level Properties
| Property | Type | Description |
|---|---|---|
schema | "lode" | Must be the literal string "lode" |
version | number | Schema major version (≥ 1) |
name | string | Human-readable name for the structure |
fields | LodeField[] | Ordered list of field definitions |
Field Properties
| Property | Type | Description |
|---|---|---|
id | number | Binary field key (1–255). Must be unique within the schema. |
name | string | Field name in the source object. Must be unique. |
type | string | Wire type. One of: string, bool, string[], map<string,string> |
required | boolean | Whether the field must be present. Defaults to true if omitted. |
Field IDs
Field IDs are the stable binary identifiers for each field. They are written as a single byte in the Vein format. This means:
- IDs range from 1 to 255 (0 is reserved)
- Renaming a field’s
nameproperty does not break binary compatibility - Changing a field’s
iddoes break binary compatibility - Once assigned, an ID should never be reused for a different field
Validation
The loadLode() function validates a schema at load time and throws on:
- Missing or incorrect
schemamarker - Invalid version (must be ≥ 1)
- Empty name
- Empty fields array
- Field ID out of range (< 1 or > 255)
- Duplicate field IDs
- Duplicate field names
- Unknown type strings
import { loadLode } from "@stacknet/lode";
// From file
const schema = loadLode("./my-schema.lode");
// From object
const schema = loadLode({
schema: "lode",
version: 1,
name: "Example",
fields: [
{ id: 1, name: "title", type: "string", required: true },
],
});Example: Model Layer Schema
model-layer-v1.lode
{
"schema": "lode",
"version": 1,
"name": "ModelLayer",
"fields": [
{ "id": 1, "name": "name", "type": "string", "required": true },
{ "id": 2, "name": "isDefault", "type": "bool", "required": true },
{ "id": 3, "name": "models", "type": "string[]", "required": true },
{ "id": 4, "name": "defaultModel", "type": "string", "required": true },
{ "id": 5, "name": "defaults", "type": "map<string,string>", "required": false }
]
}Schema Evolution
To evolve a schema without breaking existing consumers:
- Add new fields with new IDs and
required: false - Never reuse a retired field ID
- Bump the version for breaking changes (type changes, new required fields)
The decoder skips unknown field IDs, so a v1 consumer can safely read a v2 payload — it simply ignores the new fields.
Last updated on