From 75c4380496b85e7d2cda2a4445c66514483baa5e Mon Sep 17 00:00:00 2001 From: Chris Nicholas Date: Tue, 24 Feb 2026 11:48:00 +0000 Subject: [PATCH 1/3] Fix license badges (#3111) --- README.md | 30 ++++++------------- packages/liveblocks-client/README.md | 22 ++++---------- packages/liveblocks-emails/README.md | 22 ++++---------- packages/liveblocks-node-lexical/README.md | 15 +++++----- .../liveblocks-node-prosemirror/README.md | 15 +++++----- packages/liveblocks-node/README.md | 22 ++++---------- packages/liveblocks-react-blocknote/README.md | 24 +++++---------- packages/liveblocks-react-lexical/README.md | 24 +++++---------- packages/liveblocks-react-tiptap/README.md | 24 +++++---------- packages/liveblocks-react-ui/README.md | 22 ++++---------- packages/liveblocks-react/README.md | 22 ++++---------- packages/liveblocks-redux/README.md | 22 ++++---------- packages/liveblocks-yjs/README.md | 16 +++++----- packages/liveblocks-zenrouter/README.md | 22 ++++---------- packages/liveblocks-zustand/README.md | 22 ++++---------- 15 files changed, 103 insertions(+), 221 deletions(-) diff --git a/README.md b/README.md index 5e371ecdb16..238f0816415 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,12 @@

- - Liveblocks - - - Liveblocks - + Liveblocks + Liveblocks

- - X - - - Discord - - - YouTube - - - License - + X + Discord + YouTube + License

**[Liveblocks](https://liveblocks.io) gives you the building blocks and @@ -90,8 +78,8 @@ notifications, and more. ## License -Most of this repository is licensed under the Apache License 2.0, Copyright -© 2021-present [Liveblocks](https://liveblocks.io). Some components are -licensed under AGPL-3.0-or-later. +Most of this repository is licensed under the Apache License 2.0, Copyright © +2021-present [Liveblocks](https://liveblocks.io). Some components are licensed +under AGPL-3.0-or-later. See [LICENSE](./LICENSE) for details. diff --git a/packages/liveblocks-client/README.md b/packages/liveblocks-client/README.md index c5abbd19429..1f46fceabf0 100644 --- a/packages/liveblocks-client/README.md +++ b/packages/liveblocks-client/README.md @@ -1,24 +1,14 @@ -

- - Liveblocks - - - Liveblocks - +

+ Liveblocks + Liveblocks

# `@liveblocks/client`

- - NPM - - - Size - - - License - + NPM + Size + License

`@liveblocks/client` provides the APIs to integrate with Liveblocks—a platform diff --git a/packages/liveblocks-emails/README.md b/packages/liveblocks-emails/README.md index a2bf6f76603..9fd5b1324de 100644 --- a/packages/liveblocks-emails/README.md +++ b/packages/liveblocks-emails/README.md @@ -1,24 +1,14 @@ -

- - Liveblocks - - - Liveblocks - +

+ Liveblocks + Liveblocks

# `@liveblocks/emails`

- - NPM - - - Size - - - License - + NPM + Size + License

`@liveblocks/emails` provides a set of functions and utilities to make sending diff --git a/packages/liveblocks-node-lexical/README.md b/packages/liveblocks-node-lexical/README.md index be6ac765f1d..2a18105f02f 100644 --- a/packages/liveblocks-node-lexical/README.md +++ b/packages/liveblocks-node-lexical/README.md @@ -1,14 +1,15 @@ -

- - Liveblocks - - - Liveblocks - +

+ Liveblocks + Liveblocks

# `@liveblocks/node-lexical` +

+ NPM + Size + License + ## License Licensed under the Apache License 2.0, Copyright © 2021-present diff --git a/packages/liveblocks-node-prosemirror/README.md b/packages/liveblocks-node-prosemirror/README.md index 8f2e7be7477..9d8b3b62f3d 100644 --- a/packages/liveblocks-node-prosemirror/README.md +++ b/packages/liveblocks-node-prosemirror/README.md @@ -1,14 +1,15 @@ -

- - Liveblocks - - - Liveblocks - +

+ Liveblocks + Liveblocks

# `@liveblocks/node-prosemirror` +

+ NPM + Size + License + ## License Licensed under the Apache License 2.0, Copyright © 2021-present diff --git a/packages/liveblocks-node/README.md b/packages/liveblocks-node/README.md index 6e36201f464..b3bcab3a04a 100644 --- a/packages/liveblocks-node/README.md +++ b/packages/liveblocks-node/README.md @@ -1,24 +1,14 @@ -

- - Liveblocks - - - Liveblocks - +

+ Liveblocks + Liveblocks

# `@liveblocks/node`

- - NPM - - - Size - - - License - + NPM + Size + License

`@liveblocks/node` provides server-side utilities to set up diff --git a/packages/liveblocks-react-blocknote/README.md b/packages/liveblocks-react-blocknote/README.md index f08f577b803..0e0c1235640 100644 --- a/packages/liveblocks-react-blocknote/README.md +++ b/packages/liveblocks-react-blocknote/README.md @@ -1,24 +1,14 @@ -

- - Liveblocks - - - Liveblocks - +

+ Liveblocks + Liveblocks

- + # `@liveblocks/react-blocknote`

- - NPM - - - Size - - - License - + NPM + Size + License

`@liveblocks/react-blocknote` provides [React](https://reactjs.org/) APIs to diff --git a/packages/liveblocks-react-lexical/README.md b/packages/liveblocks-react-lexical/README.md index 8fc3a2949b0..ac6d7394ca2 100644 --- a/packages/liveblocks-react-lexical/README.md +++ b/packages/liveblocks-react-lexical/README.md @@ -1,24 +1,14 @@ -

- - Liveblocks - - - Liveblocks - +

+ Liveblocks + Liveblocks

- + # `@liveblocks/react-lexical`

- - NPM - - - Size - - - License - + NPM + Size + License

`@liveblocks/react-lexical` provides [React](https://reactjs.org/) APIs to diff --git a/packages/liveblocks-react-tiptap/README.md b/packages/liveblocks-react-tiptap/README.md index 5817568e657..929927abea9 100644 --- a/packages/liveblocks-react-tiptap/README.md +++ b/packages/liveblocks-react-tiptap/README.md @@ -1,24 +1,14 @@ -

- - Liveblocks - - - Liveblocks - +

+ Liveblocks + Liveblocks

- + # `@liveblocks/react-tiptap`

- - NPM - - - Size - - - License - + NPM + Size + License

`@liveblocks/react-tiptap` provides [React](https://reactjs.org/) APIs to diff --git a/packages/liveblocks-react-ui/README.md b/packages/liveblocks-react-ui/README.md index 2b1231e063a..cc4fa8e3281 100644 --- a/packages/liveblocks-react-ui/README.md +++ b/packages/liveblocks-react-ui/README.md @@ -1,24 +1,14 @@ -

- - Liveblocks - - - Liveblocks - +

+ Liveblocks + Liveblocks

# `@liveblocks/react-ui`

- - NPM - - - Size - - - License - + NPM + Size + License

`@liveblocks/react-ui` provides [React](https://reactjs.org/) pre-built diff --git a/packages/liveblocks-react/README.md b/packages/liveblocks-react/README.md index 07584c44eda..5b72ce31c72 100644 --- a/packages/liveblocks-react/README.md +++ b/packages/liveblocks-react/README.md @@ -1,24 +1,14 @@ -

- - Liveblocks - - - Liveblocks - +

+ Liveblocks + Liveblocks

# `@liveblocks/react`

- - NPM - - - Size - - - License - + NPM + Size + License

`@liveblocks/react` provides [React](https://reactjs.org/) hooks and providers diff --git a/packages/liveblocks-redux/README.md b/packages/liveblocks-redux/README.md index 971045dca45..b5f1e6c9315 100644 --- a/packages/liveblocks-redux/README.md +++ b/packages/liveblocks-redux/README.md @@ -1,24 +1,14 @@ -

- - Liveblocks - - - Liveblocks - +

+ Liveblocks + Liveblocks

# `@liveblocks/redux`

- - NPM - - - Size - - - License - + NPM + Size + License

`@liveblocks/redux` provides a diff --git a/packages/liveblocks-yjs/README.md b/packages/liveblocks-yjs/README.md index 4a945171283..bcb76f6bfeb 100644 --- a/packages/liveblocks-yjs/README.md +++ b/packages/liveblocks-yjs/README.md @@ -1,14 +1,16 @@ -

- - Liveblocks - - - Liveblocks - +

+ Liveblocks + Liveblocks

# `@liveblocks/yjs` +

+ NPM + Size + License +

+ `@liveblocks/yjs` is a Yjs provider to integrate [Yjs](https://github.com/yjs/yjs) applications with Liveblocks—a platform to build, host, and scale collaborative applications with zero configuration, no diff --git a/packages/liveblocks-zenrouter/README.md b/packages/liveblocks-zenrouter/README.md index 3b2923e60da..11da92a1426 100644 --- a/packages/liveblocks-zenrouter/README.md +++ b/packages/liveblocks-zenrouter/README.md @@ -1,24 +1,14 @@ -

- - Liveblocks - - - Liveblocks - +

+ Liveblocks + Liveblocks

# `@liveblocks/zenrouter`

- - NPM - - - Size - - - License - + NPM + Size + License

Zen Router is an opinionated API router with batteries included, encouraging diff --git a/packages/liveblocks-zustand/README.md b/packages/liveblocks-zustand/README.md index 38cade6326d..78461219a9f 100644 --- a/packages/liveblocks-zustand/README.md +++ b/packages/liveblocks-zustand/README.md @@ -1,24 +1,14 @@ -

- - Liveblocks - - - Liveblocks - +

+ Liveblocks + Liveblocks

# `@liveblocks/zustand`

- - NPM - - - Size - - - License - + NPM + Size + License

`@liveblocks/zustand` provides a From 4f1a6b937d64f82d4074d1eab29e5683e1535b3a Mon Sep 17 00:00:00 2001 From: Chris Nicholas Date: Tue, 24 Feb 2026 11:48:07 +0000 Subject: [PATCH 2/3] Refactor README.md for badge links and formatting (PR 1613) Original commit: d05804fd54a9db0cd8526736a5076fa6b9c50cb8 --- packages/liveblocks-server/README.md | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/packages/liveblocks-server/README.md b/packages/liveblocks-server/README.md index 0ecc195f2f2..4b4436163d7 100644 --- a/packages/liveblocks-server/README.md +++ b/packages/liveblocks-server/README.md @@ -1,24 +1,14 @@

- - Liveblocks - - - Liveblocks - + Liveblocks + Liveblocks

# `@liveblocks/server`

- - NPM - - - Size - - - License - + NPM + Size + License

`@liveblocks/server` provides the core Liveblocks server functionality. It From 1b523ba407ed8a69431d23095b40a437f9f5f242 Mon Sep 17 00:00:00 2001 From: Vincent Driessen Date: Tue, 24 Feb 2026 16:29:45 +0100 Subject: [PATCH 3/3] Zen polish (PR 1614) Original commit: ce301eeae1cbd9eb0232dbc11b82403a2383c17b --- packages/liveblocks-zenrouter/README.md | 100 ++++++++------------ packages/liveblocks-zenrouter/src/Relay.ts | 4 +- packages/liveblocks-zenrouter/src/Router.ts | 16 ++-- 3 files changed, 49 insertions(+), 71 deletions(-) diff --git a/packages/liveblocks-zenrouter/README.md b/packages/liveblocks-zenrouter/README.md index 11da92a1426..c4caaebd5d3 100644 --- a/packages/liveblocks-zenrouter/README.md +++ b/packages/liveblocks-zenrouter/README.md @@ -30,27 +30,25 @@ The main purpose of this router is to implement an API backend. import { object, string } from "decoders"; import { Router } from "@liveblocks/zenrouter"; -const app = new Router(/* ... */); +const zen = new Router(/* ... */); -app.route( +zen.route( "GET /greet/", ({ p }) => ({ result: `Hi, ${p.name}!` }) ); -app.route( +zen.route( "POST /greet", - object({ - name: string, - }), + object({ name: string }), ({ body }) => ({ result: `Hi, ${body.name}!`, }) ); -export default app; +export default zen; ``` ## The Zen Router pipeline @@ -59,60 +57,40 @@ export default app; ## Principles -General principles: - -- It should be hard to make a mistake in your router setup. -- It should be hard to forget something that will bite you later. -- Secure by default. - -Pragmatic: - -- Implementing real world endpoints should be joyful, easy, and type-safe. -- All requests are JSON (by default) -- All responses are JSON arrays or objects (by default) -- All error responses will have at least an `{ error }` key with a - human-readable string in there -- You can _throw_ any HTTP error or other exception to short-circuit a non-2xx - response. -- Will return JSON error responses by default for all known HTTP errors. Can be - customized. -- CORS support is built-in, and can be enabled with a simple `{ cors: true }` - that is a sane default for most cases. - -Secure/sane by default: - -- Will automatically manage OPTIONS routes and responses -- All requests must be authorized. Authorization is not opt-in, but opt-out. -- All params are verified: `/foo//` (strings by default, or possibly - decoded, always type-safe, available as `p.bar` and `p.qux`) -- All query strings are type-safely accessible: `/foo?abc=hi` accessible as `q` - will be `{ abc: 'hi' }` -- JSON bodies of POST requests will be decoded using a per-request decoder -- Path params cannot be "empty" strings nor can be optional -- All routes params are URI-decoded by default, this is not left to userland. -- CORS can simply be enabled on a Router instance out of the box, following the - simple philosophy that when you want to enable CORS, you wish to enable it for - all endpoints in that router. - -Maintainability: - -- All route patterns are static, and fully qualified, and thus "greppable". This - keeps them readable and unambigious over time. -- In particular, this means it won't allow for a "base" prefix URL setup, which - is often used in other router libraries to DRY up your route strings, but in - practice this makes the code base harder to user over time (because different - subrouters can have what seems to be the same route pattern). -- Routes are registered not just by path, but also by method, as part of the - definition. This will make the routes much more readable and obvious, e.g. - `app.route("POST /v2/foo/bar")` instead of `app.post("/v2/foo/bar")`. -- No complex middlewares. There is just the request context and auth functions. - Those are the only two places where "middleware" can live. No per-route - middlewares. -- No monkey-patching of the request. The request context is the user-defined - place to carry data alongside the request. -- Default error handling can be configured on a per-status code basis (used when - handlers throw a (custom) HttpError), individual requests can always bypass - this by throwing a custom Response. +### Pragmatic + +- Implementing real-world endpoints should be joyful, easy, and type-safe. +- All requests and responses are JSON by default. +- All error responses have at least an `{ error }` key with a human-readable + string. +- You can _throw_ any HTTP error to short-circuit a non-2xx response. +- JSON error responses for all known HTTP status codes, customizable per status + code. +- CORS support is built-in with a sane `{ cors: true }` default that applies to + all endpoints in the router. `OPTIONS` routes and responses are managed + automatically. + +### Secure by default + +- All requests must be authorized. Authorization is opt-out, not opt-in. +- All path params are verified and type-safe (`/foo//` available as + `p.bar` and `p.qux`), cannot be empty, and are URI-decoded automatically. +- Input JSON bodies of POST requests must be validated, and are made available + as a fully-type safe `body` in the handler. +- All query strings are type-safely accessible (`/foo?abc=hi` as `q.abc`). + +### Maintainable + +- All route patterns are static, fully qualified, and thus greppable. No "base" + prefix URL setup, which in practice makes codebases harder to navigate over + time. +- Routes include the method in the definition (`zen.route("POST /v2/foo/bar")` + instead of `zen.post("/v2/foo/bar")`). +- No complex middlewares. Only the request context and auth functions can carry + data alongside a request. No per-route middlewares, no monkey-patching of the + request object. +- Default error handling is configurable per status code; individual handlers + can always bypass it by throwing a custom Response. ## License diff --git a/packages/liveblocks-zenrouter/src/Relay.ts b/packages/liveblocks-zenrouter/src/Relay.ts index e2a2f5ed44d..27b6e8f2eef 100644 --- a/packages/liveblocks-zenrouter/src/Relay.ts +++ b/packages/liveblocks-zenrouter/src/Relay.ts @@ -33,8 +33,8 @@ type RelayOptions = { * If no matching route is found, it will return a generic 404 error response. */ export class ZenRelay { - #_errorHandler: ErrorHandler; - #_routers: [prefixMatcher: RegExp, handler: RequestHandler][] = []; + readonly #_errorHandler: ErrorHandler; + readonly #_routers: [prefixMatcher: RegExp, handler: RequestHandler][] = []; constructor(options?: RelayOptions) { this.#_errorHandler = options?.errorHandler ?? new ErrorHandler(); diff --git a/packages/liveblocks-zenrouter/src/Router.ts b/packages/liveblocks-zenrouter/src/Router.ts index ca078f780c5..211517dfe49 100644 --- a/packages/liveblocks-zenrouter/src/Router.ts +++ b/packages/liveblocks-zenrouter/src/Router.ts @@ -153,14 +153,14 @@ export class ZenRouter< AC, TParams extends Record = {}, > { - #_debug: boolean; - #_contextFn: (req: Request, ...args: readonly any[]) => RC; - #_defaultAuthFn: AuthFn; - #_routes: RouteTuple[]; - #_paramDecoders: TParams; - #_errorHandler: ErrorHandler; - #_cors: Partial | null; - #_otel: OtelConfig | undefined; + readonly #_debug: boolean; + readonly #_contextFn: (req: Request, ...args: readonly any[]) => RC; + readonly #_defaultAuthFn: AuthFn; + readonly #_routes: RouteTuple[]; + readonly #_paramDecoders: TParams; + readonly #_errorHandler: ErrorHandler; + readonly #_cors: Partial | null; + readonly #_otel: OtelConfig | undefined; constructor(options?: RouterOptions) { this.#_errorHandler = options?.errorHandler ?? new ErrorHandler();