I Shipped...

2 June 2026 (3PRs)

a fix for admin secrets being exposed in server startup logs

The Jazz server was logging its full inspector URL at startup, which had the admin secret embedded directly in the link — meaning anyone with access to the logs could see the credential. I removed the secret from the logged URL and added a warning that fires when the server starts without production auth settings configured, so developers aren't silently running in an open state.

a fix for a stack overflow when forwarding rows with deep parent history

When a row has a very long chain of ancestors — around 300 levels deep — the code that forwards rows was calling itself recursively, eventually running out of call-stack space and crashing. I replaced the recursive approach with an iterative post-order walk, so deeply nested row histories no longer cause a stack overflow.

a fix for a permissions head-before-bundle race causing local write denials

When the permission header for a piece of data arrived before the data itself, Jazz was incorrectly rejecting local writes. I removed a redundant authorization call so that Jazz waits until the full data bundle is received before enforcing permissions, eliminating a race condition that caused intermittent test failures in CI.

1 June 2026 (1PR)

a fix for declaration files being emitted outside declarationDir in Svelte's language tools

When a Svelte component imported a TypeScript file from outside the configured source root, the emitDts tool would create .d.ts type declaration files in the wrong place — sometimes nesting them deep in the source tree with doubled absolute paths. I fixed the file-writing hook to skip any declarations that fall outside the intended output directory and to only prepend relative path prefixes when the filename is already relative.

29 May 2026 (1PR)

connection-per-client caps and idle handshake timeouts for the Jazz sync server

I added two defences to the Jazz sync server to prevent a type of denial-of-service attack called a "reconnect storm". First, I capped the number of simultaneous WebSocket connections allowed per client at 4, automatically dropping the oldest connection when the limit is hit and sending a "RateLimited" error code. Second, I added a 10-second timeout for connections that start their handshake but never finish, so idle half-open connections can't pile up indefinitely.

28 May 2026 (2PRs)

a security fix for unauthenticated OOM via WebSocket handshake decompression

I found that the WebSocket handshake frame (the first message when a new connection opens) was being decompressed before we'd checked who was connecting. A malicious actor could send a tiny compressed frame that claimed to expand to gigabytes, crashing the server by running out of memory. I added a check that rejects any handshake frame claiming to be larger than 1 MB — since a real handshake is only a few kilobytes of data, anything bigger is suspicious.

a fix for a Next.js SSR crash caused by duplicate React instances in withJazz

When using jazz with Next.js, our withJazz helper was mistakenly telling Next.js to load jazz-tools as a separate server-side module instead of bundling it together with your app. This caused two separate copies of React to be loaded at the same time — one for the server-rendered pages, one for the client components — which crashes Next.js during pre-rendering. I fixed it by only excluding jazz-napi (the native binary) from bundling, so jazz-tools gets bundled normally with your app and there's just one React instance throughout.

22 May 2026 (3PRs)

documentation for several new Jazz features including the schema hash CLI

I wrote docs for several previously-undocumented Jazz features: a CLI command for inspecting local schema hashes, guidance on what values to use in JWT sub claims (and why changing them later causes problems), how permission columns like $canRead work within nested queries, and two performance optimizations — .indexOnly() for leaner index lookups and .merge("counter") for summing concurrent integer edits without conflicts.

an interactive write-tier diagram for the Jazz docs

I added an interactive diagram to the Jazz documentation that lets you pick a durability tier — local, edge, or global — and watch how a data write propagates across a network of devices. This makes it easier to understand how Jazz handles consistency at different levels and what happens when a device is offline, without having to read through dense text explanations.

a custom declarative diagram engine to replace Mermaid in the Jazz docs

I replaced the Mermaid diagram library in the Jazz docs with a custom-built engine using <Graph> and <Sequence> components. Mermaid wasn't great for interactive, mobile-friendly diagrams — theming and layout control were too limited. The new engine handles desktop and mobile layouts in a single definition and supports animations. I also migrated the four existing diagrams and added 35 unit tests covering the geometry and layout logic.

21 May 2026 (1PR)

a fix for MCP server crashes when node:sqlite is unavailable

I fixed a crash in the Jazz MCP server that happened on Node.js versions older than 22. The crash was caused by the text-search fallback accidentally importing node:sqlite — a database built-in that doesn't exist in older Node versions — before it even had a chance to activate. I extracted the SQLite-free parsing helpers into a new standalone file so the fallback module's dependency chain never touches the database code.

18 May 2026 (5PRs)

reactive LocalFirstAuth support for Svelte and Vue

Jazz already had a React hook for LocalFirstAuth — a way to handle user login in local-first apps (apps that work offline and sync data in the background). I added matching reactive integrations for Svelte and Vue, so developers using those frameworks can use LocalFirstAuth without having to wire up their own reactivity. I also fixed a crash that occurred when the module was imported on the server side, and made sign-out properly propagate across all open tabs.

LocalFirstAuth framework hooks in the Jazz starter templates

The Jazz starter templates had a lot of repetitive boilerplate for setting up authentication. I updated the SvelteKit, React, and Next.js starters to use the new LocalFirstAuth reactive class and framework-specific hooks, which means cleaner code and auth state that automatically rebuilds when something changes — no manual page reload needed.

dropping Node.js 20 support in favour of Node.js 22

Node.js 20 reached end-of-life, meaning it no longer receives security updates. I bumped the minimum required Node.js version to 22.12 and took the opportunity to clean up backwards-compatibility workarounds scattered across 19 files that only existed to support older Node versions.

a Vue 3 todo example for Jazz

I added a new example app showing how to build a local-first todo list using Vue 3 and Jazz. It mirrors the existing React, Svelte, and TypeScript examples, so Vue developers now have a reference starting point too. The example also includes browser-based integration tests using Vitest.

a fix for the jazz-tools CLI silently doing nothing when run through pnpm

When you install Jazz using pnpm, it creates a symlink (a shortcut) pointing to the actual CLI program. The CLI checks whether it's the entry point by comparing file paths, but the symlinked path and the real path are different strings, so it thought it wasn't the entry point and quietly exited without doing anything — making schema pushes and migrations appear to succeed while actually no-oping. I fixed it by resolving both paths to their real locations before comparing them, so the CLI now dispatches correctly whether called directly or through pnpm's symlinks.

15 May 2026 (2PRs)

an animated diagram showing how Jazz syncs data across tiers in the docs

I replaced a static diagram on the "how sync works" docs page with an animated SVG that shows how writes flow between global sync servers, edge servers, and local clients in real time. To keep things readable, I made each writer get a randomly generated color that's always different enough from its previous color. I also refactored the diagram building blocks into a shared module so future diagrams can reuse the same code.

a Dashboard link to the Jazz docs site navigation

I added a link to the Jazz Dashboard in the top navigation bar of the docs site, alongside the existing Blog and Docs links. It opens in a new tab and makes it easier for users to jump between the documentation and the dashboard without having to hunt for the URL.

14 May 2026 (1PR)

a type-level fix for hopTo destination row type inference

When you use hopTo() to jump from one table to a related table in a Jazz query, TypeScript was wrongly inferring that the result still had the type of the original table instead of the destination. I fixed this by properly threading the destination table's type information through the hopTo method, so now TypeScript correctly knows the shape of the data you're working with after the hop. The runtime behaviour was already correct — this was a purely type-level fix.

13 May 2026 (1PR)

three new TypeScript-only starter templates

Jazz's starter templates were all React-based, making it hard to see how Jazz works without a UI framework in the way. I added three new TypeScript-only starters (ts-localfirst, ts-hybrid, and ts-betterauth) that use plain DOM manipulation inside Jazz subscription callbacks, so the core API is front and centre.