Skip to content

v0.2.0

Choose a tag to compare

@grrowl grrowl released this 31 May 05:44
· 119 commits to main since this release

Changed

  • Author-owned schema; registerSync wires the sync. Breaking. Collection
    definitions are now { table, pk } — ddl is removed. You create your tables
    yourself (raw DDL, Drizzle, any migrator), then call this.registerSync(registry)
    — typically in your constructor's blockConcurrencyWhile, after migrating. It
    validates each table (one PRAGMA: the pk is a sole TEXT client key — D9) and
    installs the CDC triggers. Lazy initRegistry-on-fetch is gone; schema exists
    before the first event. Forget the call → this.registry throws loud. This also
    retires runSyncedWrite's "caller ensures init" caveat. See
    ADR-0007.

  • The cursor fetch frame now mirrors @tanstack/db's LoadSubsetOptions.
    Breaking wire change (client and server ship together). The frame carries a
    base where plus a raw cursor: { whereFrom, whereCurrent } — TanStack's own
    CursorExpressions names and semantics (the cursor expressions exclude the
    base where) — replacing the previous private where/ties fields that
    combined the predicates client-side. The server now composes base AND whereCurrent (ties, unbounded) and base AND whereFrom (next page, bounded by
    limit). Behaviour is unchanged (identical compiled SQL); the win is
    traceability to upstream. A malformed cursor (a missing half) is now rejected
    loudly instead of degrading to an unbounded scan. See
    ADR-0005.

  • Collection pk validation accepts TEXT affinity, not the literal "TEXT".
    registerSync now admits any TEXT-affinity pk (TEXT, VARCHAR, CHAR,
    NVARCHAR, …) so ORM/migrator-generated DDL composes; INTEGER (rowid alias)
    and other non-TEXT affinities are still rejected loudly (they'd break optimistic
    id parity). Part of ADR-0007.

Added

  • runSyncedWrite(fn) — a protected SyncDurableObject primitive for
    server-originated writes (an agent inserting a row, a webhook, a cron/
    alarm job, an admin edit, a bulk seed): apply a raw synchronous SQL closure
    in a transaction, then broadcast the resulting CDC to connected clients.
    Outside the client mutation flow — no txId, no receipt, no dedup (idempotency
    rides the collection's mandated stable keys).
    See ADR-0006.
  • examples/board — an at-scale stress example: 5,000 tasks on one DO,
    bounded window load, useLiveInfiniteQuery cursor scroll-back, and a mutable
    order key (updated_at) so voting/starring bumps a task to the top (move-in
    via the always-emit upsert). A server-side firehose makes the deferred
    bounded-window-under-churn limitation visible: loaded climbs past window.
  • A real-tie integration test (unbounded boundary ties + limited next page + base
    predicate composed into both halves) covering the cursor fetch against the DO.
  • A move-in integration test: a cold row bumped server-side arrives via the
    no-where live sub and upserts into the collection (ADR-0002 C4).