Repository navigation
v0.6.0 — subscriptions survive hibernation wake
Added
-
Typed oversize-frame handling (ADR-0018; part of
#28).
An oversize client mutation used to be dropped silently server-side
(ADR-0012'smaxFrameBytesguard), surfacing only as a confirmation
timeout — and in production Cloudflare's ~1 MiB edge cap on inbound
WebSocket messages means the frame may never reach the DO at all. The
transport now guards before sending: amut/callwhose encoded size
exceeds the 1 MiB edge cap rejects immediately with
MutationRejectedError(code"FRAME_TOO_LARGE"), so the optimistic
overlay rolls back promptly. The server's silent drop stays as defense in
depth. Outbound gains a warn-only fixed 1 MiB threshold: a larger encoded
frame logs aconsole.warnwith size and collection but is still sent
whole — column projection (#28a) remains the real fix for oversized
full-row re-sends. The limits are infrastructure facts (Cloudflare's edge
cap), not application preferences, so they are constants, not options. -
Transport reconnect policy (ADR-0016; fixes #25, #26). One option,
reconnectDelay?: number | ((attempt, closeCode?, closeReason?) => number | null)
(null= stop), replacesreconnectDelayMs(breaking, pre-1.0: a
number keeps the old meaning — the default policy's base delay). The
default (defaultReconnectDelay) replaces the fixed interval with capped
exponential backoff + full jitter (base 250 ms; cap 30 s; attempt counter
resets on a successful open) and treats application close codes 4000-4999
as terminal, so an accept-then-close auth rejection (e.g. 4403) no longer
retries forever. A terminal stop surfaces through the new
onClosed(code, reason)hook, making auth closes distinguishable from
transient drops. -
Cohosting docs moved to
recipes/cohosting.mdand re-grounded. The
README's cohosting section shrinks to the pitch, the code sample, and a
pointer; the recipe carries the rules, an honest account of what is verified
and how (CI fake-host tests vs. source audit at pinned versions vs. the
untested wake restore), and a reframed@cloudflare/actorsstory. Verified
against@cloudflare/actors@0.0.1-beta.6: theActorclass hibernates fine
on its own but won't cohost out of the box (itsSocketshelper takes over
socket connections completely andActorclaims the DO-wide auto-response
slot), while the Actors helpers (Alarms,Storage) compose cleanly with
sync over a plainDurableObjectbase — which Actors' own examples document.
Supersedes the 0.5.0 "host defect" phrasing.
Fixed
- Subscriptions survive hibernation wake (ADR-0019; field report against
0.5.1). Hibernatable sockets survive a DO eviction by design, but the
subscription registry was instance memory: a wake restored the socket set
and nothing else, so an idle client's live queries went silently dead on a
still-open socket — its own mutations still confirmed while deltas fanned
out to nobody, and the client's only re-subscribe trigger (the close path)
never fired. Subscriptions are now written through to a durable
_sync_substable keyed by a per-socket id tag stamped at accept, and
restored onto surviving sockets duringregisterSyncon every wake —
before anything can dispatch or drain. No wire or client change: an
unmodified 0.5.1 client against a fixed server recovers fully. Orphaned
rows (a socket that dies withoutwebSocketClose) are swept during the
existing compaction housekeeping; no idle timers (ADR-0006 invariant
intact). Pinned bytests/hibernation.test.tsunder real evictions
(evictDurableObject, unlocked by the vitest 4 migration — the
eviction-based wake test issue #29 asked for), in five shapes: eviction
after successful broadcasts, eviction before the first-ever broadcast,
eviction of a cohosted base (tagged-restore branch, host socket untouched),
a restored sub whose collection left the schema (reconciled:reset+
row dropped, healthy subs untouched), and a restored predicate that no
longer compiles (socket closed with a non-terminal code so reconnect
re-subscribes — aresetwould strand the query, adversarial review).
Sockets accepted by a pre-fix build that survive an in-place upgrade
carry no id tag and keep the old behavior (dead until reconnect) — a
one-release sharp edge, documented in ADR-0019. - Rejection
codenow survives tx-dedup replay (#21). The dedup record
persisted only the rejection message, so a client retrying the sametxId
got the reason with no machine-readablecode— breaking code-based error
handling on exactly the retry path it exists for._sync_seen_txgains an
error_codecolumn (added in place on wake for already-deployed DOs), and
the replayedrejectedframe is now shaped identically to the original:
{ code, message }when a code was recorded,{ message }otherwise. - BLOB columns no longer corrupt to
{}over the wire (ADR-0017,
#27).
workerd'sSqlStoragereturns BLOB values as bareArrayBuffer, which the
msgpack encoder fell through toencodeMapon (and the JSON debug codec
stringified as{}) — clients silently received an empty object, for
snapshots and deltas alike. Both codecs now normalizeArrayBufferat
emission, so BLOB columns arrive on the client as aUint8Arraywith the
exact bytes.