Thank you for being patient! We're working hard on resolving the issue
Wire types describe what a cell carries on the network. Encodings turn wire payloads into typed runtime values.
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;
}
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.
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 { /* ... */ },
}));
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.
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.
__learnings/2026-04-13-encoding-registry-decode-safe.toml —
the exemplar decode / decodeSafe pattern