All notable changes to this project are documented here.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
The Elixir package (musubi) and the JS packages (@musubi/client,
@musubi/react) share this changelog. Per-package version numbers are
not in lockstep yet; entries note which surface they affect.
Unreleased
0.5.0 — 2026-05-27
Changed
- Command replies are now returned in native Elixir shape (atom keys,
structs, atom values), symmetric with
render/1;Musubi.Wire.to_wire/1moves to the transport egress (#59). Revises #57. Client wire contract unchanged. Breaking (Elixir API): tests asserting wire-shaped replies fromdispatch_command/3/command/4must switch to native shape.
0.4.0 — 2026-05-26
Changed
- Command replies now serialize through
Musubi.Wire(#57). Replies match the wire shape the client receives (string keys, stringified atoms), and schema validation runs against that form — fixing atom-valued and nested reply-field validation.:after_commandhooks and[:musubi, :auth, :deny]telemetry still see the raw reply (atom keys/values).
Added
Musubi.Wiresupport forDateTime/NaiveDateTime/Date/Time(ISO8601) andURI(string) (#57).MapSet,Decimal, and tuples stay unhandled and raiseProtocol.UndefinedError— convert first.
0.3.0 — 2026-05-20
Added
- File uploads (#54). Top-level
upload :name, optsDSL declared per store, outsidestate do. The framework auto-injects{"__musubi_upload__": "<name>"}markers into render output. Upload state ships through an independentupload_opsenvelope stream (config / add / progress / complete / error / cancel / reset), parallel tostream_ops; progress mutation does not pollute__changed__or triggerrender/1. Authorization uses a per-entrymusubi_upload:<entry_ref>sub-channel joined with aPhoenix.Token(HMAC,max_age: 600). External (S3/R2 direct) mode ships in v1 via the optionalupload_external/3callback. Store facade:consume_uploaded_entries/3,cancel_upload/3,uploaded_entries/2. New optional callback:handle_progress/3. Client surface exposespage.<name>as a stable reactiveUploadHandlewith TanStack-stylestatusenum andisXxxmirrors; no separate React hook. Full reference indocs/uploads.md; design decisions inspec/decisions/BDR-0024..0028.
Changed
- BREAKING (DSL) —
command :name, ...is replaced by the block-formcommand :name do ... end, with explicitpayload do ... endandreply do ... endsub-blocks for schema declaration. Reply validation is now mandatory when areply doblock is declared. Migration: rewrite eachcommand :name, payload: ..., reply: ...call as the block form (#53). - README documents how to wire a Phoenix endpoint socket for Musubi (#52).
Fixed
cart_pageexample: declare command reply types so the example compiles under the strict reply validation (#51).
0.2.0 — 2026-05-18
Added
Musubi.Testingtest harness —mount/3,dispatch_command/4,render/2, and theassigns/2escape hatch for asserting on store state from ExUnit.createMusubiclient factory — bind a store type once and reuse the resulting page/command/subscribe API across an application.- React Suspense integration and an
<MusubiProvider>that accepts a rawPhoenix.Socketdirectly. - Structured command errors.
useMusubiCommandnow returns a mutation-shaped value (mutate,isPending,data,error, …). - Phoenix matrix in CI; publish workflow; MIT LICENSE and README badges.
Changed
- BREAKING (rename) — Package renamed from
ArbortoMusubithroughout the codebase, docs, and configuration. Arbor.Storefacade reshaped to mirror LiveView's call surface, includingassign_new/3andupdate/3.
Performance
- Resolver short-circuits
render/1when the root socket is unchanged; cached childwire_statestitches into the parent wire output without re-walk. - Reconciler checks parent assign value equality before computing changed-key intersections; deep-tree leaf dirty detection is prune-safe.
- Page server skips
Jsonpatchdiffing when the wire root is structurally equal between cycles. - Client invalidates
snapshotCacheby op path instead of clearing the entire cache.
Fixed
- Reconciler deep-tree leaf dirty detection now survives prune cycles without losing references.
0.1.0 — 2026-05-17
Initial public release of the Musubi runtime (then Arbor):
- Server-authoritative, page-scoped runtime over
Phoenix.Channel. - Stores declared via
use Musubi.Storewithstate do … end, command handlers, async helpers, and arender/1callback. - Per-page diff pipeline emitting RFC 6902 JSON Patch envelopes.
- LV-aligned change tracking via per-key
__changed__flags. - Streams with stable wire markers and an independent
stream_opsdelta channel; LiveView-aligned semantics. - Async helpers:
assign_async/3,4,start_async/3,4,cancel_async/2,3,stream_async/3,4. - TypeScript client and React adapter that materialize the diff stream into immutable snapshots.