a simpler query propagation option
I removed the old propagate query option so propagation is the single public way to control forwarding. Applications that need a query to stay local can now use propagation: "local-only" consistently.
I removed the old propagate query option so propagation is the single public way to control forwarding. Applications that need a query to stay local can now use propagation: "local-only" consistently.
I added reactive one-row helpers for React, Vue, Solid, and Svelte. They keep the query live while making loading, empty, and populated results clear without making developers pull the first item out of an array themselves.
I changed upsert to take the table, row ID, data, and optional settings in that order. This keeps the row ID separate from mutation settings and matches the shape used by the other row mutation methods.
I made global sequence allocation fail safely when the counter reaches its maximum value. The final value can be used once, but any later allocation now returns a clear error instead of wrapping around and reusing an old sequence number, and every current allocation path uses the same guard.
I replaced loosely shaped subscription messages with typed events that the native and TypeScript layers can agree on. The subscription manager now prepares the exact row layout once, so each update can decode fixed positions instead of guessing from field names, while unknown or redefined layouts fail clearly.
I fixed prepared queries so a number used in an access rule can be compared correctly even when it arrives in a different integer size. Values that cannot be converted safely keep their original type, which makes the permission check fail closed instead of silently matching the wrong value.
I fixed prepared permission queries that combine rules with and without a claim. Each active binding now gets the right route information, so the claimless branch no longer disappears or produces results for the wrong binding.
I updated Jazz's integration tests and simulation benchmark to use the new transaction API. The tests now pass the correct opening batch identifier and check that a committed batch exists before waiting for the change to become safely stored at the edge.
I changed startup recovery to scan only transactions that have a real sequence number. Pending or rejected local transactions are handled by their own replay paths, so recovery no longer spends time scanning unrelated history.
I added a set of reconnect tests that cover membership and permission changes while someone is disconnected. They check that the client receives exactly the rows that were added, changed, or removed, so future changes cannot accidentally reload everything.
I added a browser benchmark that measures how long it takes to load a large set of related records. It uses a repeatable project-board dataset and records the row counts and the time needed to turn the returned data into usable objects, giving us public coverage for this path without changing production behaviour.
I added a testing-only benchmark that measures the main stages of opening Jazz and recovering its saved data. The measurements now follow the current storage layout, including the final step that restores aliases, so future performance work can target real costs.
I made Jazz's SUM, AVG, MIN, and MAX behave like SQL when there are no rows or only null values, while keeping grouped queries and COUNT working as before. I also added support for signed 64-bit numbers and carried the resulting types through the public subscription API.
I updated the starter projects to use the tested Better Auth 1.6.24 release. I replaced an outdated token-request helper with the typed request supported by that release, keeping the starter authentication flows and compatibility checks aligned.
I fixed reconnects after a user's permissions changed while they were offline. The server now uses a complete membership response when a fast data-progress marker could miss an old-but-newly-visible row or a revoked row, while keeping the fast path for ordinary updates.
I fixed local one-shot reads and streams retaining internal listeners after they had finished or been dropped. They now clean themselves up immediately, including error paths, while shared streams stay alive until their last owner leaves; regression tests cover these cases.
I fixed browser-worker transport dropping the hidden column-name information needed to decode relation results. Without it, a relation could be matched with the wrong scalar value; the information is now preserved across the boundary, with regression coverage for nested relations.
I added a repeatable benchmark that measures how a large number of routes affects attaching subscriptions, processing writes, retained data, and memory. It covers 1 to 1,000 routes and gives the next optimisation work a trustworthy baseline without changing runtime behaviour.
I added a benchmark comparing a saved query result that is already kept up to date with one rebuilt from storage. The maintained result stayed at one read and about 494 encoded bytes, while rebuilding grew from 401 to 40,001 reads as the source grew from 100 to 10,000 rows, while producing the same result.
I added optional timing receipts to our benchmark for reopening a saved database and running its first query. They split the wait into recognisable steps: preparing the query, running it, turning the returned data into rows, and finishing the result. This shows where an optimisation actually helps, while normal reads do not pay the profiling cost.