clone

a deno framework for local-first web apps that open instantly, work offline and sync when users choose

feat/141-effect-library
lofi / docs / examples / payloads.md
payloads.md 1.8K rendered
1# Binary and structured payloads23Two column types carry non-scalar values: `s.bytes()` for binary data and `s.json()` for structured4data. Both round-trip through the engine byte- and shape-exact — verified in5`package/schema/conformance_test.ts`.67## Declare the payload columns89```ts10// src/schema.ts11import { s } from "@nzip/lofi/schema";1213export const app = s.defineApp({14 attachments: s.table({15 fileName: s.string(),16 thumbnail: s.bytes(),17 metadata: s.json(),18 }),19});20```2122```ts23const attachment = await db.insert(app.attachments, {24 fileName: "cover.png",25 thumbnail: new Uint8Array(await blob.arrayBuffer()),26 metadata: { width: 320, height: 180, palette: ["#282828", "#ebdbb2"] },27}).wait({ tier: "global" });28// Reads return the same Uint8Array bytes and the same nested JSON shape.29```3031## Choosing between them3233- **`s.bytes()`** stores an opaque `Uint8Array`: thumbnails, hashes, encrypted blobs, anything the34 app treats as bytes. One pinned constraint: payloads under 32 bytes are unreliable in the current35 alpha — pad short values, or store small binary-ish data as `s.json()` until upstream fixes it.36- **`s.json()`** stores any JSON value and reads back the same nested shape. Reach for it when the37 data is a document the app consumes whole. When you need to _filter_ on a field, promote that38 field to its own typed column instead — `where` addresses columns, not JSON internals.39- **`s.array(inner)`** sits between the two: use it when the value is a flat list of one typed40 element and `s.json()` when the shape nests.4142Rows travel through sync whole, so a payload column is for data sized like a row — icons and43metadata, not video. Large media belongs outside the table with a payload column holding the44reference (hash, URL, or identifier).