diff --git a/assets/management-api/access-tokens.png b/assets/management-api/access-tokens.png
index 98bf40138c6..f57a7b0bda2 100644
Binary files a/assets/management-api/access-tokens.png and b/assets/management-api/access-tokens.png differ
diff --git a/assets/management-api/generate-access-token-dialog.png b/assets/management-api/generate-access-token-dialog.png
index 0b1fc6338ae..20eb105493c 100644
Binary files a/assets/management-api/generate-access-token-dialog.png and b/assets/management-api/generate-access-token-dialog.png differ
diff --git a/assets/nextjs-starter-kit/starter-kit-apps.mp4 b/assets/nextjs-starter-kit/starter-kit-apps.mp4
new file mode 100644
index 00000000000..8ba274a48a4
Binary files /dev/null and b/assets/nextjs-starter-kit/starter-kit-apps.mp4 differ
diff --git a/assets/nextjs-starter-kit/starter-kit.mp4 b/assets/nextjs-starter-kit/starter-kit.mp4
index 6bb924a96ea..fb7977c1286 100644
Binary files a/assets/nextjs-starter-kit/starter-kit.mp4 and b/assets/nextjs-starter-kit/starter-kit.mp4 differ
diff --git a/docs/pages/platform/management-api.mdx b/docs/pages/platform/management-api.mdx
index 969dbcb8be4..0e6226f523b 100644
--- a/docs/pages/platform/management-api.mdx
+++ b/docs/pages/platform/management-api.mdx
@@ -121,19 +121,28 @@ delete icon next to it.
## Access tokens expiry
-All Management API access tokens expire after one year from the date of
-generation. The expiration date is displayed when you generate a new token, and
-you can view it for existing tokens in the Management API tokens list.
+All Management API access tokens have an expiration date. When generating a new
+token, you can choose from the following expiration options:
+
+- **7 days**: Token expires 7 days from creation
+- **30 days**: Token expires 30 days from creation
+- **90 days**: Token expires 90 days from creation
+- **1 year**: Token expires 1 year from creation (default)
+- **Custom date**: Choose a specific expiration date, up to a maximum of 1 year
+ from today
+
+The expiration date is displayed when you generate a new token, and you can view
+it for existing tokens in the Management API tokens list.
When a token expires, you'll need to generate a new token to continue using the
Management API. Make sure to rotate your tokens before they expire to avoid
interruptions in your API access.
-
-
-Zen Router is an opinionated router, with batteries included and encouraging
-patterns that remain maintable over time as your application grows.
+
+
+# `@liveblocks/zenrouter`
+
+
+
+Zen Router is an opinionated API router with batteries included, encouraging
+patterns that remain maintainable as your application grows.
## Installation
@@ -102,3 +123,10 @@ Maintainability:
- 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.
+
+## License
+
+Licensed under the Apache License 2.0, Copyright © 2021-present
+[Liveblocks](https://liveblocks.io).
+
+See [LICENSE](../../licenses/LICENSE-APACHE-2.0) for more information.
diff --git a/packages/liveblocks-zenrouter/assets/zen-router.webp b/packages/liveblocks-zenrouter/assets/zen-router.webp
deleted file mode 100644
index 1816d38800a..00000000000
Binary files a/packages/liveblocks-zenrouter/assets/zen-router.webp and /dev/null differ
diff --git a/packages/liveblocks-zenrouter/package.json b/packages/liveblocks-zenrouter/package.json
index e679e61dc5a..86090c677dd 100644
--- a/packages/liveblocks-zenrouter/package.json
+++ b/packages/liveblocks-zenrouter/package.json
@@ -1,6 +1,6 @@
{
"name": "@liveblocks/zenrouter",
- "version": "1.0.11",
+ "version": "1.0.12",
"description": "An opinionated router library for building APIs following best practices.",
"type": "module",
"main": "./dist/index.js",
@@ -38,12 +38,10 @@
"license": "Apache-2.0",
"devDependencies": {
"@liveblocks/eslint-config": "*",
+ "decoders": "^2.8.0",
"hotscript": "^1.0.13",
- "nanoid": "^3"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.9.0",
- "decoders": "^2.8.0-1"
+ "nanoid": "^3",
+ "zod": "^4.1.8"
},
"repository": {
"type": "git",
diff --git a/packages/liveblocks-zenrouter/src/Router.ts b/packages/liveblocks-zenrouter/src/Router.ts
index e05c0c73254..ca078f780c5 100644
--- a/packages/liveblocks-zenrouter/src/Router.ts
+++ b/packages/liveblocks-zenrouter/src/Router.ts
@@ -2,18 +2,17 @@
// TODO: Make this a local definition?
import type { Json, JsonObject } from "@liveblocks/core";
-import { context, trace } from "@opentelemetry/api";
-import type { Decoder } from "decoders";
-import { formatShort } from "decoders";
import type {
ExtractParams,
HttpVerb,
- MapDecoderTypes,
+ MapSchemaOutput,
Pattern,
RouteMatcher,
} from "~/lib/matchers.js";
import { routeMatcher, sortHttpVerbsInPlace } from "~/lib/matchers.js";
+import type { OtelConfig } from "~/lib/otel.js";
+import type { StandardSchemaV1 } from "~/lib/standard-schema.js";
import { mapv, raise } from "~/lib/utils.js";
import type { HttpError } from "~/responses/index.js";
import { abort, json, ValidationError } from "~/responses/index.js";
@@ -104,11 +103,11 @@ type RouteTuple>, + ExtractParams
>, never > ): void; public route
( pattern: P, - bodyDecoder: Decoder
, + bodySchema: StandardSchemaV1>, + ExtractParams
>,
TBody
>
): void;
@@ -212,12 +219,12 @@ export class ZenRouter<
public route(first: any, second: any, third?: any): void {
/* eslint-enable @typescript-eslint/explicit-module-boundary-types */
const pattern = first;
- const bodyDecoder = arguments.length >= 3 ? second : null;
+ const bodySchema = arguments.length >= 3 ? second : null;
const handler = arguments.length >= 3 ? third : second;
/* eslint-enable @typescript-eslint/no-unsafe-assignment */
this.#_register(
pattern,
- bodyDecoder,
+ bodySchema,
handler as RouteHandler (
pattern: P,
- bodyDecoder: Decoder = Pipe<
* For:
*
* {
- * a: Decoder