Something went wrong

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

Row Identity - Lona Docs Log in

Row Identity

Three layers, each with a job.

RowKey — wire format

The protocol-level identifier. Variants:

VariantFormExample
Userr_<hex>r_3f9a8b2e7c1d4e6f
Lookup:<key>:weather, :home
Virtualr_<hex>~<preset>r_3f9a~daily-stats
Systemsystem(<name>)system(footer)

Pure value type. === works for comparison, but prefer a.equals(b) — see the comparison rule below.

import { RowKey } from "@tento-lona/sheets";

const key = RowKey.parse("r_3f9a8b2e7c1d4e6f");
key.isVirtual();      // false
key.isSystem();       // false
key.toHex();          // "3f9a8b2e7c1d4e6f"

RowLocalId — session identity

The interned identifier inside a Sheet. Wraps a RowKey, created via RowLocalId.Registry. Reference equality holds — use RowLocalId as a Map/Set key without worrying about hash collisions or string allocation.

Aliasing: a row with both a UUID and a lookup key gets one RowLocalId covering both names; the registry keeps them unified.

const localId = sheet.idRegistry.resolveFromString("r_3f9a8b2e7c1d4e6f");
sheet.findRow(localId);

RowId — interned cross-sheet identifier

Globally interned via RowId.intern. Used at API boundaries where you call RowsClient, SheetModel, etc.

import { RowId } from "@tento-lona/sheets";

const rowId = RowId.intern("r_3f9a8b2e7c1d4e6f");
await rowsClient.fetch(rowId);

Conversion at boundaries

From → ToCall
RowIdRowLocalIdregistry.resolveFromString(rowId.toString())
RowLocalIdRowIdRowId.parse(localId.toString())
RowLocalId → string (DOM/API)localId.toString()
RowKeyRowIdRowId.intern(key.toString())

When to use which

  • Inside SDK / UI code reasoning about a single Sheet — RowLocalId. Reference equality, no string allocation.
  • Inside server requests, cache keys, or wire payloads — RowId.
  • Inside encoders, descriptors, or wire-shape logic — RowKey (variant introspection).

Comparison rule

For all three, prefer .equals() over ===. Each is interned, so reference equality usually works — but instances can diverge across JSON round-trips, registry rebuilds, or test boundaries. === silently gives false negatives in those cases.

// GOOD
if (a.equals(b)) { ... }

// BAD — fragile across boundaries
if (a === b) { ... }

(See __learnings/2026-04-11-sheetid-reference-equality.toml.)