Something went wrong

Thank you for being patient! We're working hard on resolving the issue

Wire Types & Encodings - Lona Docs Log in

Wire Types & Encodings

Wire types describe what a cell carries on the network. Encodings turn wire payloads into typed runtime values.

Dtype

Every cell has a Dtype describing its value shape:

type Dtype =
  | "string" | "number" | "boolean"
  | "datetime" | "date"
  | "obj"            // shape-tagged object (event, task, weather, …)
  | "lisp"           // formula expression
  | "opaque"         // pass-through
  ;

CellEntry carries the value plus optional cardinality + style:

interface CellEntry {
  value: CellValue;
  cardinality?: CellCardinality;
  style?: CellStyle;
}

Cardinality

type Cardinality = "single" | "multi";

A multi-cardinality cell has a stable cellId per entry — multiple events on one day, multiple tasks on one date column.

Shape registry

Object cells (Dtype: "obj") carry a ShapeKey identifying the schema. The ShapeRegistry resolves the key to a runtime Shape<T> validator + sample value:

import { defineShape, ShapeRegistry, EVENT_SHAPE } from "@tento-lona/sheets";

const reg = new ShapeRegistry();
reg.register(EVENT_SHAPE);                  // built-in
reg.register(defineShape<MyShape>({         // app-specific
  key: "myshape.v1",
  validate(v): v is MyShape { /* ... */ },
}));

Encoding registry

Encodings turn wire JSON into the canonical typed value. Each encoder is (wire, ctx) → canonical | null (returns null on failure for decodeSafe; throws for decode).

Built-ins:

import {
  EncodingRegistry,
  EVENT_V1, eventV1,
  TASK_V1, taskV1,
  WEATHER_V1, weatherV1,
  SLOT_V1, slotV1,
  registerBuiltinEncodings,
} from "@tento-lona/sheets";

const enc = new EncodingRegistry();
registerBuiltinEncodings(enc);

const event = eventV1.decode(wireJson, ctx);
// or, fail-soft:
const eventOrNull = enc.decodeSafe(EVENT_V1, wireJson, ctx);

The exemplar decode / decodeSafe pair lives in encoding-registry.ts: an unsafe function that throws + a *Safe variant that catches, logs with full context, and returns null. Pick the variant your call-site needs — there is no automatic fallback.

Wire ↔ canonical at boundaries

HttpBackend / TestBackend
        │  (raw wire JSON)
        ▼
NormalizingBackend  ← runs encoders → canonical CellEntry
        │
        ▼
   Sheet / SheetRow

NormalizingBackend wraps a transport-level backend and runs the encoding registry on every read. App code that talks to a NormalizingBackend only ever sees canonical values.

See also

  • Backends — the transport layer
  • __learnings/2026-04-13-encoding-registry-decode-safe.toml — the exemplar decode / decodeSafe pattern