From c68fa0f1b86b6e1cae4a0273632862b12d744825 Mon Sep 17 00:00:00 2001
From: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
Date: Thu, 19 Mar 2026 01:42:04 +0000
Subject: [PATCH 1/6] chore: sync sponsors
---
README.md | 4 +--
apps/content/.vitepress/theme/sponsors.ts | 26 +++++++++----------
packages/ai-sdk/README.md | 4 +--
packages/arktype/README.md | 4 +--
packages/client/README.md | 4 +--
packages/contract/README.md | 4 +--
packages/durable-iterator/README.md | 4 +--
packages/hey-api/README.md | 4 +--
packages/interop/README.md | 4 +--
packages/json-schema/README.md | 4 +--
packages/nest/README.md | 4 +--
packages/openapi-client/README.md | 4 +--
packages/openapi/README.md | 4 +--
packages/otel/README.md | 4 +--
packages/pino/README.md | 4 +--
packages/publisher-durable-object/README.md | 4 +--
packages/publisher/README.md | 4 +--
packages/ratelimit/README.md | 4 +--
packages/react-query/README.md | 4 +--
packages/react-swr/README.md | 4 +--
packages/react/README.md | 4 +--
packages/server/README.md | 4 +--
packages/shared/README.md | 4 +--
packages/solid-query/README.md | 4 +--
packages/standard-server-aws-lambda/README.md | 4 +--
packages/standard-server-fastify/README.md | 4 +--
packages/standard-server-fetch/README.md | 4 +--
packages/standard-server-node/README.md | 4 +--
packages/standard-server-peer/README.md | 4 +--
packages/standard-server/README.md | 4 +--
packages/svelte-query/README.md | 4 +--
packages/tanstack-query/README.md | 4 +--
packages/trpc/README.md | 4 +--
packages/valibot/README.md | 4 +--
packages/vue-colada/README.md | 4 +--
packages/vue-query/README.md | 4 +--
packages/zod/README.md | 4 +--
playgrounds/astro/README.md | 4 +--
playgrounds/browser-extension/README.md | 4 +--
playgrounds/bun-websocket-otel/README.md | 4 +--
playgrounds/cloudflare-worker/README.md | 4 +--
playgrounds/contract-first/README.md | 4 +--
playgrounds/electron/README.md | 4 +--
playgrounds/nest/README.md | 4 +--
playgrounds/next/README.md | 4 +--
playgrounds/nuxt/README.md | 4 +--
playgrounds/solid-start/README.md | 4 +--
playgrounds/svelte-kit/README.md | 4 +--
playgrounds/tanstack-start/README.md | 4 +--
49 files changed, 109 insertions(+), 109 deletions(-)
diff --git a/README.md b/README.md
index 2c5a3e709..c356546d4 100644
--- a/README.md
+++ b/README.md
@@ -223,7 +223,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -251,13 +250,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/apps/content/.vitepress/theme/sponsors.ts b/apps/content/.vitepress/theme/sponsors.ts
index d4d8e9ccd..cb367ffc4 100644
--- a/apps/content/.vitepress/theme/sponsors.ts
+++ b/apps/content/.vitepress/theme/sponsors.ts
@@ -56,19 +56,6 @@ export const sponsors: JSONSponsor[] = [
sidebarSize: 'normal',
sidebarLogo: 'https://cdn.jsdelivr.net/gh/middleapi/static/assets/MisskeyHQ_TextLogo.png',
},
- {
- name: 'Valerii Petryniak',
- login: 'valerii15298',
- avatar: 'https://avatars.githubusercontent.com/u/44531564?u=88ac74d9bacd20401518441907acad21063cd397&v=4',
- amount: 200,
- link: 'https://valerii15298.github.io/?ref=orpc',
- org: false,
- createdAt: '2025-05-22T21:44:12Z',
- tierTitle: '🥈 Silver Sponsor',
- tierLevel: 5,
- sidebarSize: 'none',
- sidebarLogo: 'https://avatars.githubusercontent.com/u/44531564?u=88ac74d9bacd20401518441907acad21063cd397&v=4',
- },
{
name: null,
login: 'christ12938',
@@ -212,6 +199,19 @@ export const sponsors: JSONSponsor[] = [
sidebarSize: 'none',
sidebarLogo: 'https://avatars.githubusercontent.com/u/23610?v=4',
},
+ {
+ name: 'Valerii Petryniak',
+ login: 'valerii15298',
+ avatar: 'https://avatars.githubusercontent.com/u/44531564?u=88ac74d9bacd20401518441907acad21063cd397&v=4',
+ amount: 10,
+ link: 'https://github.com/valerii15298?ref=orpc',
+ org: false,
+ createdAt: '2025-05-22T21:44:12Z',
+ tierTitle: 'Sponsors',
+ tierLevel: 2,
+ sidebarSize: 'none',
+ sidebarLogo: 'https://avatars.githubusercontent.com/u/44531564?u=88ac74d9bacd20401518441907acad21063cd397&v=4',
+ },
{
name: 'happyboy',
login: 'happyboy2022',
diff --git a/packages/ai-sdk/README.md b/packages/ai-sdk/README.md
index 422512175..4a325e07f 100644
--- a/packages/ai-sdk/README.md
+++ b/packages/ai-sdk/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/arktype/README.md b/packages/arktype/README.md
index be9760818..886d2d29f 100644
--- a/packages/arktype/README.md
+++ b/packages/arktype/README.md
@@ -122,7 +122,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -150,13 +149,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/client/README.md b/packages/client/README.md
index bcf37a5e9..64187d26c 100644
--- a/packages/client/README.md
+++ b/packages/client/README.md
@@ -113,7 +113,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -141,13 +140,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/contract/README.md b/packages/contract/README.md
index fb53bbcc2..b8ca6e45a 100644
--- a/packages/contract/README.md
+++ b/packages/contract/README.md
@@ -126,7 +126,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -154,13 +153,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/durable-iterator/README.md b/packages/durable-iterator/README.md
index 6ff70580e..622b788b0 100644
--- a/packages/durable-iterator/README.md
+++ b/packages/durable-iterator/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/hey-api/README.md b/packages/hey-api/README.md
index a438e1642..05e833464 100644
--- a/packages/hey-api/README.md
+++ b/packages/hey-api/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/interop/README.md b/packages/interop/README.md
index 00b38e1b5..5cedb917e 100644
--- a/packages/interop/README.md
+++ b/packages/interop/README.md
@@ -100,7 +100,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -128,13 +127,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/json-schema/README.md b/packages/json-schema/README.md
index f8dbc4913..b839a8113 100644
--- a/packages/json-schema/README.md
+++ b/packages/json-schema/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/nest/README.md b/packages/nest/README.md
index fd4474e04..6bb8f0e14 100644
--- a/packages/nest/README.md
+++ b/packages/nest/README.md
@@ -147,7 +147,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -175,13 +174,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/openapi-client/README.md b/packages/openapi-client/README.md
index 213032676..8a959bd5d 100644
--- a/packages/openapi-client/README.md
+++ b/packages/openapi-client/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/openapi/README.md b/packages/openapi/README.md
index e845fdc0a..043ef4cf7 100644
--- a/packages/openapi/README.md
+++ b/packages/openapi/README.md
@@ -116,7 +116,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -144,13 +143,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/otel/README.md b/packages/otel/README.md
index 91cc4046d..52a12cefb 100644
--- a/packages/otel/README.md
+++ b/packages/otel/README.md
@@ -114,7 +114,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -142,13 +141,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/pino/README.md b/packages/pino/README.md
index 573c16d25..9e0755692 100644
--- a/packages/pino/README.md
+++ b/packages/pino/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/publisher-durable-object/README.md b/packages/publisher-durable-object/README.md
index de61413c9..b31e3e32f 100644
--- a/packages/publisher-durable-object/README.md
+++ b/packages/publisher-durable-object/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/publisher/README.md b/packages/publisher/README.md
index c059bc869..3ffef1762 100644
--- a/packages/publisher/README.md
+++ b/packages/publisher/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/ratelimit/README.md b/packages/ratelimit/README.md
index 5534be886..cfd8c78a3 100644
--- a/packages/ratelimit/README.md
+++ b/packages/ratelimit/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/react-query/README.md b/packages/react-query/README.md
index ef0517ca7..990fd71f9 100644
--- a/packages/react-query/README.md
+++ b/packages/react-query/README.md
@@ -135,7 +135,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -163,13 +162,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/react-swr/README.md b/packages/react-swr/README.md
index 56f7161bc..7fc656e12 100644
--- a/packages/react-swr/README.md
+++ b/packages/react-swr/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/react/README.md b/packages/react/README.md
index 5ebdb0f04..d21b18151 100644
--- a/packages/react/README.md
+++ b/packages/react/README.md
@@ -168,7 +168,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -196,13 +195,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/server/README.md b/packages/server/README.md
index 1c9d1c344..10a279dc3 100644
--- a/packages/server/README.md
+++ b/packages/server/README.md
@@ -143,7 +143,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -171,13 +170,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/shared/README.md b/packages/shared/README.md
index a0e3e9045..3df74855a 100644
--- a/packages/shared/README.md
+++ b/packages/shared/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/solid-query/README.md b/packages/solid-query/README.md
index fdc01a69d..0135a9368 100644
--- a/packages/solid-query/README.md
+++ b/packages/solid-query/README.md
@@ -135,7 +135,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -163,13 +162,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/standard-server-aws-lambda/README.md b/packages/standard-server-aws-lambda/README.md
index 4ba1f998b..da0c6eb43 100644
--- a/packages/standard-server-aws-lambda/README.md
+++ b/packages/standard-server-aws-lambda/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/standard-server-fastify/README.md b/packages/standard-server-fastify/README.md
index df3bfb12f..1a2efb0bf 100644
--- a/packages/standard-server-fastify/README.md
+++ b/packages/standard-server-fastify/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/standard-server-fetch/README.md b/packages/standard-server-fetch/README.md
index 1785bb767..b65e4d6be 100644
--- a/packages/standard-server-fetch/README.md
+++ b/packages/standard-server-fetch/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/standard-server-node/README.md b/packages/standard-server-node/README.md
index 2dcce1426..a42f0e082 100644
--- a/packages/standard-server-node/README.md
+++ b/packages/standard-server-node/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/standard-server-peer/README.md b/packages/standard-server-peer/README.md
index 3c6fe4374..fd3bd3674 100644
--- a/packages/standard-server-peer/README.md
+++ b/packages/standard-server-peer/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/standard-server/README.md b/packages/standard-server/README.md
index c65bcdfb5..d51f6aa80 100644
--- a/packages/standard-server/README.md
+++ b/packages/standard-server/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/svelte-query/README.md b/packages/svelte-query/README.md
index 010fb17df..90d60f538 100644
--- a/packages/svelte-query/README.md
+++ b/packages/svelte-query/README.md
@@ -135,7 +135,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -163,13 +162,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/tanstack-query/README.md b/packages/tanstack-query/README.md
index 22f2aa14b..a85454e8a 100644
--- a/packages/tanstack-query/README.md
+++ b/packages/tanstack-query/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/trpc/README.md b/packages/trpc/README.md
index bcf2f6c6f..89157643e 100644
--- a/packages/trpc/README.md
+++ b/packages/trpc/README.md
@@ -93,7 +93,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -121,13 +120,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/valibot/README.md b/packages/valibot/README.md
index 3dd3b933e..a1a89dd10 100644
--- a/packages/valibot/README.md
+++ b/packages/valibot/README.md
@@ -120,7 +120,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -148,13 +147,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/vue-colada/README.md b/packages/vue-colada/README.md
index 8e9895b6a..85b59b46f 100644
--- a/packages/vue-colada/README.md
+++ b/packages/vue-colada/README.md
@@ -122,7 +122,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -150,13 +149,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/vue-query/README.md b/packages/vue-query/README.md
index 9780ece6a..787b4403d 100644
--- a/packages/vue-query/README.md
+++ b/packages/vue-query/README.md
@@ -135,7 +135,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -163,13 +162,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/packages/zod/README.md b/packages/zod/README.md
index 756d7f60b..721832d4a 100644
--- a/packages/zod/README.md
+++ b/packages/zod/README.md
@@ -157,7 +157,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -185,13 +184,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/playgrounds/astro/README.md b/playgrounds/astro/README.md
index 99480dee9..4ca339a4d 100644
--- a/playgrounds/astro/README.md
+++ b/playgrounds/astro/README.md
@@ -38,7 +38,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -66,13 +65,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/playgrounds/browser-extension/README.md b/playgrounds/browser-extension/README.md
index d1509aa45..2b1d2ae68 100644
--- a/playgrounds/browser-extension/README.md
+++ b/playgrounds/browser-extension/README.md
@@ -35,7 +35,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -63,13 +62,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/playgrounds/bun-websocket-otel/README.md b/playgrounds/bun-websocket-otel/README.md
index 4892e1d5b..8fdda6ba9 100644
--- a/playgrounds/bun-websocket-otel/README.md
+++ b/playgrounds/bun-websocket-otel/README.md
@@ -39,7 +39,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -67,13 +66,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/playgrounds/cloudflare-worker/README.md b/playgrounds/cloudflare-worker/README.md
index ccda7f8d0..71d5fbdec 100644
--- a/playgrounds/cloudflare-worker/README.md
+++ b/playgrounds/cloudflare-worker/README.md
@@ -38,7 +38,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -66,13 +65,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/playgrounds/contract-first/README.md b/playgrounds/contract-first/README.md
index 3e0058d99..473622100 100644
--- a/playgrounds/contract-first/README.md
+++ b/playgrounds/contract-first/README.md
@@ -38,7 +38,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -66,13 +65,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/playgrounds/electron/README.md b/playgrounds/electron/README.md
index 18760105f..4743d639b 100644
--- a/playgrounds/electron/README.md
+++ b/playgrounds/electron/README.md
@@ -35,7 +35,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -63,13 +62,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/playgrounds/nest/README.md b/playgrounds/nest/README.md
index fe4b226d7..7095ea43e 100644
--- a/playgrounds/nest/README.md
+++ b/playgrounds/nest/README.md
@@ -37,7 +37,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -65,13 +64,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/playgrounds/next/README.md b/playgrounds/next/README.md
index 99364b7af..04891807a 100644
--- a/playgrounds/next/README.md
+++ b/playgrounds/next/README.md
@@ -38,7 +38,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -66,13 +65,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/playgrounds/nuxt/README.md b/playgrounds/nuxt/README.md
index c50f5bebd..2e93f7df0 100644
--- a/playgrounds/nuxt/README.md
+++ b/playgrounds/nuxt/README.md
@@ -38,7 +38,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -66,13 +65,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/playgrounds/solid-start/README.md b/playgrounds/solid-start/README.md
index 21669505b..707d2e086 100644
--- a/playgrounds/solid-start/README.md
+++ b/playgrounds/solid-start/README.md
@@ -38,7 +38,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -66,13 +65,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/playgrounds/svelte-kit/README.md b/playgrounds/svelte-kit/README.md
index f6f71f7d2..4caf0802c 100644
--- a/playgrounds/svelte-kit/README.md
+++ b/playgrounds/svelte-kit/README.md
@@ -38,7 +38,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -66,13 +65,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
diff --git a/playgrounds/tanstack-start/README.md b/playgrounds/tanstack-start/README.md
index c1b289c15..05e4cdf5a 100644
--- a/playgrounds/tanstack-start/README.md
+++ b/playgrounds/tanstack-start/README.md
@@ -38,7 +38,6 @@ If you find oRPC valuable and would like to support its development, you can do
@@ -66,13 +65,14 @@ If you find oRPC valuable and would like to support its development, you can do
Ryota Murakami
David Cramer
+ Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
- Ryan Vogel
+ Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
From 6068d87b447de2f130b8665d7e81a100ddaca753 Mon Sep 17 00:00:00 2001
From: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
Date: Sun, 22 Mar 2026 01:40:43 +0000
Subject: [PATCH 2/6] chore: sync sponsors
---
README.md | 6 ++---
apps/content/.vitepress/theme/sponsors.ts | 26 +++++++++----------
packages/ai-sdk/README.md | 6 ++---
packages/arktype/README.md | 6 ++---
packages/client/README.md | 6 ++---
packages/contract/README.md | 6 ++---
packages/durable-iterator/README.md | 6 ++---
packages/hey-api/README.md | 6 ++---
packages/interop/README.md | 6 ++---
packages/json-schema/README.md | 6 ++---
packages/nest/README.md | 6 ++---
packages/openapi-client/README.md | 6 ++---
packages/openapi/README.md | 6 ++---
packages/otel/README.md | 6 ++---
packages/pino/README.md | 6 ++---
packages/publisher-durable-object/README.md | 6 ++---
packages/publisher/README.md | 6 ++---
packages/ratelimit/README.md | 6 ++---
packages/react-query/README.md | 6 ++---
packages/react-swr/README.md | 6 ++---
packages/react/README.md | 6 ++---
packages/server/README.md | 6 ++---
packages/shared/README.md | 6 ++---
packages/solid-query/README.md | 6 ++---
packages/standard-server-aws-lambda/README.md | 6 ++---
packages/standard-server-fastify/README.md | 6 ++---
packages/standard-server-fetch/README.md | 6 ++---
packages/standard-server-node/README.md | 6 ++---
packages/standard-server-peer/README.md | 6 ++---
packages/standard-server/README.md | 6 ++---
packages/svelte-query/README.md | 6 ++---
packages/tanstack-query/README.md | 6 ++---
packages/trpc/README.md | 6 ++---
packages/valibot/README.md | 6 ++---
packages/vue-colada/README.md | 6 ++---
packages/vue-query/README.md | 6 ++---
packages/zod/README.md | 6 ++---
playgrounds/astro/README.md | 6 ++---
playgrounds/browser-extension/README.md | 6 ++---
playgrounds/bun-websocket-otel/README.md | 6 ++---
playgrounds/cloudflare-worker/README.md | 6 ++---
playgrounds/contract-first/README.md | 6 ++---
playgrounds/electron/README.md | 6 ++---
playgrounds/nest/README.md | 6 ++---
playgrounds/next/README.md | 6 ++---
playgrounds/nuxt/README.md | 6 ++---
playgrounds/solid-start/README.md | 6 ++---
playgrounds/svelte-kit/README.md | 6 ++---
playgrounds/tanstack-start/README.md | 6 ++---
49 files changed, 157 insertions(+), 157 deletions(-)
diff --git a/README.md b/README.md
index c356546d4..2bd819aa0 100644
--- a/README.md
+++ b/README.md
@@ -240,24 +240,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -314,6 +313,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## References
diff --git a/apps/content/.vitepress/theme/sponsors.ts b/apps/content/.vitepress/theme/sponsors.ts
index cb367ffc4..31e43a677 100644
--- a/apps/content/.vitepress/theme/sponsors.ts
+++ b/apps/content/.vitepress/theme/sponsors.ts
@@ -95,19 +95,6 @@ export const sponsors: JSONSponsor[] = [
sidebarSize: 'none',
sidebarLogo: 'https://avatars.githubusercontent.com/u/39349270?v=4',
},
- {
- name: 'Sefa Eyeoglu',
- login: 'Scrumplex',
- avatar: 'https://avatars.githubusercontent.com/u/11587657?u=ab503582165c0bbff0cca47ce31c9450bb1553c9&v=4',
- amount: 20,
- link: 'https://github.com/Scrumplex?ref=orpc',
- org: false,
- createdAt: '2026-02-19T13:13:45Z',
- tierTitle: 'Sponsors',
- tierLevel: 2,
- sidebarSize: 'none',
- sidebarLogo: 'https://avatars.githubusercontent.com/u/11587657?u=ab503582165c0bbff0cca47ce31c9450bb1553c9&v=4',
- },
{
name: 'あわわわとーにゅ',
login: 'u1-liquid',
@@ -810,4 +797,17 @@ export const sponsors: JSONSponsor[] = [
sidebarSize: 'none',
sidebarLogo: 'https://avatars.githubusercontent.com/u/5012724?u=7cfa13652f7ac5fb3c56d880e3eb3fbe40c3ea34&v=4',
},
+ {
+ name: 'Sefa Eyeoglu',
+ login: 'Scrumplex',
+ avatar: 'https://avatars.githubusercontent.com/u/11587657?u=ab503582165c0bbff0cca47ce31c9450bb1553c9&v=4',
+ amount: -1,
+ link: 'https://github.com/Scrumplex?ref=orpc',
+ org: false,
+ createdAt: '2026-02-19T13:13:45Z',
+ tierTitle: 'Past Sponsors',
+ tierLevel: 0,
+ sidebarSize: 'none',
+ sidebarLogo: 'https://avatars.githubusercontent.com/u/11587657?u=ab503582165c0bbff0cca47ce31c9450bb1553c9&v=4',
+ },
]
diff --git a/packages/ai-sdk/README.md b/packages/ai-sdk/README.md
index 4a325e07f..6bf4dea9e 100644
--- a/packages/ai-sdk/README.md
+++ b/packages/ai-sdk/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/arktype/README.md b/packages/arktype/README.md
index 886d2d29f..affc23530 100644
--- a/packages/arktype/README.md
+++ b/packages/arktype/README.md
@@ -139,24 +139,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -213,6 +212,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/client/README.md b/packages/client/README.md
index 64187d26c..f6f407f29 100644
--- a/packages/client/README.md
+++ b/packages/client/README.md
@@ -130,24 +130,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -204,6 +203,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/contract/README.md b/packages/contract/README.md
index b8ca6e45a..a7198c691 100644
--- a/packages/contract/README.md
+++ b/packages/contract/README.md
@@ -143,24 +143,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -217,6 +216,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/durable-iterator/README.md b/packages/durable-iterator/README.md
index 622b788b0..8ef067775 100644
--- a/packages/durable-iterator/README.md
+++ b/packages/durable-iterator/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/hey-api/README.md b/packages/hey-api/README.md
index 05e833464..3a42eddbf 100644
--- a/packages/hey-api/README.md
+++ b/packages/hey-api/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/interop/README.md b/packages/interop/README.md
index 5cedb917e..c3ab39d78 100644
--- a/packages/interop/README.md
+++ b/packages/interop/README.md
@@ -117,24 +117,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -191,6 +190,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/json-schema/README.md b/packages/json-schema/README.md
index b839a8113..320e258a1 100644
--- a/packages/json-schema/README.md
+++ b/packages/json-schema/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/nest/README.md b/packages/nest/README.md
index 6bb8f0e14..5f0b98f19 100644
--- a/packages/nest/README.md
+++ b/packages/nest/README.md
@@ -164,24 +164,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -238,6 +237,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/openapi-client/README.md b/packages/openapi-client/README.md
index 8a959bd5d..23f6840f1 100644
--- a/packages/openapi-client/README.md
+++ b/packages/openapi-client/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/openapi/README.md b/packages/openapi/README.md
index 043ef4cf7..1e385925d 100644
--- a/packages/openapi/README.md
+++ b/packages/openapi/README.md
@@ -133,24 +133,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -207,6 +206,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/otel/README.md b/packages/otel/README.md
index 52a12cefb..18d040a9b 100644
--- a/packages/otel/README.md
+++ b/packages/otel/README.md
@@ -131,24 +131,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -205,6 +204,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/pino/README.md b/packages/pino/README.md
index 9e0755692..de6c1b373 100644
--- a/packages/pino/README.md
+++ b/packages/pino/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/publisher-durable-object/README.md b/packages/publisher-durable-object/README.md
index b31e3e32f..5e085e708 100644
--- a/packages/publisher-durable-object/README.md
+++ b/packages/publisher-durable-object/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/publisher/README.md b/packages/publisher/README.md
index 3ffef1762..6d1e56752 100644
--- a/packages/publisher/README.md
+++ b/packages/publisher/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/ratelimit/README.md b/packages/ratelimit/README.md
index cfd8c78a3..a59f94c73 100644
--- a/packages/ratelimit/README.md
+++ b/packages/ratelimit/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/react-query/README.md b/packages/react-query/README.md
index 990fd71f9..f8714e4a7 100644
--- a/packages/react-query/README.md
+++ b/packages/react-query/README.md
@@ -152,24 +152,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -226,6 +225,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/react-swr/README.md b/packages/react-swr/README.md
index 7fc656e12..83f190c25 100644
--- a/packages/react-swr/README.md
+++ b/packages/react-swr/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/react/README.md b/packages/react/README.md
index d21b18151..dca63c781 100644
--- a/packages/react/README.md
+++ b/packages/react/README.md
@@ -185,24 +185,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -259,6 +258,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/server/README.md b/packages/server/README.md
index 10a279dc3..c7efe359a 100644
--- a/packages/server/README.md
+++ b/packages/server/README.md
@@ -160,24 +160,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -234,6 +233,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/shared/README.md b/packages/shared/README.md
index 3df74855a..66d5d101c 100644
--- a/packages/shared/README.md
+++ b/packages/shared/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/solid-query/README.md b/packages/solid-query/README.md
index 0135a9368..fd8a524eb 100644
--- a/packages/solid-query/README.md
+++ b/packages/solid-query/README.md
@@ -152,24 +152,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -226,6 +225,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/standard-server-aws-lambda/README.md b/packages/standard-server-aws-lambda/README.md
index da0c6eb43..a17da0365 100644
--- a/packages/standard-server-aws-lambda/README.md
+++ b/packages/standard-server-aws-lambda/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/standard-server-fastify/README.md b/packages/standard-server-fastify/README.md
index 1a2efb0bf..408815266 100644
--- a/packages/standard-server-fastify/README.md
+++ b/packages/standard-server-fastify/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/standard-server-fetch/README.md b/packages/standard-server-fetch/README.md
index b65e4d6be..94baac1e1 100644
--- a/packages/standard-server-fetch/README.md
+++ b/packages/standard-server-fetch/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/standard-server-node/README.md b/packages/standard-server-node/README.md
index a42f0e082..08194671f 100644
--- a/packages/standard-server-node/README.md
+++ b/packages/standard-server-node/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/standard-server-peer/README.md b/packages/standard-server-peer/README.md
index fd3bd3674..f0c3385a3 100644
--- a/packages/standard-server-peer/README.md
+++ b/packages/standard-server-peer/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/standard-server/README.md b/packages/standard-server/README.md
index d51f6aa80..171e18d5f 100644
--- a/packages/standard-server/README.md
+++ b/packages/standard-server/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/svelte-query/README.md b/packages/svelte-query/README.md
index 90d60f538..77ac8614e 100644
--- a/packages/svelte-query/README.md
+++ b/packages/svelte-query/README.md
@@ -152,24 +152,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -226,6 +225,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/tanstack-query/README.md b/packages/tanstack-query/README.md
index a85454e8a..f54d38802 100644
--- a/packages/tanstack-query/README.md
+++ b/packages/tanstack-query/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/trpc/README.md b/packages/trpc/README.md
index 89157643e..77c53474e 100644
--- a/packages/trpc/README.md
+++ b/packages/trpc/README.md
@@ -110,24 +110,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -184,6 +183,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/valibot/README.md b/packages/valibot/README.md
index a1a89dd10..d8c8d2512 100644
--- a/packages/valibot/README.md
+++ b/packages/valibot/README.md
@@ -137,24 +137,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -211,6 +210,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/vue-colada/README.md b/packages/vue-colada/README.md
index 85b59b46f..c3c8e4369 100644
--- a/packages/vue-colada/README.md
+++ b/packages/vue-colada/README.md
@@ -139,24 +139,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -213,6 +212,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/vue-query/README.md b/packages/vue-query/README.md
index 787b4403d..0e26fcedc 100644
--- a/packages/vue-query/README.md
+++ b/packages/vue-query/README.md
@@ -152,24 +152,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -226,6 +225,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/packages/zod/README.md b/packages/zod/README.md
index 721832d4a..90638cf23 100644
--- a/packages/zod/README.md
+++ b/packages/zod/README.md
@@ -174,24 +174,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -248,6 +247,7 @@ If you find oRPC valuable and would like to support its development, you can do
+
## License
diff --git a/playgrounds/astro/README.md b/playgrounds/astro/README.md
index 4ca339a4d..65bd103d9 100644
--- a/playgrounds/astro/README.md
+++ b/playgrounds/astro/README.md
@@ -55,24 +55,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -129,4 +128,5 @@ If you find oRPC valuable and would like to support its development, you can do
+
diff --git a/playgrounds/browser-extension/README.md b/playgrounds/browser-extension/README.md
index 2b1d2ae68..3ec303184 100644
--- a/playgrounds/browser-extension/README.md
+++ b/playgrounds/browser-extension/README.md
@@ -52,24 +52,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -126,4 +125,5 @@ If you find oRPC valuable and would like to support its development, you can do
+
diff --git a/playgrounds/bun-websocket-otel/README.md b/playgrounds/bun-websocket-otel/README.md
index 8fdda6ba9..587e86990 100644
--- a/playgrounds/bun-websocket-otel/README.md
+++ b/playgrounds/bun-websocket-otel/README.md
@@ -56,24 +56,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -130,4 +129,5 @@ If you find oRPC valuable and would like to support its development, you can do
+
diff --git a/playgrounds/cloudflare-worker/README.md b/playgrounds/cloudflare-worker/README.md
index 71d5fbdec..a5679812b 100644
--- a/playgrounds/cloudflare-worker/README.md
+++ b/playgrounds/cloudflare-worker/README.md
@@ -55,24 +55,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -129,4 +128,5 @@ If you find oRPC valuable and would like to support its development, you can do
+
diff --git a/playgrounds/contract-first/README.md b/playgrounds/contract-first/README.md
index 473622100..ab497e619 100644
--- a/playgrounds/contract-first/README.md
+++ b/playgrounds/contract-first/README.md
@@ -55,24 +55,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -129,4 +128,5 @@ If you find oRPC valuable and would like to support its development, you can do
+
diff --git a/playgrounds/electron/README.md b/playgrounds/electron/README.md
index 4743d639b..f20357daf 100644
--- a/playgrounds/electron/README.md
+++ b/playgrounds/electron/README.md
@@ -52,24 +52,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -126,4 +125,5 @@ If you find oRPC valuable and would like to support its development, you can do
+
diff --git a/playgrounds/nest/README.md b/playgrounds/nest/README.md
index 7095ea43e..92bea6ca1 100644
--- a/playgrounds/nest/README.md
+++ b/playgrounds/nest/README.md
@@ -54,24 +54,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -128,4 +127,5 @@ If you find oRPC valuable and would like to support its development, you can do
+
diff --git a/playgrounds/next/README.md b/playgrounds/next/README.md
index 04891807a..dd13e83e4 100644
--- a/playgrounds/next/README.md
+++ b/playgrounds/next/README.md
@@ -55,24 +55,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -129,4 +128,5 @@ If you find oRPC valuable and would like to support its development, you can do
+
diff --git a/playgrounds/nuxt/README.md b/playgrounds/nuxt/README.md
index 2e93f7df0..284adeb91 100644
--- a/playgrounds/nuxt/README.md
+++ b/playgrounds/nuxt/README.md
@@ -55,24 +55,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -129,4 +128,5 @@ If you find oRPC valuable and would like to support its development, you can do
+
diff --git a/playgrounds/solid-start/README.md b/playgrounds/solid-start/README.md
index 707d2e086..caa16711e 100644
--- a/playgrounds/solid-start/README.md
+++ b/playgrounds/solid-start/README.md
@@ -55,24 +55,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -129,4 +128,5 @@ If you find oRPC valuable and would like to support its development, you can do
+
diff --git a/playgrounds/svelte-kit/README.md b/playgrounds/svelte-kit/README.md
index 4caf0802c..cef387daa 100644
--- a/playgrounds/svelte-kit/README.md
+++ b/playgrounds/svelte-kit/README.md
@@ -55,24 +55,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -129,4 +128,5 @@ If you find oRPC valuable and would like to support its development, you can do
+
diff --git a/playgrounds/tanstack-start/README.md b/playgrounds/tanstack-start/README.md
index 05e4cdf5a..ab7985258 100644
--- a/playgrounds/tanstack-start/README.md
+++ b/playgrounds/tanstack-start/README.md
@@ -55,24 +55,23 @@ If you find oRPC valuable and would like to support its development, you can do
Reece McDonald
- Sefa Eyeoglu
あわわわとーにゅ
nk
supastarter
Dexter Miguel
herrfugbaum
+ Ryota Murakami
- Ryota Murakami
David Cramer
Valerii Petryniak
happyboy
Valerii Strilets
Kyle Mistele
Andrew Peters
+ Ryan Vogel
- Ryan Vogel
Peter Adam
Chen, Zhi-Yuan
Ryan Soderberg
@@ -129,4 +128,5 @@ If you find oRPC valuable and would like to support its development, you can do
+
From 4abbd0c458e947e11ba636d241405acebdfddab4 Mon Sep 17 00:00:00 2001
From: Dinh Le
Date: Fri, 5 Jun 2026 10:30:28 +0700
Subject: [PATCH 3/6] fix(client): move global ORPCError constructors
registration to static block for better bundler compatibility
---
packages/client/src/error.ts | 44 ++++++++++++++++++++++++------------
1 file changed, 30 insertions(+), 14 deletions(-)
diff --git a/packages/client/src/error.ts b/packages/client/src/error.ts
index 8e9dd1c9b..f4e1db9ad 100644
--- a/packages/client/src/error.ts
+++ b/packages/client/src/error.ts
@@ -99,15 +99,7 @@ export type ORPCErrorOptions
& { defined?: boolean, status?: number, message?: string }
& (undefined extends TData ? { data?: TData } : { data: TData })
-/**
- * Store all ORPCError constructors
- * for workaround of instanceof check in case multiple dependency graphs exist
- *
- * @info `Symbol.for` is global symbol registry and shared across different dependency graphs
- */
-const GLOBAL_ORPC_ERROR_CONSTRUCTORS_SYMBOL = Symbol.for(`__${ORPC_CLIENT_PACKAGE_NAME}@${ORPC_CLIENT_PACKAGE_VERSION}/error/ORPC_ERROR_CONSTRUCTORS__`)
-void ((globalThis as any)[GLOBAL_ORPC_ERROR_CONSTRUCTORS_SYMBOL] ??= new WeakSet())
-const globalORPCErrorConstructors: WeakSet = (globalThis as any)[GLOBAL_ORPC_ERROR_CONSTRUCTORS_SYMBOL]
+let globalORPCErrorConstructors: WeakSet
export class ORPCError extends Error {
readonly defined: boolean
@@ -115,6 +107,35 @@ export class ORPCError extends Error {
readonly status: number
readonly data: TData
+ /**
+ * Placed inside a static block (rather than at module level) to ensure this
+ * registration is treated as part of the class definition by bundlers.
+ *
+ * With `"sideEffects": false` in package.json, bundlers like webpack/Rollup
+ * are allowed to tree-shake any module-level statements that appear to have
+ * no consumers. A free-floating `globalORPCErrorConstructors.add(ORPCError)`
+ * at module level could be dropped entirely if the bundler decides the module
+ * is only partially used.
+ *
+ * By placing this inside `static {}`, the registration becomes inseparable
+ * from the class body itself — a bundler cannot include `ORPCError` without
+ * executing this block.
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Static_initialization_blocks
+ */
+ static {
+ /**
+ * Store all ORPCError constructors
+ * for workaround of instanceof check in case multiple dependency graphs exist
+ *
+ * @info `Symbol.for` is global symbol registry and shared across different dependency graphs
+ */
+ const GLOBAL_ORPC_ERROR_CONSTRUCTORS_SYMBOL = Symbol.for(`__${ORPC_CLIENT_PACKAGE_NAME}@${ORPC_CLIENT_PACKAGE_VERSION}/error/ORPC_ERROR_CONSTRUCTORS__`)
+ void ((globalThis as any)[GLOBAL_ORPC_ERROR_CONSTRUCTORS_SYMBOL] ??= new WeakSet())
+ globalORPCErrorConstructors = (globalThis as any)[GLOBAL_ORPC_ERROR_CONSTRUCTORS_SYMBOL]
+ globalORPCErrorConstructors.add(ORPCError)
+ }
+
constructor(code: TCode, ...rest: MaybeOptionalOptions>) {
const options = resolveMaybeOptionalOptions(rest)
@@ -167,11 +188,6 @@ export class ORPCError extends Error {
return super[Symbol.hasInstance](instance)
}
}
-/**
- * Store ORPCError constructor
- * for workaround of instanceof check in case multiple dependency graphs exist
- */
-globalORPCErrorConstructors.add(ORPCError)
export type ORPCErrorJSON = Pick, 'defined' | 'code' | 'status' | 'message' | 'data'>
From 7134a36f642782c55b0ee8333531fda1d1ac1152 Mon Sep 17 00:00:00 2001
From: Dinh Le
Date: Sun, 21 Jun 2026 19:50:35 +0700
Subject: [PATCH 4/6] feat: v2
---
.env.example | 5 +-
.github/FUNDING.yml | 2 +-
.github/dependabot.yml | 4 -
.github/workflows/ci.yaml | 52 +-
.github/workflows/pullfrog.yml | 57 -
.github/workflows/release.yaml | 12 +-
.github/workflows/sponsors-sync.yaml | 12 +-
README.md | 203 +-
apps/content/.vitepress/config.ts | 196 +-
apps/content/blog/v1-announcement.md | 6 +-
apps/content/docs/adapters/astro.md | 42 -
apps/content/docs/adapters/browser.md | 171 -
apps/content/docs/adapters/electron.md | 71 -
apps/content/docs/adapters/elysia.md | 44 -
apps/content/docs/adapters/express.md | 52 -
apps/content/docs/adapters/fastify.md | 53 -
apps/content/docs/adapters/fetch-api.md | 213 +
apps/content/docs/adapters/h3.md | 43 -
apps/content/docs/adapters/hono.md | 79 -
apps/content/docs/adapters/http.md | 298 -
apps/content/docs/adapters/message-port.md | 52 +-
apps/content/docs/adapters/next.md | 193 -
apps/content/docs/adapters/node-http.md | 134 +
apps/content/docs/adapters/nuxt.md | 123 -
apps/content/docs/adapters/react-native.md | 59 -
apps/content/docs/adapters/remix.md | 36 -
apps/content/docs/adapters/solid-start.md | 140 -
apps/content/docs/adapters/svelte-kit.md | 105 -
apps/content/docs/adapters/tanstack-start.md | 112 -
apps/content/docs/adapters/web-workers.md | 61 -
apps/content/docs/adapters/websocket.md | 198 +-
apps/content/docs/adapters/worker-threads.md | 61 -
.../docs/advanced/building-custom-plugins.md | 109 -
.../exceeds-the-maximum-length-problem.md | 36 +-
...expanding-type-support-for-openapi-link.md | 84 +
.../docs/advanced/extend-body-parser.md | 80 -
.../docs/advanced/publish-client-to-npm.md | 16 +-
.../docs/advanced/rpc-json-serializer.md | 84 -
apps/content/docs/advanced/rpc-protocol.md | 150 -
.../docs/advanced/scaling-large-projects.md | 104 +
apps/content/docs/advanced/superjson.md | 143 -
.../docs/advanced/testing-and-mocking.md | 46 +
apps/content/docs/advanced/testing-mocking.md | 51 -
.../docs/advanced/validation-errors.md | 165 +-
.../docs/best-practices/dedupe-middleware.md | 115 +-
.../docs/best-practices/monorepo-setup.md | 8 +-
.../docs/best-practices/no-throw-literal.md | 20 +-
.../docs/best-practices/optimize-ssr.md | 250 -
.../docs/best-practices/optimizing-ssr.md | 166 +
apps/content/docs/binary-data.md | 60 +
apps/content/docs/client/client-side.md | 184 +-
apps/content/docs/client/dynamic-link.md | 25 +-
apps/content/docs/client/error-handling.md | 57 +-
apps/content/docs/client/event-iterator.md | 49 +-
apps/content/docs/client/rpc-link.md | 181 -
apps/content/docs/client/server-side.md | 184 +-
apps/content/docs/comparison.md | 41 -
apps/content/docs/context.md | 148 +-
.../docs/contract-first/define-contract.md | 144 -
.../docs/contract-first/implement-contract.md | 111 -
.../docs/contract-first/router-to-contract.md | 55 -
apps/content/docs/contract/implementation.md | 140 +
apps/content/docs/contract/procedure.md | 85 +
apps/content/docs/contract/router.md | 158 +
apps/content/docs/ecosystem.md | 48 -
apps/content/docs/error-handling.md | 205 +-
apps/content/docs/event-iterator.md | 105 +-
.../content/docs/examples/openai-streaming.md | 53 -
apps/content/docs/file-upload-download.md | 36 -
apps/content/docs/getting-started.md | 183 +-
apps/content/docs/helpers/base64url.md | 7 +-
apps/content/docs/helpers/cookie.md | 9 +-
apps/content/docs/helpers/encryption.md | 7 +-
apps/content/docs/helpers/form-data.md | 15 +-
apps/content/docs/helpers/publisher.md | 242 +-
apps/content/docs/helpers/ratelimit.md | 220 +-
apps/content/docs/helpers/signing.md | 7 +-
apps/content/docs/integrations/ai-sdk.md | 220 -
apps/content/docs/integrations/better-auth.md | 81 -
.../docs/integrations/durable-iterator.md | 444 -
apps/content/docs/integrations/effect.md | 272 +
apps/content/docs/integrations/evlog.md | 117 +
apps/content/docs/integrations/next.md | 324 +
.../docs/integrations/opentelemetry.md | 82 +-
.../content/docs/integrations/pinia-colada.md | 171 -
apps/content/docs/integrations/pino.md | 60 +-
apps/content/docs/integrations/react-swr.md | 204 -
apps/content/docs/integrations/sentry.md | 83 -
.../integrations/tanstack-query-old/basic.md | 144 -
.../integrations/tanstack-query-old/react.md | 123 -
.../integrations/tanstack-query-old/solid.md | 88 -
.../integrations/tanstack-query-old/svelte.md | 67 -
.../integrations/tanstack-query-old/vue.md | 67 -
.../docs/integrations/tanstack-query.md | 388 +-
apps/content/docs/metadata.md | 134 +-
apps/content/docs/middleware.md | 158 +-
apps/content/docs/migrations/from-trpc.md | 52 +-
.../advanced/customizing-error-response.md | 96 -
.../advanced/disabling-output-validation.md | 49 -
...expanding-type-support-for-openapi-link.md | 73 -
.../advanced/openapi-json-serializer.md | 64 -
.../openapi/advanced/redirect-response.md | 33 -
apps/content/docs/openapi/bracket-notation.md | 56 +-
.../docs/openapi/client/openapi-link.md | 159 -
apps/content/docs/openapi/error-handling.md | 56 -
apps/content/docs/openapi/getting-started.md | 203 -
apps/content/docs/openapi/handler.md | 278 +
.../docs/openapi/input-and-output-mapping.md | 282 +
.../docs/openapi/input-output-structure.md | 118 -
.../docs/openapi/integrations/hey-api.md | 44 -
.../implement-contract-in-nest.md | 373 -
.../content/docs/openapi/integrations/trpc.md | 133 -
apps/content/docs/openapi/link.md | 316 +
apps/content/docs/openapi/openapi-handler.md | 108 -
.../docs/openapi/openapi-specification.md | 352 -
.../docs/openapi/openapi-to-contract.md | 53 -
.../docs/openapi/plugins/openapi-reference.md | 43 -
.../docs/openapi/plugins/smart-coercion.md | 153 -
.../openapi/plugins/zod-smart-coercion.md | 159 -
apps/content/docs/openapi/routing.md | 191 +-
apps/content/docs/openapi/scalar.md | 20 +-
apps/content/docs/openapi/serializer.md | 166 +
apps/content/docs/openapi/specification.md | 320 +
apps/content/docs/playgrounds.md | 58 +-
apps/content/docs/plugins/batch-requests.md | 203 -
apps/content/docs/plugins/batch.md | 146 +
apps/content/docs/plugins/body-compression.md | 30 +
apps/content/docs/plugins/body-limit.md | 23 +-
apps/content/docs/plugins/client-retry.md | 95 -
apps/content/docs/plugins/compression.md | 33 -
apps/content/docs/plugins/cors.md | 28 +-
apps/content/docs/plugins/csrf-guard.md | 39 +
apps/content/docs/plugins/dedupe-requests.md | 86 -
apps/content/docs/plugins/dedupe.md | 101 +
apps/content/docs/plugins/hibernation.md | 215 -
.../content/docs/plugins/openapi-reference.md | 67 +
apps/content/docs/plugins/request-headers.md | 37 +-
.../docs/plugins/request-validation.md | 86 +-
apps/content/docs/plugins/response-headers.md | 38 +-
.../docs/plugins/response-validation.md | 78 +-
apps/content/docs/plugins/rethrow-handler.md | 38 -
apps/content/docs/plugins/retry-after.md | 45 +-
apps/content/docs/plugins/retry.md | 95 +
.../docs/plugins/simple-csrf-protection.md | 55 -
apps/content/docs/plugins/smart-coercion.md | 176 +
.../content/docs/plugins/strict-get-method.md | 43 -
apps/content/docs/procedure.md | 128 +-
apps/content/docs/router.md | 92 +-
apps/content/docs/rpc-handler.md | 139 -
apps/content/docs/rpc/handler.md | 276 +
apps/content/docs/rpc/link.md | 336 +
apps/content/docs/rpc/protocol.md | 136 +
apps/content/docs/rpc/serializer.md | 182 +
apps/content/docs/server-action.md | 316 -
.../mini-orpc/beyond-the-basics.md | 2 +-
apps/content/package.json | 53 +-
apps/content/public/_redirects | 4 +
.../shared/common-error-status-map-table.md | 24 +
.../common-plugin-handler-compatibility.md | 3 +
.../common-plugin-link-compatibility.md | 3 +
apps/content/shared/planet.ts | 17 +-
.../router-keys-compatibility-warning.md | 3 +
.../shared/standard-server-cors-warning.md | 12 +
apps/content/vercel.json | 15 +
eslint.config.js | 7 +
knip.json | 4 -
package.json | 68 +-
packages/ai-sdk/package.json | 50 -
packages/ai-sdk/src/index.test.ts | 3 -
packages/ai-sdk/src/index.ts | 8 -
packages/ai-sdk/src/tool.test-d.ts | 164 -
packages/ai-sdk/src/tool.test.ts | 130 -
packages/ai-sdk/src/tool.ts | 163 -
packages/ai-sdk/tsconfig.json | 16 -
packages/arktype/README.md | 109 +-
packages/arktype/package.json | 12 +-
packages/arktype/src/converter.test.ts | 170 +-
packages/arktype/src/converter.ts | 83 +-
packages/arktype/src/index.test.ts | 5 +
packages/arktype/tsconfig.json | 6 +-
packages/client/README.md | 100 +-
packages/client/package.json | 13 +-
.../client/src/adapters/fetch/index.test.ts | 3 +
packages/client/src/adapters/fetch/index.ts | 3 +-
.../adapters/fetch/link-fetch-client.test.ts | 92 -
.../src/adapters/fetch/link-fetch-client.ts | 60 -
.../src/adapters/fetch/plugin.test-d.ts | 9 -
.../client/src/adapters/fetch/plugin.test.ts | 54 +-
packages/client/src/adapters/fetch/plugin.ts | 27 +-
.../src/adapters/fetch/rpc-link.test.ts | 347 +-
.../client/src/adapters/fetch/rpc-link.ts | 25 +-
.../client/src/adapters/fetch/transport.ts | 89 +
.../src/adapters/message-port/index.test.ts | 3 +
.../client/src/adapters/message-port/index.ts | 2 +-
.../src/adapters/message-port/link-client.ts | 70 -
.../message-port/message-port.test.ts | 198 +-
.../src/adapters/message-port/message-port.ts | 6 +-
.../adapters/message-port/rpc-link.test.ts | 209 +-
.../src/adapters/message-port/rpc-link.ts | 24 +-
.../src/adapters/message-port/transport.ts | 80 +
.../client/src/adapters/standard/codec.ts | 20 +
.../src/adapters/standard/index.test.ts | 6 +
.../client/src/adapters/standard/index.ts | 7 +-
.../client/src/adapters/standard/link.test.ts | 151 +-
packages/client/src/adapters/standard/link.ts | 178 +-
.../src/adapters/standard/plugin.test.ts | 38 +-
.../client/src/adapters/standard/plugin.ts | 44 +-
.../standard/rpc-json-serializer.test.ts | 212 -
.../adapters/standard/rpc-json-serializer.ts | 222 -
.../adapters/standard/rpc-link-codec.test.ts | 398 +-
.../src/adapters/standard/rpc-link-codec.ts | 136 +-
.../src/adapters/standard/rpc-link.test.ts | 212 -
.../client/src/adapters/standard/rpc-link.ts | 22 -
.../adapters/standard/rpc-serializer.test.ts | 200 -
.../src/adapters/standard/rpc-serializer.ts | 104 -
.../client/src/adapters/standard/transport.ts | 15 +
.../client/src/adapters/standard/types.ts | 11 -
.../src/adapters/standard/utils.test.ts | 23 -
.../client/src/adapters/standard/utils.ts | 24 -
.../src/adapters/websocket/index.test.ts | 3 +
.../client/src/adapters/websocket/index.ts | 2 +-
.../src/adapters/websocket/link-client.ts | 59 -
.../src/adapters/websocket/rpc-link.test.ts | 487 +-
.../client/src/adapters/websocket/rpc-link.ts | 25 +-
.../src/adapters/websocket/transport.ts | 234 +
packages/client/src/client-safe.test-d.ts | 4 +-
packages/client/src/client-safe.ts | 23 +-
packages/client/src/client.test-d.ts | 109 +-
packages/client/src/client.test.ts | 170 +-
packages/client/src/client.ts | 83 +-
packages/client/src/consts.ts | 35 +-
packages/client/src/dynamic-link.test-d.ts | 2 +-
packages/client/src/dynamic-link.ts | 4 +-
packages/client/src/error-utils.test-d.ts | 43 +
packages/client/src/error-utils.test.ts | 237 +
packages/client/src/error-utils.ts | 64 +
packages/client/src/error.test-d.ts | 29 +-
packages/client/src/error.test.ts | 151 +-
packages/client/src/error.ts | 246 +-
packages/client/src/event-iterator.test.ts | 251 +-
packages/client/src/event-iterator.ts | 70 +-
packages/client/src/index.test.ts | 9 +
packages/client/src/index.ts | 17 +-
packages/client/src/plugins/batch.test.ts | 1218 +-
packages/client/src/plugins/batch.ts | 491 +-
.../src/plugins/dedupe-requests.test.ts | 195 -
.../client/src/plugins/dedupe-requests.ts | 180 -
packages/client/src/plugins/dedupe.test.ts | 424 +
packages/client/src/plugins/dedupe.ts | 244 +
packages/client/src/plugins/index.test.ts | 8 +
packages/client/src/plugins/index.ts | 3 +-
.../client/src/plugins/retry-after.test.ts | 316 +-
packages/client/src/plugins/retry-after.ts | 105 +-
packages/client/src/plugins/retry.test.ts | 721 +-
packages/client/src/plugins/retry.ts | 155 +-
.../plugins/simple-csrf-protection.test.ts | 62 -
.../src/plugins/simple-csrf-protection.ts | 75 -
.../client/src/rpc-json-serializer.test.ts | 221 +
packages/client/src/rpc-json-serializer.ts | 301 +
packages/client/src/rpc-serializer.test.ts | 293 +
packages/client/src/rpc-serializer.ts | 132 +
packages/client/src/types.test-d.ts | 32 +-
packages/client/src/types.ts | 47 +-
packages/client/src/utils.test-d.ts | 64 +-
packages/client/src/utils.test.ts | 59 +-
packages/client/src/utils.ts | 79 +-
packages/client/tests/e2e.test-d.ts | 49 -
packages/client/tests/e2e.test.ts | 48 -
packages/client/tests/helpers.ts | 150 -
packages/client/tsconfig.json | 7 +-
packages/contract/README.md | 113 +-
packages/contract/package.json | 12 +-
.../contract/src/builder-variants.test-d.ts | 356 +-
packages/contract/src/builder-variants.ts | 267 +-
packages/contract/src/builder.test-d.ts | 155 +-
packages/contract/src/builder.test.ts | 283 +-
packages/contract/src/builder.ts | 248 +-
packages/contract/src/caller.test-d.ts | 105 +
packages/contract/src/caller.test.ts | 140 +
packages/contract/src/caller.ts | 80 +
packages/contract/src/config.test.ts | 6 -
packages/contract/src/config.ts | 26 -
packages/contract/src/error-utils.test-d.ts | 12 +
packages/contract/src/error-utils.test.ts | 283 +
packages/contract/src/error-utils.ts | 77 +
packages/contract/src/error.test-d.ts | 33 +-
packages/contract/src/error.test.ts | 92 +-
packages/contract/src/error.ts | 77 +-
packages/contract/src/event-iterator.test.ts | 111 +-
packages/contract/src/event-iterator.ts | 39 +-
packages/contract/src/index.test.ts | 5 +
packages/contract/src/index.ts | 11 +-
packages/contract/src/link-utils.test-d.ts | 10 -
packages/contract/src/link-utils.test.ts | 23 -
packages/contract/src/link-utils.ts | 27 -
packages/contract/src/meta-built-in.test.ts | 39 +
packages/contract/src/meta-built-in.ts | 35 +
packages/contract/src/meta-utils.test.ts | 80 +
packages/contract/src/meta-utils.ts | 100 +
packages/contract/src/meta.test.ts | 29 +-
packages/contract/src/meta.ts | 58 +-
packages/contract/src/plugins/index.test.ts | 7 +-
.../src/plugins/request-validation.test.ts | 153 +-
.../src/plugins/request-validation.ts | 101 +-
.../src/plugins/response-validation.test.ts | 204 +-
.../src/plugins/response-validation.ts | 108 +-
.../contract/src/procedure-client.test-d.ts | 25 +-
packages/contract/src/procedure-client.ts | 12 +-
packages/contract/src/procedure.test.ts | 115 +-
packages/contract/src/procedure.ts | 80 +-
packages/contract/src/route.test.ts | 65 -
packages/contract/src/route.ts | 187 -
packages/contract/src/router-client.test-d.ts | 45 +-
packages/contract/src/router-client.ts | 14 +-
packages/contract/src/router-utils.test-d.ts | 113 +-
packages/contract/src/router-utils.test.ts | 406 +-
packages/contract/src/router-utils.ts | 176 +-
packages/contract/src/router.test-d.ts | 96 +-
packages/contract/src/router.ts | 73 +-
packages/contract/src/schema-utils.test.ts | 24 +-
packages/contract/src/schema-utils.ts | 42 +-
packages/contract/src/schema.test-d.ts | 106 +-
packages/contract/src/schema.test.ts | 17 -
packages/contract/src/schema.ts | 39 +-
packages/contract/src/types.ts | 2 -
packages/contract/tests/e2e.test-d.ts | 20 -
packages/contract/tests/helpers.ts | 76 -
packages/contract/tests/shared.ts | 73 -
packages/contract/tsconfig.json | 2 +-
packages/durable-iterator/README.md | 194 -
packages/durable-iterator/build.config.ts | 7 -
packages/durable-iterator/package.json | 62 -
.../durable-iterator/src/client/index.test.ts | 3 -
packages/durable-iterator/src/client/index.ts | 2 -
.../src/client/iterator.test-d.ts | 18 -
.../src/client/iterator.test.ts | 76 -
.../durable-iterator/src/client/iterator.ts | 80 -
.../src/client/plugin.test.ts | 546 -
.../durable-iterator/src/client/plugin.ts | 273 -
packages/durable-iterator/src/consts.ts | 4 -
packages/durable-iterator/src/contract.ts | 20 -
.../src/durable-object/handler.ts | 339 -
.../src/durable-object/index.test.ts | 12 -
.../src/durable-object/index.ts | 8 -
.../src/durable-object/object-state.test.ts | 47 -
.../src/durable-object/object-state.ts | 60 -
.../src/durable-object/object.test.ts | 603 -
.../src/durable-object/object.ts | 75 -
.../src/durable-object/resume-storage.test.ts | 136 -
.../src/durable-object/resume-storage.ts | 240 -
.../src/durable-object/upgrade.test.ts | 138 -
.../src/durable-object/upgrade.ts | 73 -
.../src/durable-object/websocket.test.ts | 75 -
.../src/durable-object/websocket.ts | 182 -
packages/durable-iterator/src/error.ts | 2 -
packages/durable-iterator/src/index.test.ts | 3 -
packages/durable-iterator/src/index.ts | 7 -
.../durable-iterator/src/iterator.test-d.ts | 41 -
.../durable-iterator/src/iterator.test.ts | 65 -
packages/durable-iterator/src/iterator.ts | 100 -
.../durable-iterator/src/object.test-d.ts | 18 -
packages/durable-iterator/src/object.ts | 18 -
packages/durable-iterator/src/plugin.test.ts | 92 -
packages/durable-iterator/src/plugin.ts | 74 -
packages/durable-iterator/src/schemas.test.ts | 266 -
packages/durable-iterator/src/schemas.ts | 60 -
packages/durable-iterator/tests/shared.ts | 38 -
packages/durable-iterator/tsconfig.json | 19 -
packages/durable-iterator/tsconfig.test.json | 16 -
packages/{hey-api => effect}/.gitignore | 0
packages/{trpc => effect}/README.md | 84 +-
packages/effect/package.json | 64 +
packages/effect/src/context.ts | 49 +
packages/effect/src/converter.test.ts | 55 +
packages/effect/src/converter.ts | 26 +
.../effect/src/extensions/effect.test-d.ts | 257 +
packages/effect/src/extensions/effect.test.ts | 57 +
packages/effect/src/extensions/effect.ts | 199 +
.../src/extensions/input-output.test-d.ts | 215 +
.../src/extensions/input-output.test.ts | 47 +
.../effect/src/extensions/input-output.ts | 156 +
packages/effect/src/handler.test-d.ts | 119 +
packages/effect/src/handler.test.ts | 185 +
packages/effect/src/handler.ts | 64 +
packages/effect/src/index.test.ts | 7 +
packages/effect/src/index.ts | 5 +
packages/effect/src/runtime.test.ts | 92 +
packages/effect/src/runtime.ts | 38 +
packages/effect/src/schema.test.ts | 19 +
packages/effect/src/schema.ts | 15 +
.../{openapi-client => effect}/tsconfig.json | 9 +-
packages/{otel => evlog}/.gitignore | 5 +-
packages/{hey-api => evlog}/README.md | 84 +-
packages/{svelte-query => evlog}/package.json | 32 +-
packages/evlog/src/adapters/node.ts | 13 +
packages/evlog/src/context.test.ts | 10 +
packages/evlog/src/context.ts | 11 +
packages/evlog/src/handler-plugin.test.ts | 491 +
packages/evlog/src/handler-plugin.ts | 256 +
packages/evlog/src/index.test.ts | 3 +
packages/evlog/src/index.ts | 2 +
packages/{trpc => evlog}/tsconfig.json | 3 +-
packages/hey-api/package.json | 45 -
packages/hey-api/src/index.ts | 1 -
packages/hey-api/src/to-orpc-client.test-d.ts | 47 -
packages/hey-api/src/to-orpc-client.test.ts | 159 -
packages/hey-api/src/to-orpc-client.ts | 62 -
packages/hey-api/tests/spec.json | 162 -
packages/hey-api/tsconfig.json | 16 -
packages/interop/README.md | 79 +-
packages/interop/package.json | 5 +-
packages/interop/tsconfig.json | 2 +-
packages/json-schema/README.md | 80 +-
packages/json-schema/package.json | 11 +-
packages/json-schema/src/coercer.test.ts | 329 +-
packages/json-schema/src/coercer.ts | 196 +-
.../json-schema/src/composition-utils.test.ts | 1620 +
packages/json-schema/src/composition-utils.ts | 496 +
packages/json-schema/src/constants.ts | 53 +
packages/json-schema/src/convert.test.ts | 67 +
packages/json-schema/src/convert.ts | 45 +
packages/json-schema/src/index.test.ts | 12 +
packages/json-schema/src/index.ts | 10 +-
packages/json-schema/src/ref-utils.test.ts | 396 +
packages/json-schema/src/ref-utils.ts | 155 +
.../src/smart-coercion-handler-plugin.test.ts | 53 +
.../src/smart-coercion-handler-plugin.ts | 63 +
.../src/smart-coercion-link-plugin.test.ts | 148 +
.../src/smart-coercion-link-plugin.ts | 94 +
.../src/smart-coercion-plugin.test.ts | 37 -
.../json-schema/src/smart-coercion-plugin.ts | 52 -
.../standard-json-schema-converter.test.ts | 94 +
.../src/standard-json-schema-converter.ts | 46 +
packages/json-schema/src/types.ts | 13 +-
packages/json-schema/src/utils.test.ts | 49 +
packages/json-schema/src/utils.ts | 60 +
packages/json-schema/tsconfig.json | 7 +-
packages/nest/.gitignore | 26 -
packages/nest/README.md | 248 -
packages/nest/build.config.ts | 13 -
packages/nest/package.json | 82 -
packages/nest/src/implement.test-d.ts | 107 -
packages/nest/src/implement.test.ts | 794 -
packages/nest/src/implement.ts | 201 -
packages/nest/src/index.test.ts | 21 -
packages/nest/src/index.ts | 47 -
packages/nest/src/module.ts | 81 -
packages/nest/src/utils.test.ts | 10 -
packages/nest/src/utils.ts | 8 -
packages/nest/tsconfig.json | 25 -
packages/nest/tsconfig.test.json | 16 -
.../{durable-iterator => next}/.gitignore | 5 +-
packages/{ai-sdk => next}/README.md | 84 +-
packages/{react => next}/package.json | 32 +-
.../src/deferred-interceptors.test.ts | 0
.../src/deferred-interceptors.ts | 0
.../next/src/extensions/actionable.test-d.ts | 45 +
.../next/src/extensions/actionable.test.ts | 19 +
packages/next/src/extensions/actionable.ts | 37 +
packages/next/src/hooks/index.test.ts | 6 +
packages/next/src/hooks/index.ts | 2 +
.../optimistic-server-function.test-d.ts | 29 +
.../optimistic-server-function.test.tsx} | 20 +-
.../src/hooks/optimistic-server-function.ts | 35 +
.../src/hooks/server-function.test-d.ts} | 56 +-
.../src/hooks/server-function.test.tsx} | 43 +-
.../src/hooks/server-function.ts} | 63 +-
packages/next/src/index.test.ts | 14 +
packages/next/src/index.ts | 9 +
.../next/src/server-form-function.test.ts | 53 +
packages/next/src/server-form-function.ts | 44 +
.../src/server-form-functionable.test-d.ts | 39 +
.../next/src/server-form-functionable.test.ts | 29 +
packages/next/src/server-form-functionable.ts | 61 +
packages/next/src/server-function.test-d.ts | 62 +
packages/next/src/server-function.test.ts | 74 +
packages/next/src/server-function.ts | 86 +
.../next/src/server-functionable.test-d.ts | 39 +
packages/next/src/server-functionable.test.ts | 29 +
packages/next/src/server-functionable.ts | 54 +
packages/{react => next}/tsconfig.json | 5 +-
packages/openapi-client/.gitignore | 26 -
packages/openapi-client/package.json | 63 -
.../src/adapters/fetch/index.ts | 1 -
.../src/adapters/fetch/openapi-link.test.ts | 99 -
.../src/adapters/fetch/openapi-link.ts | 23 -
.../src/adapters/standard/bracket-notation.ts | 211 -
.../src/adapters/standard/index.ts | 7 -
.../standard/openapi-json-serializer.test.ts | 257 -
.../standard/openapi-json-serializer.ts | 81 -
.../standard/openapi-link-codec.test.ts | 489 -
.../adapters/standard/openapi-link-codec.ts | 265 -
.../adapters/standard/openapi-link.test.ts | 101 -
.../src/adapters/standard/openapi-link.ts | 25 -
.../standard/openapi-serializer.test.ts | 398 -
.../adapters/standard/openapi-serializer.ts | 91 -
.../src/adapters/standard/utils.test.ts | 17 -
.../src/adapters/standard/utils.ts | 20 -
.../openapi-client/src/helpers/index.test.ts | 3 -
packages/openapi-client/src/helpers/index.ts | 1 -
packages/openapi-client/src/index.ts | 1 -
packages/openapi/README.md | 103 +-
packages/openapi/package.json | 50 +-
.../openapi/src/adapters/aws-lambda/index.ts | 1 -
.../aws-lambda/openapi-handler.test.ts | 80 -
.../adapters/aws-lambda/openapi-handler.ts | 17 -
.../src/adapters/fastify/index.test.ts | 3 -
.../openapi/src/adapters/fastify/index.ts | 1 -
.../adapters/fastify/openapi-handler.test.ts | 21 -
.../src/adapters/fastify/openapi-handler.ts | 20 -
.../openapi/src/adapters/fetch/index.test.ts | 6 +
packages/openapi/src/adapters/fetch/index.ts | 1 +
.../adapters/fetch/openapi-handler.test.ts | 72 +-
.../src/adapters/fetch/openapi-handler.ts | 25 +-
.../src/adapters/fetch/openapi-link.test.ts | 165 +
.../src/adapters/fetch/openapi-link.ts | 24 +
.../openapi/src/adapters/node/index.test.ts | 5 +
.../src/adapters/node/openapi-handler.test.ts | 71 +-
.../src/adapters/node/openapi-handler.ts | 25 +-
.../src/adapters/standard/index.test.ts | 7 +
.../openapi/src/adapters/standard/index.ts | 5 +-
.../adapters/standard/openapi-codec.test.ts | 358 -
.../src/adapters/standard/openapi-codec.ts | 149 -
.../standard/openapi-handler-codec.test.ts | 827 +
.../standard/openapi-handler-codec.ts | 307 +
.../adapters/standard/openapi-handler.test.ts | 23 -
.../src/adapters/standard/openapi-handler.ts | 25 -
.../standard/openapi-link-codec.test.ts | 746 +
.../adapters/standard/openapi-link-codec.ts | 534 +
.../adapters/standard/openapi-matcher.test.ts | 455 +-
.../src/adapters/standard/openapi-matcher.ts | 243 +-
.../src/adapters/standard/utils.test.ts | 13 -
.../openapi/src/adapters/standard/utils.ts | 19 -
.../src}/bracket-notation.test.ts | 124 +-
packages/openapi/src/bracket-notation.ts | 194 +
packages/openapi/src/caller.test-d.ts | 104 +
packages/openapi/src/caller.test.ts | 30 +
packages/openapi/src/caller.ts | 41 +
packages/openapi/src/constants.test.ts | 8 +
packages/openapi/src/constants.ts | 4 +
packages/openapi/src/extensions/route.test.ts | 33 +
packages/openapi/src/extensions/route.ts | 105 +
.../src/helpers/form-data.test.ts} | 2 +-
.../src/helpers/form-data.ts} | 17 +-
packages/openapi/src/helpers/index.test.ts | 5 +
packages/openapi/src/helpers/index.ts | 1 +
packages/openapi/src/index.test.ts | 9 +
packages/openapi/src/index.ts | 22 +-
packages/openapi/src/meta.test.ts | 314 +
packages/openapi/src/meta.ts | 420 +
packages/openapi/src/openapi-custom.test.ts | 106 -
packages/openapi/src/openapi-custom.ts | 67 -
.../openapi/src/openapi-generator.test.ts | 5068 ++-
packages/openapi/src/openapi-generator.ts | 1516 +-
.../src/openapi-json-serializer.test.ts | 172 +
.../openapi/src/openapi-json-serializer.ts | 244 +
.../openapi/src/openapi-serializer.test.ts | 318 +
packages/openapi/src/openapi-serializer.ts | 140 +
packages/openapi/src/openapi-utils.test.ts | 892 -
packages/openapi/src/openapi-utils.ts | 316 -
packages/openapi/src/plugins/index.test.ts | 5 +
.../src/plugins/openapi-reference.test.ts | 408 +-
.../openapi/src/plugins/openapi-reference.ts | 478 +-
packages/openapi/src/router-client.test.ts | 59 -
packages/openapi/src/router-client.ts | 49 -
packages/openapi/src/schema-converter.test.ts | 50 -
packages/openapi/src/schema-converter.ts | 54 -
packages/openapi/src/schema-utils.test.ts | 386 -
packages/openapi/src/schema-utils.ts | 254 -
packages/openapi/src/schema.ts | 68 -
.../src/types.test-d.ts | 0
.../{openapi-client => openapi}/src/types.ts | 20 +-
packages/openapi/src/utils.test.ts | 107 +
packages/openapi/src/utils.ts | 57 +
packages/openapi/tsconfig.json | 6 +-
packages/{ai-sdk => opentelemetry}/.gitignore | 0
.../README.md | 84 +-
packages/{otel => opentelemetry}/package.json | 11 +-
packages/{otel => opentelemetry}/src/index.ts | 0
.../opentelemetry/src/instrumentation.test.ts | 49 +
packages/opentelemetry/src/instrumentation.ts | 39 +
.../{otel => opentelemetry}/tsconfig.json | 2 +-
packages/otel/README.md | 215 -
packages/otel/build.config.ts | 9 -
packages/otel/src/consts.ts | 2 -
packages/otel/src/instrumentation.test.ts | 38 -
packages/otel/src/instrumentation.ts | 30 -
packages/pino/README.md | 84 +-
packages/pino/package.json | 12 +-
packages/pino/src/context.test.ts | 4 +-
packages/pino/src/context.ts | 6 +-
packages/pino/src/handler-plugin.test.ts | 457 +-
packages/pino/src/handler-plugin.ts | 208 +-
packages/pino/src/index.test.ts | 4 +-
packages/pino/tsconfig.json | 2 +-
packages/publisher-durable-object/.gitignore | 26 -
packages/publisher-durable-object/README.md | 194 -
.../publisher-durable-object/build.config.ts | 7 -
.../publisher-durable-object/package.json | 48 -
.../src/durable-object.test.ts | 266 -
.../src/durable-object.ts | 66 -
.../src/durable-publisher.test.ts | 394 -
.../src/durable-publisher.ts | 131 -
.../src/index.test.ts | 9 -
.../publisher-durable-object/src/index.ts | 4 -
.../src/resume-storage.test.ts | 446 -
.../src/resume-storage.ts | 236 -
.../publisher-durable-object/src/types.ts | 6 -
.../publisher-durable-object/tests/shared.ts | 67 -
.../publisher-durable-object/tsconfig.json | 21 -
.../tsconfig.test.json | 16 -
packages/publisher/README.md | 84 +-
packages/publisher/package.json | 37 +-
.../publisher/src/adapters/ioredis.test.ts | 678 -
packages/publisher/src/adapters/ioredis.ts | 327 -
.../publisher/src/adapters/memory.test.ts | 351 +-
packages/publisher/src/adapters/memory.ts | 197 +-
packages/publisher/src/adapters/redis.test.ts | 423 +
packages/publisher/src/adapters/redis.ts | 227 +
.../src/adapters/upstash-redis.test.ts | 610 -
.../publisher/src/adapters/upstash-redis.ts | 301 -
.../publisher/src/adapters/upstash.test.ts | 480 +
packages/publisher/src/adapters/upstash.ts | 323 +
packages/publisher/src/index.test.ts | 4 +-
packages/publisher/src/publisher.test.ts | 413 +-
packages/publisher/src/publisher.ts | 112 +-
.../publisher/tests/redis-adapters.test.ts | 96 +
packages/publisher/tsconfig.json | 6 +-
packages/ratelimit/README.md | 84 +-
packages/ratelimit/package.json | 37 +-
.../src/adapters/cloudflare-ratelimit.test.ts | 17 -
.../src/adapters/cloudflare-ratelimit.ts | 13 -
.../ratelimit/src/adapters/memory.test.ts | 273 +-
packages/ratelimit/src/adapters/memory.ts | 112 +-
packages/ratelimit/src/adapters/redis.test.ts | 411 +-
packages/ratelimit/src/adapters/redis.ts | 182 +-
.../src/adapters/upstash-ratelimit.test.ts | 80 -
.../src/adapters/upstash-ratelimit.ts | 48 -
.../ratelimit/src/adapters/upstash.test.ts | 174 +
packages/ratelimit/src/adapters/upstash.ts | 90 +
packages/ratelimit/src/handler-plugin.test.ts | 249 +-
packages/ratelimit/src/handler-plugin.ts | 74 +-
packages/ratelimit/src/index.test.ts | 7 +-
packages/ratelimit/src/middleware.test-d.ts | 34 +-
packages/ratelimit/src/middleware.test.ts | 331 +-
packages/ratelimit/src/middleware.ts | 58 +-
packages/ratelimit/src/types.ts | 16 +-
packages/ratelimit/tests/e2e.test.ts | 14 +-
packages/ratelimit/tsconfig.json | 6 +-
packages/react-query/.gitignore | 26 -
packages/react-query/README.md | 236 -
packages/react-query/package.json | 53 -
.../react-query/src/general-utils.test-d.ts | 32 -
.../react-query/src/general-utils.test.ts | 18 -
packages/react-query/src/general-utils.ts | 25 -
packages/react-query/src/index.ts | 13 -
.../react-query/src/procedure-utils.test-d.ts | 385 -
.../react-query/src/procedure-utils.test.ts | 125 -
packages/react-query/src/procedure-utils.ts | 105 -
.../react-query/src/router-utils.test-d.ts | 31 -
packages/react-query/src/router-utils.test.ts | 63 -
packages/react-query/src/router-utils.ts | 59 -
packages/react-query/src/types.ts | 35 -
packages/react-query/tests/e2e.test-d.ts | 271 -
packages/react-query/tests/e2e.test.tsx | 169 -
packages/react-query/tests/shared.tsx | 14 -
packages/react-query/tsconfig.json | 16 -
packages/react-swr/.gitignore | 26 -
packages/react-swr/README.md | 194 -
packages/react-swr/package.json | 46 -
.../react-swr/src/general-utils.test-d.ts | 35 -
packages/react-swr/src/general-utils.test.ts | 22 -
packages/react-swr/src/general-utils.ts | 37 -
packages/react-swr/src/index.test.ts | 3 -
packages/react-swr/src/index.ts | 6 -
.../react-swr/src/procedure-utils.test-d.ts | 221 -
.../react-swr/src/procedure-utils.test.ts | 251 -
packages/react-swr/src/procedure-utils.ts | 192 -
packages/react-swr/src/router-utils.test-d.ts | 38 -
packages/react-swr/src/router-utils.test.ts | 66 -
packages/react-swr/src/router-utils.ts | 60 -
packages/react-swr/src/types.ts | 90 -
packages/react-swr/src/utils.test.ts | 43 -
packages/react-swr/src/utils.ts | 13 -
packages/react-swr/tests/e2e.test-d.tsx | 107 -
packages/react-swr/tests/e2e.test.tsx | 119 -
packages/react-swr/tests/shared.tsx | 5 -
packages/react-swr/tsconfig.json | 16 -
packages/react/.gitignore | 26 -
packages/react/README.md | 269 -
packages/react/src/action-form.test.ts | 83 -
packages/react/src/action-form.ts | 61 -
packages/react/src/hooks/index.ts | 2 -
.../hooks/optimistic-server-action.test-d.ts | 25 -
.../src/hooks/optimistic-server-action.ts | 35 -
packages/react/src/index.ts | 3 -
packages/server/README.md | 130 +-
packages/server/package.json | 82 +-
.../server/src/adapters/aws-lambda/handler.ts | 44 -
.../server/src/adapters/aws-lambda/index.ts | 2 -
.../adapters/aws-lambda/rpc-handler.test.ts | 112 -
.../src/adapters/aws-lambda/rpc-handler.ts | 33 -
.../server/src/adapters/bun-ws/handler.ts | 52 -
packages/server/src/adapters/bun-ws/index.ts | 2 -
.../src/adapters/bun-ws/rpc-handler.test.ts | 60 -
.../server/src/adapters/bun-ws/rpc-handler.ts | 17 -
.../server/src/adapters/crossws/handler.ts | 73 +-
.../server/src/adapters/crossws/index.test.ts | 3 +
.../src/adapters/crossws/rpc-handler.test.ts | 212 +-
.../src/adapters/crossws/rpc-handler.ts | 23 +-
.../src/adapters/fastify/handler.test-d.ts | 17 -
.../src/adapters/fastify/handler.test.ts | 133 -
.../server/src/adapters/fastify/handler.ts | 62 -
.../server/src/adapters/fastify/index.test.ts | 3 -
packages/server/src/adapters/fastify/index.ts | 2 -
.../src/adapters/fastify/rpc-handler.test.ts | 38 -
.../src/adapters/fastify/rpc-handler.ts | 33 -
.../fetch/body-compression-plugin.test.ts | 179 +
.../adapters/fetch/body-compression-plugin.ts | 138 +
.../adapters/fetch/body-limit-plugin.test.ts | 94 +-
.../src/adapters/fetch/body-limit-plugin.ts | 98 +-
.../adapters/fetch/compression-plugin.test.ts | 648 -
.../src/adapters/fetch/compression-plugin.ts | 151 -
.../src/adapters/fetch/handler.test-d.ts | 16 -
.../server/src/adapters/fetch/handler.test.ts | 136 -
packages/server/src/adapters/fetch/handler.ts | 53 +-
.../server/src/adapters/fetch/index.test.ts | 7 +
packages/server/src/adapters/fetch/index.ts | 2 +-
.../src/adapters/fetch/plugin.test-d.ts | 9 -
.../server/src/adapters/fetch/plugin.test.ts | 43 +-
packages/server/src/adapters/fetch/plugin.ts | 43 +-
.../src/adapters/fetch/rpc-handler.test.ts | 120 +-
.../server/src/adapters/fetch/rpc-handler.ts | 46 +-
.../src/adapters/message-port/handler.ts | 158 +-
.../src/adapters/message-port/index.test.ts | 3 +
.../adapters/message-port/rpc-handler.test.ts | 325 +-
.../src/adapters/message-port/rpc-handler.ts | 22 +-
.../node/body-compression-plugin.test.ts | 107 +
.../adapters/node/body-compression-plugin.ts | 89 +
.../adapters/node/body-limit-plugin.test.ts | 138 +-
.../src/adapters/node/body-limit-plugin.ts | 81 +-
.../adapters/node/compression-plugin.test.ts | 240 -
.../src/adapters/node/compression-plugin.ts | 98 -
.../src/adapters/node/handler.test-d.ts | 17 -
.../server/src/adapters/node/handler.test.ts | 150 -
packages/server/src/adapters/node/handler.ts | 57 +-
.../server/src/adapters/node/index.test.ts | 7 +
packages/server/src/adapters/node/index.ts | 2 +-
.../server/src/adapters/node/plugin.test-d.ts | 9 -
.../server/src/adapters/node/plugin.test.ts | 45 +-
packages/server/src/adapters/node/plugin.ts | 43 +-
.../src/adapters/node/rpc-handler.test.ts | 120 +-
.../server/src/adapters/node/rpc-handler.ts | 47 +-
.../src/adapters/standard-peer/index.test.ts | 3 +
.../src/adapters/standard-peer/utils.test.ts | 167 +-
.../src/adapters/standard-peer/utils.ts | 44 +-
.../server/src/adapters/standard/codec.ts | 33 +
.../src/adapters/standard/handler.test.ts | 588 +-
.../server/src/adapters/standard/handler.ts | 303 +-
.../src/adapters/standard/index.test.ts | 9 +
.../server/src/adapters/standard/index.ts | 5 +-
.../src/adapters/standard/plugin.test.ts | 39 +-
.../server/src/adapters/standard/plugin.ts | 46 +-
.../src/adapters/standard/rpc-codec.test.ts | 110 -
.../server/src/adapters/standard/rpc-codec.ts | 45 -
.../standard/rpc-handler-codec.test.ts | 292 +
.../adapters/standard/rpc-handler-codec.ts | 92 +
.../src/adapters/standard/rpc-handler.test.ts | 26 -
.../src/adapters/standard/rpc-handler.ts | 24 -
.../src/adapters/standard/rpc-matcher.test.ts | 336 +-
.../src/adapters/standard/rpc-matcher.ts | 202 +-
.../server/src/adapters/standard/types.ts | 23 -
.../src/adapters/standard/utils.test-d.ts | 11 -
.../src/adapters/standard/utils.test.ts | 20 +-
.../server/src/adapters/standard/utils.ts | 10 +-
.../server/src/adapters/websocket/handler.ts | 95 +-
.../src/adapters/websocket/index.test.ts | 3 +
.../adapters/websocket/rpc-handler.test.ts | 220 +-
.../src/adapters/websocket/rpc-handler.ts | 23 +-
packages/server/src/adapters/ws/handler.ts | 39 -
packages/server/src/adapters/ws/index.ts | 2 -
.../src/adapters/ws/rpc-handler.test.ts | 73 -
.../server/src/adapters/ws/rpc-handler.ts | 17 -
.../server/src/builder-variants.test-d.ts | 1596 +-
packages/server/src/builder-variants.ts | 758 +-
packages/server/src/builder.test-d.ts | 588 +-
packages/server/src/builder.test.ts | 522 +-
packages/server/src/builder.ts | 448 +-
packages/server/src/config.test.ts | 6 -
packages/server/src/config.ts | 19 -
packages/server/src/constants.test.ts | 6 +
packages/server/src/constants.ts | 2 +
packages/server/src/context.test-d.ts | 40 +-
packages/server/src/context.test.ts | 6 -
packages/server/src/context.ts | 26 +-
packages/server/src/error.test-d.ts | 21 +-
packages/server/src/error.test.ts | 32 +-
packages/server/src/error.ts | 58 +-
.../server/src/extensions/callable.test-d.ts | 45 +
.../server/src/extensions/callable.test.ts | 13 +
packages/server/src/extensions/callable.ts | 38 +
packages/server/src/helpers/base64url.ts | 2 +-
.../server/src/helpers/encryption.test.ts | 24 +
packages/server/src/helpers/index.test.ts | 8 +
packages/server/src/helpers/signing.test.ts | 27 +
.../src/hibernation/event-iterator.test.ts | 73 -
.../server/src/hibernation/event-iterator.ts | 48 -
packages/server/src/hibernation/index.ts | 3 -
.../server/src/hibernation/plugin.test.ts | 85 -
packages/server/src/hibernation/plugin.ts | 64 -
.../src/implementer-procedure.test-d.ts | 505 +-
.../server/src/implementer-procedure.test.ts | 92 +
packages/server/src/implementer-procedure.ts | 253 +-
.../server/src/implementer-router.test-d.ts | 802 +
.../server/src/implementer-router.test.ts | 208 +
packages/server/src/implementer-router.ts | 253 +
.../server/src/implementer-variants.test-d.ts | 174 -
packages/server/src/implementer-variants.ts | 69 -
packages/server/src/implementer.test-d.ts | 253 +-
packages/server/src/implementer.test.ts | 181 +-
packages/server/src/implementer.ts | 257 +-
packages/server/src/index.test.ts | 9 +
packages/server/src/index.ts | 57 +-
packages/server/src/lazy.test.ts | 66 +-
packages/server/src/lazy.ts | 73 +-
packages/server/src/link-utils.test-d.ts | 10 -
packages/server/src/link-utils.test.ts | 24 -
packages/server/src/link-utils.ts | 26 -
.../server/src/middleware-decorated.test-d.ts | 212 +-
.../server/src/middleware-decorated.test.ts | 272 +-
packages/server/src/middleware-decorated.ts | 187 +-
packages/server/src/middleware-utils.test.ts | 48 -
packages/server/src/middleware-utils.ts | 31 -
packages/server/src/middleware.test-d.ts | 127 +-
packages/server/src/middleware.ts | 69 +-
packages/server/src/plugins/batch.test.ts | 816 +-
packages/server/src/plugins/batch.ts | 306 +-
packages/server/src/plugins/cors.test.ts | 263 +-
packages/server/src/plugins/cors.ts | 184 +-
.../server/src/plugins/csrf-guard.test.ts | 94 +
packages/server/src/plugins/csrf-guard.ts | 45 +
packages/server/src/plugins/index.test.ts | 9 +
packages/server/src/plugins/index.ts | 4 +-
.../src/plugins/request-headers.test.ts | 118 +-
.../server/src/plugins/request-headers.ts | 40 +-
.../src/plugins/response-headers.test.ts | 175 +-
.../server/src/plugins/response-headers.ts | 90 +-
packages/server/src/plugins/rethrow.test.ts | 195 -
packages/server/src/plugins/rethrow.ts | 88 -
.../plugins/simple-csrf-protection.test.ts | 81 -
.../src/plugins/simple-csrf-protection.ts | 103 -
.../src/plugins/strict-get-method.test.ts | 58 -
.../server/src/plugins/strict-get-method.ts | 66 -
.../server/src/procedure-action.test-d.ts | 100 -
packages/server/src/procedure-action.test.ts | 64 -
packages/server/src/procedure-action.ts | 62 -
.../server/src/procedure-client.test-d.ts | 140 +-
packages/server/src/procedure-client.test.ts | 1276 +-
packages/server/src/procedure-client.ts | 370 +-
.../server/src/procedure-decorated.test-d.ts | 307 +-
.../server/src/procedure-decorated.test.ts | 255 +-
packages/server/src/procedure-decorated.ts | 238 +-
packages/server/src/procedure-utils.test-d.ts | 92 +-
packages/server/src/procedure-utils.test.ts | 135 +-
packages/server/src/procedure-utils.ts | 108 +-
packages/server/src/procedure.test-d.ts | 26 -
packages/server/src/procedure.test.ts | 67 +-
packages/server/src/procedure.ts | 118 +-
packages/server/src/router-client.test-d.ts | 66 +-
packages/server/src/router-client.test.ts | 135 +-
packages/server/src/router-client.ts | 59 +-
packages/server/src/router-hidden.test.ts | 18 +-
packages/server/src/router-hidden.ts | 11 +-
packages/server/src/router-utils.test-d.ts | 232 +-
packages/server/src/router-utils.test.ts | 701 +-
packages/server/src/router-utils.ts | 413 +-
packages/server/src/router.test-d.ts | 205 +-
packages/server/src/router.ts | 58 +-
packages/server/tests/advanced.test.ts | 20 -
packages/server/tests/message-port.test.ts | 33 -
packages/server/tests/shared.ts | 79 -
packages/server/tsconfig.json | 7 +-
packages/shared/README.md | 80 +-
packages/shared/package.json | 12 +-
packages/shared/src/args.ts | 2 +-
packages/shared/src/buffer.test.ts | 52 +-
packages/shared/src/buffer.ts | 35 +-
packages/shared/src/chain.ts | 7 -
packages/shared/src/compare.test.ts | 120 +
packages/shared/src/compare.ts | 70 +
packages/shared/src/consts.ts | 2 -
packages/shared/src/error.test.ts | 45 +-
packages/shared/src/error.ts | 11 +-
packages/shared/src/event-publisher.test-d.ts | 75 -
packages/shared/src/event-publisher.test.ts | 303 -
packages/shared/src/event-publisher.ts | 155 -
packages/shared/src/function.test.ts | 60 +-
packages/shared/src/function.ts | 27 +-
packages/shared/src/http.test.ts | 131 +
packages/shared/src/http.ts | 53 +
packages/shared/src/id.test.ts | 31 +-
packages/shared/src/id.ts | 10 -
packages/shared/src/index.test.ts | 5 +
packages/shared/src/index.ts | 36 +-
packages/shared/src/interceptor.test-d.ts | 70 +-
packages/shared/src/interceptor.test.ts | 408 +-
packages/shared/src/interceptor.ts | 22 +-
packages/shared/src/iterator.test.ts | 498 +-
packages/shared/src/iterator.ts | 204 +-
packages/shared/src/json.test-d.ts | 7 -
packages/shared/src/json.test.ts | 16 -
packages/shared/src/json.ts | 12 -
packages/shared/src/object.test.ts | 339 +-
packages/shared/src/object.ts | 117 +-
packages/shared/src/opentelemetry.test.ts | 255 +
packages/shared/src/opentelemetry.ts | 173 +
packages/shared/src/otel.test.ts | 364 -
packages/shared/src/otel.ts | 194 -
packages/shared/src/plugin.test.ts | 168 +
packages/shared/src/plugin.ts | 112 +
packages/shared/src/promise.test.ts | 53 +
packages/shared/src/promise.ts | 25 +
packages/shared/src/proxy.test.ts | 162 +-
packages/shared/src/proxy.ts | 73 +-
packages/shared/src/queue.test.ts | 50 +-
packages/shared/src/queue.ts | 14 +-
packages/shared/src/signal.test.ts | 140 +
packages/shared/src/signal.ts | 57 +
packages/shared/src/stream.test.ts | 336 +-
packages/shared/src/stream.ts | 132 +-
packages/shared/src/types.test-d.ts | 21 +-
packages/shared/src/types.ts | 13 +-
packages/shared/src/value.test.ts | 7 +-
packages/shared/src/value.ts | 7 -
packages/shared/tsconfig.json | 2 +-
packages/solid-query/.gitignore | 26 -
packages/solid-query/README.md | 236 -
packages/solid-query/package.json | 52 -
.../solid-query/src/general-utils.test-d.ts | 32 -
.../solid-query/src/general-utils.test.ts | 18 -
packages/solid-query/src/general-utils.ts | 25 -
packages/solid-query/src/index.ts | 13 -
.../solid-query/src/procedure-utils.test-d.ts | 336 -
.../solid-query/src/procedure-utils.test.ts | 125 -
packages/solid-query/src/procedure-utils.ts | 98 -
.../solid-query/src/router-utils.test-d.ts | 31 -
packages/solid-query/src/router-utils.test.ts | 63 -
packages/solid-query/src/router-utils.ts | 59 -
packages/solid-query/src/types.ts | 42 -
packages/solid-query/tests/e2e.test-d.ts | 199 -
packages/solid-query/tests/e2e.test.tsx | 169 -
packages/solid-query/tests/shared.tsx | 14 -
packages/solid-query/tsconfig.json | 16 -
.../standard-server-aws-lambda/.gitignore | 26 -
packages/standard-server-aws-lambda/README.md | 194 -
.../standard-server-aws-lambda/package.json | 46 -
.../src/body.test.ts | 349 -
.../standard-server-aws-lambda/src/body.ts | 88 -
.../src/event-iterator.test.ts | 23 -
.../src/event-iterator.ts | 23 -
.../src/headers.test.ts | 32 -
.../standard-server-aws-lambda/src/headers.ts | 36 -
.../standard-server-aws-lambda/src/index.ts | 13 -
.../src/request.test.ts | 94 -
.../standard-server-aws-lambda/src/request.ts | 20 -
.../src/response.test.ts | 252 -
.../src/response.ts | 47 -
.../src/types.test-d.ts | 6 -
.../standard-server-aws-lambda/src/types.ts | 39 -
.../src/url.test.ts | 11 -
.../standard-server-aws-lambda/src/url.ts | 5 -
.../standard-server-aws-lambda/tsconfig.json | 19 -
packages/standard-server-fastify/.gitignore | 26 -
packages/standard-server-fastify/README.md | 194 -
packages/standard-server-fastify/package.json | 57 -
.../standard-server-fastify/src/index.test.ts | 3 -
packages/standard-server-fastify/src/index.ts | 4 -
.../src/request.test.ts | 79 -
.../standard-server-fastify/src/request.ts | 26 -
.../src/response.test.ts | 306 -
.../standard-server-fastify/src/response.ts | 27 -
.../standard-server-fastify/tsconfig.json | 19 -
packages/standard-server-fetch/.gitignore | 26 -
packages/standard-server-fetch/README.md | 194 -
packages/standard-server-fetch/package.json | 43 -
.../playground/event-source-client.ts | 13 -
.../playground/event-source.http | 11 -
.../playground/event-source.ts | 47 -
.../standard-server-fetch/src/body.test.ts | 327 -
packages/standard-server-fetch/src/body.ts | 111 -
.../src/event-iterator.test.ts | 584 -
.../src/event-iterator.ts | 262 -
.../standard-server-fetch/src/headers.test.ts | 44 -
packages/standard-server-fetch/src/headers.ts | 40 -
packages/standard-server-fetch/src/index.ts | 5 -
.../standard-server-fetch/src/request.test.ts | 140 -
packages/standard-server-fetch/src/request.ts | 36 -
.../src/response.test.ts | 140 -
.../standard-server-fetch/src/response.ts | 36 -
packages/standard-server-fetch/tsconfig.json | 16 -
packages/standard-server-node/.gitignore | 26 -
packages/standard-server-node/README.md | 194 -
packages/standard-server-node/package.json | 46 -
.../playground/event-source.ts | 47 -
.../standard-server-node/src/body.test.ts | 458 -
packages/standard-server-node/src/body.ts | 141 -
.../src/event-iterator.test.ts | 40 -
.../src/event-iterator.ts | 27 -
.../standard-server-node/src/headers.test.ts | 17 -
packages/standard-server-node/src/headers.ts | 15 -
packages/standard-server-node/src/index.ts | 9 -
.../standard-server-node/src/method.test.ts | 7 -
packages/standard-server-node/src/method.ts | 3 -
.../standard-server-node/src/request.test.ts | 56 -
packages/standard-server-node/src/request.ts | 22 -
.../standard-server-node/src/response.test.ts | 305 -
packages/standard-server-node/src/response.ts | 44 -
.../standard-server-node/src/signal.test.ts | 64 -
packages/standard-server-node/src/signal.ts | 16 -
packages/standard-server-node/src/types.ts | 17 -
packages/standard-server-node/src/url.test.ts | 32 -
packages/standard-server-node/src/url.ts | 13 -
packages/standard-server-node/tsconfig.json | 16 -
packages/standard-server-peer/.gitignore | 26 -
packages/standard-server-peer/README.md | 194 -
packages/standard-server-peer/package.json | 40 -
.../standard-server-peer/src/client.test.ts | 589 -
packages/standard-server-peer/src/client.ts | 254 -
.../standard-server-peer/src/codec.test.ts | 1187 -
packages/standard-server-peer/src/codec.ts | 417 -
.../src/event-iterator.test.ts | 445 -
.../src/event-iterator.ts | 184 -
packages/standard-server-peer/src/index.ts | 5 -
.../standard-server-peer/src/server.test.ts | 688 -
packages/standard-server-peer/src/server.ts | 257 -
packages/standard-server-peer/src/types.ts | 7 -
.../standard-server-peer/tests/e2e.test.ts | 114 -
packages/standard-server-peer/tsconfig.json | 16 -
packages/standard-server/.gitignore | 26 -
packages/standard-server/README.md | 194 -
packages/standard-server/package.json | 45 -
packages/standard-server/src/batch/index.ts | 3 -
.../standard-server/src/batch/request.test.ts | 116 -
packages/standard-server/src/batch/request.ts | 58 -
.../src/batch/response.test.ts | 126 -
.../standard-server/src/batch/response.ts | 117 -
.../standard-server/src/batch/signal.test.ts | 57 -
packages/standard-server/src/batch/signal.ts | 28 -
.../src/event-iterator/decoder.test.ts | 254 -
.../src/event-iterator/decoder.ts | 110 -
.../src/event-iterator/encoder.test.ts | 44 -
.../src/event-iterator/encoder.ts | 79 -
.../src/event-iterator/errors.ts | 17 -
.../src/event-iterator/index.ts | 5 -
.../src/event-iterator/meta.test.ts | 31 -
.../src/event-iterator/meta.ts | 47 -
.../src/event-iterator/types.ts | 12 -
.../standard-server/src/hibernation.test.ts | 15 -
packages/standard-server/src/hibernation.ts | 26 -
packages/standard-server/src/index.ts | 4 -
packages/standard-server/src/types.ts | 50 -
packages/standard-server/src/utils.test.ts | 160 -
packages/standard-server/src/utils.ts | 93 -
packages/standard-server/tsconfig.json | 15 -
packages/svelte-query/.gitignore | 26 -
packages/svelte-query/README.md | 236 -
.../svelte-query/src/general-utils.test-d.ts | 32 -
.../svelte-query/src/general-utils.test.ts | 18 -
packages/svelte-query/src/general-utils.ts | 25 -
packages/svelte-query/src/index.ts | 13 -
.../src/procedure-utils.test-d.ts | 339 -
.../svelte-query/src/procedure-utils.test.tsx | 125 -
packages/svelte-query/src/procedure-utils.ts | 98 -
.../svelte-query/src/router-utils.test-d.ts | 31 -
.../svelte-query/src/router-utils.test.tsx | 63 -
packages/svelte-query/src/router-utils.ts | 59 -
packages/svelte-query/src/types.ts | 42 -
packages/svelte-query/tests/e2e.test-d.ts | 199 -
packages/svelte-query/tests/e2e.test.tsx | 173 -
packages/svelte-query/tests/shared.tsx | 14 -
packages/svelte-query/tsconfig.json | 15 -
packages/tanstack-query/README.md | 80 +-
packages/tanstack-query/package.json | 29 +-
.../src/contract-utils.test-d.ts | 157 +
.../tanstack-query/src/contract-utils.test.ts | 145 +
packages/tanstack-query/src/contract-utils.ts | 92 +
.../src/general-utils.test-d.ts | 30 -
.../tanstack-query/src/general-utils.test.ts | 21 -
packages/tanstack-query/src/general-utils.ts | 22 -
packages/tanstack-query/src/index.test.ts | 7 +-
packages/tanstack-query/src/index.ts | 2 +-
packages/tanstack-query/src/key.ts | 2 +-
.../tanstack-query/src/live-query.test.ts | 14 +-
packages/tanstack-query/src/live-query.ts | 8 +-
packages/tanstack-query/src/plugin.test.ts | 111 +
packages/tanstack-query/src/plugin.ts | 78 +
.../src/procedure-utils.angular.test-d.ts | 46 +-
.../src/procedure-utils.react.test-d.ts | 67 +-
.../src/procedure-utils.solid.test-d.ts | 43 +-
.../src/procedure-utils.svelte.test-d.ts | 42 +-
.../src/procedure-utils.test-d.ts | 742 +-
.../src/procedure-utils.test.ts | 779 +-
.../tanstack-query/src/procedure-utils.ts | 810 +-
.../src/procedure-utils.vue.test-d.ts | 103 +-
.../tanstack-query/src/router-utils.test-d.ts | 112 +-
.../tanstack-query/src/router-utils.test.ts | 284 +-
packages/tanstack-query/src/router-utils.ts | 179 +-
.../tanstack-query/src/stream-query.test.ts | 50 +-
packages/tanstack-query/src/stream-query.ts | 16 +-
packages/tanstack-query/src/types.ts | 108 +-
.../tanstack-query/tests/__shared__/orpc.tsx | 46 +
packages/tanstack-query/tests/e2e.test-d.ts | 246 +-
packages/tanstack-query/tests/e2e.test.tsx | 186 +-
.../tanstack-query/tests/live-query.test.tsx | 40 -
packages/tanstack-query/tests/shared.tsx | 14 -
packages/tanstack-query/tsconfig.json | 4 +-
packages/trpc/.gitignore | 26 -
packages/trpc/package.json | 49 -
packages/trpc/src/index.ts | 1 -
packages/trpc/src/to-orpc-router.test-d.ts | 45 -
packages/trpc/src/to-orpc-router.test.ts | 189 -
packages/trpc/src/to-orpc-router.ts | 162 -
packages/trpc/tests/shared.ts | 67 -
packages/valibot/README.md | 107 +-
packages/valibot/package.json | 14 +-
packages/valibot/src/converter.test.ts | 141 +-
packages/valibot/src/converter.ts | 91 +-
packages/valibot/src/index.test.ts | 5 +
packages/valibot/tsconfig.json | 6 +-
packages/vue-colada/.gitignore | 26 -
packages/vue-colada/README.md | 223 -
packages/vue-colada/package.json | 53 -
.../vue-colada/src/general-utils.test-d.ts | 25 -
packages/vue-colada/src/general-utils.test.ts | 23 -
packages/vue-colada/src/general-utils.ts | 22 -
packages/vue-colada/src/index.ts | 11 -
packages/vue-colada/src/key.test.ts | 15 -
packages/vue-colada/src/key.ts | 26 -
.../vue-colada/src/procedure-utils.test-d.ts | 157 -
.../vue-colada/src/procedure-utils.test.ts | 117 -
packages/vue-colada/src/procedure-utils.ts | 66 -
.../vue-colada/src/router-utils.test-d.ts | 31 -
packages/vue-colada/src/router-utils.test.ts | 63 -
packages/vue-colada/src/router-utils.ts | 59 -
packages/vue-colada/src/types.ts | 19 -
packages/vue-colada/tests/e2e.test-d.ts | 82 -
packages/vue-colada/tests/e2e.test.tsx | 83 -
packages/vue-colada/tests/shared.tsx | 19 -
packages/vue-colada/tsconfig.json | 16 -
packages/vue-query/.gitignore | 26 -
packages/vue-query/README.md | 236 -
packages/vue-query/package.json | 51 -
.../vue-query/src/general-utils.test-d.ts | 25 -
packages/vue-query/src/general-utils.test.ts | 23 -
packages/vue-query/src/general-utils.ts | 22 -
packages/vue-query/src/index.ts | 14 -
.../vue-query/src/procedure-utils.test-d.ts | 384 -
.../vue-query/src/procedure-utils.test.ts | 187 -
packages/vue-query/src/procedure-utils.ts | 108 -
packages/vue-query/src/router-utils.test-d.ts | 31 -
packages/vue-query/src/router-utils.test.ts | 63 -
packages/vue-query/src/router-utils.ts | 59 -
packages/vue-query/src/types.test-d.ts | 15 -
packages/vue-query/src/types.ts | 69 -
packages/vue-query/src/utils.test-d.ts | 42 -
packages/vue-query/src/utils.test.ts | 88 -
packages/vue-query/src/utils.ts | 29 -
packages/vue-query/tests/e2e.test-d.ts | 193 -
packages/vue-query/tests/e2e.test.tsx | 175 -
packages/vue-query/tests/shared.tsx | 14 -
packages/vue-query/tsconfig.json | 16 -
packages/zod/README.md | 144 +-
packages/zod/package.json | 28 +-
packages/zod/src/coercer.test.ts | 396 -
packages/zod/src/coercer.ts | 404 -
packages/zod/src/converter.components.test.ts | 289 -
packages/zod/src/converter.test.ts | 624 +-
packages/zod/src/converter.ts | 749 +-
packages/zod/src/custom-json-schema.test-d.ts | 62 -
packages/zod/src/custom-json-schema.test.ts | 34 -
packages/zod/src/custom-json-schema.ts | 57 -
packages/zod/src/index.test.ts | 5 +
packages/zod/src/index.ts | 21 -
packages/zod/src/schemas/base.ts | 55 -
packages/zod/src/schemas/blob.test.ts | 11 -
packages/zod/src/schemas/blob.ts | 20 -
packages/zod/src/schemas/file.test.ts | 32 -
packages/zod/src/schemas/file.ts | 49 -
packages/zod/src/schemas/regexp.test.ts | 10 -
packages/zod/src/schemas/regexp.ts | 20 -
packages/zod/src/schemas/url.test.ts | 10 -
packages/zod/src/schemas/url.ts | 20 -
.../zod/src/zod4/coercer.combination.test.ts | 180 -
packages/zod/src/zod4/coercer.native.test.ts | 170 -
packages/zod/src/zod4/coercer.rest.test.ts | 15 -
.../zod/src/zod4/coercer.structure.test.ts | 167 -
packages/zod/src/zod4/coercer.test.ts | 39 -
packages/zod/src/zod4/coercer.ts | 398 -
.../src/zod4/converter.combination.test.ts | 35 -
.../zod/src/zod4/converter.components.test.ts | 278 -
packages/zod/src/zod4/converter.meta.test.ts | 121 -
.../zod/src/zod4/converter.native.test.ts | 140 -
.../zod/src/zod4/converter.number.test.ts | 46 -
.../zod/src/zod4/converter.processed.test.ts | 27 -
packages/zod/src/zod4/converter.rest.test.ts | 20 -
.../zod/src/zod4/converter.string.test.ts | 161 -
.../zod/src/zod4/converter.structure.test.ts | 120 -
packages/zod/src/zod4/converter.test.ts | 69 -
packages/zod/src/zod4/converter.ts | 662 -
packages/zod/src/zod4/index.ts | 3 -
packages/zod/src/zod4/registries.ts | 60 -
packages/zod/tests/shared.ts | 60 -
packages/zod/tsconfig.json | 2 +-
playgrounds/astro/.gitignore | 24 -
playgrounds/astro/.vscode/settings.json | 3 -
playgrounds/astro/README.md | 135 -
playgrounds/astro/astro.config.mjs | 9 -
playgrounds/astro/package.json | 31 -
.../astro/src/components/orpc-mutation.tsx | 58 -
.../astro/src/components/orpc-query.tsx | 78 -
.../astro/src/components/orpc-stream.tsx | 16 -
playgrounds/astro/src/lib/orpc.ts | 23 -
playgrounds/astro/src/middlewares/auth.ts | 14 -
playgrounds/astro/src/middlewares/db.ts | 109 -
playgrounds/astro/src/middlewares/retry.ts | 35 -
playgrounds/astro/src/orpc.ts | 9 -
playgrounds/astro/src/pages/api/[...rest].ts | 78 -
playgrounds/astro/src/pages/index.astro | 18 -
playgrounds/astro/src/pages/rpc/[...rest].ts | 30 -
playgrounds/astro/src/playground-client.ts | 21 -
.../astro/src/playground-tanstack-query.ts | 29 -
playgrounds/astro/src/polyfill.ts | 21 -
playgrounds/astro/src/routers/auth.ts | 45 -
playgrounds/astro/src/routers/index.ts | 20 -
playgrounds/astro/src/routers/planet.ts | 98 -
playgrounds/astro/src/routers/sse.ts | 22 -
playgrounds/astro/src/schemas/auth.ts | 10 -
playgrounds/astro/src/schemas/planet.ts | 27 -
playgrounds/astro/src/schemas/user.ts | 37 -
playgrounds/astro/src/shared/query.ts | 3 -
playgrounds/astro/tsconfig.json | 14 -
playgrounds/browser-extension/.gitignore | 24 -
.../browser-extension/.vscode/settings.json | 3 -
playgrounds/browser-extension/README.md | 132 -
.../entrypoints/background/index.ts | 10 -
.../background/middlewares/auth.ts | 25 -
.../entrypoints/background/middlewares/db.ts | 109 -
.../background/middlewares/retry.ts | 35 -
.../entrypoints/background/orpc.ts | 9 -
.../entrypoints/background/routers/auth.ts | 45 -
.../entrypoints/background/routers/index.ts | 20 -
.../entrypoints/background/routers/planet.ts | 98 -
.../entrypoints/background/routers/sse.ts | 22 -
.../entrypoints/background/schemas/auth.ts | 10 -
.../entrypoints/background/schemas/planet.ts | 27 -
.../entrypoints/background/schemas/user.ts | 37 -
.../browser-extension/entrypoints/content.ts | 6 -
.../entrypoints/popup/App.tsx | 17 -
.../popup/components/orpc-mutation.tsx | 58 -
.../popup/components/orpc-query.tsx | 76 -
.../popup/components/orpc-stream.tsx | 15 -
.../entrypoints/popup/index.html | 13 -
.../entrypoints/popup/lib/orpc.ts | 15 -
.../entrypoints/popup/main.tsx | 14 -
.../entrypoints/popup/playground-client.ts | 21 -
.../popup/playground-tanstac-query.ts | 29 -
playgrounds/browser-extension/package.json | 34 -
.../browser-extension/public/icon/128.png | Bin 3074 -> 0 bytes
.../browser-extension/public/icon/16.png | Bin 559 -> 0 bytes
.../browser-extension/public/icon/32.png | Bin 916 -> 0 bytes
.../browser-extension/public/icon/48.png | Bin 1334 -> 0 bytes
.../browser-extension/public/icon/96.png | Bin 2366 -> 0 bytes
playgrounds/browser-extension/public/wxt.svg | 15 -
playgrounds/browser-extension/tsconfig.json | 7 -
playgrounds/browser-extension/wxt.config.ts | 6 -
playgrounds/bun-websocket-otel/.gitignore | 34 -
playgrounds/bun-websocket-otel/README.md | 136 -
playgrounds/bun-websocket-otel/bun-env.d.ts | 17 -
playgrounds/bun-websocket-otel/package.json | 36 -
playgrounds/bun-websocket-otel/src/App.tsx | 29 -
.../src/components/orpc-mutation.tsx | 58 -
.../src/components/orpc-query.tsx | 68 -
.../src/components/orpc-sse.tsx | 43 -
playgrounds/bun-websocket-otel/src/consts.ts | 1 -
.../bun-websocket-otel/src/frontend.tsx | 29 -
playgrounds/bun-websocket-otel/src/index.html | 12 -
playgrounds/bun-websocket-otel/src/index.tsx | 66 -
.../src/instrumentation-client.ts | 26 -
.../bun-websocket-otel/src/instrumentation.ts | 52 -
.../bun-websocket-otel/src/lib/orpc.ts | 17 -
.../src/middlewares/auth.ts | 32 -
.../bun-websocket-otel/src/middlewares/db.ts | 116 -
.../src/middlewares/retry.ts | 52 -
playgrounds/bun-websocket-otel/src/orpc.ts | 9 -
.../src/playground-client.ts | 21 -
.../src/playground-tanstack-query.ts | 29 -
.../bun-websocket-otel/src/routers/auth.ts | 39 -
.../bun-websocket-otel/src/routers/index.ts | 20 -
.../bun-websocket-otel/src/routers/planet.ts | 74 -
.../bun-websocket-otel/src/routers/sse.ts | 9 -
.../bun-websocket-otel/src/schemas/auth.ts | 10 -
.../bun-websocket-otel/src/schemas/planet.ts | 27 -
.../bun-websocket-otel/src/schemas/user.ts | 37 -
playgrounds/bun-websocket-otel/tsconfig.json | 34 -
playgrounds/cloudflare-worker/.gitignore | 27 -
.../cloudflare-worker/.vscode/settings.json | 3 -
playgrounds/cloudflare-worker/README.md | 135 -
playgrounds/cloudflare-worker/index.html | 12 -
playgrounds/cloudflare-worker/package.json | 37 -
playgrounds/cloudflare-worker/src/App.tsx | 42 -
.../src/components/chat-room-v2.tsx | 44 -
.../src/components/chat-room.tsx | 51 -
.../src/components/orpc-mutation.tsx | 58 -
.../src/components/orpc-query.tsx | 68 -
.../src/components/orpc-stream.tsx | 15 -
playgrounds/cloudflare-worker/src/lib/orpc.ts | 30 -
playgrounds/cloudflare-worker/src/main.tsx | 14 -
.../cloudflare-worker/src/vite-env.d.ts | 1 -
playgrounds/cloudflare-worker/tsconfig.json | 19 -
playgrounds/cloudflare-worker/vite.config.ts | 9 -
.../worker-configuration.d.ts | 10824 -----
.../cloudflare-worker/worker/dos/chat-room.ts | 33 -
.../cloudflare-worker/worker/dos/publisher.ts | 11 -
playgrounds/cloudflare-worker/worker/index.ts | 123 -
.../worker/middlewares/auth.ts | 35 -
.../worker/middlewares/db.ts | 109 -
.../worker/middlewares/retry.ts | 35 -
playgrounds/cloudflare-worker/worker/orpc.ts | 16 -
.../cloudflare-worker/worker/routers/auth.ts | 45 -
.../cloudflare-worker/worker/routers/index.ts | 32 -
.../worker/routers/message-v2.ts | 12 -
.../worker/routers/message.ts | 22 -
.../worker/routers/planet.ts | 98 -
.../cloudflare-worker/worker/routers/sse.ts | 22 -
.../cloudflare-worker/worker/schemas/auth.ts | 10 -
.../worker/schemas/planet.ts | 27 -
.../cloudflare-worker/worker/schemas/user.ts | 37 -
playgrounds/cloudflare-worker/wrangler.jsonc | 63 -
playgrounds/contract-first/.gitignore | 4 -
.../contract-first/.vscode/settings.json | 3 -
playgrounds/contract-first/README.md | 135 -
playgrounds/contract-first/package.json | 25 -
.../contract-first/src/contract/auth.ts | 32 -
.../contract-first/src/contract/index.ts | 20 -
.../contract-first/src/contract/planet.ts | 58 -
.../contract-first/src/contract/sse.ts | 11 -
playgrounds/contract-first/src/lib/orpc.ts | 16 -
playgrounds/contract-first/src/main.ts | 105 -
.../contract-first/src/middlewares/db.ts | 113 -
.../contract-first/src/middlewares/retry.ts | 35 -
playgrounds/contract-first/src/orpc.ts | 25 -
.../contract-first/src/playground-client.ts | 21 -
.../src/playground-tanstack-query.ts | 29 -
playgrounds/contract-first/src/polyfill.ts | 21 -
.../contract-first/src/routers/auth.ts | 20 -
.../contract-first/src/routers/index.ts | 21 -
.../contract-first/src/routers/planet.ts | 57 -
playgrounds/contract-first/src/routers/sse.ts | 14 -
.../contract-first/src/schemas/auth.ts | 10 -
.../contract-first/src/schemas/planet.ts | 27 -
.../contract-first/src/schemas/user.ts | 37 -
playgrounds/contract-first/tsconfig.json | 24 -
playgrounds/electron/.gitignore | 6 -
playgrounds/electron/.vscode/settings.json | 3 -
playgrounds/electron/README.md | 132 -
playgrounds/electron/electron-builder.yml | 43 -
playgrounds/electron/electron.vite.config.ts | 20 -
playgrounds/electron/package.json | 38 -
playgrounds/electron/src/main/index.ts | 84 -
.../electron/src/main/middlewares/auth.ts | 25 -
.../electron/src/main/middlewares/db.ts | 109 -
.../electron/src/main/middlewares/retry.ts | 35 -
playgrounds/electron/src/main/orpc.ts | 9 -
playgrounds/electron/src/main/routers/auth.ts | 45 -
.../electron/src/main/routers/index.ts | 20 -
.../electron/src/main/routers/planet.ts | 98 -
playgrounds/electron/src/main/routers/sse.ts | 22 -
playgrounds/electron/src/main/schemas/auth.ts | 10 -
.../electron/src/main/schemas/planet.ts | 27 -
playgrounds/electron/src/main/schemas/user.ts | 37 -
playgrounds/electron/src/preload/index.d.ts | 8 -
playgrounds/electron/src/preload/index.ts | 32 -
playgrounds/electron/src/renderer/index.html | 17 -
playgrounds/electron/src/renderer/src/App.tsx | 19 -
.../renderer/src/components/orpc-mutation.tsx | 58 -
.../renderer/src/components/orpc-query.tsx | 76 -
.../renderer/src/components/orpc-stream.tsx | 15 -
.../electron/src/renderer/src/lib/orpc.ts | 19 -
.../electron/src/renderer/src/main.tsx | 14 -
.../src/renderer/src/playground-client.ts | 21 -
.../renderer/src/playground-tanstack-query.ts | 29 -
playgrounds/electron/tsconfig.json | 27 -
playgrounds/electron/tsconfig.node.json | 15 -
playgrounds/nest/.gitignore | 56 -
playgrounds/nest/.vscode/settings.json | 3 -
playgrounds/nest/README.md | 134 -
playgrounds/nest/build.config.ts | 18 -
playgrounds/nest/nest-cli.json | 9 -
playgrounds/nest/package.json | 40 -
playgrounds/nest/src/app.module.ts | 49 -
playgrounds/nest/src/auth/auth.controller.ts | 37 -
playgrounds/nest/src/contract/auth.ts | 32 -
playgrounds/nest/src/contract/index.ts | 20 -
playgrounds/nest/src/contract/planet.ts | 56 -
playgrounds/nest/src/contract/sse.ts | 11 -
playgrounds/nest/src/lib/orpc.ts | 17 -
playgrounds/nest/src/main.ts | 11 -
.../nest/src/other/other.controller.ts | 23 -
.../nest/src/planet/planet.controller.ts | 61 -
playgrounds/nest/src/planet/planet.service.ts | 81 -
playgrounds/nest/src/playground-client.ts | 21 -
.../nest/src/playground-tanstack-query.ts | 29 -
.../src/reference/reference.controller.ts | 44 -
.../nest/src/reference/reference.service.ts | 45 -
playgrounds/nest/src/schemas/auth.ts | 10 -
playgrounds/nest/src/schemas/planet.ts | 27 -
playgrounds/nest/src/schemas/user.ts | 37 -
playgrounds/nest/tsconfig.build.json | 4 -
playgrounds/nest/tsconfig.json | 25 -
playgrounds/next/.gitignore | 4 +-
playgrounds/next/.vscode/settings.json | 3 -
playgrounds/next/README.md | 22 +-
playgrounds/next/next.config.ts | 7 +-
playgrounds/next/package.json | 48 +-
playgrounds/next/public/file.svg | 1 -
playgrounds/next/public/globe.svg | 1 -
playgrounds/next/public/next.svg | 1 -
playgrounds/next/public/vercel.svg | 1 -
playgrounds/next/public/window.svg | 1 -
playgrounds/next/src/app/actions.ts | 46 +-
.../next/src/app/api/[[...rest]]/route.ts | 80 +-
playgrounds/next/src/app/error.tsx | 12 -
playgrounds/next/src/app/favicon.ico | Bin 25931 -> 0 bytes
playgrounds/next/src/app/global.css | 802 +
playgrounds/next/src/app/layout.tsx | 6 +-
playgrounds/next/src/app/loading.tsx | 3 -
playgrounds/next/src/app/orpc-mutation.tsx | 60 -
playgrounds/next/src/app/orpc-query.tsx | 70 -
.../next/src/app/orpc-server-action.tsx | 24 -
playgrounds/next/src/app/orpc-stream.tsx | 17 -
playgrounds/next/src/app/page.tsx | 58 +-
.../next/src/app/rpc/[[...rest]]/route.ts | 18 +-
playgrounds/next/src/components/chat-room.tsx | 84 +
.../src/components/create-planet-form.tsx | 89 +
.../src/components/planet-table-skeleton.tsx | 62 +
.../next/src/components/planet-table.tsx | 146 +
.../next/src/components/reference-links.tsx | 48 +
.../next/src/components/server-function.tsx | 54 +
playgrounds/next/src/components/top-bar.tsx | 36 +
playgrounds/next/src/context.ts | 8 +
playgrounds/next/src/instrumentation.ts | 21 +-
playgrounds/next/src/lib/orpc.server.ts | 23 -
playgrounds/next/src/lib/orpc.ts | 27 +-
playgrounds/next/src/middlewares/auth.ts | 35 -
playgrounds/next/src/middlewares/db.ts | 109 -
playgrounds/next/src/middlewares/retry.ts | 35 -
playgrounds/next/src/orpc.ts | 31 +-
playgrounds/next/src/playground-client.ts | 21 -
.../next/src/playground-tanstack-query.ts | 29 -
playgrounds/next/src/polyfill.ts | 21 -
playgrounds/next/src/routers/auth.ts | 48 -
playgrounds/next/src/routers/file.ts | 52 +
playgrounds/next/src/routers/index.ts | 22 +-
playgrounds/next/src/routers/message.ts | 36 +
playgrounds/next/src/routers/planet.ts | 187 +-
playgrounds/next/src/routers/sse.ts | 22 -
playgrounds/next/src/schemas/auth.ts | 10 -
playgrounds/next/src/schemas/planet.ts | 24 +-
playgrounds/next/src/schemas/user.ts | 37 -
playgrounds/next/tsconfig.json | 17 +-
playgrounds/nuxt/.gitignore | 28 -
playgrounds/nuxt/.vscode/settings.json | 3 -
playgrounds/nuxt/README.md | 135 -
playgrounds/nuxt/app/app.vue | 18 -
.../nuxt/app/components/orpc-mutation.vue | 56 -
.../nuxt/app/components/orpc-query.vue | 56 -
.../nuxt/app/components/orpc-stream.vue | 21 -
playgrounds/nuxt/app/plugins/orpc.client.ts | 32 -
playgrounds/nuxt/app/plugins/orpc.server.ts | 26 -
playgrounds/nuxt/app/plugins/vue-query.ts | 36 -
playgrounds/nuxt/nuxt.config.ts | 5 -
playgrounds/nuxt/package.json | 25 -
playgrounds/nuxt/public/favicon.ico | Bin 4286 -> 0 bytes
playgrounds/nuxt/public/robots.txt | 1 -
playgrounds/nuxt/server/middlewares/db.ts | 109 -
playgrounds/nuxt/server/middlewares/retry.ts | 35 -
playgrounds/nuxt/server/orpc.ts | 24 -
playgrounds/nuxt/server/playground-client.ts | 21 -
.../nuxt/server/playground-tanstack-query.ts | 29 -
playgrounds/nuxt/server/plugins/polyfills.ts | 23 -
playgrounds/nuxt/server/routers/auth.ts | 45 -
playgrounds/nuxt/server/routers/index.ts | 20 -
playgrounds/nuxt/server/routers/planet.ts | 98 -
playgrounds/nuxt/server/routers/sse.ts | 22 -
playgrounds/nuxt/server/routes/api/[...].ts | 84 -
playgrounds/nuxt/server/routes/api/index.ts | 1 -
playgrounds/nuxt/server/routes/rpc/[...].ts | 33 -
playgrounds/nuxt/server/routes/rpc/index.ts | 1 -
playgrounds/nuxt/server/schemas/auth.ts | 10 -
playgrounds/nuxt/server/schemas/planet.ts | 27 -
playgrounds/nuxt/server/schemas/user.ts | 37 -
playgrounds/nuxt/server/tsconfig.json | 3 -
playgrounds/nuxt/tsconfig.json | 4 -
playgrounds/solid-start/.gitignore | 28 -
playgrounds/solid-start/.vscode/settings.json | 3 -
playgrounds/solid-start/README.md | 135 -
playgrounds/solid-start/app.config.ts | 11 -
playgrounds/solid-start/package.json | 25 -
playgrounds/solid-start/public/favicon.ico | Bin 664 -> 0 bytes
playgrounds/solid-start/src/app.tsx | 30 -
playgrounds/solid-start/src/entry-client.tsx | 4 -
playgrounds/solid-start/src/entry-server.tsx | 21 -
playgrounds/solid-start/src/global.d.ts | 1 -
.../solid-start/src/lib/orpc.server.ts | 29 -
playgrounds/solid-start/src/lib/orpc.ts | 33 -
playgrounds/solid-start/src/middlewares/db.ts | 109 -
.../solid-start/src/middlewares/retry.ts | 35 -
playgrounds/solid-start/src/orpc.ts | 24 -
.../solid-start/src/playground-client.ts | 21 -
.../src/playground-tanstack-query.ts | 29 -
playgrounds/solid-start/src/polyfill.ts | 21 -
playgrounds/solid-start/src/routers/auth.ts | 45 -
playgrounds/solid-start/src/routers/index.ts | 20 -
playgrounds/solid-start/src/routers/planet.ts | 98 -
playgrounds/solid-start/src/routers/sse.ts | 22 -
.../solid-start/src/routes/api/[...rest].ts | 85 -
.../solid-start/src/routes/api/index.ts | 8 -
playgrounds/solid-start/src/routes/index.tsx | 24 -
.../solid-start/src/routes/orpc-mutation.tsx | 58 -
.../solid-start/src/routes/orpc-query.tsx | 64 -
.../solid-start/src/routes/orpc-stream.tsx | 17 -
.../solid-start/src/routes/rpc/[...rest].ts | 35 -
.../solid-start/src/routes/rpc/index.ts | 8 -
playgrounds/solid-start/src/schemas/auth.ts | 10 -
playgrounds/solid-start/src/schemas/planet.ts | 27 -
playgrounds/solid-start/src/schemas/user.ts | 37 -
playgrounds/solid-start/tsconfig.json | 20 -
playgrounds/svelte-kit/.gitignore | 23 -
playgrounds/svelte-kit/.npmrc | 1 -
playgrounds/svelte-kit/.vscode/settings.json | 3 -
playgrounds/svelte-kit/README.md | 135 -
playgrounds/svelte-kit/package.json | 31 -
playgrounds/svelte-kit/src/app.d.ts | 13 -
playgrounds/svelte-kit/src/app.html | 12 -
playgrounds/svelte-kit/src/hooks.server.ts | 1 -
playgrounds/svelte-kit/src/lib/index.ts | 1 -
playgrounds/svelte-kit/src/lib/orpc.server.ts | 26 -
playgrounds/svelte-kit/src/lib/orpc.ts | 32 -
playgrounds/svelte-kit/src/middlewares/db.ts | 109 -
.../svelte-kit/src/middlewares/retry.ts | 35 -
playgrounds/svelte-kit/src/orpc.ts | 24 -
.../svelte-kit/src/playground-client.ts | 21 -
.../src/playground-tanstack-query.ts | 29 -
playgrounds/svelte-kit/src/polyfill.ts | 21 -
playgrounds/svelte-kit/src/routers/auth.ts | 45 -
playgrounds/svelte-kit/src/routers/index.ts | 20 -
playgrounds/svelte-kit/src/routers/planet.ts | 98 -
playgrounds/svelte-kit/src/routers/sse.ts | 22 -
.../svelte-kit/src/routes/+page.svelte | 27 -
.../src/routes/api/[...rest]/+server.ts | 84 -
.../src/routes/orpc-mutation.svelte | 56 -
.../svelte-kit/src/routes/orpc-query.svelte | 57 -
.../svelte-kit/src/routes/orpc-stream.svelte | 18 -
.../src/routes/rpc/[...rest]/+server.ts | 36 -
playgrounds/svelte-kit/src/schemas/auth.ts | 10 -
playgrounds/svelte-kit/src/schemas/planet.ts | 27 -
playgrounds/svelte-kit/src/schemas/user.ts | 37 -
playgrounds/svelte-kit/static/favicon.png | Bin 1571 -> 0 bytes
playgrounds/svelte-kit/svelte.config.js | 18 -
playgrounds/svelte-kit/tsconfig.json | 19 -
playgrounds/svelte-kit/vite.config.ts | 10 -
playgrounds/tanstack-start/.gitignore | 22 -
.../tanstack-start/.vscode/settings.json | 3 -
playgrounds/tanstack-start/README.md | 135 -
playgrounds/tanstack-start/package.json | 36 -
.../src/components/orpc-mutation.tsx | 58 -
.../src/components/orpc-query.tsx | 68 -
.../src/components/orpc-stream.tsx | 15 -
playgrounds/tanstack-start/src/lib/orpc.ts | 48 -
.../tanstack-start/src/middlewares/auth.ts | 27 -
.../tanstack-start/src/middlewares/db.ts | 109 -
.../tanstack-start/src/middlewares/retry.ts | 35 -
playgrounds/tanstack-start/src/orpc.ts | 9 -
.../tanstack-start/src/playground-client.ts | 21 -
.../src/playground-tanstack-query.ts | 29 -
playgrounds/tanstack-start/src/polyfill.ts | 21 -
.../tanstack-start/src/routeTree.gen.ts | 104 -
playgrounds/tanstack-start/src/router.tsx | 26 -
.../tanstack-start/src/routers/auth.ts | 45 -
.../tanstack-start/src/routers/index.ts | 20 -
.../tanstack-start/src/routers/planet.ts | 98 -
playgrounds/tanstack-start/src/routers/sse.ts | 22 -
.../tanstack-start/src/routes/__root.tsx | 50 -
.../tanstack-start/src/routes/api/$.ts | 81 -
.../tanstack-start/src/routes/api/rpc.$.ts | 33 -
.../tanstack-start/src/routes/index.tsx | 27 -
.../tanstack-start/src/schemas/auth.ts | 10 -
.../tanstack-start/src/schemas/planet.ts | 27 -
.../tanstack-start/src/schemas/user.ts | 37 -
playgrounds/tanstack-start/tsconfig.json | 19 -
playgrounds/tanstack-start/vite.config.ts | 17 -
pnpm-lock.yaml | 35364 ++++------------
pnpm-workspace.yaml | 32 +-
scripts/{sync-sponsor.ts => sync-sponsors.ts} | 2 +-
.../__shared__/client-server.hono-fetch.ts | 55 +
.../__shared__/client-server.node-http.ts | 52 +
tests/batch/__shared__/client-server.ts | 30 +
tests/batch/batch-plugin.test.ts | 187 +
.../__shared__/client-server.hono-fetch.ts | 44 +
.../__shared__/client-server.node-http.ts | 42 +
tests/openapi/__shared__/client-server.ts | 13 +
tests/openapi/abort-signal.test.ts | 44 +
tests/openapi/data-transfer.test.ts | 307 +
.../__shared__/built-in-support-data-types.ts | 54 +-
.../__shared__/client-server.hono-fetch.ts | 45 +
.../__shared__/client-server.message-port.ts | 33 +
.../rpc/__shared__/client-server.node-http.ts | 42 +
tests/rpc/__shared__/client-server.node-ws.ts | 43 +
tests/rpc/__shared__/client-server.ts | 30 +
tests/rpc/abort-signal.test.ts | 39 +
tests/rpc/data-transfer.test.ts | 114 +
tests/rpc/stream.test.ts | 68 +
tsconfig.base.json | 1 +
tsconfig.json | 18 -
vitest.config.ts | 47 +-
vitest.javascript.ts | 2 +-
1626 files changed, 68582 insertions(+), 135549 deletions(-)
delete mode 100644 .github/workflows/pullfrog.yml
delete mode 100644 apps/content/docs/adapters/astro.md
delete mode 100644 apps/content/docs/adapters/browser.md
delete mode 100644 apps/content/docs/adapters/electron.md
delete mode 100644 apps/content/docs/adapters/elysia.md
delete mode 100644 apps/content/docs/adapters/express.md
delete mode 100644 apps/content/docs/adapters/fastify.md
create mode 100644 apps/content/docs/adapters/fetch-api.md
delete mode 100644 apps/content/docs/adapters/h3.md
delete mode 100644 apps/content/docs/adapters/hono.md
delete mode 100644 apps/content/docs/adapters/http.md
delete mode 100644 apps/content/docs/adapters/next.md
create mode 100644 apps/content/docs/adapters/node-http.md
delete mode 100644 apps/content/docs/adapters/nuxt.md
delete mode 100644 apps/content/docs/adapters/react-native.md
delete mode 100644 apps/content/docs/adapters/remix.md
delete mode 100644 apps/content/docs/adapters/solid-start.md
delete mode 100644 apps/content/docs/adapters/svelte-kit.md
delete mode 100644 apps/content/docs/adapters/tanstack-start.md
delete mode 100644 apps/content/docs/adapters/web-workers.md
delete mode 100644 apps/content/docs/adapters/worker-threads.md
delete mode 100644 apps/content/docs/advanced/building-custom-plugins.md
create mode 100644 apps/content/docs/advanced/expanding-type-support-for-openapi-link.md
delete mode 100644 apps/content/docs/advanced/extend-body-parser.md
delete mode 100644 apps/content/docs/advanced/rpc-json-serializer.md
delete mode 100644 apps/content/docs/advanced/rpc-protocol.md
create mode 100644 apps/content/docs/advanced/scaling-large-projects.md
delete mode 100644 apps/content/docs/advanced/superjson.md
create mode 100644 apps/content/docs/advanced/testing-and-mocking.md
delete mode 100644 apps/content/docs/advanced/testing-mocking.md
delete mode 100644 apps/content/docs/best-practices/optimize-ssr.md
create mode 100644 apps/content/docs/best-practices/optimizing-ssr.md
create mode 100644 apps/content/docs/binary-data.md
delete mode 100644 apps/content/docs/client/rpc-link.md
delete mode 100644 apps/content/docs/comparison.md
delete mode 100644 apps/content/docs/contract-first/define-contract.md
delete mode 100644 apps/content/docs/contract-first/implement-contract.md
delete mode 100644 apps/content/docs/contract-first/router-to-contract.md
create mode 100644 apps/content/docs/contract/implementation.md
create mode 100644 apps/content/docs/contract/procedure.md
create mode 100644 apps/content/docs/contract/router.md
delete mode 100644 apps/content/docs/ecosystem.md
delete mode 100644 apps/content/docs/examples/openai-streaming.md
delete mode 100644 apps/content/docs/file-upload-download.md
delete mode 100644 apps/content/docs/integrations/ai-sdk.md
delete mode 100644 apps/content/docs/integrations/better-auth.md
delete mode 100644 apps/content/docs/integrations/durable-iterator.md
create mode 100644 apps/content/docs/integrations/effect.md
create mode 100644 apps/content/docs/integrations/evlog.md
create mode 100644 apps/content/docs/integrations/next.md
delete mode 100644 apps/content/docs/integrations/pinia-colada.md
delete mode 100644 apps/content/docs/integrations/react-swr.md
delete mode 100644 apps/content/docs/integrations/sentry.md
delete mode 100644 apps/content/docs/integrations/tanstack-query-old/basic.md
delete mode 100644 apps/content/docs/integrations/tanstack-query-old/react.md
delete mode 100644 apps/content/docs/integrations/tanstack-query-old/solid.md
delete mode 100644 apps/content/docs/integrations/tanstack-query-old/svelte.md
delete mode 100644 apps/content/docs/integrations/tanstack-query-old/vue.md
delete mode 100644 apps/content/docs/openapi/advanced/customizing-error-response.md
delete mode 100644 apps/content/docs/openapi/advanced/disabling-output-validation.md
delete mode 100644 apps/content/docs/openapi/advanced/expanding-type-support-for-openapi-link.md
delete mode 100644 apps/content/docs/openapi/advanced/openapi-json-serializer.md
delete mode 100644 apps/content/docs/openapi/advanced/redirect-response.md
delete mode 100644 apps/content/docs/openapi/client/openapi-link.md
delete mode 100644 apps/content/docs/openapi/error-handling.md
delete mode 100644 apps/content/docs/openapi/getting-started.md
create mode 100644 apps/content/docs/openapi/handler.md
create mode 100644 apps/content/docs/openapi/input-and-output-mapping.md
delete mode 100644 apps/content/docs/openapi/input-output-structure.md
delete mode 100644 apps/content/docs/openapi/integrations/hey-api.md
delete mode 100644 apps/content/docs/openapi/integrations/implement-contract-in-nest.md
delete mode 100644 apps/content/docs/openapi/integrations/trpc.md
create mode 100644 apps/content/docs/openapi/link.md
delete mode 100644 apps/content/docs/openapi/openapi-handler.md
delete mode 100644 apps/content/docs/openapi/openapi-specification.md
delete mode 100644 apps/content/docs/openapi/openapi-to-contract.md
delete mode 100644 apps/content/docs/openapi/plugins/openapi-reference.md
delete mode 100644 apps/content/docs/openapi/plugins/smart-coercion.md
delete mode 100644 apps/content/docs/openapi/plugins/zod-smart-coercion.md
create mode 100644 apps/content/docs/openapi/serializer.md
create mode 100644 apps/content/docs/openapi/specification.md
delete mode 100644 apps/content/docs/plugins/batch-requests.md
create mode 100644 apps/content/docs/plugins/batch.md
create mode 100644 apps/content/docs/plugins/body-compression.md
delete mode 100644 apps/content/docs/plugins/client-retry.md
delete mode 100644 apps/content/docs/plugins/compression.md
create mode 100644 apps/content/docs/plugins/csrf-guard.md
delete mode 100644 apps/content/docs/plugins/dedupe-requests.md
create mode 100644 apps/content/docs/plugins/dedupe.md
delete mode 100644 apps/content/docs/plugins/hibernation.md
create mode 100644 apps/content/docs/plugins/openapi-reference.md
delete mode 100644 apps/content/docs/plugins/rethrow-handler.md
create mode 100644 apps/content/docs/plugins/retry.md
delete mode 100644 apps/content/docs/plugins/simple-csrf-protection.md
create mode 100644 apps/content/docs/plugins/smart-coercion.md
delete mode 100644 apps/content/docs/plugins/strict-get-method.md
delete mode 100644 apps/content/docs/rpc-handler.md
create mode 100644 apps/content/docs/rpc/handler.md
create mode 100644 apps/content/docs/rpc/link.md
create mode 100644 apps/content/docs/rpc/protocol.md
create mode 100644 apps/content/docs/rpc/serializer.md
delete mode 100644 apps/content/docs/server-action.md
create mode 100644 apps/content/public/_redirects
create mode 100644 apps/content/shared/common-error-status-map-table.md
create mode 100644 apps/content/shared/common-plugin-handler-compatibility.md
create mode 100644 apps/content/shared/common-plugin-link-compatibility.md
create mode 100644 apps/content/shared/router-keys-compatibility-warning.md
create mode 100644 apps/content/shared/standard-server-cors-warning.md
create mode 100644 apps/content/vercel.json
delete mode 100644 knip.json
delete mode 100644 packages/ai-sdk/package.json
delete mode 100644 packages/ai-sdk/src/index.test.ts
delete mode 100644 packages/ai-sdk/src/index.ts
delete mode 100644 packages/ai-sdk/src/tool.test-d.ts
delete mode 100644 packages/ai-sdk/src/tool.test.ts
delete mode 100644 packages/ai-sdk/src/tool.ts
delete mode 100644 packages/ai-sdk/tsconfig.json
create mode 100644 packages/arktype/src/index.test.ts
create mode 100644 packages/client/src/adapters/fetch/index.test.ts
delete mode 100644 packages/client/src/adapters/fetch/link-fetch-client.test.ts
delete mode 100644 packages/client/src/adapters/fetch/link-fetch-client.ts
delete mode 100644 packages/client/src/adapters/fetch/plugin.test-d.ts
create mode 100644 packages/client/src/adapters/fetch/transport.ts
create mode 100644 packages/client/src/adapters/message-port/index.test.ts
delete mode 100644 packages/client/src/adapters/message-port/link-client.ts
create mode 100644 packages/client/src/adapters/message-port/transport.ts
create mode 100644 packages/client/src/adapters/standard/codec.ts
create mode 100644 packages/client/src/adapters/standard/index.test.ts
delete mode 100644 packages/client/src/adapters/standard/rpc-json-serializer.test.ts
delete mode 100644 packages/client/src/adapters/standard/rpc-json-serializer.ts
delete mode 100644 packages/client/src/adapters/standard/rpc-link.test.ts
delete mode 100644 packages/client/src/adapters/standard/rpc-link.ts
delete mode 100644 packages/client/src/adapters/standard/rpc-serializer.test.ts
delete mode 100644 packages/client/src/adapters/standard/rpc-serializer.ts
create mode 100644 packages/client/src/adapters/standard/transport.ts
delete mode 100644 packages/client/src/adapters/standard/types.ts
delete mode 100644 packages/client/src/adapters/standard/utils.test.ts
delete mode 100644 packages/client/src/adapters/standard/utils.ts
create mode 100644 packages/client/src/adapters/websocket/index.test.ts
delete mode 100644 packages/client/src/adapters/websocket/link-client.ts
create mode 100644 packages/client/src/adapters/websocket/transport.ts
create mode 100644 packages/client/src/error-utils.test-d.ts
create mode 100644 packages/client/src/error-utils.test.ts
create mode 100644 packages/client/src/error-utils.ts
create mode 100644 packages/client/src/index.test.ts
delete mode 100644 packages/client/src/plugins/dedupe-requests.test.ts
delete mode 100644 packages/client/src/plugins/dedupe-requests.ts
create mode 100644 packages/client/src/plugins/dedupe.test.ts
create mode 100644 packages/client/src/plugins/dedupe.ts
create mode 100644 packages/client/src/plugins/index.test.ts
delete mode 100644 packages/client/src/plugins/simple-csrf-protection.test.ts
delete mode 100644 packages/client/src/plugins/simple-csrf-protection.ts
create mode 100644 packages/client/src/rpc-json-serializer.test.ts
create mode 100644 packages/client/src/rpc-json-serializer.ts
create mode 100644 packages/client/src/rpc-serializer.test.ts
create mode 100644 packages/client/src/rpc-serializer.ts
delete mode 100644 packages/client/tests/e2e.test-d.ts
delete mode 100644 packages/client/tests/e2e.test.ts
delete mode 100644 packages/client/tests/helpers.ts
create mode 100644 packages/contract/src/caller.test-d.ts
create mode 100644 packages/contract/src/caller.test.ts
create mode 100644 packages/contract/src/caller.ts
delete mode 100644 packages/contract/src/config.test.ts
delete mode 100644 packages/contract/src/config.ts
create mode 100644 packages/contract/src/error-utils.test-d.ts
create mode 100644 packages/contract/src/error-utils.test.ts
create mode 100644 packages/contract/src/error-utils.ts
create mode 100644 packages/contract/src/index.test.ts
delete mode 100644 packages/contract/src/link-utils.test-d.ts
delete mode 100644 packages/contract/src/link-utils.test.ts
delete mode 100644 packages/contract/src/link-utils.ts
create mode 100644 packages/contract/src/meta-built-in.test.ts
create mode 100644 packages/contract/src/meta-built-in.ts
create mode 100644 packages/contract/src/meta-utils.test.ts
create mode 100644 packages/contract/src/meta-utils.ts
delete mode 100644 packages/contract/src/route.test.ts
delete mode 100644 packages/contract/src/route.ts
delete mode 100644 packages/contract/src/schema.test.ts
delete mode 100644 packages/contract/src/types.ts
delete mode 100644 packages/contract/tests/e2e.test-d.ts
delete mode 100644 packages/contract/tests/helpers.ts
delete mode 100644 packages/contract/tests/shared.ts
delete mode 100644 packages/durable-iterator/README.md
delete mode 100644 packages/durable-iterator/build.config.ts
delete mode 100644 packages/durable-iterator/package.json
delete mode 100644 packages/durable-iterator/src/client/index.test.ts
delete mode 100644 packages/durable-iterator/src/client/index.ts
delete mode 100644 packages/durable-iterator/src/client/iterator.test-d.ts
delete mode 100644 packages/durable-iterator/src/client/iterator.test.ts
delete mode 100644 packages/durable-iterator/src/client/iterator.ts
delete mode 100644 packages/durable-iterator/src/client/plugin.test.ts
delete mode 100644 packages/durable-iterator/src/client/plugin.ts
delete mode 100644 packages/durable-iterator/src/consts.ts
delete mode 100644 packages/durable-iterator/src/contract.ts
delete mode 100644 packages/durable-iterator/src/durable-object/handler.ts
delete mode 100644 packages/durable-iterator/src/durable-object/index.test.ts
delete mode 100644 packages/durable-iterator/src/durable-object/index.ts
delete mode 100644 packages/durable-iterator/src/durable-object/object-state.test.ts
delete mode 100644 packages/durable-iterator/src/durable-object/object-state.ts
delete mode 100644 packages/durable-iterator/src/durable-object/object.test.ts
delete mode 100644 packages/durable-iterator/src/durable-object/object.ts
delete mode 100644 packages/durable-iterator/src/durable-object/resume-storage.test.ts
delete mode 100644 packages/durable-iterator/src/durable-object/resume-storage.ts
delete mode 100644 packages/durable-iterator/src/durable-object/upgrade.test.ts
delete mode 100644 packages/durable-iterator/src/durable-object/upgrade.ts
delete mode 100644 packages/durable-iterator/src/durable-object/websocket.test.ts
delete mode 100644 packages/durable-iterator/src/durable-object/websocket.ts
delete mode 100644 packages/durable-iterator/src/error.ts
delete mode 100644 packages/durable-iterator/src/index.test.ts
delete mode 100644 packages/durable-iterator/src/index.ts
delete mode 100644 packages/durable-iterator/src/iterator.test-d.ts
delete mode 100644 packages/durable-iterator/src/iterator.test.ts
delete mode 100644 packages/durable-iterator/src/iterator.ts
delete mode 100644 packages/durable-iterator/src/object.test-d.ts
delete mode 100644 packages/durable-iterator/src/object.ts
delete mode 100644 packages/durable-iterator/src/plugin.test.ts
delete mode 100644 packages/durable-iterator/src/plugin.ts
delete mode 100644 packages/durable-iterator/src/schemas.test.ts
delete mode 100644 packages/durable-iterator/src/schemas.ts
delete mode 100644 packages/durable-iterator/tests/shared.ts
delete mode 100644 packages/durable-iterator/tsconfig.json
delete mode 100644 packages/durable-iterator/tsconfig.test.json
rename packages/{hey-api => effect}/.gitignore (100%)
rename packages/{trpc => effect}/README.md (86%)
create mode 100644 packages/effect/package.json
create mode 100644 packages/effect/src/context.ts
create mode 100644 packages/effect/src/converter.test.ts
create mode 100644 packages/effect/src/converter.ts
create mode 100644 packages/effect/src/extensions/effect.test-d.ts
create mode 100644 packages/effect/src/extensions/effect.test.ts
create mode 100644 packages/effect/src/extensions/effect.ts
create mode 100644 packages/effect/src/extensions/input-output.test-d.ts
create mode 100644 packages/effect/src/extensions/input-output.test.ts
create mode 100644 packages/effect/src/extensions/input-output.ts
create mode 100644 packages/effect/src/handler.test-d.ts
create mode 100644 packages/effect/src/handler.test.ts
create mode 100644 packages/effect/src/handler.ts
create mode 100644 packages/effect/src/index.test.ts
create mode 100644 packages/effect/src/index.ts
create mode 100644 packages/effect/src/runtime.test.ts
create mode 100644 packages/effect/src/runtime.ts
create mode 100644 packages/effect/src/schema.test.ts
create mode 100644 packages/effect/src/schema.ts
rename packages/{openapi-client => effect}/tsconfig.json (68%)
rename packages/{otel => evlog}/.gitignore (88%)
rename packages/{hey-api => evlog}/README.md (86%)
rename packages/{svelte-query => evlog}/package.json (56%)
create mode 100644 packages/evlog/src/adapters/node.ts
create mode 100644 packages/evlog/src/context.test.ts
create mode 100644 packages/evlog/src/context.ts
create mode 100644 packages/evlog/src/handler-plugin.test.ts
create mode 100644 packages/evlog/src/handler-plugin.ts
create mode 100644 packages/evlog/src/index.test.ts
create mode 100644 packages/evlog/src/index.ts
rename packages/{trpc => evlog}/tsconfig.json (83%)
delete mode 100644 packages/hey-api/package.json
delete mode 100644 packages/hey-api/src/index.ts
delete mode 100644 packages/hey-api/src/to-orpc-client.test-d.ts
delete mode 100644 packages/hey-api/src/to-orpc-client.test.ts
delete mode 100644 packages/hey-api/src/to-orpc-client.ts
delete mode 100644 packages/hey-api/tests/spec.json
delete mode 100644 packages/hey-api/tsconfig.json
create mode 100644 packages/json-schema/src/composition-utils.test.ts
create mode 100644 packages/json-schema/src/composition-utils.ts
create mode 100644 packages/json-schema/src/constants.ts
create mode 100644 packages/json-schema/src/convert.test.ts
create mode 100644 packages/json-schema/src/convert.ts
create mode 100644 packages/json-schema/src/index.test.ts
create mode 100644 packages/json-schema/src/ref-utils.test.ts
create mode 100644 packages/json-schema/src/ref-utils.ts
create mode 100644 packages/json-schema/src/smart-coercion-handler-plugin.test.ts
create mode 100644 packages/json-schema/src/smart-coercion-handler-plugin.ts
create mode 100644 packages/json-schema/src/smart-coercion-link-plugin.test.ts
create mode 100644 packages/json-schema/src/smart-coercion-link-plugin.ts
delete mode 100644 packages/json-schema/src/smart-coercion-plugin.test.ts
delete mode 100644 packages/json-schema/src/smart-coercion-plugin.ts
create mode 100644 packages/json-schema/src/standard-json-schema-converter.test.ts
create mode 100644 packages/json-schema/src/standard-json-schema-converter.ts
create mode 100644 packages/json-schema/src/utils.test.ts
create mode 100644 packages/json-schema/src/utils.ts
delete mode 100644 packages/nest/.gitignore
delete mode 100644 packages/nest/README.md
delete mode 100644 packages/nest/build.config.ts
delete mode 100644 packages/nest/package.json
delete mode 100644 packages/nest/src/implement.test-d.ts
delete mode 100644 packages/nest/src/implement.test.ts
delete mode 100644 packages/nest/src/implement.ts
delete mode 100644 packages/nest/src/index.test.ts
delete mode 100644 packages/nest/src/index.ts
delete mode 100644 packages/nest/src/module.ts
delete mode 100644 packages/nest/src/utils.test.ts
delete mode 100644 packages/nest/src/utils.ts
delete mode 100644 packages/nest/tsconfig.json
delete mode 100644 packages/nest/tsconfig.test.json
rename packages/{durable-iterator => next}/.gitignore (88%)
rename packages/{ai-sdk => next}/README.md (86%)
rename packages/{react => next}/package.json (58%)
rename packages/{react => next}/src/deferred-interceptors.test.ts (100%)
rename packages/{react => next}/src/deferred-interceptors.ts (100%)
create mode 100644 packages/next/src/extensions/actionable.test-d.ts
create mode 100644 packages/next/src/extensions/actionable.test.ts
create mode 100644 packages/next/src/extensions/actionable.ts
create mode 100644 packages/next/src/hooks/index.test.ts
create mode 100644 packages/next/src/hooks/index.ts
create mode 100644 packages/next/src/hooks/optimistic-server-function.test-d.ts
rename packages/{react/src/hooks/optimistic-server-action.test.tsx => next/src/hooks/optimistic-server-function.test.tsx} (74%)
create mode 100644 packages/next/src/hooks/optimistic-server-function.ts
rename packages/{react/src/hooks/server-action.test-d.ts => next/src/hooks/server-function.test-d.ts} (69%)
rename packages/{react/src/hooks/server-action.test.tsx => next/src/hooks/server-function.test.tsx} (90%)
rename packages/{react/src/hooks/server-action.ts => next/src/hooks/server-function.ts} (55%)
create mode 100644 packages/next/src/index.test.ts
create mode 100644 packages/next/src/index.ts
create mode 100644 packages/next/src/server-form-function.test.ts
create mode 100644 packages/next/src/server-form-function.ts
create mode 100644 packages/next/src/server-form-functionable.test-d.ts
create mode 100644 packages/next/src/server-form-functionable.test.ts
create mode 100644 packages/next/src/server-form-functionable.ts
create mode 100644 packages/next/src/server-function.test-d.ts
create mode 100644 packages/next/src/server-function.test.ts
create mode 100644 packages/next/src/server-function.ts
create mode 100644 packages/next/src/server-functionable.test-d.ts
create mode 100644 packages/next/src/server-functionable.test.ts
create mode 100644 packages/next/src/server-functionable.ts
rename packages/{react => next}/tsconfig.json (77%)
delete mode 100644 packages/openapi-client/.gitignore
delete mode 100644 packages/openapi-client/package.json
delete mode 100644 packages/openapi-client/src/adapters/fetch/index.ts
delete mode 100644 packages/openapi-client/src/adapters/fetch/openapi-link.test.ts
delete mode 100644 packages/openapi-client/src/adapters/fetch/openapi-link.ts
delete mode 100644 packages/openapi-client/src/adapters/standard/bracket-notation.ts
delete mode 100644 packages/openapi-client/src/adapters/standard/index.ts
delete mode 100644 packages/openapi-client/src/adapters/standard/openapi-json-serializer.test.ts
delete mode 100644 packages/openapi-client/src/adapters/standard/openapi-json-serializer.ts
delete mode 100644 packages/openapi-client/src/adapters/standard/openapi-link-codec.test.ts
delete mode 100644 packages/openapi-client/src/adapters/standard/openapi-link-codec.ts
delete mode 100644 packages/openapi-client/src/adapters/standard/openapi-link.test.ts
delete mode 100644 packages/openapi-client/src/adapters/standard/openapi-link.ts
delete mode 100644 packages/openapi-client/src/adapters/standard/openapi-serializer.test.ts
delete mode 100644 packages/openapi-client/src/adapters/standard/openapi-serializer.ts
delete mode 100644 packages/openapi-client/src/adapters/standard/utils.test.ts
delete mode 100644 packages/openapi-client/src/adapters/standard/utils.ts
delete mode 100644 packages/openapi-client/src/helpers/index.test.ts
delete mode 100644 packages/openapi-client/src/helpers/index.ts
delete mode 100644 packages/openapi-client/src/index.ts
delete mode 100644 packages/openapi/src/adapters/aws-lambda/index.ts
delete mode 100644 packages/openapi/src/adapters/aws-lambda/openapi-handler.test.ts
delete mode 100644 packages/openapi/src/adapters/aws-lambda/openapi-handler.ts
delete mode 100644 packages/openapi/src/adapters/fastify/index.test.ts
delete mode 100644 packages/openapi/src/adapters/fastify/index.ts
delete mode 100644 packages/openapi/src/adapters/fastify/openapi-handler.test.ts
delete mode 100644 packages/openapi/src/adapters/fastify/openapi-handler.ts
create mode 100644 packages/openapi/src/adapters/fetch/index.test.ts
create mode 100644 packages/openapi/src/adapters/fetch/openapi-link.test.ts
create mode 100644 packages/openapi/src/adapters/fetch/openapi-link.ts
create mode 100644 packages/openapi/src/adapters/node/index.test.ts
create mode 100644 packages/openapi/src/adapters/standard/index.test.ts
delete mode 100644 packages/openapi/src/adapters/standard/openapi-codec.test.ts
delete mode 100644 packages/openapi/src/adapters/standard/openapi-codec.ts
create mode 100644 packages/openapi/src/adapters/standard/openapi-handler-codec.test.ts
create mode 100644 packages/openapi/src/adapters/standard/openapi-handler-codec.ts
delete mode 100644 packages/openapi/src/adapters/standard/openapi-handler.test.ts
delete mode 100644 packages/openapi/src/adapters/standard/openapi-handler.ts
create mode 100644 packages/openapi/src/adapters/standard/openapi-link-codec.test.ts
create mode 100644 packages/openapi/src/adapters/standard/openapi-link-codec.ts
delete mode 100644 packages/openapi/src/adapters/standard/utils.test.ts
delete mode 100644 packages/openapi/src/adapters/standard/utils.ts
rename packages/{openapi-client/src/adapters/standard => openapi/src}/bracket-notation.test.ts (70%)
create mode 100644 packages/openapi/src/bracket-notation.ts
create mode 100644 packages/openapi/src/caller.test-d.ts
create mode 100644 packages/openapi/src/caller.test.ts
create mode 100644 packages/openapi/src/caller.ts
create mode 100644 packages/openapi/src/constants.test.ts
create mode 100644 packages/openapi/src/constants.ts
create mode 100644 packages/openapi/src/extensions/route.test.ts
create mode 100644 packages/openapi/src/extensions/route.ts
rename packages/{openapi-client/src/adapters/standard/bracket-notation-utils.test.ts => openapi/src/helpers/form-data.test.ts} (97%)
rename packages/{openapi-client/src/adapters/standard/bracket-notation-utils.ts => openapi/src/helpers/form-data.ts} (85%)
create mode 100644 packages/openapi/src/helpers/index.test.ts
create mode 100644 packages/openapi/src/helpers/index.ts
create mode 100644 packages/openapi/src/index.test.ts
create mode 100644 packages/openapi/src/meta.test.ts
create mode 100644 packages/openapi/src/meta.ts
delete mode 100644 packages/openapi/src/openapi-custom.test.ts
delete mode 100644 packages/openapi/src/openapi-custom.ts
create mode 100644 packages/openapi/src/openapi-json-serializer.test.ts
create mode 100644 packages/openapi/src/openapi-json-serializer.ts
create mode 100644 packages/openapi/src/openapi-serializer.test.ts
create mode 100644 packages/openapi/src/openapi-serializer.ts
delete mode 100644 packages/openapi/src/openapi-utils.test.ts
delete mode 100644 packages/openapi/src/openapi-utils.ts
create mode 100644 packages/openapi/src/plugins/index.test.ts
delete mode 100644 packages/openapi/src/router-client.test.ts
delete mode 100644 packages/openapi/src/router-client.ts
delete mode 100644 packages/openapi/src/schema-converter.test.ts
delete mode 100644 packages/openapi/src/schema-converter.ts
delete mode 100644 packages/openapi/src/schema-utils.test.ts
delete mode 100644 packages/openapi/src/schema-utils.ts
delete mode 100644 packages/openapi/src/schema.ts
rename packages/{openapi-client => openapi}/src/types.test-d.ts (100%)
rename packages/{openapi-client => openapi}/src/types.ts (68%)
create mode 100644 packages/openapi/src/utils.test.ts
create mode 100644 packages/openapi/src/utils.ts
rename packages/{ai-sdk => opentelemetry}/.gitignore (100%)
rename packages/{openapi-client => opentelemetry}/README.md (85%)
rename packages/{otel => opentelemetry}/package.json (77%)
rename packages/{otel => opentelemetry}/src/index.ts (100%)
create mode 100644 packages/opentelemetry/src/instrumentation.test.ts
create mode 100644 packages/opentelemetry/src/instrumentation.ts
rename packages/{otel => opentelemetry}/tsconfig.json (85%)
delete mode 100644 packages/otel/README.md
delete mode 100644 packages/otel/build.config.ts
delete mode 100644 packages/otel/src/consts.ts
delete mode 100644 packages/otel/src/instrumentation.test.ts
delete mode 100644 packages/otel/src/instrumentation.ts
delete mode 100644 packages/publisher-durable-object/.gitignore
delete mode 100644 packages/publisher-durable-object/README.md
delete mode 100644 packages/publisher-durable-object/build.config.ts
delete mode 100644 packages/publisher-durable-object/package.json
delete mode 100644 packages/publisher-durable-object/src/durable-object.test.ts
delete mode 100644 packages/publisher-durable-object/src/durable-object.ts
delete mode 100644 packages/publisher-durable-object/src/durable-publisher.test.ts
delete mode 100644 packages/publisher-durable-object/src/durable-publisher.ts
delete mode 100644 packages/publisher-durable-object/src/index.test.ts
delete mode 100644 packages/publisher-durable-object/src/index.ts
delete mode 100644 packages/publisher-durable-object/src/resume-storage.test.ts
delete mode 100644 packages/publisher-durable-object/src/resume-storage.ts
delete mode 100644 packages/publisher-durable-object/src/types.ts
delete mode 100644 packages/publisher-durable-object/tests/shared.ts
delete mode 100644 packages/publisher-durable-object/tsconfig.json
delete mode 100644 packages/publisher-durable-object/tsconfig.test.json
delete mode 100644 packages/publisher/src/adapters/ioredis.test.ts
delete mode 100644 packages/publisher/src/adapters/ioredis.ts
create mode 100644 packages/publisher/src/adapters/redis.test.ts
create mode 100644 packages/publisher/src/adapters/redis.ts
delete mode 100644 packages/publisher/src/adapters/upstash-redis.test.ts
delete mode 100644 packages/publisher/src/adapters/upstash-redis.ts
create mode 100644 packages/publisher/src/adapters/upstash.test.ts
create mode 100644 packages/publisher/src/adapters/upstash.ts
create mode 100644 packages/publisher/tests/redis-adapters.test.ts
delete mode 100644 packages/ratelimit/src/adapters/cloudflare-ratelimit.test.ts
delete mode 100644 packages/ratelimit/src/adapters/cloudflare-ratelimit.ts
delete mode 100644 packages/ratelimit/src/adapters/upstash-ratelimit.test.ts
delete mode 100644 packages/ratelimit/src/adapters/upstash-ratelimit.ts
create mode 100644 packages/ratelimit/src/adapters/upstash.test.ts
create mode 100644 packages/ratelimit/src/adapters/upstash.ts
delete mode 100644 packages/react-query/.gitignore
delete mode 100644 packages/react-query/README.md
delete mode 100644 packages/react-query/package.json
delete mode 100644 packages/react-query/src/general-utils.test-d.ts
delete mode 100644 packages/react-query/src/general-utils.test.ts
delete mode 100644 packages/react-query/src/general-utils.ts
delete mode 100644 packages/react-query/src/index.ts
delete mode 100644 packages/react-query/src/procedure-utils.test-d.ts
delete mode 100644 packages/react-query/src/procedure-utils.test.ts
delete mode 100644 packages/react-query/src/procedure-utils.ts
delete mode 100644 packages/react-query/src/router-utils.test-d.ts
delete mode 100644 packages/react-query/src/router-utils.test.ts
delete mode 100644 packages/react-query/src/router-utils.ts
delete mode 100644 packages/react-query/src/types.ts
delete mode 100644 packages/react-query/tests/e2e.test-d.ts
delete mode 100644 packages/react-query/tests/e2e.test.tsx
delete mode 100644 packages/react-query/tests/shared.tsx
delete mode 100644 packages/react-query/tsconfig.json
delete mode 100644 packages/react-swr/.gitignore
delete mode 100644 packages/react-swr/README.md
delete mode 100644 packages/react-swr/package.json
delete mode 100644 packages/react-swr/src/general-utils.test-d.ts
delete mode 100644 packages/react-swr/src/general-utils.test.ts
delete mode 100644 packages/react-swr/src/general-utils.ts
delete mode 100644 packages/react-swr/src/index.test.ts
delete mode 100644 packages/react-swr/src/index.ts
delete mode 100644 packages/react-swr/src/procedure-utils.test-d.ts
delete mode 100644 packages/react-swr/src/procedure-utils.test.ts
delete mode 100644 packages/react-swr/src/procedure-utils.ts
delete mode 100644 packages/react-swr/src/router-utils.test-d.ts
delete mode 100644 packages/react-swr/src/router-utils.test.ts
delete mode 100644 packages/react-swr/src/router-utils.ts
delete mode 100644 packages/react-swr/src/types.ts
delete mode 100644 packages/react-swr/src/utils.test.ts
delete mode 100644 packages/react-swr/src/utils.ts
delete mode 100644 packages/react-swr/tests/e2e.test-d.tsx
delete mode 100644 packages/react-swr/tests/e2e.test.tsx
delete mode 100644 packages/react-swr/tests/shared.tsx
delete mode 100644 packages/react-swr/tsconfig.json
delete mode 100644 packages/react/.gitignore
delete mode 100644 packages/react/README.md
delete mode 100644 packages/react/src/action-form.test.ts
delete mode 100644 packages/react/src/action-form.ts
delete mode 100644 packages/react/src/hooks/index.ts
delete mode 100644 packages/react/src/hooks/optimistic-server-action.test-d.ts
delete mode 100644 packages/react/src/hooks/optimistic-server-action.ts
delete mode 100644 packages/react/src/index.ts
delete mode 100644 packages/server/src/adapters/aws-lambda/handler.ts
delete mode 100644 packages/server/src/adapters/aws-lambda/index.ts
delete mode 100644 packages/server/src/adapters/aws-lambda/rpc-handler.test.ts
delete mode 100644 packages/server/src/adapters/aws-lambda/rpc-handler.ts
delete mode 100644 packages/server/src/adapters/bun-ws/handler.ts
delete mode 100644 packages/server/src/adapters/bun-ws/index.ts
delete mode 100644 packages/server/src/adapters/bun-ws/rpc-handler.test.ts
delete mode 100644 packages/server/src/adapters/bun-ws/rpc-handler.ts
create mode 100644 packages/server/src/adapters/crossws/index.test.ts
delete mode 100644 packages/server/src/adapters/fastify/handler.test-d.ts
delete mode 100644 packages/server/src/adapters/fastify/handler.test.ts
delete mode 100644 packages/server/src/adapters/fastify/handler.ts
delete mode 100644 packages/server/src/adapters/fastify/index.test.ts
delete mode 100644 packages/server/src/adapters/fastify/index.ts
delete mode 100644 packages/server/src/adapters/fastify/rpc-handler.test.ts
delete mode 100644 packages/server/src/adapters/fastify/rpc-handler.ts
create mode 100644 packages/server/src/adapters/fetch/body-compression-plugin.test.ts
create mode 100644 packages/server/src/adapters/fetch/body-compression-plugin.ts
delete mode 100644 packages/server/src/adapters/fetch/compression-plugin.test.ts
delete mode 100644 packages/server/src/adapters/fetch/compression-plugin.ts
delete mode 100644 packages/server/src/adapters/fetch/handler.test-d.ts
delete mode 100644 packages/server/src/adapters/fetch/handler.test.ts
create mode 100644 packages/server/src/adapters/fetch/index.test.ts
delete mode 100644 packages/server/src/adapters/fetch/plugin.test-d.ts
create mode 100644 packages/server/src/adapters/message-port/index.test.ts
create mode 100644 packages/server/src/adapters/node/body-compression-plugin.test.ts
create mode 100644 packages/server/src/adapters/node/body-compression-plugin.ts
delete mode 100644 packages/server/src/adapters/node/compression-plugin.test.ts
delete mode 100644 packages/server/src/adapters/node/compression-plugin.ts
delete mode 100644 packages/server/src/adapters/node/handler.test-d.ts
delete mode 100644 packages/server/src/adapters/node/handler.test.ts
create mode 100644 packages/server/src/adapters/node/index.test.ts
delete mode 100644 packages/server/src/adapters/node/plugin.test-d.ts
create mode 100644 packages/server/src/adapters/standard-peer/index.test.ts
create mode 100644 packages/server/src/adapters/standard/codec.ts
create mode 100644 packages/server/src/adapters/standard/index.test.ts
delete mode 100644 packages/server/src/adapters/standard/rpc-codec.test.ts
delete mode 100644 packages/server/src/adapters/standard/rpc-codec.ts
create mode 100644 packages/server/src/adapters/standard/rpc-handler-codec.test.ts
create mode 100644 packages/server/src/adapters/standard/rpc-handler-codec.ts
delete mode 100644 packages/server/src/adapters/standard/rpc-handler.test.ts
delete mode 100644 packages/server/src/adapters/standard/rpc-handler.ts
delete mode 100644 packages/server/src/adapters/standard/types.ts
delete mode 100644 packages/server/src/adapters/standard/utils.test-d.ts
create mode 100644 packages/server/src/adapters/websocket/index.test.ts
delete mode 100644 packages/server/src/adapters/ws/handler.ts
delete mode 100644 packages/server/src/adapters/ws/index.ts
delete mode 100644 packages/server/src/adapters/ws/rpc-handler.test.ts
delete mode 100644 packages/server/src/adapters/ws/rpc-handler.ts
delete mode 100644 packages/server/src/config.test.ts
delete mode 100644 packages/server/src/config.ts
create mode 100644 packages/server/src/constants.test.ts
create mode 100644 packages/server/src/constants.ts
delete mode 100644 packages/server/src/context.test.ts
create mode 100644 packages/server/src/extensions/callable.test-d.ts
create mode 100644 packages/server/src/extensions/callable.test.ts
create mode 100644 packages/server/src/extensions/callable.ts
create mode 100644 packages/server/src/helpers/index.test.ts
delete mode 100644 packages/server/src/hibernation/event-iterator.test.ts
delete mode 100644 packages/server/src/hibernation/event-iterator.ts
delete mode 100644 packages/server/src/hibernation/index.ts
delete mode 100644 packages/server/src/hibernation/plugin.test.ts
delete mode 100644 packages/server/src/hibernation/plugin.ts
create mode 100644 packages/server/src/implementer-procedure.test.ts
create mode 100644 packages/server/src/implementer-router.test-d.ts
create mode 100644 packages/server/src/implementer-router.test.ts
create mode 100644 packages/server/src/implementer-router.ts
delete mode 100644 packages/server/src/implementer-variants.test-d.ts
delete mode 100644 packages/server/src/implementer-variants.ts
create mode 100644 packages/server/src/index.test.ts
delete mode 100644 packages/server/src/link-utils.test-d.ts
delete mode 100644 packages/server/src/link-utils.test.ts
delete mode 100644 packages/server/src/link-utils.ts
delete mode 100644 packages/server/src/middleware-utils.test.ts
delete mode 100644 packages/server/src/middleware-utils.ts
create mode 100644 packages/server/src/plugins/csrf-guard.test.ts
create mode 100644 packages/server/src/plugins/csrf-guard.ts
create mode 100644 packages/server/src/plugins/index.test.ts
delete mode 100644 packages/server/src/plugins/rethrow.test.ts
delete mode 100644 packages/server/src/plugins/rethrow.ts
delete mode 100644 packages/server/src/plugins/simple-csrf-protection.test.ts
delete mode 100644 packages/server/src/plugins/simple-csrf-protection.ts
delete mode 100644 packages/server/src/plugins/strict-get-method.test.ts
delete mode 100644 packages/server/src/plugins/strict-get-method.ts
delete mode 100644 packages/server/src/procedure-action.test-d.ts
delete mode 100644 packages/server/src/procedure-action.test.ts
delete mode 100644 packages/server/src/procedure-action.ts
delete mode 100644 packages/server/src/procedure.test-d.ts
delete mode 100644 packages/server/tests/advanced.test.ts
delete mode 100644 packages/server/tests/message-port.test.ts
delete mode 100644 packages/server/tests/shared.ts
delete mode 100644 packages/shared/src/chain.ts
create mode 100644 packages/shared/src/compare.test.ts
create mode 100644 packages/shared/src/compare.ts
delete mode 100644 packages/shared/src/event-publisher.test-d.ts
delete mode 100644 packages/shared/src/event-publisher.test.ts
delete mode 100644 packages/shared/src/event-publisher.ts
create mode 100644 packages/shared/src/http.test.ts
create mode 100644 packages/shared/src/http.ts
create mode 100644 packages/shared/src/index.test.ts
delete mode 100644 packages/shared/src/json.test-d.ts
delete mode 100644 packages/shared/src/json.test.ts
delete mode 100644 packages/shared/src/json.ts
create mode 100644 packages/shared/src/opentelemetry.test.ts
create mode 100644 packages/shared/src/opentelemetry.ts
delete mode 100644 packages/shared/src/otel.test.ts
delete mode 100644 packages/shared/src/otel.ts
create mode 100644 packages/shared/src/plugin.test.ts
create mode 100644 packages/shared/src/plugin.ts
create mode 100644 packages/shared/src/promise.test.ts
create mode 100644 packages/shared/src/promise.ts
create mode 100644 packages/shared/src/signal.test.ts
create mode 100644 packages/shared/src/signal.ts
delete mode 100644 packages/solid-query/.gitignore
delete mode 100644 packages/solid-query/README.md
delete mode 100644 packages/solid-query/package.json
delete mode 100644 packages/solid-query/src/general-utils.test-d.ts
delete mode 100644 packages/solid-query/src/general-utils.test.ts
delete mode 100644 packages/solid-query/src/general-utils.ts
delete mode 100644 packages/solid-query/src/index.ts
delete mode 100644 packages/solid-query/src/procedure-utils.test-d.ts
delete mode 100644 packages/solid-query/src/procedure-utils.test.ts
delete mode 100644 packages/solid-query/src/procedure-utils.ts
delete mode 100644 packages/solid-query/src/router-utils.test-d.ts
delete mode 100644 packages/solid-query/src/router-utils.test.ts
delete mode 100644 packages/solid-query/src/router-utils.ts
delete mode 100644 packages/solid-query/src/types.ts
delete mode 100644 packages/solid-query/tests/e2e.test-d.ts
delete mode 100644 packages/solid-query/tests/e2e.test.tsx
delete mode 100644 packages/solid-query/tests/shared.tsx
delete mode 100644 packages/solid-query/tsconfig.json
delete mode 100644 packages/standard-server-aws-lambda/.gitignore
delete mode 100644 packages/standard-server-aws-lambda/README.md
delete mode 100644 packages/standard-server-aws-lambda/package.json
delete mode 100644 packages/standard-server-aws-lambda/src/body.test.ts
delete mode 100644 packages/standard-server-aws-lambda/src/body.ts
delete mode 100644 packages/standard-server-aws-lambda/src/event-iterator.test.ts
delete mode 100644 packages/standard-server-aws-lambda/src/event-iterator.ts
delete mode 100644 packages/standard-server-aws-lambda/src/headers.test.ts
delete mode 100644 packages/standard-server-aws-lambda/src/headers.ts
delete mode 100644 packages/standard-server-aws-lambda/src/index.ts
delete mode 100644 packages/standard-server-aws-lambda/src/request.test.ts
delete mode 100644 packages/standard-server-aws-lambda/src/request.ts
delete mode 100644 packages/standard-server-aws-lambda/src/response.test.ts
delete mode 100644 packages/standard-server-aws-lambda/src/response.ts
delete mode 100644 packages/standard-server-aws-lambda/src/types.test-d.ts
delete mode 100644 packages/standard-server-aws-lambda/src/types.ts
delete mode 100644 packages/standard-server-aws-lambda/src/url.test.ts
delete mode 100644 packages/standard-server-aws-lambda/src/url.ts
delete mode 100644 packages/standard-server-aws-lambda/tsconfig.json
delete mode 100644 packages/standard-server-fastify/.gitignore
delete mode 100644 packages/standard-server-fastify/README.md
delete mode 100644 packages/standard-server-fastify/package.json
delete mode 100644 packages/standard-server-fastify/src/index.test.ts
delete mode 100644 packages/standard-server-fastify/src/index.ts
delete mode 100644 packages/standard-server-fastify/src/request.test.ts
delete mode 100644 packages/standard-server-fastify/src/request.ts
delete mode 100644 packages/standard-server-fastify/src/response.test.ts
delete mode 100644 packages/standard-server-fastify/src/response.ts
delete mode 100644 packages/standard-server-fastify/tsconfig.json
delete mode 100644 packages/standard-server-fetch/.gitignore
delete mode 100644 packages/standard-server-fetch/README.md
delete mode 100644 packages/standard-server-fetch/package.json
delete mode 100644 packages/standard-server-fetch/playground/event-source-client.ts
delete mode 100644 packages/standard-server-fetch/playground/event-source.http
delete mode 100644 packages/standard-server-fetch/playground/event-source.ts
delete mode 100644 packages/standard-server-fetch/src/body.test.ts
delete mode 100644 packages/standard-server-fetch/src/body.ts
delete mode 100644 packages/standard-server-fetch/src/event-iterator.test.ts
delete mode 100644 packages/standard-server-fetch/src/event-iterator.ts
delete mode 100644 packages/standard-server-fetch/src/headers.test.ts
delete mode 100644 packages/standard-server-fetch/src/headers.ts
delete mode 100644 packages/standard-server-fetch/src/index.ts
delete mode 100644 packages/standard-server-fetch/src/request.test.ts
delete mode 100644 packages/standard-server-fetch/src/request.ts
delete mode 100644 packages/standard-server-fetch/src/response.test.ts
delete mode 100644 packages/standard-server-fetch/src/response.ts
delete mode 100644 packages/standard-server-fetch/tsconfig.json
delete mode 100644 packages/standard-server-node/.gitignore
delete mode 100644 packages/standard-server-node/README.md
delete mode 100644 packages/standard-server-node/package.json
delete mode 100644 packages/standard-server-node/playground/event-source.ts
delete mode 100644 packages/standard-server-node/src/body.test.ts
delete mode 100644 packages/standard-server-node/src/body.ts
delete mode 100644 packages/standard-server-node/src/event-iterator.test.ts
delete mode 100644 packages/standard-server-node/src/event-iterator.ts
delete mode 100644 packages/standard-server-node/src/headers.test.ts
delete mode 100644 packages/standard-server-node/src/headers.ts
delete mode 100644 packages/standard-server-node/src/index.ts
delete mode 100644 packages/standard-server-node/src/method.test.ts
delete mode 100644 packages/standard-server-node/src/method.ts
delete mode 100644 packages/standard-server-node/src/request.test.ts
delete mode 100644 packages/standard-server-node/src/request.ts
delete mode 100644 packages/standard-server-node/src/response.test.ts
delete mode 100644 packages/standard-server-node/src/response.ts
delete mode 100644 packages/standard-server-node/src/signal.test.ts
delete mode 100644 packages/standard-server-node/src/signal.ts
delete mode 100644 packages/standard-server-node/src/types.ts
delete mode 100644 packages/standard-server-node/src/url.test.ts
delete mode 100644 packages/standard-server-node/src/url.ts
delete mode 100644 packages/standard-server-node/tsconfig.json
delete mode 100644 packages/standard-server-peer/.gitignore
delete mode 100644 packages/standard-server-peer/README.md
delete mode 100644 packages/standard-server-peer/package.json
delete mode 100644 packages/standard-server-peer/src/client.test.ts
delete mode 100644 packages/standard-server-peer/src/client.ts
delete mode 100644 packages/standard-server-peer/src/codec.test.ts
delete mode 100644 packages/standard-server-peer/src/codec.ts
delete mode 100644 packages/standard-server-peer/src/event-iterator.test.ts
delete mode 100644 packages/standard-server-peer/src/event-iterator.ts
delete mode 100644 packages/standard-server-peer/src/index.ts
delete mode 100644 packages/standard-server-peer/src/server.test.ts
delete mode 100644 packages/standard-server-peer/src/server.ts
delete mode 100644 packages/standard-server-peer/src/types.ts
delete mode 100644 packages/standard-server-peer/tests/e2e.test.ts
delete mode 100644 packages/standard-server-peer/tsconfig.json
delete mode 100644 packages/standard-server/.gitignore
delete mode 100644 packages/standard-server/README.md
delete mode 100644 packages/standard-server/package.json
delete mode 100644 packages/standard-server/src/batch/index.ts
delete mode 100644 packages/standard-server/src/batch/request.test.ts
delete mode 100644 packages/standard-server/src/batch/request.ts
delete mode 100644 packages/standard-server/src/batch/response.test.ts
delete mode 100644 packages/standard-server/src/batch/response.ts
delete mode 100644 packages/standard-server/src/batch/signal.test.ts
delete mode 100644 packages/standard-server/src/batch/signal.ts
delete mode 100644 packages/standard-server/src/event-iterator/decoder.test.ts
delete mode 100644 packages/standard-server/src/event-iterator/decoder.ts
delete mode 100644 packages/standard-server/src/event-iterator/encoder.test.ts
delete mode 100644 packages/standard-server/src/event-iterator/encoder.ts
delete mode 100644 packages/standard-server/src/event-iterator/errors.ts
delete mode 100644 packages/standard-server/src/event-iterator/index.ts
delete mode 100644 packages/standard-server/src/event-iterator/meta.test.ts
delete mode 100644 packages/standard-server/src/event-iterator/meta.ts
delete mode 100644 packages/standard-server/src/event-iterator/types.ts
delete mode 100644 packages/standard-server/src/hibernation.test.ts
delete mode 100644 packages/standard-server/src/hibernation.ts
delete mode 100644 packages/standard-server/src/index.ts
delete mode 100644 packages/standard-server/src/types.ts
delete mode 100644 packages/standard-server/src/utils.test.ts
delete mode 100644 packages/standard-server/src/utils.ts
delete mode 100644 packages/standard-server/tsconfig.json
delete mode 100644 packages/svelte-query/.gitignore
delete mode 100644 packages/svelte-query/README.md
delete mode 100644 packages/svelte-query/src/general-utils.test-d.ts
delete mode 100644 packages/svelte-query/src/general-utils.test.ts
delete mode 100644 packages/svelte-query/src/general-utils.ts
delete mode 100644 packages/svelte-query/src/index.ts
delete mode 100644 packages/svelte-query/src/procedure-utils.test-d.ts
delete mode 100644 packages/svelte-query/src/procedure-utils.test.tsx
delete mode 100644 packages/svelte-query/src/procedure-utils.ts
delete mode 100644 packages/svelte-query/src/router-utils.test-d.ts
delete mode 100644 packages/svelte-query/src/router-utils.test.tsx
delete mode 100644 packages/svelte-query/src/router-utils.ts
delete mode 100644 packages/svelte-query/src/types.ts
delete mode 100644 packages/svelte-query/tests/e2e.test-d.ts
delete mode 100644 packages/svelte-query/tests/e2e.test.tsx
delete mode 100644 packages/svelte-query/tests/shared.tsx
delete mode 100644 packages/svelte-query/tsconfig.json
create mode 100644 packages/tanstack-query/src/contract-utils.test-d.ts
create mode 100644 packages/tanstack-query/src/contract-utils.test.ts
create mode 100644 packages/tanstack-query/src/contract-utils.ts
delete mode 100644 packages/tanstack-query/src/general-utils.test-d.ts
delete mode 100644 packages/tanstack-query/src/general-utils.test.ts
delete mode 100644 packages/tanstack-query/src/general-utils.ts
create mode 100644 packages/tanstack-query/src/plugin.test.ts
create mode 100644 packages/tanstack-query/src/plugin.ts
create mode 100644 packages/tanstack-query/tests/__shared__/orpc.tsx
delete mode 100644 packages/tanstack-query/tests/live-query.test.tsx
delete mode 100644 packages/tanstack-query/tests/shared.tsx
delete mode 100644 packages/trpc/.gitignore
delete mode 100644 packages/trpc/package.json
delete mode 100644 packages/trpc/src/index.ts
delete mode 100644 packages/trpc/src/to-orpc-router.test-d.ts
delete mode 100644 packages/trpc/src/to-orpc-router.test.ts
delete mode 100644 packages/trpc/src/to-orpc-router.ts
delete mode 100644 packages/trpc/tests/shared.ts
create mode 100644 packages/valibot/src/index.test.ts
delete mode 100644 packages/vue-colada/.gitignore
delete mode 100644 packages/vue-colada/README.md
delete mode 100644 packages/vue-colada/package.json
delete mode 100644 packages/vue-colada/src/general-utils.test-d.ts
delete mode 100644 packages/vue-colada/src/general-utils.test.ts
delete mode 100644 packages/vue-colada/src/general-utils.ts
delete mode 100644 packages/vue-colada/src/index.ts
delete mode 100644 packages/vue-colada/src/key.test.ts
delete mode 100644 packages/vue-colada/src/key.ts
delete mode 100644 packages/vue-colada/src/procedure-utils.test-d.ts
delete mode 100644 packages/vue-colada/src/procedure-utils.test.ts
delete mode 100644 packages/vue-colada/src/procedure-utils.ts
delete mode 100644 packages/vue-colada/src/router-utils.test-d.ts
delete mode 100644 packages/vue-colada/src/router-utils.test.ts
delete mode 100644 packages/vue-colada/src/router-utils.ts
delete mode 100644 packages/vue-colada/src/types.ts
delete mode 100644 packages/vue-colada/tests/e2e.test-d.ts
delete mode 100644 packages/vue-colada/tests/e2e.test.tsx
delete mode 100644 packages/vue-colada/tests/shared.tsx
delete mode 100644 packages/vue-colada/tsconfig.json
delete mode 100644 packages/vue-query/.gitignore
delete mode 100644 packages/vue-query/README.md
delete mode 100644 packages/vue-query/package.json
delete mode 100644 packages/vue-query/src/general-utils.test-d.ts
delete mode 100644 packages/vue-query/src/general-utils.test.ts
delete mode 100644 packages/vue-query/src/general-utils.ts
delete mode 100644 packages/vue-query/src/index.ts
delete mode 100644 packages/vue-query/src/procedure-utils.test-d.ts
delete mode 100644 packages/vue-query/src/procedure-utils.test.ts
delete mode 100644 packages/vue-query/src/procedure-utils.ts
delete mode 100644 packages/vue-query/src/router-utils.test-d.ts
delete mode 100644 packages/vue-query/src/router-utils.test.ts
delete mode 100644 packages/vue-query/src/router-utils.ts
delete mode 100644 packages/vue-query/src/types.test-d.ts
delete mode 100644 packages/vue-query/src/types.ts
delete mode 100644 packages/vue-query/src/utils.test-d.ts
delete mode 100644 packages/vue-query/src/utils.test.ts
delete mode 100644 packages/vue-query/src/utils.ts
delete mode 100644 packages/vue-query/tests/e2e.test-d.ts
delete mode 100644 packages/vue-query/tests/e2e.test.tsx
delete mode 100644 packages/vue-query/tests/shared.tsx
delete mode 100644 packages/vue-query/tsconfig.json
delete mode 100644 packages/zod/src/coercer.test.ts
delete mode 100644 packages/zod/src/coercer.ts
delete mode 100644 packages/zod/src/converter.components.test.ts
delete mode 100644 packages/zod/src/custom-json-schema.test-d.ts
delete mode 100644 packages/zod/src/custom-json-schema.test.ts
delete mode 100644 packages/zod/src/custom-json-schema.ts
create mode 100644 packages/zod/src/index.test.ts
delete mode 100644 packages/zod/src/schemas/base.ts
delete mode 100644 packages/zod/src/schemas/blob.test.ts
delete mode 100644 packages/zod/src/schemas/blob.ts
delete mode 100644 packages/zod/src/schemas/file.test.ts
delete mode 100644 packages/zod/src/schemas/file.ts
delete mode 100644 packages/zod/src/schemas/regexp.test.ts
delete mode 100644 packages/zod/src/schemas/regexp.ts
delete mode 100644 packages/zod/src/schemas/url.test.ts
delete mode 100644 packages/zod/src/schemas/url.ts
delete mode 100644 packages/zod/src/zod4/coercer.combination.test.ts
delete mode 100644 packages/zod/src/zod4/coercer.native.test.ts
delete mode 100644 packages/zod/src/zod4/coercer.rest.test.ts
delete mode 100644 packages/zod/src/zod4/coercer.structure.test.ts
delete mode 100644 packages/zod/src/zod4/coercer.test.ts
delete mode 100644 packages/zod/src/zod4/coercer.ts
delete mode 100644 packages/zod/src/zod4/converter.combination.test.ts
delete mode 100644 packages/zod/src/zod4/converter.components.test.ts
delete mode 100644 packages/zod/src/zod4/converter.meta.test.ts
delete mode 100644 packages/zod/src/zod4/converter.native.test.ts
delete mode 100644 packages/zod/src/zod4/converter.number.test.ts
delete mode 100644 packages/zod/src/zod4/converter.processed.test.ts
delete mode 100644 packages/zod/src/zod4/converter.rest.test.ts
delete mode 100644 packages/zod/src/zod4/converter.string.test.ts
delete mode 100644 packages/zod/src/zod4/converter.structure.test.ts
delete mode 100644 packages/zod/src/zod4/converter.test.ts
delete mode 100644 packages/zod/src/zod4/converter.ts
delete mode 100644 packages/zod/src/zod4/index.ts
delete mode 100644 packages/zod/src/zod4/registries.ts
delete mode 100644 packages/zod/tests/shared.ts
delete mode 100644 playgrounds/astro/.gitignore
delete mode 100644 playgrounds/astro/.vscode/settings.json
delete mode 100644 playgrounds/astro/README.md
delete mode 100644 playgrounds/astro/astro.config.mjs
delete mode 100644 playgrounds/astro/package.json
delete mode 100644 playgrounds/astro/src/components/orpc-mutation.tsx
delete mode 100644 playgrounds/astro/src/components/orpc-query.tsx
delete mode 100644 playgrounds/astro/src/components/orpc-stream.tsx
delete mode 100644 playgrounds/astro/src/lib/orpc.ts
delete mode 100644 playgrounds/astro/src/middlewares/auth.ts
delete mode 100644 playgrounds/astro/src/middlewares/db.ts
delete mode 100644 playgrounds/astro/src/middlewares/retry.ts
delete mode 100644 playgrounds/astro/src/orpc.ts
delete mode 100644 playgrounds/astro/src/pages/api/[...rest].ts
delete mode 100644 playgrounds/astro/src/pages/index.astro
delete mode 100644 playgrounds/astro/src/pages/rpc/[...rest].ts
delete mode 100644 playgrounds/astro/src/playground-client.ts
delete mode 100644 playgrounds/astro/src/playground-tanstack-query.ts
delete mode 100644 playgrounds/astro/src/polyfill.ts
delete mode 100644 playgrounds/astro/src/routers/auth.ts
delete mode 100644 playgrounds/astro/src/routers/index.ts
delete mode 100644 playgrounds/astro/src/routers/planet.ts
delete mode 100644 playgrounds/astro/src/routers/sse.ts
delete mode 100644 playgrounds/astro/src/schemas/auth.ts
delete mode 100644 playgrounds/astro/src/schemas/planet.ts
delete mode 100644 playgrounds/astro/src/schemas/user.ts
delete mode 100644 playgrounds/astro/src/shared/query.ts
delete mode 100644 playgrounds/astro/tsconfig.json
delete mode 100644 playgrounds/browser-extension/.gitignore
delete mode 100644 playgrounds/browser-extension/.vscode/settings.json
delete mode 100644 playgrounds/browser-extension/README.md
delete mode 100644 playgrounds/browser-extension/entrypoints/background/index.ts
delete mode 100644 playgrounds/browser-extension/entrypoints/background/middlewares/auth.ts
delete mode 100644 playgrounds/browser-extension/entrypoints/background/middlewares/db.ts
delete mode 100644 playgrounds/browser-extension/entrypoints/background/middlewares/retry.ts
delete mode 100644 playgrounds/browser-extension/entrypoints/background/orpc.ts
delete mode 100644 playgrounds/browser-extension/entrypoints/background/routers/auth.ts
delete mode 100644 playgrounds/browser-extension/entrypoints/background/routers/index.ts
delete mode 100644 playgrounds/browser-extension/entrypoints/background/routers/planet.ts
delete mode 100644 playgrounds/browser-extension/entrypoints/background/routers/sse.ts
delete mode 100644 playgrounds/browser-extension/entrypoints/background/schemas/auth.ts
delete mode 100644 playgrounds/browser-extension/entrypoints/background/schemas/planet.ts
delete mode 100644 playgrounds/browser-extension/entrypoints/background/schemas/user.ts
delete mode 100644 playgrounds/browser-extension/entrypoints/content.ts
delete mode 100644 playgrounds/browser-extension/entrypoints/popup/App.tsx
delete mode 100644 playgrounds/browser-extension/entrypoints/popup/components/orpc-mutation.tsx
delete mode 100644 playgrounds/browser-extension/entrypoints/popup/components/orpc-query.tsx
delete mode 100644 playgrounds/browser-extension/entrypoints/popup/components/orpc-stream.tsx
delete mode 100644 playgrounds/browser-extension/entrypoints/popup/index.html
delete mode 100644 playgrounds/browser-extension/entrypoints/popup/lib/orpc.ts
delete mode 100644 playgrounds/browser-extension/entrypoints/popup/main.tsx
delete mode 100644 playgrounds/browser-extension/entrypoints/popup/playground-client.ts
delete mode 100644 playgrounds/browser-extension/entrypoints/popup/playground-tanstac-query.ts
delete mode 100644 playgrounds/browser-extension/package.json
delete mode 100644 playgrounds/browser-extension/public/icon/128.png
delete mode 100644 playgrounds/browser-extension/public/icon/16.png
delete mode 100644 playgrounds/browser-extension/public/icon/32.png
delete mode 100644 playgrounds/browser-extension/public/icon/48.png
delete mode 100644 playgrounds/browser-extension/public/icon/96.png
delete mode 100644 playgrounds/browser-extension/public/wxt.svg
delete mode 100644 playgrounds/browser-extension/tsconfig.json
delete mode 100644 playgrounds/browser-extension/wxt.config.ts
delete mode 100644 playgrounds/bun-websocket-otel/.gitignore
delete mode 100644 playgrounds/bun-websocket-otel/README.md
delete mode 100644 playgrounds/bun-websocket-otel/bun-env.d.ts
delete mode 100644 playgrounds/bun-websocket-otel/package.json
delete mode 100644 playgrounds/bun-websocket-otel/src/App.tsx
delete mode 100644 playgrounds/bun-websocket-otel/src/components/orpc-mutation.tsx
delete mode 100644 playgrounds/bun-websocket-otel/src/components/orpc-query.tsx
delete mode 100644 playgrounds/bun-websocket-otel/src/components/orpc-sse.tsx
delete mode 100644 playgrounds/bun-websocket-otel/src/consts.ts
delete mode 100644 playgrounds/bun-websocket-otel/src/frontend.tsx
delete mode 100644 playgrounds/bun-websocket-otel/src/index.html
delete mode 100644 playgrounds/bun-websocket-otel/src/index.tsx
delete mode 100644 playgrounds/bun-websocket-otel/src/instrumentation-client.ts
delete mode 100644 playgrounds/bun-websocket-otel/src/instrumentation.ts
delete mode 100644 playgrounds/bun-websocket-otel/src/lib/orpc.ts
delete mode 100644 playgrounds/bun-websocket-otel/src/middlewares/auth.ts
delete mode 100644 playgrounds/bun-websocket-otel/src/middlewares/db.ts
delete mode 100644 playgrounds/bun-websocket-otel/src/middlewares/retry.ts
delete mode 100644 playgrounds/bun-websocket-otel/src/orpc.ts
delete mode 100644 playgrounds/bun-websocket-otel/src/playground-client.ts
delete mode 100644 playgrounds/bun-websocket-otel/src/playground-tanstack-query.ts
delete mode 100644 playgrounds/bun-websocket-otel/src/routers/auth.ts
delete mode 100644 playgrounds/bun-websocket-otel/src/routers/index.ts
delete mode 100644 playgrounds/bun-websocket-otel/src/routers/planet.ts
delete mode 100644 playgrounds/bun-websocket-otel/src/routers/sse.ts
delete mode 100644 playgrounds/bun-websocket-otel/src/schemas/auth.ts
delete mode 100644 playgrounds/bun-websocket-otel/src/schemas/planet.ts
delete mode 100644 playgrounds/bun-websocket-otel/src/schemas/user.ts
delete mode 100644 playgrounds/bun-websocket-otel/tsconfig.json
delete mode 100644 playgrounds/cloudflare-worker/.gitignore
delete mode 100644 playgrounds/cloudflare-worker/.vscode/settings.json
delete mode 100644 playgrounds/cloudflare-worker/README.md
delete mode 100644 playgrounds/cloudflare-worker/index.html
delete mode 100644 playgrounds/cloudflare-worker/package.json
delete mode 100644 playgrounds/cloudflare-worker/src/App.tsx
delete mode 100644 playgrounds/cloudflare-worker/src/components/chat-room-v2.tsx
delete mode 100644 playgrounds/cloudflare-worker/src/components/chat-room.tsx
delete mode 100644 playgrounds/cloudflare-worker/src/components/orpc-mutation.tsx
delete mode 100644 playgrounds/cloudflare-worker/src/components/orpc-query.tsx
delete mode 100644 playgrounds/cloudflare-worker/src/components/orpc-stream.tsx
delete mode 100644 playgrounds/cloudflare-worker/src/lib/orpc.ts
delete mode 100644 playgrounds/cloudflare-worker/src/main.tsx
delete mode 100644 playgrounds/cloudflare-worker/src/vite-env.d.ts
delete mode 100644 playgrounds/cloudflare-worker/tsconfig.json
delete mode 100644 playgrounds/cloudflare-worker/vite.config.ts
delete mode 100644 playgrounds/cloudflare-worker/worker-configuration.d.ts
delete mode 100644 playgrounds/cloudflare-worker/worker/dos/chat-room.ts
delete mode 100644 playgrounds/cloudflare-worker/worker/dos/publisher.ts
delete mode 100644 playgrounds/cloudflare-worker/worker/index.ts
delete mode 100644 playgrounds/cloudflare-worker/worker/middlewares/auth.ts
delete mode 100644 playgrounds/cloudflare-worker/worker/middlewares/db.ts
delete mode 100644 playgrounds/cloudflare-worker/worker/middlewares/retry.ts
delete mode 100644 playgrounds/cloudflare-worker/worker/orpc.ts
delete mode 100644 playgrounds/cloudflare-worker/worker/routers/auth.ts
delete mode 100644 playgrounds/cloudflare-worker/worker/routers/index.ts
delete mode 100644 playgrounds/cloudflare-worker/worker/routers/message-v2.ts
delete mode 100644 playgrounds/cloudflare-worker/worker/routers/message.ts
delete mode 100644 playgrounds/cloudflare-worker/worker/routers/planet.ts
delete mode 100644 playgrounds/cloudflare-worker/worker/routers/sse.ts
delete mode 100644 playgrounds/cloudflare-worker/worker/schemas/auth.ts
delete mode 100644 playgrounds/cloudflare-worker/worker/schemas/planet.ts
delete mode 100644 playgrounds/cloudflare-worker/worker/schemas/user.ts
delete mode 100644 playgrounds/cloudflare-worker/wrangler.jsonc
delete mode 100644 playgrounds/contract-first/.gitignore
delete mode 100644 playgrounds/contract-first/.vscode/settings.json
delete mode 100644 playgrounds/contract-first/README.md
delete mode 100644 playgrounds/contract-first/package.json
delete mode 100644 playgrounds/contract-first/src/contract/auth.ts
delete mode 100644 playgrounds/contract-first/src/contract/index.ts
delete mode 100644 playgrounds/contract-first/src/contract/planet.ts
delete mode 100644 playgrounds/contract-first/src/contract/sse.ts
delete mode 100644 playgrounds/contract-first/src/lib/orpc.ts
delete mode 100644 playgrounds/contract-first/src/main.ts
delete mode 100644 playgrounds/contract-first/src/middlewares/db.ts
delete mode 100644 playgrounds/contract-first/src/middlewares/retry.ts
delete mode 100644 playgrounds/contract-first/src/orpc.ts
delete mode 100644 playgrounds/contract-first/src/playground-client.ts
delete mode 100644 playgrounds/contract-first/src/playground-tanstack-query.ts
delete mode 100644 playgrounds/contract-first/src/polyfill.ts
delete mode 100644 playgrounds/contract-first/src/routers/auth.ts
delete mode 100644 playgrounds/contract-first/src/routers/index.ts
delete mode 100644 playgrounds/contract-first/src/routers/planet.ts
delete mode 100644 playgrounds/contract-first/src/routers/sse.ts
delete mode 100644 playgrounds/contract-first/src/schemas/auth.ts
delete mode 100644 playgrounds/contract-first/src/schemas/planet.ts
delete mode 100644 playgrounds/contract-first/src/schemas/user.ts
delete mode 100644 playgrounds/contract-first/tsconfig.json
delete mode 100644 playgrounds/electron/.gitignore
delete mode 100644 playgrounds/electron/.vscode/settings.json
delete mode 100644 playgrounds/electron/README.md
delete mode 100644 playgrounds/electron/electron-builder.yml
delete mode 100644 playgrounds/electron/electron.vite.config.ts
delete mode 100644 playgrounds/electron/package.json
delete mode 100644 playgrounds/electron/src/main/index.ts
delete mode 100644 playgrounds/electron/src/main/middlewares/auth.ts
delete mode 100644 playgrounds/electron/src/main/middlewares/db.ts
delete mode 100644 playgrounds/electron/src/main/middlewares/retry.ts
delete mode 100644 playgrounds/electron/src/main/orpc.ts
delete mode 100644 playgrounds/electron/src/main/routers/auth.ts
delete mode 100644 playgrounds/electron/src/main/routers/index.ts
delete mode 100644 playgrounds/electron/src/main/routers/planet.ts
delete mode 100644 playgrounds/electron/src/main/routers/sse.ts
delete mode 100644 playgrounds/electron/src/main/schemas/auth.ts
delete mode 100644 playgrounds/electron/src/main/schemas/planet.ts
delete mode 100644 playgrounds/electron/src/main/schemas/user.ts
delete mode 100644 playgrounds/electron/src/preload/index.d.ts
delete mode 100644 playgrounds/electron/src/preload/index.ts
delete mode 100644 playgrounds/electron/src/renderer/index.html
delete mode 100644 playgrounds/electron/src/renderer/src/App.tsx
delete mode 100644 playgrounds/electron/src/renderer/src/components/orpc-mutation.tsx
delete mode 100644 playgrounds/electron/src/renderer/src/components/orpc-query.tsx
delete mode 100644 playgrounds/electron/src/renderer/src/components/orpc-stream.tsx
delete mode 100644 playgrounds/electron/src/renderer/src/lib/orpc.ts
delete mode 100644 playgrounds/electron/src/renderer/src/main.tsx
delete mode 100644 playgrounds/electron/src/renderer/src/playground-client.ts
delete mode 100644 playgrounds/electron/src/renderer/src/playground-tanstack-query.ts
delete mode 100644 playgrounds/electron/tsconfig.json
delete mode 100644 playgrounds/electron/tsconfig.node.json
delete mode 100644 playgrounds/nest/.gitignore
delete mode 100644 playgrounds/nest/.vscode/settings.json
delete mode 100644 playgrounds/nest/README.md
delete mode 100644 playgrounds/nest/build.config.ts
delete mode 100644 playgrounds/nest/nest-cli.json
delete mode 100644 playgrounds/nest/package.json
delete mode 100644 playgrounds/nest/src/app.module.ts
delete mode 100644 playgrounds/nest/src/auth/auth.controller.ts
delete mode 100644 playgrounds/nest/src/contract/auth.ts
delete mode 100644 playgrounds/nest/src/contract/index.ts
delete mode 100644 playgrounds/nest/src/contract/planet.ts
delete mode 100644 playgrounds/nest/src/contract/sse.ts
delete mode 100644 playgrounds/nest/src/lib/orpc.ts
delete mode 100644 playgrounds/nest/src/main.ts
delete mode 100644 playgrounds/nest/src/other/other.controller.ts
delete mode 100644 playgrounds/nest/src/planet/planet.controller.ts
delete mode 100644 playgrounds/nest/src/planet/planet.service.ts
delete mode 100644 playgrounds/nest/src/playground-client.ts
delete mode 100644 playgrounds/nest/src/playground-tanstack-query.ts
delete mode 100644 playgrounds/nest/src/reference/reference.controller.ts
delete mode 100644 playgrounds/nest/src/reference/reference.service.ts
delete mode 100644 playgrounds/nest/src/schemas/auth.ts
delete mode 100644 playgrounds/nest/src/schemas/planet.ts
delete mode 100644 playgrounds/nest/src/schemas/user.ts
delete mode 100644 playgrounds/nest/tsconfig.build.json
delete mode 100644 playgrounds/nest/tsconfig.json
delete mode 100644 playgrounds/next/.vscode/settings.json
delete mode 100644 playgrounds/next/public/file.svg
delete mode 100644 playgrounds/next/public/globe.svg
delete mode 100644 playgrounds/next/public/next.svg
delete mode 100644 playgrounds/next/public/vercel.svg
delete mode 100644 playgrounds/next/public/window.svg
delete mode 100644 playgrounds/next/src/app/error.tsx
delete mode 100644 playgrounds/next/src/app/favicon.ico
create mode 100644 playgrounds/next/src/app/global.css
delete mode 100644 playgrounds/next/src/app/loading.tsx
delete mode 100644 playgrounds/next/src/app/orpc-mutation.tsx
delete mode 100644 playgrounds/next/src/app/orpc-query.tsx
delete mode 100644 playgrounds/next/src/app/orpc-server-action.tsx
delete mode 100644 playgrounds/next/src/app/orpc-stream.tsx
create mode 100644 playgrounds/next/src/components/chat-room.tsx
create mode 100644 playgrounds/next/src/components/create-planet-form.tsx
create mode 100644 playgrounds/next/src/components/planet-table-skeleton.tsx
create mode 100644 playgrounds/next/src/components/planet-table.tsx
create mode 100644 playgrounds/next/src/components/reference-links.tsx
create mode 100644 playgrounds/next/src/components/server-function.tsx
create mode 100644 playgrounds/next/src/components/top-bar.tsx
create mode 100644 playgrounds/next/src/context.ts
delete mode 100644 playgrounds/next/src/lib/orpc.server.ts
delete mode 100644 playgrounds/next/src/middlewares/auth.ts
delete mode 100644 playgrounds/next/src/middlewares/db.ts
delete mode 100644 playgrounds/next/src/middlewares/retry.ts
delete mode 100644 playgrounds/next/src/playground-client.ts
delete mode 100644 playgrounds/next/src/playground-tanstack-query.ts
delete mode 100644 playgrounds/next/src/polyfill.ts
delete mode 100644 playgrounds/next/src/routers/auth.ts
create mode 100644 playgrounds/next/src/routers/file.ts
create mode 100644 playgrounds/next/src/routers/message.ts
delete mode 100644 playgrounds/next/src/routers/sse.ts
delete mode 100644 playgrounds/next/src/schemas/auth.ts
delete mode 100644 playgrounds/next/src/schemas/user.ts
delete mode 100644 playgrounds/nuxt/.gitignore
delete mode 100644 playgrounds/nuxt/.vscode/settings.json
delete mode 100644 playgrounds/nuxt/README.md
delete mode 100644 playgrounds/nuxt/app/app.vue
delete mode 100644 playgrounds/nuxt/app/components/orpc-mutation.vue
delete mode 100644 playgrounds/nuxt/app/components/orpc-query.vue
delete mode 100644 playgrounds/nuxt/app/components/orpc-stream.vue
delete mode 100644 playgrounds/nuxt/app/plugins/orpc.client.ts
delete mode 100644 playgrounds/nuxt/app/plugins/orpc.server.ts
delete mode 100644 playgrounds/nuxt/app/plugins/vue-query.ts
delete mode 100644 playgrounds/nuxt/nuxt.config.ts
delete mode 100644 playgrounds/nuxt/package.json
delete mode 100644 playgrounds/nuxt/public/favicon.ico
delete mode 100644 playgrounds/nuxt/public/robots.txt
delete mode 100644 playgrounds/nuxt/server/middlewares/db.ts
delete mode 100644 playgrounds/nuxt/server/middlewares/retry.ts
delete mode 100644 playgrounds/nuxt/server/orpc.ts
delete mode 100644 playgrounds/nuxt/server/playground-client.ts
delete mode 100644 playgrounds/nuxt/server/playground-tanstack-query.ts
delete mode 100644 playgrounds/nuxt/server/plugins/polyfills.ts
delete mode 100644 playgrounds/nuxt/server/routers/auth.ts
delete mode 100644 playgrounds/nuxt/server/routers/index.ts
delete mode 100644 playgrounds/nuxt/server/routers/planet.ts
delete mode 100644 playgrounds/nuxt/server/routers/sse.ts
delete mode 100644 playgrounds/nuxt/server/routes/api/[...].ts
delete mode 100644 playgrounds/nuxt/server/routes/api/index.ts
delete mode 100644 playgrounds/nuxt/server/routes/rpc/[...].ts
delete mode 100644 playgrounds/nuxt/server/routes/rpc/index.ts
delete mode 100644 playgrounds/nuxt/server/schemas/auth.ts
delete mode 100644 playgrounds/nuxt/server/schemas/planet.ts
delete mode 100644 playgrounds/nuxt/server/schemas/user.ts
delete mode 100644 playgrounds/nuxt/server/tsconfig.json
delete mode 100644 playgrounds/nuxt/tsconfig.json
delete mode 100644 playgrounds/solid-start/.gitignore
delete mode 100644 playgrounds/solid-start/.vscode/settings.json
delete mode 100644 playgrounds/solid-start/README.md
delete mode 100644 playgrounds/solid-start/app.config.ts
delete mode 100644 playgrounds/solid-start/package.json
delete mode 100644 playgrounds/solid-start/public/favicon.ico
delete mode 100644 playgrounds/solid-start/src/app.tsx
delete mode 100644 playgrounds/solid-start/src/entry-client.tsx
delete mode 100644 playgrounds/solid-start/src/entry-server.tsx
delete mode 100644 playgrounds/solid-start/src/global.d.ts
delete mode 100644 playgrounds/solid-start/src/lib/orpc.server.ts
delete mode 100644 playgrounds/solid-start/src/lib/orpc.ts
delete mode 100644 playgrounds/solid-start/src/middlewares/db.ts
delete mode 100644 playgrounds/solid-start/src/middlewares/retry.ts
delete mode 100644 playgrounds/solid-start/src/orpc.ts
delete mode 100644 playgrounds/solid-start/src/playground-client.ts
delete mode 100644 playgrounds/solid-start/src/playground-tanstack-query.ts
delete mode 100644 playgrounds/solid-start/src/polyfill.ts
delete mode 100644 playgrounds/solid-start/src/routers/auth.ts
delete mode 100644 playgrounds/solid-start/src/routers/index.ts
delete mode 100644 playgrounds/solid-start/src/routers/planet.ts
delete mode 100644 playgrounds/solid-start/src/routers/sse.ts
delete mode 100644 playgrounds/solid-start/src/routes/api/[...rest].ts
delete mode 100644 playgrounds/solid-start/src/routes/api/index.ts
delete mode 100644 playgrounds/solid-start/src/routes/index.tsx
delete mode 100644 playgrounds/solid-start/src/routes/orpc-mutation.tsx
delete mode 100644 playgrounds/solid-start/src/routes/orpc-query.tsx
delete mode 100644 playgrounds/solid-start/src/routes/orpc-stream.tsx
delete mode 100644 playgrounds/solid-start/src/routes/rpc/[...rest].ts
delete mode 100644 playgrounds/solid-start/src/routes/rpc/index.ts
delete mode 100644 playgrounds/solid-start/src/schemas/auth.ts
delete mode 100644 playgrounds/solid-start/src/schemas/planet.ts
delete mode 100644 playgrounds/solid-start/src/schemas/user.ts
delete mode 100644 playgrounds/solid-start/tsconfig.json
delete mode 100644 playgrounds/svelte-kit/.gitignore
delete mode 100644 playgrounds/svelte-kit/.npmrc
delete mode 100644 playgrounds/svelte-kit/.vscode/settings.json
delete mode 100644 playgrounds/svelte-kit/README.md
delete mode 100644 playgrounds/svelte-kit/package.json
delete mode 100644 playgrounds/svelte-kit/src/app.d.ts
delete mode 100644 playgrounds/svelte-kit/src/app.html
delete mode 100644 playgrounds/svelte-kit/src/hooks.server.ts
delete mode 100644 playgrounds/svelte-kit/src/lib/index.ts
delete mode 100644 playgrounds/svelte-kit/src/lib/orpc.server.ts
delete mode 100644 playgrounds/svelte-kit/src/lib/orpc.ts
delete mode 100644 playgrounds/svelte-kit/src/middlewares/db.ts
delete mode 100644 playgrounds/svelte-kit/src/middlewares/retry.ts
delete mode 100644 playgrounds/svelte-kit/src/orpc.ts
delete mode 100644 playgrounds/svelte-kit/src/playground-client.ts
delete mode 100644 playgrounds/svelte-kit/src/playground-tanstack-query.ts
delete mode 100644 playgrounds/svelte-kit/src/polyfill.ts
delete mode 100644 playgrounds/svelte-kit/src/routers/auth.ts
delete mode 100644 playgrounds/svelte-kit/src/routers/index.ts
delete mode 100644 playgrounds/svelte-kit/src/routers/planet.ts
delete mode 100644 playgrounds/svelte-kit/src/routers/sse.ts
delete mode 100644 playgrounds/svelte-kit/src/routes/+page.svelte
delete mode 100644 playgrounds/svelte-kit/src/routes/api/[...rest]/+server.ts
delete mode 100644 playgrounds/svelte-kit/src/routes/orpc-mutation.svelte
delete mode 100644 playgrounds/svelte-kit/src/routes/orpc-query.svelte
delete mode 100644 playgrounds/svelte-kit/src/routes/orpc-stream.svelte
delete mode 100644 playgrounds/svelte-kit/src/routes/rpc/[...rest]/+server.ts
delete mode 100644 playgrounds/svelte-kit/src/schemas/auth.ts
delete mode 100644 playgrounds/svelte-kit/src/schemas/planet.ts
delete mode 100644 playgrounds/svelte-kit/src/schemas/user.ts
delete mode 100644 playgrounds/svelte-kit/static/favicon.png
delete mode 100644 playgrounds/svelte-kit/svelte.config.js
delete mode 100644 playgrounds/svelte-kit/tsconfig.json
delete mode 100644 playgrounds/svelte-kit/vite.config.ts
delete mode 100644 playgrounds/tanstack-start/.gitignore
delete mode 100644 playgrounds/tanstack-start/.vscode/settings.json
delete mode 100644 playgrounds/tanstack-start/README.md
delete mode 100644 playgrounds/tanstack-start/package.json
delete mode 100644 playgrounds/tanstack-start/src/components/orpc-mutation.tsx
delete mode 100644 playgrounds/tanstack-start/src/components/orpc-query.tsx
delete mode 100644 playgrounds/tanstack-start/src/components/orpc-stream.tsx
delete mode 100644 playgrounds/tanstack-start/src/lib/orpc.ts
delete mode 100644 playgrounds/tanstack-start/src/middlewares/auth.ts
delete mode 100644 playgrounds/tanstack-start/src/middlewares/db.ts
delete mode 100644 playgrounds/tanstack-start/src/middlewares/retry.ts
delete mode 100644 playgrounds/tanstack-start/src/orpc.ts
delete mode 100644 playgrounds/tanstack-start/src/playground-client.ts
delete mode 100644 playgrounds/tanstack-start/src/playground-tanstack-query.ts
delete mode 100644 playgrounds/tanstack-start/src/polyfill.ts
delete mode 100644 playgrounds/tanstack-start/src/routeTree.gen.ts
delete mode 100644 playgrounds/tanstack-start/src/router.tsx
delete mode 100644 playgrounds/tanstack-start/src/routers/auth.ts
delete mode 100644 playgrounds/tanstack-start/src/routers/index.ts
delete mode 100644 playgrounds/tanstack-start/src/routers/planet.ts
delete mode 100644 playgrounds/tanstack-start/src/routers/sse.ts
delete mode 100644 playgrounds/tanstack-start/src/routes/__root.tsx
delete mode 100644 playgrounds/tanstack-start/src/routes/api/$.ts
delete mode 100644 playgrounds/tanstack-start/src/routes/api/rpc.$.ts
delete mode 100644 playgrounds/tanstack-start/src/routes/index.tsx
delete mode 100644 playgrounds/tanstack-start/src/schemas/auth.ts
delete mode 100644 playgrounds/tanstack-start/src/schemas/planet.ts
delete mode 100644 playgrounds/tanstack-start/src/schemas/user.ts
delete mode 100644 playgrounds/tanstack-start/tsconfig.json
delete mode 100644 playgrounds/tanstack-start/vite.config.ts
rename scripts/{sync-sponsor.ts => sync-sponsors.ts} (97%)
create mode 100644 tests/batch/__shared__/client-server.hono-fetch.ts
create mode 100644 tests/batch/__shared__/client-server.node-http.ts
create mode 100644 tests/batch/__shared__/client-server.ts
create mode 100644 tests/batch/batch-plugin.test.ts
create mode 100644 tests/openapi/__shared__/client-server.hono-fetch.ts
create mode 100644 tests/openapi/__shared__/client-server.node-http.ts
create mode 100644 tests/openapi/__shared__/client-server.ts
create mode 100644 tests/openapi/abort-signal.test.ts
create mode 100644 tests/openapi/data-transfer.test.ts
rename packages/client/tests/shared.ts => tests/rpc/__shared__/built-in-support-data-types.ts (57%)
create mode 100644 tests/rpc/__shared__/client-server.hono-fetch.ts
create mode 100644 tests/rpc/__shared__/client-server.message-port.ts
create mode 100644 tests/rpc/__shared__/client-server.node-http.ts
create mode 100644 tests/rpc/__shared__/client-server.node-ws.ts
create mode 100644 tests/rpc/__shared__/client-server.ts
create mode 100644 tests/rpc/abort-signal.test.ts
create mode 100644 tests/rpc/data-transfer.test.ts
create mode 100644 tests/rpc/stream.test.ts
diff --git a/.env.example b/.env.example
index c0baf4787..2d4a7f949 100644
--- a/.env.example
+++ b/.env.example
@@ -1,8 +1,9 @@
# copy this file and rename it to .env
# then fill in the appropriate values
-# Some tests in the project depend on Redis or Upstash Redis
-# You can create a free redis instance at upstash and copy the connection details here
+# Some project tests depend on Redis or Upstash Redis.
+# You can create a free Redis instance on Upstash and add its connection details here.
+# Point Redis and Upstash variables to the same server, as some cross-adapter tests rely on this.
REDIS_URL=
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN=
\ No newline at end of file
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index 2304f61bc..008c75c77 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1,6 +1,6 @@
# These are supported funding model platforms
-github: [dinwwwh] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
+github: [unnoq] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 2bf8b2873..235eb3382 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -12,16 +12,12 @@ updates:
- eslint
- '@antfu/eslint-config'
- 'eslint-plugin-*'
- hey-api:
- patterns:
- - '@hey-api/*'
dev-dependencies-minor-patch:
dependency-type: development
exclude-patterns:
- eslint
- '@antfu/eslint-config'
- 'eslint-plugin-*'
- - '@hey-api/*'
- compression # inline
update-types:
- minor
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 7ece118fc..6d34a3f6e 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -6,15 +6,16 @@ on:
pull_request:
branches: [main]
+permissions:
+ contents: read
+
jobs:
- lint:
+ lint_and_typecheck:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
-
- - uses: pnpm/action-setup@v4
+ - uses: actions/checkout@v7
- - run: pnpm env use --global 22
+ - uses: pnpm/action-setup@v6
- run: pnpm i
@@ -22,50 +23,39 @@ jobs:
- run: pnpm run type:check
- - name: Ensure apps/content builds successfully
- working-directory: apps/content
- run: pnpm run build
-
- test:
+ test_node_matrix:
runs-on: ubuntu-latest
- services:
- redis:
- image: redis:7-alpine
- options: >-
- --health-cmd "redis-cli ping"
- --health-interval 10s
- --health-timeout 5s
- --health-retries 5
- ports:
- - 6379:6379
+ strategy:
+ matrix:
+ node-version: [24, 22, 20]
+ fail-fast: false
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v7
- - uses: pnpm/action-setup@v4
+ - uses: pnpm/action-setup@v6
- - run: pnpm env use --global 22
+ - run: pnpm runtime set node ${{ matrix.node-version }}
- run: pnpm i
- run: pnpm run test:coverage
env:
- REDIS_URL: redis://localhost:6379
+ REDIS_URL: ${{ secrets.REDIS_URL }}
UPSTASH_REDIS_REST_URL: ${{ secrets.UPSTASH_REDIS_REST_URL }}
UPSTASH_REDIS_REST_TOKEN: ${{ secrets.UPSTASH_REDIS_REST_TOKEN }}
- - uses: codecov/codecov-action@v5
+ - uses: codecov/codecov-action@v7
+ if: matrix.node-version == 24
with:
token: ${{ secrets.CODECOV_TOKEN }}
- publish-commit:
+ publish_preview:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
-
- - uses: pnpm/action-setup@v4
+ - uses: actions/checkout@v7
- - run: pnpm env use --global 22
+ - uses: pnpm/action-setup@v6
- run: pnpm i
- - run: pnpm run packages:publish:commit
+ - run: pnpm --filter='./packages/*' run -r build && pnpm exec pkg-pr-new publish './packages/*' --pnpm --compact --template './playgrounds/*'
diff --git a/.github/workflows/pullfrog.yml b/.github/workflows/pullfrog.yml
deleted file mode 100644
index 19401170c..000000000
--- a/.github/workflows/pullfrog.yml
+++ /dev/null
@@ -1,57 +0,0 @@
-# PULLFROG ACTION — DO NOT EDIT EXCEPT WHERE INDICATED
-name: Pullfrog
-run-name: ${{ inputs.name || github.workflow }}
-on:
- workflow_dispatch:
- inputs:
- prompt:
- type: string
- description: Agent prompt
- name:
- type: string
- description: Run name
-
-permissions:
- contents: read
-
-jobs:
- pullfrog:
- runs-on: ubuntu-latest
- permissions:
- id-token: write
- contents: read
- steps:
- - name: Checkout code
- uses: actions/checkout@v6
- with:
- fetch-depth: 1
- - name: Run agent
- uses: pullfrog/pullfrog@v0
- with:
- prompt: ${{ inputs.prompt }}
- env:
- # add at least one provider API key
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
- OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
- GOOGLE_GENERATIVE_AI_API_KEY:
- ${{ secrets.GOOGLE_GENERATIVE_AI_API_KEY }}
- GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
- XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
- DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
- MOONSHOT_API_KEY: ${{ secrets.MOONSHOT_API_KEY }}
- OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
- OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
-
- # for Amazon Bedrock (https://docs.pullfrog.com/bedrock)
- # AWS_BEARER_TOKEN_BEDROCK: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }}
- # AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
- # AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- # AWS_REGION: us-east-1
- # BEDROCK_MODEL_ID:
-
- # for Google Vertex AI (https://docs.pullfrog.com/vertex)
- # VERTEX_SERVICE_ACCOUNT_JSON: ${{ secrets.VERTEX_SERVICE_ACCOUNT_JSON }}
- # GOOGLE_CLOUD_PROJECT: my-project
- # VERTEX_LOCATION: global
- # VERTEX_MODEL_ID:
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 3d3f27a7c..c62e4f4c7 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -39,13 +39,11 @@ jobs:
exit 1
fi
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v7
with:
fetch-depth: 0
- - uses: pnpm/action-setup@v4
-
- - run: pnpm env use --global 22
+ - uses: pnpm/action-setup@v6
- run: pnpm i
@@ -53,16 +51,16 @@ jobs:
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
- - run: pnpm run packages:bump ${{ github.event.inputs.version }} --yes
+ - run: pnpm exec bumpp -r ${{ github.event.inputs.version }} --yes
- run: pnpm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN}"
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- - run: pnpm run packages:publish --tag=${{ steps.version.outputs.preid || 'latest' }}
+ - run: pnpm --filter='./packages/*' run -r build && pnpm --filter='./packages/*' publish -r --access=public --tag=${{ steps.version.outputs.preid || 'latest' }}
env:
NPM_CONFIG_PROVENANCE: true
- - run: pnpm run packages:changelog:github
+ - run: pnpm exec changelogithub --draft
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/sponsors-sync.yaml b/.github/workflows/sponsors-sync.yaml
index 9962a7782..68a2225cd 100644
--- a/.github/workflows/sponsors-sync.yaml
+++ b/.github/workflows/sponsors-sync.yaml
@@ -11,19 +11,15 @@ jobs:
permissions:
contents: write
steps:
- - uses: actions/checkout@v4
- with:
- ref: main
-
- - uses: pnpm/action-setup@v4
+ - uses: actions/checkout@v7
- - run: pnpm env use --global 22
+ - uses: pnpm/action-setup@v6
- run: pnpm i
- - run: pnpm sponsors:sync
+ - run: pnpm run sponsors:sync
- - uses: EndBug/add-and-commit@v9
+ - uses: EndBug/add-and-commit@v10
with:
author_name: GitHub Actions
author_email: 41898282+github-actions[bot]@users.noreply.github.com
diff --git a/README.md b/README.md
index 293bc5c11..27fc183ad 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,4 @@
-
-
-
-
-
+oRPC - Typesafe APIs Made Simple 🪄
-Typesafe APIs Made Simple 🪄
+## Documentation
-**oRPC is a powerful combination of RPC and OpenAPI**, makes it easy to build APIs that are end-to-end type-safe and adhere to OpenAPI standards
+You can read the documentation [here](https://orpc.dev).
----
+## Packages
-## Highlights
+**Core**
-- **🔗 End-to-End Type Safety**: Ensure type-safe inputs, outputs, and errors from client to server.
-- **📘 First-Class OpenAPI**: Built-in support that fully adheres to the OpenAPI standard.
-- **📝 Contract-First Development**: Optionally define your API contract before implementation.
-- **🔍 First-Class OpenTelemetry**: Seamlessly integrate with OpenTelemetry for observability.
-- **⚙️ Framework Integrations**: Seamlessly integrate with TanStack Query (React, Vue, Solid, Svelte, Angular), SWR, Pinia Colada, and more.
-- **🚀 Server Actions**: Fully compatible with React Server Actions on Next.js, TanStack Start, and other platforms.
-- **🔠 Standard Schema Support**: Works out of the box with Zod, Valibot, ArkType, and other schema validators.
-- **🗃️ Native Types**: Supports native types like Date, File, Blob, BigInt, URL, and more.
-- **⏱️ Lazy Router**: Enhance cold start times with our lazy routing feature.
-- **📡 SSE & Streaming**: Enjoy full type-safe support for SSE and streaming.
-- **🌍 Multi-Runtime Support**: Fast and lightweight on Cloudflare, Deno, Bun, Node.js, and beyond.
-- **🔌 Extendability**: Easily extend functionality with plugins, middleware, and interceptors.
+- [@orpc/contract](https://www.npmjs.com/package/@orpc/contract): Define type-safe contracts for your API.
+- [@orpc/server](https://www.npmjs.com/package/@orpc/server): Implement your API or contract on the server.
+- [@orpc/client](https://www.npmjs.com/package/@orpc/client): Consume your API from the client with full type safety.
+- [@orpc/openapi](https://www.npmjs.com/package/@orpc/openapi): Bring OpenAPI compatibility to your APIs.
-## Documentation
+**Schema validation**
-You can find the full documentation [here](https://orpc.dev).
+- [@orpc/zod](https://www.npmjs.com/package/@orpc/zod): Integrate with [Zod](https://zod.dev/).
+- [@orpc/valibot](https://www.npmjs.com/package/@orpc/valibot): Integrate with [Valibot](https://valibot.dev/).
+- [@orpc/arktype](https://www.npmjs.com/package/@orpc/arktype): Integrate with [ArkType](https://arktype.io/).
-## Packages
+**Framework & ecosystem integrations**
+
+- [@orpc/next](https://www.npmjs.com/package/@orpc/react): Use oRPC with [Next.js Server Functions](https://nextjs.org/docs/app/getting-started/mutating-data).
+- [@orpc/tanstack-query](https://www.npmjs.com/package/@orpc/tanstack-query): Integrate with [TanStack Query](https://tanstack.com/query/latest).
+- [@orpc/experimental-effect](https://www.npmjs.com/package/@orpc/experimental-effect): Integrate with [Effect](https://effect.website/).
+
+**Built-in features**
+
+- [@orpc/publisher](https://www.npmjs.com/package/@orpc/publisher): Pub/Sub.
+- [@orpc/ratelimit](https://www.npmjs.com/package/@orpc/ratelimit): Rate limiting.
+- [@orpc/json-schema](https://www.npmjs.com/package/@orpc/json-schema): Smart coercion for OpenAPI requests.
+
+**Observability**
-- [@orpc/contract](https://www.npmjs.com/package/@orpc/contract): Build your API contract.
-- [@orpc/server](https://www.npmjs.com/package/@orpc/server): Build your API or implement API contract.
-- [@orpc/client](https://www.npmjs.com/package/@orpc/client): Consume your API on the client with type-safety.
-- [@orpc/openapi](https://www.npmjs.com/package/@orpc/openapi): Generate OpenAPI specs and handle OpenAPI requests.
-- [@orpc/otel](https://www.npmjs.com/package/@orpc/otel): [OpenTelemetry](https://opentelemetry.io/) integration for observability.
-- [@orpc/nest](https://www.npmjs.com/package/@orpc/nest): Deeply integrate oRPC with [NestJS](https://nestjs.com/).
-- [@orpc/react](https://www.npmjs.com/package/@orpc/react): Utilities for integrating oRPC with React and React Server Actions.
-- [@orpc/tanstack-query](https://www.npmjs.com/package/@orpc/tanstack-query): [TanStack Query](https://tanstack.com/query/latest) integration.
-- [@orpc/experimental-react-swr](https://www.npmjs.com/package/@orpc/experimental-react-swr): [SWR](https://swr.vercel.app/) integration.
-- [@orpc/vue-colada](https://www.npmjs.com/package/@orpc/vue-colada): Integration with [Pinia Colada](https://pinia-colada.esm.dev/).
-- [@orpc/hey-api](https://www.npmjs.com/package/@orpc/hey-api): [Hey API](https://heyapi.dev/) integration.
-- [@orpc/zod](https://www.npmjs.com/package/@orpc/zod): More schemas that [Zod](https://zod.dev/) doesn't support yet.
-- [@orpc/valibot](https://www.npmjs.com/package/@orpc/valibot): OpenAPI spec generation from [Valibot](https://valibot.dev/).
-- [@orpc/arktype](https://www.npmjs.com/package/@orpc/arktype): OpenAPI spec generation from [ArkType](https://arktype.io/).
-
-## Overview
-
-This is a quick overview of how to use oRPC. For more details, please refer to the [documentation](https://orpc.dev).
-
-1. **Define your router:**
-
- ```ts
- import type { IncomingHttpHeaders } from 'node:http'
- import { ORPCError, os } from '@orpc/server'
- import * as z from 'zod'
-
- const PlanetSchema = z.object({
- id: z.number().int().min(1),
- name: z.string(),
- description: z.string().optional(),
- })
-
- export const listPlanet = os
- .input(
- z.object({
- limit: z.number().int().min(1).max(100).optional(),
- cursor: z.number().int().min(0).default(0),
- }),
- )
- .handler(async ({ input }) => {
- // your list code here
- return [{ id: 1, name: 'name' }]
- })
-
- export const findPlanet = os
- .input(PlanetSchema.pick({ id: true }))
- .handler(async ({ input }) => {
- // your find code here
- return { id: 1, name: 'name' }
- })
-
- export const createPlanet = os
- .$context<{ headers: IncomingHttpHeaders }>()
- .use(({ context, next }) => {
- const user = parseJWT(context.headers.authorization?.split(' ')[1])
-
- if (user) {
- return next({ context: { user } })
- }
-
- throw new ORPCError('UNAUTHORIZED')
- })
- .input(PlanetSchema.omit({ id: true }))
- .handler(async ({ input, context }) => {
- // your create code here
- return { id: 1, name: 'name' }
- })
-
- export const router = {
- planet: {
- list: listPlanet,
- find: findPlanet,
- create: createPlanet
- }
- }
- ```
-
-2. **Create your server:**
-
- ```ts
- import { createServer } from 'node:http'
- import { RPCHandler } from '@orpc/server/node'
- import { CORSPlugin } from '@orpc/server/plugins'
-
- const handler = new RPCHandler(router, {
- plugins: [new CORSPlugin()]
- })
-
- const server = createServer(async (req, res) => {
- const result = await handler.handle(req, res, {
- context: { headers: req.headers }
- })
-
- if (!result.matched) {
- res.statusCode = 404
- res.end('No procedure matched')
- }
- })
-
- server.listen(
- 3000,
- '127.0.0.1',
- () => console.log('Listening on 127.0.0.1:3000')
- )
- ```
-
-3. **Create your client:**
-
- ```ts
- import type { RouterClient } from '@orpc/server'
- import { createORPCClient } from '@orpc/client'
- import { RPCLink } from '@orpc/client/fetch'
-
- const link = new RPCLink({
- url: 'http://127.0.0.1:3000',
- headers: { Authorization: 'Bearer token' },
- })
-
- export const orpc: RouterClient = createORPCClient(link)
- ```
-
-4. **Consume your API:**
-
- ```ts
- import { orpc } from './client'
-
- const planets = await orpc.planet.list({ limit: 10 })
- ```
-
-5. **Generate OpenAPI Spec:**
-
- ```ts
- import { OpenAPIGenerator } from '@orpc/openapi'
- import { ZodToJsonSchemaConverter } from '@orpc/zod/zod4'
-
- const generator = new OpenAPIGenerator({
- schemaConverters: [new ZodToJsonSchemaConverter()]
- })
-
- const spec = await generator.generate(router, {
- info: {
- title: 'Planet API',
- version: '1.0.0'
- }
- })
-
- console.log(spec)
- ```
+- [@orpc/opentelemetry](https://www.npmjs.com/package/@orpc/opentelemetry): Instrument your API with [OpenTelemetry](https://opentelemetry.io/).
+- [@orpc/pino](https://www.npmjs.com/package/@orpc/pino): Log with [Pino](https://getpino.io/).
+- [@orpc/evlog](https://www.npmjs.com/package/@orpc/evlog): Log with [Evlog](https://evlog.dev/).
## Sponsors
-If you find oRPC valuable and would like to support its development, you can do so here: [GitHub Sponsors](https://github.com/sponsors/dinwwwh).
+Like what we build over at [middleapi](https://github.com/middleapi)? You can help keep it going here: [GitHub Sponsors](https://github.com/sponsors/dinwwwh). Every bit helps! 🚀
### 🏆 Platinum Sponsor
diff --git a/apps/content/.vitepress/config.ts b/apps/content/.vitepress/config.ts
index 423151563..07a382416 100644
--- a/apps/content/.vitepress/config.ts
+++ b/apps/content/.vitepress/config.ts
@@ -11,6 +11,7 @@ export default withMermaid(defineConfig({
description: 'Easy to build APIs that are end-to-end type-safe and adhere to OpenAPI standards',
lastUpdated: true,
cleanUrls: true,
+ ignoreDeadLinks: true, // TODO: turn off this flag
markdown: {
theme: {
light: 'github-light',
@@ -64,8 +65,7 @@ export default withMermaid(defineConfig({
copyright: 'Copyright © 2024-present MiddleAPI & oRPC contributors.',
},
nav: [
- { text: 'Docs', link: '/docs/getting-started', activeMatch: '/docs/(?!openapi/)' },
- { text: 'OpenAPI', link: '/docs/openapi/getting-started', activeMatch: '/docs/openapi/' },
+ { text: 'Docs', link: '/docs/getting-started', activeMatch: '/docs/' },
{ text: 'Blog', link: '/blog/v1-announcement', activeMatch: '/blog/' },
{ text: 'Learn & Contribute', link: '/learn-and-contribute/overview', activeMatch: '/learn-and-contribute/' },
{
@@ -82,77 +82,87 @@ export default withMermaid(defineConfig({
sidebar: {
'/docs/': [
{ text: 'Getting Started', link: '/docs/getting-started' },
- { text: 'Comparison', link: '/docs/comparison' },
{ text: 'Procedure', link: '/docs/procedure' },
{ text: 'Router', link: '/docs/router' },
{ text: 'Middleware', link: '/docs/middleware' },
{ text: 'Context', link: '/docs/context' },
{ text: 'Error Handling', link: '/docs/error-handling' },
- { text: 'File Upload/Download', link: '/docs/file-upload-download' },
+ { text: 'Binary Data', link: '/docs/binary-data' },
{ text: 'Event Iterator (SSE)', link: '/docs/event-iterator' },
- { text: 'Server Action', link: '/docs/server-action' },
{ text: 'Metadata', link: '/docs/metadata' },
- { text: 'RPC Handler', link: '/docs/rpc-handler' },
- { text: 'OpenAPI', link: '/docs/openapi/getting-started' },
- { text: 'Ecosystem', link: '/docs/ecosystem' },
{ text: 'Playgrounds', link: '/docs/playgrounds' },
{
- text: 'Contract First',
+ text: 'RPC',
collapsed: true,
items: [
- { text: 'Define Contract', link: '/docs/contract-first/define-contract' },
- { text: 'Implement Contract', link: '/docs/contract-first/implement-contract' },
- { text: 'Router to Contract', link: '/docs/contract-first/router-to-contract' },
- { text: 'OpenAPI to Contract', link: '/docs/openapi/openapi-to-contract' },
+ { text: 'RPC Protocol', link: '/docs/rpc/protocol' },
+ { text: 'RPC Serializer', link: '/docs/rpc/serializer' },
+ { text: 'RPC Handler', link: '/docs/rpc/handler' },
+ { text: 'RPC Link', link: '/docs/rpc/link' },
+ ],
+ },
+ {
+ text: 'OpenAPI',
+ collapsed: true,
+ items: [
+ { text: 'OpenAPI Routing', link: '/docs/openapi/routing' },
+ { text: 'Input and Output Mapping', link: '/docs/openapi/input-and-output-mapping' },
+ { text: 'Bracket Notation', link: '/docs/openapi/bracket-notation' },
+ { text: 'OpenAPI Serializer', link: '/docs/openapi/serializer' },
+ { text: 'OpenAPI Handler', link: '/docs/openapi/handler' },
+ { text: 'OpenAPI Link', link: '/docs/openapi/link' },
+ { text: 'OpenAPI Specification', link: '/docs/openapi/specification' },
+ { text: 'OpenAPI Scalar (Swagger)', link: '/docs/openapi/scalar' },
+ ],
+ },
+ {
+ text: 'Contract',
+ collapsed: true,
+ items: [
+ { text: 'Procedure Contract', link: '/docs/contract/procedure' },
+ { text: 'Router Contract', link: '/docs/contract/router' },
+ { text: 'Contract Implementation', link: '/docs/contract/implementation' },
+ ],
+ },
+ {
+ text: 'Client',
+ collapsed: true,
+ items: [
+ { text: 'Server-Side', link: '/docs/client/server-side' },
+ { text: 'Client-Side', link: '/docs/client/client-side' },
+ { text: 'Error Handling', link: '/docs/client/error-handling' },
+ { text: 'Event Iterator', link: '/docs/client/event-iterator' },
+ { text: 'Dynamic Link', link: '/docs/client/dynamic-link' },
],
},
{
text: 'Adapters',
collapsed: true,
items: [
- { text: 'HTTP', link: '/docs/adapters/http' },
+ { text: 'Fetch API', link: '/docs/adapters/fetch-api' },
+ { text: 'Node HTTP', link: '/docs/adapters/node-http' },
{ text: 'Websocket', link: '/docs/adapters/websocket' },
{ text: 'Message Port', link: '/docs/adapters/message-port' },
- { text: '---' },
- { text: 'Astro', link: '/docs/adapters/astro' },
- { text: 'Browser', link: '/docs/adapters/browser' },
- { text: 'Electron', link: '/docs/adapters/electron' },
- { text: 'Elysia', link: '/docs/adapters/elysia' },
- { text: 'Express', link: '/docs/adapters/express' },
- { text: 'Fastify', link: '/docs/adapters/fastify' },
- { text: 'H3', link: '/docs/adapters/h3' },
- { text: 'Hono', link: '/docs/adapters/hono' },
- { text: 'Next.js', link: '/docs/adapters/next' },
- { text: 'Nuxt', link: '/docs/adapters/nuxt' },
- { text: 'React Native', link: '/docs/adapters/react-native' },
- { text: 'Remix', link: '/docs/adapters/remix' },
- { text: 'Solid Start', link: '/docs/adapters/solid-start' },
- { text: 'Svelte Kit', link: '/docs/adapters/svelte-kit' },
- { text: 'Tanstack Start', link: '/docs/adapters/tanstack-start' },
- { text: 'Web Workers', link: '/docs/adapters/web-workers' },
- { text: 'Worker Threads', link: '/docs/adapters/worker-threads' },
],
},
{
text: 'Plugins',
collapsed: true,
items: [
+ { text: 'Batch', link: '/docs/plugins/batch' },
+ { text: 'Body Compression', link: '/docs/plugins/body-compression' },
+ { text: 'Body Limit', link: '/docs/plugins/body-limit' },
{ text: 'CORS', link: '/docs/plugins/cors' },
+ { text: 'CSRF Guard', link: '/docs/plugins/csrf-guard' },
+ { text: 'Dedupe', link: '/docs/plugins/dedupe' },
+ { text: 'OpenAPI Reference', link: '/docs/plugins/openapi-reference' },
{ text: 'Request Headers', link: '/docs/plugins/request-headers' },
- { text: 'Response Headers', link: '/docs/plugins/response-headers' },
{ text: 'Request Validation', link: '/docs/plugins/request-validation' },
+ { text: 'Response Headers', link: '/docs/plugins/response-headers' },
{ text: 'Response Validation', link: '/docs/plugins/response-validation' },
- { text: 'Hibernation', link: '/docs/plugins/hibernation' },
- { text: 'Dedupe Requests', link: '/docs/plugins/dedupe-requests' },
- { text: 'Batch Requests', link: '/docs/plugins/batch-requests' },
- { text: 'Client Retry', link: '/docs/plugins/client-retry' },
{ text: 'Retry After', link: '/docs/plugins/retry-after' },
- { text: 'Rethrow Handler', link: '/docs/plugins/rethrow-handler' },
- { text: 'Compression', link: '/docs/plugins/compression' },
- { text: 'Body Limit', link: '/docs/plugins/body-limit' },
- { text: 'Simple CSRF Protection', link: '/docs/plugins/simple-csrf-protection' },
- { text: 'Strict GET method', link: '/docs/plugins/strict-get-method' },
- { text: 'Logging', link: '/docs/integrations/pino' },
+ { text: 'Retry', link: '/docs/plugins/retry' },
+ { text: 'Smart Coercion', link: '/docs/plugins/smart-coercion' },
],
},
{
@@ -168,52 +178,26 @@ export default withMermaid(defineConfig({
{ text: 'Signing', link: '/docs/helpers/signing' },
],
},
- {
- text: 'Client',
- collapsed: true,
- items: [
- { text: 'Server-Side', link: '/docs/client/server-side' },
- { text: 'Client-Side', link: '/docs/client/client-side' },
- { text: 'Error Handling', link: '/docs/client/error-handling' },
- { text: 'Event Iterator', link: '/docs/client/event-iterator' },
- { text: 'RPC Link', link: '/docs/client/rpc-link' },
- { text: 'Dynamic Link', link: '/docs/client/dynamic-link' },
- ],
- },
{
text: 'Integrations',
collapsed: true,
items: [
- { text: 'AI SDK', link: '/docs/integrations/ai-sdk' },
- { text: 'Better Auth', link: '/docs/integrations/better-auth' },
- { text: 'Durable Iterator', link: '/docs/integrations/durable-iterator' },
- { text: 'Hey API', link: '/docs/openapi/integrations/hey-api' },
+ { text: 'Effect', link: '/docs/integrations/effect' },
+ { text: 'Evlog', link: '/docs/integrations/evlog' },
+ { text: 'Next.js', link: '/docs/integrations/next' },
{ text: 'OpenTelemetry', link: '/docs/integrations/opentelemetry' },
- { text: 'Pinia Colada', link: '/docs/integrations/pinia-colada' },
{ text: 'Pino', link: '/docs/integrations/pino' },
- { text: 'React SWR', link: '/docs/integrations/react-swr' },
- { text: 'Sentry', link: '/docs/integrations/sentry' },
{ text: 'Tanstack Query', link: '/docs/integrations/tanstack-query' },
- {
- text: 'Tanstack Query (Old)',
- collapsed: true,
- items: [
- { text: 'Basic', link: '/docs/integrations/tanstack-query-old/basic' },
- { text: 'React', link: '/docs/integrations/tanstack-query-old/react' },
- { text: 'Vue', link: '/docs/integrations/tanstack-query-old/vue' },
- { text: 'Solid', link: '/docs/integrations/tanstack-query-old/solid' },
- { text: 'Svelte', link: '/docs/integrations/tanstack-query-old/svelte' },
- ],
- },
- { text: 'NestJS', link: '/docs/openapi/integrations/implement-contract-in-nest' },
- { text: 'tRPC', link: '/docs/openapi/integrations/trpc' },
],
},
{
- text: 'Examples',
+ text: 'Extensions',
collapsed: true,
items: [
- { text: 'OpenAI Streaming', link: '/docs/examples/openai-streaming' },
+ { text: '.callable', link: '/docs/client/server-side#callable-extension' },
+ { text: '.route', link: '/docs/openapi/routing#callable-extension' },
+ { text: '.actionable', link: '/docs/integrations/next#actionable-extension' },
+ { text: '.effect', link: '/docs/integrations/effect#effect-extension' },
],
},
{
@@ -223,21 +207,18 @@ export default withMermaid(defineConfig({
{ text: 'Dedupe Middleware', link: '/docs/best-practices/dedupe-middleware' },
{ text: 'Monorepo Setup', link: '/docs/best-practices/monorepo-setup' },
{ text: 'No Throw Literal', link: '/docs/best-practices/no-throw-literal' },
- { text: 'Optimize SSR', link: '/docs/best-practices/optimize-ssr' },
+ { text: 'Optimizing SSR', link: '/docs/best-practices/optimizing-ssr' },
],
},
{
text: 'Advanced',
collapsed: true,
items: [
- { text: 'Building Custom Plugins', link: '/docs/advanced/building-custom-plugins' },
{ text: 'Exceeds the maximum length ...', link: '/docs/advanced/exceeds-the-maximum-length-problem' },
- { text: 'Extend Body Parser', link: '/docs/advanced/extend-body-parser' },
+ { text: 'Expanding Type Support for OpenAPI Link', link: '/docs/advanced/expanding-type-support-for-openapi-link' },
{ text: 'Publish Client to NPM', link: '/docs/advanced/publish-client-to-npm' },
- { text: 'RPC JSON Serializer', link: '/docs/advanced/rpc-json-serializer' },
- { text: 'RPC Protocol', link: '/docs/advanced/rpc-protocol' },
- { text: 'SuperJson', link: '/docs/advanced/superjson' },
- { text: 'Testing & Mocking', link: '/docs/advanced/testing-mocking' },
+ { text: 'Scaling Large Projects', link: '/docs/advanced/scaling-large-projects' },
+ { text: 'Testing and Mocking', link: '/docs/advanced/testing-and-mocking' },
{ text: 'Validation Errors', link: '/docs/advanced/validation-errors' },
],
},
@@ -249,53 +230,6 @@ export default withMermaid(defineConfig({
],
},
],
- '/docs/openapi/': [
- { text: 'Getting Started', link: '/docs/openapi/getting-started' },
- { text: 'Routing', link: '/docs/openapi/routing' },
- { text: 'Input/Output Structure', link: '/docs/openapi/input-output-structure' },
- { text: 'Error Handling', link: '/docs/openapi/error-handling' },
- { text: 'Bracket Notation', link: '/docs/openapi/bracket-notation' },
- { text: 'OpenAPI Handler', link: '/docs/openapi/openapi-handler' },
- { text: 'OpenAPI Specification', link: '/docs/openapi/openapi-specification' },
- { text: 'Scalar (Swagger)', link: '/docs/openapi/scalar' },
- { text: 'OpenAPI to Contract', link: '/docs/openapi/openapi-to-contract' },
- {
- text: 'Plugins',
- collapsed: true,
- items: [
- { text: 'OpenAPI Reference (Swagger)', link: '/docs/openapi/plugins/openapi-reference' },
- { text: 'Smart Coercion', link: '/docs/openapi/plugins/smart-coercion' },
- { text: 'Zod Smart Coercion (old)', link: '/docs/openapi/plugins/zod-smart-coercion' },
- ],
- },
- {
- text: 'Client',
- collapsed: true,
- items: [
- { text: 'OpenAPI Link', link: '/docs/openapi/client/openapi-link' },
- ],
- },
- {
- text: 'Integrations',
- collapsed: true,
- items: [
- { text: 'Hey API', link: '/docs/openapi/integrations/hey-api' },
- { text: 'Implement Contract in NestJS', link: '/docs/openapi/integrations/implement-contract-in-nest' },
- { text: 'tRPC', link: '/docs/openapi/integrations/trpc' },
- ],
- },
- {
- text: 'Advanced',
- collapsed: true,
- items: [
- { text: 'Customizing Error Response', link: '/docs/openapi/advanced/customizing-error-response' },
- { text: 'Disabling Output Validation', link: '/docs/openapi/advanced/disabling-output-validation' },
- { text: 'Expanding Type Support for OpenAPI Link', link: '/docs/openapi/advanced/expanding-type-support-for-openapi-link' },
- { text: 'OpenAPI JSON Serializer', link: '/docs/openapi/advanced/openapi-json-serializer' },
- { text: 'Redirect Response', link: '/docs/openapi/advanced/redirect-response' },
- ],
- },
- ],
'/blog/': [
{ text: 'V1 Announcement', link: '/blog/v1-announcement' },
],
diff --git a/apps/content/blog/v1-announcement.md b/apps/content/blog/v1-announcement.md
index 8e17caead..7bbebdd35 100644
--- a/apps/content/blog/v1-announcement.md
+++ b/apps/content/blog/v1-announcement.md
@@ -125,10 +125,10 @@ In this long journey, I specially thank all my sponsors, they help me to keep go
- [Robbe95](https://github.com/Robbe95)
- And my first sponsor (private) to start my story
-If you're interested in sponsoring oRPC, you can do it [here](https://github.com/sponsors/dinwwwh).
+If you're interesting in sponsoring oRPC, you can do it [here](https://github.com/sponsors/unnoq).
-
-
+
+
diff --git a/apps/content/docs/adapters/astro.md b/apps/content/docs/adapters/astro.md
deleted file mode 100644
index 2a3c8aa2a..000000000
--- a/apps/content/docs/adapters/astro.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-title: Astro Adapter
-description: Use oRPC inside an Astro project
----
-
-# Astro Adapter
-
-[Astro](https://astro.build/) is a JavaScript web framework optimized for building fast, content-driven websites. For additional context, refer to the [HTTP Adapter](/docs/adapters/http) guide.
-
-## Basic
-
-::: code-group
-
-```ts [pages/rpc/[...rest].ts]
-import { RPCHandler } from '@orpc/server/fetch'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-export const prerender = false
-
-export const ALL: APIRoute = async ({ request }) => {
- const { response } = await handler.handle(request, {
- prefix: '/rpc',
- context: {},
- })
-
- return response ?? new Response('Not found', { status: 404 })
-}
-```
-
-:::
-
-::: info
-The `handler` can be any supported oRPC handler, such as [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or another custom handler.
-:::
diff --git a/apps/content/docs/adapters/browser.md b/apps/content/docs/adapters/browser.md
deleted file mode 100644
index 6fc574176..000000000
--- a/apps/content/docs/adapters/browser.md
+++ /dev/null
@@ -1,171 +0,0 @@
----
-title: Browser Adapter
-description: Type-safe communication between browser scripts using Message Port Adapter
----
-
-# Browser Adapter
-
-Enable type-safe communication between browser scripts using the [Message Port Adapter](/docs/adapters/message-port).
-
-## Between Extension Scripts
-
-To set up communication between scripts in a browser extension (e.g. background, content, popup), configure one script to listen for connections and upgrade them, and another to initiate the connection.
-
-::: warning
-The browser extension [Message Passing API](https://developer.chrome.com/docs/extensions/develop/concepts/messaging) does not support transferring binary data, which means oRPC features like `File` and `Blob` cannot be used natively. However, you can temporarily work around this limitation by extending the [RPC JSON Serializer](/docs/advanced/rpc-json-serializer#extending-native-data-types) to encode binary data as Base64.
-:::
-
-::: code-group
-
-```ts [server]
-import { RPCHandler } from '@orpc/server/message-port'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-browser.runtime.onConnect.addListener((port) => {
- handler.upgrade(port, {
- context: {}, // provide initial context if needed
- })
-})
-```
-
-```ts [client]
-import { RPCLink } from '@orpc/client/message-port'
-
-const port = browser.runtime.connect()
-
-const link = new RPCLink({
- port,
-})
-```
-
-:::
-
-:::info
-This only shows how to configure the link. For full client examples, see [Client-Side Clients](/docs/client/client-side).
-:::
-
-## Window to Window
-
-To enable communication between two window contexts (e.g. parent and popup), one must listen and upgrade the port, and the other must initiate the connection.
-
-::: code-group
-
-```ts [opener]
-import { RPCHandler } from '@orpc/server/message-port'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-window.addEventListener('message', (event) => {
- if (event.data instanceof MessagePort) {
- handler.upgrade(event.data, {
- context: {}, // Optional context
- })
-
- event.data.start()
- }
-})
-
-window.open('/example/popup', 'popup', 'width=680,height=520')
-```
-
-```ts [popup]
-import { RPCLink } from '@orpc/client/message-port'
-
-const { port1: serverPort, port2: clientPort } = new MessageChannel()
-
-window.opener.postMessage(serverPort, '*', [serverPort])
-
-const link = new RPCLink({
- port: clientPort,
-})
-
-clientPort.start()
-```
-
-:::
-
-## Advanced Relay Pattern
-
-In some advanced cases, direct communication between scripts isn't possible. For example, a content script running in the ["MAIN" world](https://developer.chrome.com/docs/extensions/reference/manifest/content-scripts#world-timings) cannot directly communicate with the background script using `browser.runtime` or `chrome.runtime` APIs.
-
-To work around this, you can use a **relay pattern** typically an additional content script running in the default **"ISOLATED" (default) world** to relay messages between the two contexts. This **relay pattern** acts as an intermediary, enabling communication where direct access is restricted.
-
-::: code-group
-
-```ts [relay]
-window.addEventListener('message', (event) => {
- if (event.data instanceof MessagePort) {
- const port = browser.runtime.connect()
-
- // Relay `message` and `close/disconnect` events between the MessagePort and runtime.Port
-
- event.data.addEventListener('message', (event) => {
- port.postMessage(event.data)
- })
-
- event.data.addEventListener('close', () => {
- port.disconnect()
- })
-
- port.onMessage.addListener((message) => {
- event.data.postMessage(message)
- })
-
- port.onDisconnect.addListener(() => {
- event.data.close()
- })
-
- event.data.start()
- }
-})
-```
-
-```ts [server]
-import { RPCHandler } from '@orpc/server/message-port'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-browser.runtime.onConnect.addListener((port) => {
- handler.upgrade(port, {
- context: {}, // provide initial context if needed
- })
-})
-```
-
-```ts [client]
-import { RPCLink } from '@orpc/client/message-port'
-
-const { port1: serverPort, port2: clientPort } = new MessageChannel()
-
-window.postMessage(serverPort, '*', [serverPort])
-
-const link = new RPCLink({
- port: clientPort,
-})
-
-clientPort.start()
-```
-
-:::
diff --git a/apps/content/docs/adapters/electron.md b/apps/content/docs/adapters/electron.md
deleted file mode 100644
index fb76c1b2a..000000000
--- a/apps/content/docs/adapters/electron.md
+++ /dev/null
@@ -1,71 +0,0 @@
----
-title: Electron Adapter
-description: Use oRPC inside an Electron project
----
-
-# Electron Adapter
-
-Establish type-safe communication between processes in [Electron](https://www.electronjs.org/) using the [Message Port Adapter](/docs/adapters/message-port). Before you start, we recommend reading the [MessagePorts in Electron](https://www.electronjs.org/docs/latest/tutorial/message-ports) guide.
-
-## Main Process
-
-Listen for a port sent from the renderer, then upgrade it:
-
-```ts
-import { RPCHandler } from '@orpc/server/message-port'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-app.whenReady().then(() => {
- ipcMain.on('start-orpc-server', async (event) => {
- const [serverPort] = event.ports
- handler.upgrade(serverPort)
- serverPort.start()
- })
-})
-```
-
-:::info
-Channel `start-orpc-server` is arbitrary. you can use any name that fits your needs.
-:::
-
-## Preload Process
-
-Receive the port from the renderer and forward it to the main process:
-
-```ts
-window.addEventListener('message', (event) => {
- if (event.data === 'start-orpc-client') {
- const [serverPort] = event.ports
-
- ipcRenderer.postMessage('start-orpc-server', null, [serverPort])
- }
-})
-```
-
-## Renderer Process
-
-Create a `MessageChannel`, send one port to the preload script, and use the other to initialize the client link:
-
-```ts
-const { port1: clientPort, port2: serverPort } = new MessageChannel()
-
-window.postMessage('start-orpc-client', '*', [serverPort])
-
-const link = new RPCLink({
- port: clientPort,
-})
-
-clientPort.start()
-```
-
-:::info
-This only shows how to configure the link. For full client examples, see [Client-Side Clients](/docs/client/client-side).
-:::
diff --git a/apps/content/docs/adapters/elysia.md b/apps/content/docs/adapters/elysia.md
deleted file mode 100644
index d21bab808..000000000
--- a/apps/content/docs/adapters/elysia.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: Elysia Adapter
-description: Use oRPC inside an Elysia project
----
-
-# Elysia Adapter
-
-[Elysia](https://elysiajs.com/) is a high-performance web framework for [Bun](https://bun.sh/) that adheres to the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). For additional context, refer to the [HTTP Adapter](/docs/adapters/http) guide.
-
-## Basic
-
-```ts
-import { Elysia } from 'elysia'
-import { RPCHandler } from '@orpc/server/fetch'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-const app = new Elysia()
- .all('/rpc*', async ({ request }: { request: Request }) => {
- const { response } = await handler.handle(request, {
- prefix: '/rpc',
- })
-
- return response ?? new Response('Not Found', { status: 404 })
- }, {
- parse: 'none' // Disable Elysia body parser to prevent "body already used" error
- })
- .listen(3000)
-
-console.log(
- `🦊 Elysia is running at http://localhost:3000`
-)
-```
-
-::: info
-The `handler` can be any supported oRPC handler, such as [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or another custom handler.
-:::
diff --git a/apps/content/docs/adapters/express.md b/apps/content/docs/adapters/express.md
deleted file mode 100644
index a15d1d9f1..000000000
--- a/apps/content/docs/adapters/express.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-title: Express.js Adapter
-description: Use oRPC inside an Express.js project
----
-
-# Express.js Adapter
-
-[Express.js](https://expressjs.com/) is a popular Node.js framework for building web applications. For additional context, refer to the [HTTP Adapter](/docs/adapters/http) guide.
-
-::: warning
-Express's [body-parser](https://expressjs.com/en/resources/middleware/body-parser.html) handles common request body types, and oRPC will use the parsed body if available. However, it doesn't support features like [Bracket Notation](/docs/openapi/bracket-notation), and in case you upload a file with `application/json`, it may be parsed as plain JSON instead of a `File`. To avoid these issues, register any body-parsing middleware **after** your oRPC middleware or only on routes that don't use oRPC.
-:::
-
-## Basic
-
-```ts
-import express from 'express'
-import cors from 'cors'
-import { RPCHandler } from '@orpc/server/node'
-import { onError } from '@orpc/server'
-
-const app = express()
-
-app.use(cors())
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-app.use('/rpc{/*path}', async (req, res, next) => {
- const { matched } = await handler.handle(req, res, {
- prefix: '/rpc',
- context: {},
- })
-
- if (matched) {
- return
- }
-
- next()
-})
-
-app.listen(3000, () => console.log('Server listening on port 3000'))
-```
-
-::: info
-The `handler` can be any supported oRPC handler, such as [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or another custom handler.
-:::
diff --git a/apps/content/docs/adapters/fastify.md b/apps/content/docs/adapters/fastify.md
deleted file mode 100644
index a5746ffb8..000000000
--- a/apps/content/docs/adapters/fastify.md
+++ /dev/null
@@ -1,53 +0,0 @@
----
-title: Fastify Adapter
-description: Use oRPC inside an Fastify project
----
-
-# Fastify Adapter
-
-[Fastify](https://fastify.dev/) is a web framework highly focused on providing the best developer experience with the least overhead and a powerful plugin architecture. For additional context, refer to the [HTTP Adapter](/docs/adapters/http) guide.
-
-::: warning
-Fastify parses common request content types by default. oRPC will use the parsed body when available.
-:::
-
-## Basic
-
-```ts
-import Fastify from 'fastify'
-import { RPCHandler } from '@orpc/server/fastify'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- })
- ]
-})
-
-const fastify = Fastify()
-
-fastify.addContentTypeParser('*', (request, payload, done) => {
- // Fully utilize oRPC feature by allowing any content type
- // And let oRPC parse the body manually by passing `undefined`
- done(null, undefined)
-})
-
-fastify.all('/rpc/*', async (req, reply) => {
- const { matched } = await handler.handle(req, reply, {
- prefix: '/rpc',
- context: {} // Provide initial context if needed
- })
-
- if (!matched) {
- reply.status(404).send('Not found')
- }
-})
-
-fastify.listen({ port: 3000 }).then(() => console.log('Server running on http://localhost:3000'))
-```
-
-::: info
-The `handler` can be any supported oRPC handler, such as [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or another custom handler.
-:::
diff --git a/apps/content/docs/adapters/fetch-api.md b/apps/content/docs/adapters/fetch-api.md
new file mode 100644
index 000000000..60a09c58e
--- /dev/null
+++ b/apps/content/docs/adapters/fetch-api.md
@@ -0,0 +1,213 @@
+## Fetch API Adapter
+
+oRPC supports the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) for both servers and clients.
+
+## Server Usage
+
+::: code-group
+
+```ts [RPC]
+import { RPCHandler } from '@orpc/server/fetch'
+import { CORSPlugin } from '@orpc/server/plugins'
+import { onError } from '@orpc/server'
+
+const handler = new RPCHandler(router, {
+ plugins: [
+ new CORSHandlerPlugin()
+ ],
+ interceptors: [
+ onError((error) => {
+ console.error(error)
+ }),
+ ],
+})
+
+export async function fetch(request: Request): Promise {
+ const { matched, response } = await handler.handle(request, {
+ prefix: '/rpc',
+ context: {} // Provide initial context if needed
+ })
+
+ if (matched) {
+ return response
+ }
+
+ return new Response('Not found', { status: 404 })
+}
+```
+
+```ts [OpenAPI]
+import { OpenAPIHandler } from '@orpc/openapi/fetch'
+import { CORSPlugin } from '@orpc/server/plugins'
+import { onError } from '@orpc/server'
+
+const handler = new OpenAPIHandler(router, {
+ plugins: [
+ new CORSHandlerPlugin()
+ ],
+ interceptors: [
+ onError((error) => {
+ console.error(error)
+ }),
+ ],
+})
+
+export async function fetch(request: Request): Promise {
+ const { matched, response } = await handler.handle(request, {
+ prefix: '/api',
+ context: {} // Provide initial context if needed
+ })
+
+ if (matched) {
+ return response
+ }
+
+ return new Response('Not found', { status: 404 })
+}
+```
+
+:::
+
+::: info
+The actual usage of `fetch` depends on the runtime environment or library you use:
+
+::: code-group
+
+```ts [Bun]
+Bun.serve({
+ fetch,
+})
+```
+
+```ts [Cloudflare Workers]
+export default {
+ fetch,
+}
+```
+
+```ts [Deno]
+Deno.serve(fetch)
+```
+
+```ts [Hono Lambda]
+import { handle } from 'hono/aws-lambda'
+
+export const handler = handle({ fetch })
+```
+
+:::
+
+
+
+## Client Usage
+
+::: code-group
+
+```ts [RPC]
+import { RPCLink } from '@orpc/client/fetch'
+import { onError } from '@orpc/client'
+
+const link = new RPCLink({
+ origin: 'https://api.example.com', // accepts async function, defaults to current origin
+ url: '/rpc', // accepts async function
+ headers: { authorization: 'bearer token' }, // accept async function
+ interceptors: [
+ onError((error) => {
+ console.error(error)
+ }),
+ ],
+ fetch: (request, init) => { // <- override fetch if needed
+ return globalThis.fetch(request, {
+ ...init,
+ credentials: 'include', // Include cookies on cross-origin requests
+ })
+ },
+})
+```
+
+```ts [OpenAPI]
+import { OpenAPILink } from '@orpc/openapi/fetch'
+import { onError } from '@orpc/client'
+
+const link = new OpenAPILink(contract, {
+ origin: 'https://api.example.com', // accepts async function, defaults to current origin
+ url: '/rpc', // accepts async function
+ headers: { authorization: 'bearer token' }, // accept async function
+ interceptors: [
+ onError((error) => {
+ console.error(error)
+ }),
+ ],
+ fetch: (request, init) => { // <- override fetch if needed
+ return globalThis.fetch(request, {
+ ...init,
+ credentials: 'include', // Include cookies on cross-origin requests
+ })
+ },
+})
+```
+
+:::
+
+::: info
+The examples above only show how to configure the link. For examples of creating a typesafe client, see [RPC Link](/docs/rpc/link#typesafe-clients) and [OpenAPI Link](/docs/openapi/link#typesafe-clients).
+:::
+
+## Event Stream Options
+
+You can configure how [event iterators](/docs/event-iterator) are streamed to the client using the `toFetchResponse.eventStream` options when creating the handler.
+
+```ts
+const handler = new OpenAPIHandler(router, {
+ toFetchResponse: {
+ eventStream: {
+ initialComment: {
+ /**
+ * If true, an initial comment is sent immediately upon stream start to flush headers.
+ * This allows the receiving side to establish the connection without waiting for the first event.
+ *
+ * @default true
+ */
+ enabled: true,
+ /**
+ * The content of the initial comment sent upon stream start. Must not include newline characters.
+ *
+ * @default ''
+ */
+ comment: '',
+ },
+ keepAlive: {
+ /**
+ * If true, a ping comment is sent periodically to keep the connection alive.
+ *
+ * @default true
+ */
+ enabled: true,
+ /**
+ * Interval (in milliseconds) between ping comments sent after the last event.
+ *
+ * @default 5000
+ */
+ interval: 5000,
+ /**
+ * The content of the ping comment. Must not include newline characters.
+ *
+ * @default ''
+ */
+ comment: '',
+ },
+ /**
+ * If true, a `close` event is sent even when the iterator completes with `undefined`.
+ * When the iterator returns a value, a `close` event is always emitted regardless of this setting.
+ *
+ * @default true
+ */
+ emptyCloseEventEnabled: true,
+ },
+ },
+})
+```
+
+::: info
+You can also configure how [event iterators](/docs/event-iterator) are streamed from client to server using `toFetchBody.eventStream` options when creating the link. However, this is rarely used because streaming requests are not widely supported in browsers and may require manually overriding the `fetch` function with `duplex`.
+:::
diff --git a/apps/content/docs/adapters/h3.md b/apps/content/docs/adapters/h3.md
deleted file mode 100644
index 970449755..000000000
--- a/apps/content/docs/adapters/h3.md
+++ /dev/null
@@ -1,43 +0,0 @@
----
-title: H3 Adapter
-description: Use oRPC inside an H3 project
----
-
-# H3 Adapter
-
-[H3](https://h3.dev/) is a universal, tiny, and fast web framework built on top of web standards. For additional context, refer to the [HTTP Adapter](/docs/adapters/http) guide.
-
-## Basic
-
-```ts
-import { H3, serve } from 'h3'
-import { RPCHandler } from '@orpc/server/fetch'
-import { onError } from '@orpc/server'
-
-const app = new H3()
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-app.use('/rpc/**', async (event) => {
- const { matched, response } = await handler.handle(event.req, {
- prefix: '/rpc',
- context: {} // Provide initial context if needed
- })
-
- if (matched) {
- return response
- }
-})
-
-serve(app, { port: 3000 })
-```
-
-::: info
-The `handler` can be any supported oRPC handler, such as [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or another custom handler.
-:::
diff --git a/apps/content/docs/adapters/hono.md b/apps/content/docs/adapters/hono.md
deleted file mode 100644
index 464595115..000000000
--- a/apps/content/docs/adapters/hono.md
+++ /dev/null
@@ -1,79 +0,0 @@
----
-title: Hono Adapter
-description: Use oRPC inside an Hono project
----
-
-# Hono Adapter
-
-[Hono](https://honojs.dev/) is a high-performance web framework built on top of [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). For additional context, refer to the [HTTP Adapter](/docs/adapters/http) guide.
-
-## Basic
-
-```ts
-import { Hono } from 'hono'
-import { RPCHandler } from '@orpc/server/fetch'
-import { onError } from '@orpc/server'
-
-const app = new Hono()
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-app.use('/rpc/*', async (c, next) => {
- const { matched, response } = await handler.handle(c.req.raw, {
- prefix: '/rpc',
- context: {} // Provide initial context if needed
- })
-
- if (matched) {
- return c.newResponse(response.body, response)
- }
-
- await next()
-})
-
-export default app
-```
-
-::: details Body Already Used Error?
-
-If Hono middleware reads the request body before the oRPC handler processes it, an error will occur. You can solve this by using a proxy to intercept the request body parsers with Hono parsers.
-
-```ts
-const BODY_PARSER_METHODS = new Set(['arrayBuffer', 'blob', 'formData', 'json', 'text'] as const)
-
-type BodyParserMethod = typeof BODY_PARSER_METHODS extends Set ? T : never
-
-app.use('/rpc/*', async (c, next) => {
- const request = new Proxy(c.req.raw, {
- get(target, prop) {
- if (BODY_PARSER_METHODS.has(prop as BodyParserMethod)) {
- return () => c.req[prop as BodyParserMethod]()
- }
- return Reflect.get(target, prop, target)
- }
- })
-
- const { matched, response } = await handler.handle(request, {
- prefix: '/rpc',
- context: {} // Provide initial context if needed
- })
-
- if (matched) {
- return c.newResponse(response.body, response)
- }
-
- await next()
-})
-```
-
-:::
-
-::: info
-The `handler` can be any supported oRPC handler, such as [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or another custom handler.
-:::
diff --git a/apps/content/docs/adapters/http.md b/apps/content/docs/adapters/http.md
deleted file mode 100644
index 5b888421c..000000000
--- a/apps/content/docs/adapters/http.md
+++ /dev/null
@@ -1,298 +0,0 @@
----
-title: HTTP
-description: How to use oRPC over HTTP?
----
-
-# HTTP
-
-oRPC includes built-in HTTP support, making it easy to expose RPC endpoints in any environment that speaks HTTP.
-
-## Server Adapters
-
-| Adapter | Target |
-| ------------ | -------------------------------------------------------------------------------------------------------------------------- |
-| `fetch` | [MDN Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) (Browser, Bun, Deno, Cloudflare Workers, etc.) |
-| `node` | Node.js built-in [`http`](https://nodejs.org/api/http.html)/[`http2`](https://nodejs.org/api/http2.html) |
-| `fastify` | [Fastify](https://fastify.dev/) |
-| `aws-lambda` | [AWS Lambda](https://aws.amazon.com/lambda/) |
-
-::: code-group
-
-```ts [node]
-import { createServer } from 'node:http' // or 'node:http2'
-import { RPCHandler } from '@orpc/server/node'
-import { CORSPlugin } from '@orpc/server/plugins'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- plugins: [
- new CORSPlugin()
- ],
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-const server = createServer(async (req, res) => {
- const { matched } = await handler.handle(req, res, {
- prefix: '/rpc',
- context: {} // Provide initial context if needed
- })
-
- if (matched) {
- return
- }
-
- res.statusCode = 404
- res.end('Not found')
-})
-
-server.listen(3000, '127.0.0.1', () => console.log('Listening on 127.0.0.1:3000'))
-```
-
-```ts [bun]
-import { RPCHandler } from '@orpc/server/fetch'
-import { CORSPlugin } from '@orpc/server/plugins'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- plugins: [
- new CORSPlugin()
- ],
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-Bun.serve({
- async fetch(request: Request) {
- const { matched, response } = await handler.handle(request, {
- prefix: '/rpc',
- context: {} // Provide initial context if needed
- })
-
- if (matched) {
- return response
- }
-
- return new Response('Not found', { status: 404 })
- }
-})
-```
-
-```ts [cloudflare]
-import { RPCHandler } from '@orpc/server/fetch'
-import { CORSPlugin } from '@orpc/server/plugins'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- plugins: [
- new CORSPlugin()
- ],
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-export default {
- async fetch(request: Request, env: any, ctx: ExecutionContext): Promise {
- const { matched, response } = await handler.handle(request, {
- prefix: '/rpc',
- context: {} // Provide initial context if needed
- })
-
- if (matched) {
- return response
- }
-
- return new Response('Not found', { status: 404 })
- }
-}
-```
-
-```ts [deno]
-import { RPCHandler } from '@orpc/server/fetch'
-import { CORSPlugin } from '@orpc/server/plugins'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- plugins: [
- new CORSPlugin()
- ],
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-Deno.serve(async (request) => {
- const { matched, response } = await handler.handle(request, {
- prefix: '/rpc',
- context: {} // Provide initial context if needed
- })
-
- if (matched) {
- return response
- }
-
- return new Response('Not found', { status: 404 })
-})
-```
-
-```ts [fastify]
-import Fastify from 'fastify'
-import { RPCHandler } from '@orpc/server/fastify'
-import { onError } from '@orpc/server'
-
-const rpcHandler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-const fastify = Fastify()
-
-fastify.addContentTypeParser('*', (request, payload, done) => {
- // Fully utilize oRPC feature by allowing any content type
- // And let oRPC parse the body manually by passing `undefined`
- done(null, undefined)
-})
-
-fastify.all('/rpc/*', async (req, reply) => {
- const { matched } = await rpcHandler.handle(req, reply, {
- prefix: '/rpc',
- })
-
- if (!matched) {
- reply.status(404).send('Not found')
- }
-})
-
-fastify.listen({ port: 3000 }).then(() => console.log('Listening on 127.0.0.1:3000'))
-```
-
-```ts [aws-lambda]
-import { APIGatewayProxyEventV2 } from 'aws-lambda'
-import { RPCHandler } from '@orpc/server/aws-lambda'
-import { onError } from '@orpc/server'
-
-const rpcHandler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-/**
- * oRPC only supports [AWS Lambda response streaming](https://aws.amazon.com/blogs/compute/introducing-aws-lambda-response-streaming/).
- * If you need support chunked responses, use a combination of Hono's `aws-lambda` adapter and oRPC.
- */
-export const handler = awslambda.streamifyResponse(async (event, responseStream, context) => {
- const { matched } = await rpcHandler.handle(event, responseStream, {
- prefix: '/rpc',
- context: {} // Provide initial context if needed
- })
-
- if (matched) {
- return
- }
-
- awslambda.HttpResponseStream.from(responseStream, {
- statusCode: 404,
- })
-
- responseStream.write('Not found')
- responseStream.end()
-})
-```
-
-:::
-
-::: info
-The `handler` can be any supported oRPC handler, such as [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or another custom handler.
-:::
-
-## Client Adapters
-
-| Adapter | Target |
-| ------- | -------------------------------------------------------------------------------------------------------------------------------- |
-| `fetch` | [MDN Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) (Browser, Node, Bun, Deno, Cloudflare Workers, etc.) |
-
-```ts
-import { RPCLink } from '@orpc/client/fetch'
-
-const link = new RPCLink({
- url: 'http://localhost:3000/rpc',
- headers: () => ({
- 'x-api-key': 'my-api-key'
- }),
- // fetch: <-- polyfill fetch if needed
-})
-```
-
-::: info
-The `link` can be any supported oRPC link, such as [RPCLink](/docs/client/rpc-link), [OpenAPILink](/docs/openapi/client/openapi-link), or another custom handler.
-:::
-
-::: info
-This only shows how to configure the http link. For full client examples, see [Client-Side Clients](/docs/client/client-side).
-:::
-
-## Event Iterator Options
-
-HTTP adapters provide reliability features for streaming [Event Iterators](/docs/event-iterator):
-
-```ts
-const handler = new RPCHandler(router, {
- eventIteratorInitialCommentEnabled: true,
- eventIteratorInitialComment: 'start',
- eventIteratorKeepAliveEnabled: true,
- eventIteratorKeepAliveInterval: 5000,
- eventIteratorKeepAliveComment: '',
-})
-
-const link = new OpenAPILink({
- eventIteratorInitialCommentEnabled: true,
- eventIteratorInitialComment: 'start',
- eventIteratorKeepAliveEnabled: true,
- eventIteratorKeepAliveInterval: 5000,
- eventIteratorKeepAliveComment: '',
-})
-```
-
-::: info
-These options are available for HTTP-based handlers and links only.
-:::
-
-::: warning
-Link options apply when streaming from **client to server**, not server to client (as with handlers). In most cases, you don't need to configure these on the link.
-:::
-
-### Initial Comment
-
-Sends an initial comment immediately when the stream starts to flush response headers early. This allows the receiving side to establish the connection without waiting for the first event.
-
-| Option | Default | Description |
-| ------------------------------------ | ------- | ------------------------------ |
-| `eventIteratorInitialCommentEnabled` | `true` | Enable/disable initial comment |
-| `eventIteratorInitialComment` | `''` | Custom comment content |
-
-### Keep-Alive Comments
-
-Sends periodic comments during inactivity to prevent connection timeouts.
-
-| Option | Default | Description |
-| -------------------------------- | ------- | ---------------------------------- |
-| `eventIteratorKeepAliveEnabled` | `true` | Enable/disable keep-alive comments |
-| `eventIteratorKeepAliveInterval` | `5000` | Interval in milliseconds |
-| `eventIteratorKeepAliveComment` | `''` | Custom comment content |
diff --git a/apps/content/docs/adapters/message-port.md b/apps/content/docs/adapters/message-port.md
index 602e1be1f..ee9aebe23 100644
--- a/apps/content/docs/adapters/message-port.md
+++ b/apps/content/docs/adapters/message-port.md
@@ -1,29 +1,18 @@
----
-title: Message Port
-description: Using oRPC with Message Ports
----
+# Message Port Adapter
-# Message Port
-
-oRPC offers built-in support for common Message Port implementations, enabling easy internal communication between different processes.
-
-| Environment | Documentation |
-| ------------------------------------------------------------------------------------------ | ---------------------------------------------- |
-| [Electron Message Port](https://www.electronjs.org/docs/latest/tutorial/message-ports) | [Adapter Guide](/docs/adapters/electron) |
-| Browser (extension background to popup/content, window to window, etc.) | [Adapter Guide](/docs/adapters/browser) |
-| [Node.js Worker Threads Port](https://nodejs.org/api/worker_threads.html#workerparentport) | [Adapter Guide](/docs/adapters/worker-threads) |
+oRPC supports the [Message Port](https://developer.mozilla.org/en-US/docs/Web/API/MessagePort) for communicating between different contexts, such as iframes, web workers, and service workers.
## Basic Usage
Message Ports work by establishing two endpoints that can communicate with each other:
-```ts [bridge]
+```ts [Bridge]
const channel = new MessageChannel()
const serverPort = channel.port1
const clientPort = channel.port2
```
-```ts [server]
+```ts [Server]
import { RPCHandler } from '@orpc/server/message-port'
import { onError } from '@orpc/server'
@@ -36,24 +25,40 @@ const handler = new RPCHandler(router, {
})
handler.upgrade(serverPort, {
- context: {}, // Provide initial context if needed
+ /**
+ * Provide initial context if needed. The context can be an async function
+ * that receives the per-call request as its first argument, and is **not**
+ * related to the initial upgrade request.
+ */
+ context: request => ({}),
})
serverPort.start()
```
-```ts [client]
+```ts [Client]
import { RPCLink } from '@orpc/client/message-port'
+import { onError } from '@orpc/client'
const link = new RPCLink({
port: clientPort,
+ interceptors: [
+ onError((error) => {
+ console.error(error)
+ }),
+ ],
+ /**
+ * Optional headers to attach to each per-call request.
+ * These can be accessed in the server context or via the Request Headers Plugin.
+ */
+ headers: () => ({})
})
clientPort.start()
```
-:::info
-This only shows how to configure the link. For full client examples, see [Client-Side Clients](/docs/client/client-side).
+::: info
+The examples above only show how to configure the link. For examples of creating a typesafe client, see [RPC Link](/docs/rpc/link#typesafe-clients).
:::
## Transfer
@@ -73,7 +78,6 @@ const handler = new RPCHandler(router, {
```ts [link]
const link = new RPCLink({
- port: clientPort,
experimental_transfer: (message) => {
const transfer = deepFindTransferableObjects(message) // implement your own logic
return transfer.length ? transfer : null // only enable when needed
@@ -83,10 +87,6 @@ const link = new RPCLink({
:::
-::: warning
-When `transfer` returns an array, messages using [the structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) for sending, which doesn't support all data types such as [Event Iterator's Metadata](/docs/event-iterator#last-event-id-event-metadata). So I recommend you only enable this when needed.
-:::
-
-::: tip
-The `transfer` option run after [RPC JSON Serializer](/docs/advanced/rpc-json-serializer) so you can combine them together to support more data types.
+::: info
+When `transfer` returns an array, messages are sent using [the structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm), which doesn't support all data types. If you need to support additional data types, consider customizing your [RPC Serializer](/docs/rpc/serializer).
:::
diff --git a/apps/content/docs/adapters/next.md b/apps/content/docs/adapters/next.md
deleted file mode 100644
index ec67e3b81..000000000
--- a/apps/content/docs/adapters/next.md
+++ /dev/null
@@ -1,193 +0,0 @@
----
-title: Next.js Adapter
-description: Use oRPC inside an Next.js project
----
-
-# Next.js Adapter
-
-[Next.js](https://nextjs.org/) is a leading React framework for server-rendered apps. oRPC works with both the [App Router](https://nextjs.org/docs/app/getting-started/installation) and [Pages Router](https://nextjs.org/docs/pages/getting-started/installation). For additional context, refer to the [HTTP Adapter](/docs/adapters/http) guide.
-
-::: info
-oRPC also provides out-of-the-box support for [Server Action](/docs/server-action) with no additional configuration required.
-:::
-
-## Server
-
-You set up an oRPC server inside Next.js using its [Route Handlers](https://nextjs.org/docs/app/building-your-application/routing/route-handlers).
-
-::: code-group
-
-```ts [app/rpc/[[...rest]]/route.ts]
-import { RPCHandler } from '@orpc/server/fetch'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-async function handleRequest(request: Request) {
- const { response } = await handler.handle(request, {
- prefix: '/rpc',
- context: {}, // Provide initial context if needed
- })
-
- return response ?? new Response('Not found', { status: 404 })
-}
-
-export const HEAD = handleRequest
-export const GET = handleRequest
-export const POST = handleRequest
-export const PUT = handleRequest
-export const PATCH = handleRequest
-export const DELETE = handleRequest
-```
-
-:::
-
-::: info
-The `handler` can be any supported oRPC handler, such as [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or another custom handler.
-:::
-
-::: details Pages Router Support?
-
-```ts [pages/api/rpc/[[...rest]].ts]
-import { RPCHandler } from '@orpc/server/node'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-export const config = {
- api: {
- bodyParser: false,
- },
-}
-
-export default async (req, res) => {
- const { matched } = await handler.handle(req, res, {
- prefix: '/api/rpc',
- context: {}, // Provide initial context if needed
- })
-
- if (matched) {
- return
- }
-
- res.statusCode = 404
- res.end('Not found')
-}
-```
-
-::: warning
-Next.js [body parser](https://nextjs.org/docs/pages/building-your-application/routing/api-routes#custom-config) may handle common request body types, and oRPC will use the parsed body if available. However, it doesn't support features like [Bracket Notation](/docs/openapi/bracket-notation), and in case you upload a file with `application/json`, it may be parsed as plain JSON instead of a `File`. To avoid these issues, disable the body parser:
-
-```ts
-export const config = {
- api: {
- bodyParser: false,
- },
-}
-```
-
-:::
-
-## Client
-
-By leveraging `headers` from `next/headers`, you can configure the RPC link to work seamlessly in both browser and server environments:
-
-```ts [lib/orpc.ts]
-import { RPCLink } from '@orpc/client/fetch'
-
-const link = new RPCLink({
- url: `${typeof window !== 'undefined' ? window.location.origin : 'http://localhost:3000'}/rpc`,
- headers: async () => {
- if (typeof window !== 'undefined') {
- return {}
- }
-
- const { headers } = await import('next/headers')
- return await headers()
- },
-})
-```
-
-:::info
-This only shows how to configure the link. For full client examples, see [Client-Side Clients](/docs/client/client-side).
-:::
-
-## Optimize SSR
-
-To reduce HTTP requests and improve latency during SSR, you can utilize a [Server-Side Client](/docs/client/server-side) during SSR. Below is a quick setup, see [Optimize SSR](/docs/best-practices/optimize-ssr) for more details.
-
-::: code-group
-
-```ts [lib/orpc.ts]
-import type { RouterClient } from '@orpc/server'
-import { RPCLink } from '@orpc/client/fetch'
-import { createORPCClient } from '@orpc/client'
-
-declare global {
- var $client: RouterClient | undefined
-}
-
-const link = new RPCLink({
- url: () => {
- if (typeof window === 'undefined') {
- throw new Error('RPCLink is not allowed on the server side.')
- }
-
- return `${window.location.origin}/rpc`
- },
-})
-
-/**
- * Fallback to client-side client if server-side client is not available.
- */
-export const client: RouterClient = globalThis.$client ?? createORPCClient(link)
-```
-
-```ts [lib/orpc.server.ts]
-import 'server-only'
-
-import { headers } from 'next/headers'
-import { createRouterClient } from '@orpc/server'
-
-globalThis.$client = createRouterClient(router, {
- /**
- * Provide initial context if needed.
- *
- * Because this client instance is shared across all requests,
- * only include context that's safe to reuse globally.
- * For per-request context, use middleware context or pass a function as the initial context.
- */
- context: async () => ({
- headers: await headers(), // provide headers if initial context required
- }),
-})
-```
-
-```ts [instrumentation.ts]
-export async function register() {
- // Conditionally import if facing runtime compatibility issues
- // if (process.env.NEXT_RUNTIME === "nodejs") {
- await import('./lib/orpc.server')
- // }
-}
-```
-
-```ts [app/layout.tsx]
-import '../lib/orpc.server' // for pre-rendering
-
-// Rest of the code
-```
-
-:::
diff --git a/apps/content/docs/adapters/node-http.md b/apps/content/docs/adapters/node-http.md
new file mode 100644
index 000000000..a1c125703
--- /dev/null
+++ b/apps/content/docs/adapters/node-http.md
@@ -0,0 +1,134 @@
+# Node HTTP Adapter
+
+oRPC supports [Node HTTP](https://nodejs.org/api/http.html), [Node HTTPS](https://nodejs.org/api/https.html), and [Node HTTP2](https://nodejs.org/api/http2.html) for servers.
+
+## Server Usage
+
+::: code-group
+
+```ts [RPC]
+import { createServer } from 'node:http' // or 'node:https' or 'node:http2'
+import { RPCHandler } from '@orpc/server/node'
+import { CORSHandlerPlugin } from '@orpc/server/plugins'
+import { onError } from '@orpc/server'
+
+const handler = new RPCHandler(router, {
+ plugins: [
+ new CORSHandlerPlugin()
+ ],
+ interceptors: [
+ onError((error) => {
+ console.error(error)
+ }),
+ ],
+})
+
+const server = createServer(async (req, res) => {
+ const { matched } = await handler.handle(req, res, {
+ prefix: '/rpc',
+ context: {} // Provide initial context if needed
+ })
+
+ if (matched) {
+ return
+ }
+
+ res.statusCode = 404
+ res.end('Not found')
+})
+
+server.listen(3000, '127.0.0.1', () => console.log('Listening on 127.0.0.1:3000'))
+```
+
+```ts [OpenAPI]
+import { createServer } from 'node:http' // or 'node:https' or 'node:http2'
+import { OpenAPIHandler } from '@orpc/openapi/node'
+import { CORSHandlerPlugin } from '@orpc/server/plugins'
+import { onError } from '@orpc/server'
+
+const handler = new OpenAPIHandler(router, {
+ plugins: [
+ new CORSHandlerPlugin()
+ ],
+ interceptors: [
+ onError((error) => {
+ console.error(error)
+ }),
+ ],
+})
+
+const server = createServer(async (req, res) => {
+ const { matched } = await handler.handle(req, res, {
+ prefix: '/api',
+ context: {} // Provide initial context if needed
+ })
+
+ if (matched) {
+ return
+ }
+
+ res.statusCode = 404
+ res.end('Not found')
+})
+
+server.listen(3000, '127.0.0.1', () => console.log('Listening on 127.0.0.1:3000'))
+```
+
+:::
+
+
+
+## Event Stream Options
+
+You can configure how [event iterators](/docs/event-iterator) are streamed to the client using the `sendStandardResponse.eventStream` options when creating the handler.
+
+```ts
+const handler = new OpenAPIHandler(router, {
+ sendStandardResponse: {
+ eventStream: {
+ initialComment: {
+ /**
+ * If true, an initial comment is sent immediately upon stream start to flush headers.
+ * This allows the receiving side to establish the connection without waiting for the first event.
+ *
+ * @default true
+ */
+ enabled: true,
+ /**
+ * The content of the initial comment sent upon stream start. Must not include newline characters.
+ *
+ * @default ''
+ */
+ comment: '',
+ },
+ keepAlive: {
+ /**
+ * If true, a ping comment is sent periodically to keep the connection alive.
+ *
+ * @default true
+ */
+ enabled: true,
+ /**
+ * Interval (in milliseconds) between ping comments sent after the last event.
+ *
+ * @default 5000
+ */
+ interval: 5000,
+ /**
+ * The content of the ping comment. Must not include newline characters.
+ *
+ * @default ''
+ */
+ comment: '',
+ },
+ /**
+ * If true, a `close` event is sent even when the iterator completes with `undefined`.
+ * When the iterator returns a value, a `close` event is always emitted regardless of this setting.
+ *
+ * @default true
+ */
+ emptyCloseEventEnabled: true,
+ },
+ },
+})
+```
diff --git a/apps/content/docs/adapters/nuxt.md b/apps/content/docs/adapters/nuxt.md
deleted file mode 100644
index 54c62b76b..000000000
--- a/apps/content/docs/adapters/nuxt.md
+++ /dev/null
@@ -1,123 +0,0 @@
----
-title: Nuxt.js Adapter
-description: Use oRPC inside an Nuxt.js project
----
-
-# Nuxt.js Adapter
-
-[Nuxt.js](https://nuxt.com/) is a popular Vue.js framework for building server-side applications. For more details, see the [HTTP Adapter](/docs/adapters/http) guide.
-
-## Server
-
-You set up an oRPC server inside Nuxt using its [Server Routes](https://nuxt.com/docs/guide/directory-structure/server#server-routes).
-
-::: code-group
-
-```ts [server/routes/rpc/[...].ts]
-import { RPCHandler } from '@orpc/server/fetch'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-export default defineEventHandler(async (event) => {
- const request = toWebRequest(event)
-
- const { response } = await handler.handle(request, {
- prefix: '/rpc',
- context: {}, // Provide initial context if needed
- })
-
- if (response) {
- return response
- }
-
- setResponseStatus(event, 404, 'Not Found')
- return 'Not found'
-})
-```
-
-```ts [server/routes/rpc/index.ts]
-export { default } from './[...]'
-```
-
-:::
-
-::: info
-The `handler` can be any supported oRPC handler, such as [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or another custom handler.
-:::
-
-## Client
-
-To make the oRPC client compatible with SSR, set it up inside a [Nuxt Plugin](https://nuxt.com/docs/guide/directory-structure/plugins).
-
-```ts [app/plugins/orpc.ts]
-export default defineNuxtPlugin(() => {
- const event = useRequestEvent()
-
- const link = new RPCLink({
- url: `${typeof window !== 'undefined' ? window.location.origin : 'http://localhost:3000'}/rpc`,
- headers: event?.headers,
- })
-
- const client: RouterClient = createORPCClient(link)
-
- return {
- provide: {
- client,
- },
- }
-})
-```
-
-:::info
-You can learn more about client setup in [Client-Side Clients](/docs/client/client-side).
-:::
-
-## Optimize SSR
-
-To reduce HTTP requests and improve latency during SSR, you can utilize a [Server-Side Client](/docs/client/server-side) during SSR. Below is a quick setup, see [Optimize SSR](/docs/best-practices/optimize-ssr) for more details.
-
-::: code-group
-
-```ts [app/plugins/orpc.client.ts]
-export default defineNuxtPlugin(() => {
- const link = new RPCLink({
- url: `${window.location.origin}/rpc`,
- headers: () => ({}),
- })
-
- const client: RouterClient = createORPCClient(link)
-
- return {
- provide: {
- client,
- },
- }
-})
-```
-
-```ts [app/plugins/orpc.server.ts]
-export default defineNuxtPlugin((nuxt) => {
- const event = useRequestEvent()
-
- const client = createRouterClient(router, {
- context: {
- headers: event?.headers, // provide headers if initial context required
- },
- })
-
- return {
- provide: {
- client,
- },
- }
-})
-```
-
-:::
diff --git a/apps/content/docs/adapters/react-native.md b/apps/content/docs/adapters/react-native.md
deleted file mode 100644
index d64ca8098..000000000
--- a/apps/content/docs/adapters/react-native.md
+++ /dev/null
@@ -1,59 +0,0 @@
----
-title: React Native Adapter
-description: Use oRPC inside a React Native project
----
-
-# React Native Adapter
-
-[React Native](https://reactnative.dev/) is a framework for building native apps using React. For additional context, refer to the [HTTP Adapter](/docs/adapters/http) guide.
-
-## Fetch Link
-
-React Native includes a [Fetch API](https://reactnative.dev/docs/network), so you can use oRPC out of the box.
-
-::: warning
-However, the Fetch API in React Native has limitations. oRPC features like [File/Blob](/docs/file-upload-download), and [Event Iterator](/docs/event-iterator) aren't supported. Follow [Support Stream #27741](https://github.com/facebook/react-native/issues/27741) for updates.
-:::
-
-::: tip
-If you're using `RPCHandler/Link`, you can temporarily add support for binary data by extending the [RPC JSON Serializer](/docs/advanced/rpc-json-serializer#extending-native-data-types) to encode these types as Base64.
-:::
-
-```ts
-import { RPCLink } from '@orpc/client/fetch'
-
-const link = new RPCLink({
- url: 'http://localhost:3000/rpc',
- headers: async ({ context }) => ({
- 'x-api-key': context?.something ?? ''
- })
- // fetch: <-- polyfill fetch if needed
-})
-```
-
-::: info
-The `link` can be any supported oRPC link, such as [RPCLink](/docs/client/rpc-link), [OpenAPILink](/docs/openapi/client/openapi-link), or another custom link.
-:::
-
-### `expo/fetch`
-
-If you're using [Expo](https://expo.dev/), you can use the [`expo/fetch`](https://docs.expo.dev/versions/latest/sdk/expo/#expofetch-api) to expand support for [Event Iterator](/docs/event-iterator).
-
-```ts
-export const link = new RPCLink({
- url: `http://localhost:3000/rpc`,
- async fetch(request, init) {
- const { fetch } = await import('expo/fetch')
-
- const resp = await fetch(request.url, {
- body: await request.blob(),
- headers: request.headers,
- method: request.method,
- signal: request.signal,
- ...init,
- })
-
- return resp
- },
-})
-```
diff --git a/apps/content/docs/adapters/remix.md b/apps/content/docs/adapters/remix.md
deleted file mode 100644
index e1a0a8937..000000000
--- a/apps/content/docs/adapters/remix.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-title: Remix Adapter
-description: Use oRPC inside an Remix project
----
-
-# Remix Adapter
-
-[Remix](https://remix.run/) is a full stack JavaScript framework for building web applications with React. For additional context, refer to the [HTTP Adapter](/docs/adapters/http) guide.
-
-## Basic
-
-```ts [app/routes/rpc.$.ts]
-import { RPCHandler } from '@orpc/server/fetch'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-export async function loader({ request }: LoaderFunctionArgs) {
- const { response } = await handler.handle(request, {
- prefix: '/rpc',
- context: {} // Provide initial context if needed
- })
-
- return response ?? new Response('Not Found', { status: 404 })
-}
-```
-
-::: info
-The `handler` can be any supported oRPC handler, such as [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or another custom handler.
-:::
diff --git a/apps/content/docs/adapters/solid-start.md b/apps/content/docs/adapters/solid-start.md
deleted file mode 100644
index d7467bb8f..000000000
--- a/apps/content/docs/adapters/solid-start.md
+++ /dev/null
@@ -1,140 +0,0 @@
----
-title: Solid Start Adapter
-description: Use oRPC inside a Solid Start project
----
-
-# Solid Start Adapter
-
-[Solid Start](https://start.solidjs.com/) is a full stack JavaScript framework for building web applications with SolidJS. For additional context, refer to the [HTTP Adapter](/docs/adapters/http) guide.
-
-## Server
-
-::: code-group
-
-```ts [src/routes/rpc/[...rest].ts]
-import type { APIEvent } from '@solidjs/start/server'
-import { RPCHandler } from '@orpc/server/fetch'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-async function handle({ request }: APIEvent) {
- const { response } = await handler.handle(request, {
- prefix: '/rpc',
- context: {} // Provide initial context if needed
- })
-
- return response ?? new Response('Not Found', { status: 404 })
-}
-
-export const HEAD = handle
-export const GET = handle
-export const POST = handle
-export const PUT = handle
-export const PATCH = handle
-export const DELETE = handle
-```
-
-```ts [src/routes/rpc/index.ts]
-import { POST as handle } from './[...rest]'
-
-export const HEAD = handle
-export const GET = handle
-export const POST = handle
-export const PUT = handle
-export const PATCH = handle
-export const DELETE = handle
-```
-
-:::
-
-::: info
-The `handler` can be any supported oRPC handler, such as [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or another custom handler.
-:::
-
-## Client
-
-On the client, use `getRequestEvent` to provide a headers function that works seamlessly with SSR. This enables usage in both server and browser environments.
-
-```ts
-import { RPCLink } from '@orpc/client/fetch'
-import { getRequestEvent } from 'solid-js/web'
-
-const link = new RPCLink({
- url: `${typeof window !== 'undefined' ? window.location.origin : 'http://localhost:3000'}/rpc`,
- headers: () => getRequestEvent()?.request.headers ?? {},
-})
-```
-
-:::info
-This only shows how to configure the link. For full client examples, see [Client-Side Clients](/docs/client/client-side).
-:::
-
-## Optimize SSR
-
-To reduce HTTP requests and improve latency during SSR, you can utilize a [Server-Side Client](/docs/client/server-side) during SSR. Below is a quick setup, see [Optimize SSR](/docs/best-practices/optimize-ssr) for more details.
-
-::: code-group
-
-```ts [src/lib/orpc.ts]
-if (typeof window === 'undefined') {
- await import('./orpc.server')
-}
-
-import type { RouterClient } from '@orpc/server'
-import { RPCLink } from '@orpc/client/fetch'
-import { createORPCClient } from '@orpc/client'
-
-declare global {
- var $client: RouterClient | undefined
-}
-
-const link = new RPCLink({
- url: () => {
- if (typeof window === 'undefined') {
- throw new Error('RPCLink is not allowed on the server side.')
- }
-
- return `${window.location.origin}/rpc`
- },
-})
-
-/**
- * Fallback to client-side client if server-side client is not available.
- */
-export const client: RouterClient = globalThis.$client ?? createORPCClient(link)
-```
-
-```ts [src/lib/orpc.server.ts]
-import { createRouterClient } from '@orpc/server'
-import { getRequestEvent } from 'solid-js/web'
-
-if (typeof window !== 'undefined') {
- throw new Error('This file should not be imported in the browser')
-}
-
-globalThis.$client = createRouterClient(router, {
- /**
- * Provide initial context if needed.
- *
- * Because this client instance is shared across all requests,
- * only include context that's safe to reuse globally.
- * For per-request context, use middleware context or pass a function as the initial context.
- */
- context: async () => {
- const headers = getRequestEvent()?.request.headers
-
- return {
- headers, // provide headers if initial context required
- }
- },
-})
-```
-
-:::
diff --git a/apps/content/docs/adapters/svelte-kit.md b/apps/content/docs/adapters/svelte-kit.md
deleted file mode 100644
index 556efb939..000000000
--- a/apps/content/docs/adapters/svelte-kit.md
+++ /dev/null
@@ -1,105 +0,0 @@
----
-title: Svelte Kit Adapter
-description: Use oRPC inside an Svelte Kit project
----
-
-# Svelte Kit Adapter
-
-[Svelte Kit](https://svelte.dev/docs/kit/introduction) is a framework for rapidly developing robust, performant web applications using Svelte. For additional context, refer to the [HTTP Adapter](/docs/adapters/http) guide.
-
-## Server
-
-::: code-group
-
-```ts [src/routes/rpc/[...rest]/+server.ts]
-import { error } from '@sveltejs/kit'
-import { RPCHandler } from '@orpc/server/fetch'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-const handle: RequestHandler = async ({ request }) => {
- const { response } = await handler.handle(request, {
- prefix: '/rpc',
- context: {} // Provide initial context if needed
- })
-
- return response ?? new Response('Not Found', { status: 404 })
-}
-
-export const GET = handle
-export const POST = handle
-export const PUT = handle
-export const PATCH = handle
-export const DELETE = handle
-```
-
-:::
-
-::: info
-The `handler` can be any supported oRPC handler, such as [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or another custom handler.
-:::
-
-## Optimize SSR
-
-To reduce HTTP requests and improve latency during SSR, you can utilize [Svelte's special `fetch`](https://svelte.dev/docs/kit/web-standards#Fetch-APIs) during SSR. Below is a quick setup, see [Optimize SSR](/docs/best-practices/optimize-ssr) for more details.
-
-::: code-group
-
-```ts [src/lib/orpc.ts]
-import type { RouterClient } from '@orpc/server'
-import { RPCLink } from '@orpc/client/fetch'
-import { createORPCClient } from '@orpc/client'
-
-declare global {
- var $client: RouterClient | undefined
-}
-
-const link = new RPCLink({
- url: () => {
- if (typeof window === 'undefined') {
- throw new Error('This link is not allowed on the server side.')
- }
-
- return `${window.location.origin}/rpc`
- },
-})
-
-export const client: RouterClient = globalThis.$client ?? createORPCClient(link)
-```
-
-```ts [src/lib/orpc.server.ts]
-import type { RouterClient } from '@orpc/server'
-import { createORPCClient } from '@orpc/client'
-import { RPCLink } from '@orpc/client/fetch'
-import { getRequestEvent } from '$app/server'
-
-if (typeof window !== 'undefined') {
- throw new Error('This file should only be imported on the server')
-}
-
-const link = new RPCLink({
- url: async () => {
- return `${getRequestEvent().url.origin}/rpc`
- },
- async fetch(request, init) {
- return getRequestEvent().fetch(request, init)
- },
-})
-
-const serverClient: RouterClient = createORPCClient(link)
-globalThis.$client = serverClient
-```
-
-```ts [src/hooks.server.ts]
-import './lib/orpc.server'
-// ...
-```
-
-:::
diff --git a/apps/content/docs/adapters/tanstack-start.md b/apps/content/docs/adapters/tanstack-start.md
deleted file mode 100644
index 80a242035..000000000
--- a/apps/content/docs/adapters/tanstack-start.md
+++ /dev/null
@@ -1,112 +0,0 @@
----
-title: TanStack Start Adapter
-description: Use oRPC inside a TanStack Start project
----
-
-# TanStack Start Adapter
-
-[TanStack Start](https://tanstack.com/start) is a full-stack React framework built on [Vite](https://vitejs.dev/) and the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). For additional context, see the [HTTP Adapter](/docs/adapters/http) guide.
-
-## Server
-
-You set up an oRPC server inside TanStack Start using its [Server Routes](https://tanstack.com/start/latest/docs/framework/react/guide/server-routes).
-
-::: code-group
-
-```ts [src/routes/api/rpc.$.ts]
-import { RPCHandler } from '@orpc/server/fetch'
-import { createFileRoute } from '@tanstack/react-router'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-export const Route = createFileRoute('/api/rpc/$')({
- server: {
- handlers: {
- ANY: async ({ request }) => {
- const { response } = await handler.handle(request, {
- prefix: '/api/rpc',
- context: {}, // Provide initial context if needed
- })
-
- return response ?? new Response('Not Found', { status: 404 })
- },
- },
- },
-})
-```
-
-:::
-
-::: info
-The `handler` can be any supported oRPC handler, including [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or a custom handler.
-:::
-
-## Client
-
-Use `createIsomorphicFn` to configure the RPC link with environment-specific settings for both browser and SSR environments:
-
-```ts
-import { RPCLink } from '@orpc/client/fetch'
-import { createIsomorphicFn } from '@tanstack/react-start'
-import { getRequestHeaders } from '@tanstack/react-start/server'
-
-const getClientLink = createIsomorphicFn()
- .client(() => new RPCLink({
- url: `${window.location.origin}/api/rpc`,
- }))
- .server(() => new RPCLink({
- url: 'http://localhost:3000/api/rpc',
- headers: () => getRequestHeaders(),
- }))
-```
-
-:::info
-This only shows how to configure the link. For full client examples, see [Client-Side Clients](/docs/client/client-side).
-:::
-
-## Optimize SSR
-
-To reduce HTTP requests and improve latency during SSR, you can utilize a [Server-Side Client](/docs/client/server-side) during SSR. Below is a quick setup, see [Optimize SSR](/docs/best-practices/optimize-ssr) for more details.
-
-::: code-group
-
-```ts [src/lib/orpc.ts]
-import { createRouterClient } from '@orpc/server'
-import type { RouterClient } from '@orpc/server'
-import { createORPCClient } from '@orpc/client'
-import { RPCLink } from '@orpc/client/fetch'
-import { getRequestHeaders } from '@tanstack/react-start/server'
-import { createIsomorphicFn } from '@tanstack/react-start'
-
-const getORPCClient = createIsomorphicFn()
- .server(() => createRouterClient(router, {
- /**
- * Provide initial context if needed.
- *
- * Because this client instance is shared across all requests,
- * only include context that's safe to reuse globally.
- * For per-request context, use middleware context or pass a function as the initial context.
- */
- context: async () => ({
- headers: getRequestHeaders(), // provide headers if initial context required
- }),
- }))
- .client((): RouterClient => {
- const link = new RPCLink({
- url: `${window.location.origin}/api/rpc`,
- })
-
- return createORPCClient(link)
- })
-
-export const client: RouterClient = getORPCClient()
-```
-
-:::
diff --git a/apps/content/docs/adapters/web-workers.md b/apps/content/docs/adapters/web-workers.md
deleted file mode 100644
index 5e574e030..000000000
--- a/apps/content/docs/adapters/web-workers.md
+++ /dev/null
@@ -1,61 +0,0 @@
----
-title: Web Workers Adapter
-description: Enable type-safe communication with Web Workers using oRPC.
----
-
-# Web Workers Adapter
-
-[Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Worker) allow JavaScript code to run in background threads, separate from the main thread of a web page. This prevents blocking the UI while performing computationally intensive tasks. Web Workers are also supported in modern runtimes like [Bun](https://bun.com/docs/api/workers), [Deno](https://docs.deno.com/examples/web_workers/), etc.
-
-With oRPC, you can establish type-safe communication channels between your main thread and Web Workers. For additional context, see the [Message Port Adapter](/docs/adapters/message-port) guide.
-
-## Web Worker
-
-Configure your Web Worker to handle oRPC requests by upgrading it with a message port handler:
-
-```ts
-import { RPCHandler } from '@orpc/server/message-port'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-handler.upgrade(self, {
- context: {}, // Provide initial context if needed
-})
-```
-
-## Main Thread
-
-Create a link to communicate with your Web Worker:
-
-```ts
-import { RPCLink } from '@orpc/client/message-port'
-
-export const link = new RPCLink({
- port: new Worker('some-worker.ts')
-})
-```
-
-:::details Using Web Workers in Vite Applications?
-You can leverage [Vite Web Workers feature](https://vite.dev/guide/features.html#web-workers) for streamlined development:
-
-```ts
-import SomeWorker from './some-worker.ts?worker' // [!code highlight]
-import { RPCLink } from '@orpc/client/message-port'
-
-export const link = new RPCLink({
- port: new SomeWorker()
-})
-```
-
-:::
-
-:::info
-This only shows how to configure the link. For full client examples, see [Client-Side Clients](/docs/client/client-side).
-:::
diff --git a/apps/content/docs/adapters/websocket.md b/apps/content/docs/adapters/websocket.md
index 8496bd0ea..93df42685 100644
--- a/apps/content/docs/adapters/websocket.md
+++ b/apps/content/docs/adapters/websocket.md
@@ -1,24 +1,18 @@
----
-title: Websocket
-description: How to use oRPC over WebSocket?
----
+# WebSocket Adapters
-# Websocket
-
-oRPC provides built-in WebSocket support for low-latency, bidirectional RPC.
+oRPC supports WebSockets for low-latency, full-duplex communication between clients and servers.
## Server Adapters
-| Adapter | Target |
-| ----------- | ------------------------------------------------------------------------------------------------------------------------ |
-| `websocket` | [MDN WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) (Browser, Deno, Cloudflare Worker, etc.) |
-| `crossws` | [Crossws](https://github.com/h3js/crossws) library (Node, Bun, Deno, SSE, etc.) |
-| `ws` | [ws](https://github.com/websockets/ws) library (Node.js) |
-| `bun-ws` | [Bun Websocket Server](https://bun.sh/docs/api/websockets) |
+| Adapter | Target |
+| ----------- | ----------------------------------------------------------------------------------------------------------------------- |
+| `websocket` | [MDN WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket), [ws](https://github.com/websockets/ws) |
+| `crossws` | [crossws](https://github.com/h3js/crossws) |
::: code-group
-```ts [Websocket]
+```ts [ws]
+import { WebSocketServer } from 'ws'
import { RPCHandler } from '@orpc/server/websocket'
import { onError } from '@orpc/server'
@@ -30,22 +24,21 @@ const handler = new RPCHandler(router, {
],
})
-Deno.serve((req) => {
- if (req.headers.get('upgrade') !== 'websocket') {
- return new Response(null, { status: 501 })
- }
-
- const { socket, response } = Deno.upgradeWebSocket(req)
+const wss = new WebSocketServer({ port: 8080 })
- handler.upgrade(socket, {
- context: {}, // Provide initial context if needed
+wss.on('connection', (ws) => {
+ handler.upgrade(ws, {
+ /**
+ * Provide initial context if needed. The context can be an async function
+ * that receives the per-call request as its first argument, and is **not**
+ * related to the initial WebSocket upgrade request.
+ */
+ context: request => ({}),
})
-
- return response
})
```
-```ts [CrossWS]
+```ts [crossws]
import { createServer } from 'node:http'
import { experimental_RPCHandler as RPCHandler } from '@orpc/server/crossws'
import { onError } from '@orpc/server'
@@ -65,7 +58,12 @@ const ws = crossws({
hooks: {
message: (peer, message) => {
handler.message(peer, message, {
- context: {}, // Provide initial context if needed
+ /**
+ * Provide initial context if needed. The context can be an async function
+ * that receives the per-call request as its first argument, and is **not**
+ * related to the initial WebSocket upgrade request.
+ */
+ context: request => ({}),
})
},
close: (peer) => {
@@ -85,9 +83,8 @@ server.on('upgrade', (req, socket, head) => {
})
```
-```ts [WS]
-import { WebSocketServer } from 'ws'
-import { RPCHandler } from '@orpc/server/ws'
+```ts [Deno]
+import { RPCHandler } from '@orpc/server/websocket'
import { onError } from '@orpc/server'
const handler = new RPCHandler(router, {
@@ -98,49 +95,27 @@ const handler = new RPCHandler(router, {
],
})
-const wss = new WebSocketServer({ port: 8080 })
-
-wss.on('connection', (ws) => {
- handler.upgrade(ws, {
- context: {}, // Provide initial context if needed
- })
-})
-```
-
-```ts [Bun WebSocket]
-import { RPCHandler } from '@orpc/server/bun-ws'
-import { onError } from '@orpc/server'
+Deno.serve((req) => {
+ if (req.headers.get('upgrade') !== 'websocket') {
+ return new Response(null, { status: 501 })
+ }
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
+ const { socket, response } = Deno.upgradeWebSocket(req)
-Bun.serve({
- fetch(req, server) {
- if (server.upgrade(req)) {
- return
- }
+ handler.upgrade(socket, {
+ /**
+ * Provide initial context if needed. The context can be an async function
+ * that receives the per-call request as its first argument, and is **not**
+ * related to the initial WebSocket upgrade request.
+ */
+ context: request => ({}),
+ })
- return new Response('Upgrade failed', { status: 500 })
- },
- websocket: {
- message(ws, message) {
- handler.message(ws, message, {
- context: {}, // Provide initial context if needed
- })
- },
- close(ws) {
- handler.close(ws)
- },
- },
+ return response
})
```
-```ts [Websocket Hibernation]
+```ts [Cloudflare Websocket Hibernation]
import { RPCHandler } from '@orpc/server/websocket'
import { onError } from '@orpc/server'
@@ -166,7 +141,12 @@ export class ChatRoom extends DurableObject {
async webSocketMessage(ws: WebSocket, message: string | ArrayBuffer): Promise {
await handler.message(ws, message, {
- context: {}, // Provide initial context if needed
+ /**
+ * Provide initial context if needed. The context can be an async function
+ * that receives the per-call request as its first argument, and is **not**
+ * related to the initial WebSocket upgrade request.
+ */
+ context: request => ({}),
})
}
@@ -178,30 +158,84 @@ export class ChatRoom extends DurableObject {
:::
-::: info
-[Hibernation Plugin](/docs/plugins/hibernation) helps you fully leverage Hibernation APIs, making it especially useful for adapters like [Cloudflare Websocket Hibernation](https://developers.cloudflare.com/durable-objects/examples/websocket-hibernation-server/).
-:::
-
## Client Adapters
-| Adapter | Target |
-| ----------- | ---------------------------------------------------------------------------------------------------------------- |
-| `websocket` | [MDN WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) (Browser, Node, Bun, Deno, etc.) |
+| Adapter | Target |
+| ----------- | ------------------------------------------------------------------------------- |
+| `websocket` | [MDN WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) |
```ts
import { RPCLink } from '@orpc/client/websocket'
-const websocket = new WebSocket('ws://localhost:3000')
-
const link = new RPCLink({
- websocket
+ connect: info => new WebSocket('ws://localhost:3000'),
+ /**
+ * Whether to connect immediately on initialization, instead of waiting
+ * for the first call. Reduces latency for the first request.
+ *
+ * @default false
+ */
+ connectOnInit: true,
+
+ /**
+ * Optional headers to attach to each per-call request.
+ * These can be accessed in the server context or via the Request Headers Plugin.
+ */
+ headers: () => ({})
})
```
-::: tip
-Use [partysocket](https://www.npmjs.com/package/partysocket) library for manually/automatically reconnect logic.
+::: info
+The examples above only show how to configure the link. For examples of creating a typesafe client, see [RPC Link](/docs/rpc/link#typesafe-clients).
:::
-:::info
-This only shows how to configure the WebSocket link. For full client examples, see [Client-Side Clients](/docs/client/client-side).
-:::
+### Auto Reconnect
+
+The client adapter has built-in support for reconnecting when the connection is lost. You can configure reconnect behavior with the `reconnect` option when creating the link.
+
+```ts
+const link = new RPCLink({
+ reconnect: {
+ /**
+ * Whether to automatically reconnect when the connection is lost.
+ *
+ * @default false
+ */
+ enabled: true,
+
+ /**
+ * Delay before a (re)connect attempt, in milliseconds.
+ *
+ * @default info => info.attempt === 1 ? 0 : 2_000
+ */
+ delay: info => info.attempt === 1 ? 0 : 2_000,
+
+ /**
+ * Maximum number of consecutive failed attempts before giving up.
+ * When exceeded, `getConnectedPeer` throws instead of retrying.
+ * Should greater than 1
+ *
+ * @default Infinity
+ */
+ maxAttempt: Infinity,
+
+ onClose: {
+ /**
+ * Whether to proactively reconnect right after the socket closes,
+ * rather than waiting for the next call to trigger reconnection.
+ * Reduces latency for the next request.
+ *
+ * @default false
+ */
+ enabled: false,
+
+ /**
+ * Delay before reconnecting after the socket closes, in milliseconds.
+ *
+ * @default 0
+ */
+ delay: 0
+ }
+ }
+})
+```
diff --git a/apps/content/docs/adapters/worker-threads.md b/apps/content/docs/adapters/worker-threads.md
deleted file mode 100644
index bcc002f7e..000000000
--- a/apps/content/docs/adapters/worker-threads.md
+++ /dev/null
@@ -1,61 +0,0 @@
----
-title: Worker Threads Adapter
-description: Enable type-safe communication between Node.js Worker Threads using oRPC.
----
-
-# Worker Threads Adapter
-
-Use [Node.js Worker Threads](https://nodejs.org/api/worker_threads.html) with oRPC for type-safe inter-thread communication via the [Message Port Adapter](/docs/adapters/message-port). Before proceeding, we recommend reviewing the [Node.js Worker Thread API](https://nodejs.org/api/worker_threads.html).
-
-## Worker Thread
-
-Listen for a `MessagePort` sent from the main thread and upgrade it:
-
-```ts
-import { parentPort } from 'node:worker_threads'
-import { RPCHandler } from '@orpc/server/message-port'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-parentPort.on('message', (message) => {
- if (message instanceof MessagePort) {
- handler.upgrade(message, {
- context: {}, // Provide initial context if needed
- })
-
- message.start()
- }
-})
-```
-
-## Main Thread
-
-Create a `MessageChannel`, send one port to the thread worker, and use the other to initialize the client link:
-
-```ts
-import { MessageChannel, Worker } from 'node:worker_threads'
-import { RPCLink } from '@orpc/client/message-port'
-
-const { port1: clientPort, port2: serverPort } = new MessageChannel()
-
-const worker = new Worker('some-worker.js')
-
-worker.postMessage(serverPort, [serverPort])
-
-const link = new RPCLink({
- port: clientPort
-})
-
-clientPort.start()
-```
-
-:::info
-This only shows how to configure the link. For full client examples, see [Client-Side Clients](/docs/client/client-side).
-:::
diff --git a/apps/content/docs/advanced/building-custom-plugins.md b/apps/content/docs/advanced/building-custom-plugins.md
deleted file mode 100644
index 3d867370a..000000000
--- a/apps/content/docs/advanced/building-custom-plugins.md
+++ /dev/null
@@ -1,109 +0,0 @@
----
-title: Building Custom Plugins
-description: Create powerful custom plugins to extend oRPC handlers and links with interceptors.
----
-
-# Building Custom Plugins
-
-This guide explains how to create custom oRPC plugins for handlers and links.
-
-## What is a Plugin?
-
-In oRPC, a plugin is a collection of `interceptors` that can work together or independently.
-
-```ts
-export class ResponseHeadersPlugin implements StandardHandlerPlugin {
- init(options: StandardHandlerOptions): void {
- options.rootInterceptors ??= []
-
- options.rootInterceptors.push(async (interceptorOptions) => {
- const resHeaders = interceptorOptions.context.resHeaders ?? new Headers()
-
- const result = await interceptorOptions.next({
- ...interceptorOptions,
- context: {
- ...interceptorOptions.context,
- resHeaders,
- },
- })
-
- if (!result.matched) {
- return result
- }
-
- const responseHeaders = clone(result.response.headers)
-
- for (const [key, value] of resHeaders) {
- if (Array.isArray(responseHeaders[key])) {
- responseHeaders[key].push(value)
- }
- else if (responseHeaders[key] !== undefined) {
- responseHeaders[key] = [responseHeaders[key], value]
- }
- else {
- responseHeaders[key] = value
- }
- }
-
- return {
- ...result,
- response: {
- ...result.response,
- headers: responseHeaders,
- },
- }
- })
- }
-}
-```
-
-Above is a snippet from the [Response Headers Plugin](/docs/plugins/response-headers). It contains a single interceptor that injects `resHeaders` into the context and merges them with the response headers after the handler executes.
-
-### Handler Plugins
-
-Handler plugins extend the functionality of your server-side handlers. You can create plugins for [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or any custom handlers you've built.
-
-When building a handler plugin, you'll work with interceptors from the [Handler Lifecycle](/docs/rpc-handler#lifecycle). These interceptors let you hook into different stages of request processing - from initial request parsing to final response formatting.
-
-Check out the [built-in handler plugins](https://github.com/middleapi/orpc/tree/main/packages/server/src/plugins) to see real-world examples of how different plugins solve common server-side challenges.
-
-### Link Plugins
-
-Link plugins enhance your client-side communication. They work with [RPCLink](/docs/client/rpc-link), [OpenAPILink](/docs/openapi/client/openapi-link), or custom links you've implemented.
-
-Link plugins use interceptors from the [Link Lifecycle](/docs/client/rpc-link#lifecycle) to modify requests before they're sent or responses after they're received. This is perfect for adding authentication, logging, retry logic, or request/response transformations.
-
-Browse the [built-in link plugins](https://github.com/middleapi/orpc/tree/main/packages/client/src/plugins) for inspiration on handling common client-side scenarios.
-
-## Communication Between Interceptors
-
-Sometimes you need interceptors to share data. For example, one interceptor might collect information that another interceptor uses later. You can achieve this by injecting context using a unique symbol.
-
-The [Strict Get Method Plugin](/docs/plugins/strict-get-method) ([Source Code](https://github.com/middleapi/orpc/blob/main/packages/server/src/plugins/strict-get-method.ts)) demonstrates this pattern. It uses `rootInterceptors` to collect HTTP methods and combines this data with procedure information in `clientInterceptors` to determine whether the method is allowed.
-
-## Plugin Order
-
-```ts
-export class ExamplePlugin implements StandardHandlerPlugin {
- order = 10 // [!code highlight]
-
- init(options: StandardHandlerOptions): void {
- options.rootInterceptors ??= []
- options.clientInterceptors ??= []
-
- options.rootInterceptors.push(async ({ next }) => {
- return await next()
- })
-
- options.clientInterceptors.push(async ({ next }) => {
- return await next()
- })
- }
-}
-```
-
-The `order` property controls plugin loading order, not interceptor execution order. To ensure your interceptor runs earlier, set a higher order value and use `.unshift` to add your interceptor, or use `.push` if you want your interceptor to run later.
-
-::: warning
-In most cases, you **should not** define the `order` property unless you need your interceptors to always run before or after other interceptors. The `order` value should be less than `1_000_000` to avoid conflicts with built-in plugins.
-:::
diff --git a/apps/content/docs/advanced/exceeds-the-maximum-length-problem.md b/apps/content/docs/advanced/exceeds-the-maximum-length-problem.md
index d43cb8d70..38722c281 100644
--- a/apps/content/docs/advanced/exceeds-the-maximum-length-problem.md
+++ b/apps/content/docs/advanced/exceeds-the-maximum-length-problem.md
@@ -1,10 +1,7 @@
----
-title: Exceeds the Maximum Length Problem
-description: How to address the Exceeds the Maximum Length Problem in oRPC.
----
-
# Exceeds the Maximum Length Problem
+TypeScript may report this error when you export a large or complex [router](/docs/router). This is a known TypeScript limitation, not an oRPC bug. TypeScript enforces it to maintain reasonable editor and type-checking performance for large types.
+
```ts twoslash
// @error: The inferred type of this node exceeds the maximum length the compiler will serialize. An explicit type annotation is needed.
export const router = {
@@ -12,11 +9,9 @@ export const router = {
}
```
-Are you seeing this error? If so, congratulations! your project is now complex enough to encounter it!
-
-## Why It Happens
+## When It Happens
-This error is expected, not a bug. Typescript enforces this to keep your IDE suggestions fast. It appears when all three of these conditions are met:
+You usually see this error when all of the following are true:
1. Your project uses `"declaration": true` in `tsconfig.json`.
2. Your project is large or your types are very complex.
@@ -24,21 +19,30 @@ This error is expected, not a bug. Typescript enforces this to keep your IDE sug
## How to Fix It
-### 1. Disable `"declaration": true` in `tsconfig.json`
+### 1. Disable `"declaration": true`
-This is the simplest option, though it may not be ideal for your project.
+If you don't need this feature, disable this option in your `tsconfig.json`:
+
+```diff [tsconfig.json]
+ {
+ "compilerOptions": {
+-- "declaration": true,
+++ "declaration": false
+ }
+ }
+```
-### 2. Define the `.output` Type for Your Procedures
+### 2. Add Explicit Output Types
-By explicitly specifying the `.output` or your `handler's return type`, you enable TypeScript to infer the output without parsing the handler's code. This approach can dramatically enhance both type-checking and IDE-suggestion speed.
+Add `.output` or an explicit handler return type to your procedures. This lets TypeScript use the declared output shape instead of fully expanding the handler implementation, which often improves both type-checking and editor performance.
:::tip
Use the [type](/docs/procedure#type-utility) utility if you just want to specify the output type without validating the output.
:::
-### 3. Export the Router in Parts
+### 3. Split the Router into Smaller Exports
-Instead of exporting one large object on the server (with `"declaration": true`), export each router segment individually and merge them on the client (where `"declaration": false`):
+If you need `"declaration": true`, avoid exporting a single massive router object from the server. Instead, export smaller router segments and combine them on the client side, where `"declaration": false`:
```ts
export const userRouter = { /** ... */ }
@@ -46,7 +50,7 @@ export const planetRouter = { /** ... */ }
export const publicRouter = { /** ... */ }
```
-Then, on the client side:
+Then define the client type from those smaller exports:
```ts
interface Router {
diff --git a/apps/content/docs/advanced/expanding-type-support-for-openapi-link.md b/apps/content/docs/advanced/expanding-type-support-for-openapi-link.md
new file mode 100644
index 000000000..e3177d47e
--- /dev/null
+++ b/apps/content/docs/advanced/expanding-type-support-for-openapi-link.md
@@ -0,0 +1,84 @@
+# Expanding Type Support for OpenAPI Link
+
+Because of [OpenAPI Serializer limitations](/docs/openapi/serializer#limitations), values like `Date` and `bigint` are received by the client in JSON-friendly form. You can convert them back to native types on the client with either [Response Validation Plugin](/docs/plugins/response-validation) or [Smart Coercion Plugin](/docs/plugins/smart-coercion), but only under the conditions described below.
+
+## Choose a Plugin
+
+- Use [Response Validation Plugin](/docs/plugins/response-validation) when you want manual control over coercion logic and can define explicit coercion rules in your schemas.
+- Use [Smart Coercion Plugin](/docs/plugins/smart-coercion) when you want automatic coercion based on schema instead of defining coercion logic yourself.
+
+::: warning
+These plugins can only restore types that the [OpenAPI Serializer](/docs/openapi/serializer) can represent. If you need additional types, extend the serializer first.
+
+Nested `Blob` and `File` values are still limited by [Bracket Notation](/docs/openapi/bracket-notation#limitations).
+:::
+
+## Use Response Validation Plugin
+
+Use [Response Validation Plugin](/docs/plugins/response-validation) when you want to manually control how values are converted back to native types. The coercion rules live in your contract schemas, so the behavior stays explicit and predictable.
+
+```ts
+const contract = oc.output(z.object({
+ date: z.coerce.date(),
+ bigint: z.coerce.bigint(),
+}))
+
+const procedure = implement(contract).handler(() => ({
+ date: new Date(),
+ bigint: 123n,
+}))
+```
+
+The server still returns JSON-friendly data:
+
+```ts
+const rawOutput = {
+ date: '2025-09-01T07:24:39.000Z',
+ bigint: '123',
+}
+```
+
+With `ResponseValidationLinkPlugin`, the client validates that response and applies your schema coercion before your code uses it.
+
+```ts
+const output = {
+ date: new Date('2025-09-01T07:24:39.000Z'),
+ bigint: 123n,
+}
+```
+
+### Setup
+
+Add the plugin to your link, then remove the `JsonifiedClient` wrapper from the client type.
+
+```ts
+import type { RouterContractClient } from '@orpc/contract'
+import { ResponseValidationLinkPlugin } from '@orpc/contract/plugins'
+
+const link = new OpenAPILink(contract, {
+ plugins: [
+ new ResponseValidationLinkPlugin(contract), // [!code ++]
+ ],
+})
+
+const client: JsonifiedClient> = createORPCClient(link) // [!code --]
+const client: RouterContractClient = createORPCClient(link) // [!code ++]
+```
+
+## Use Smart Coercion Plugin
+
+Use [Smart Coercion Plugin](/docs/plugins/smart-coercion) when you want the client to coerce values automatically from schema instead of adding coercion logic to each schema manually.
+
+```ts
+import type { RouterContractClient } from '@orpc/contract'
+import { SmartCoercionLinkPlugin } from '@orpc/json-schema'
+
+const link = new OpenAPILink(contract, {
+ plugins: [
+ new SmartCoercionLinkPlugin(contract), // [!code ++]
+ ],
+})
+
+const client: JsonifiedClient> = createORPCClient(link) // [!code --]
+const client: RouterContractClient = createORPCClient(link) // [!code ++]
+```
diff --git a/apps/content/docs/advanced/extend-body-parser.md b/apps/content/docs/advanced/extend-body-parser.md
deleted file mode 100644
index 3e5f6f6a1..000000000
--- a/apps/content/docs/advanced/extend-body-parser.md
+++ /dev/null
@@ -1,80 +0,0 @@
----
-title: Extend Body Parser
-description: Extend the body parser for more efficient handling of large payloads, extend the data types.
----
-
-# Extend Body Parser
-
-In some cases, you may need to extend the body parser to handle larger payloads or additional data types. This can be done by creating a custom body parser that extends the default functionality.
-
-```ts
-import { RPCHandler } from '@orpc/server/fetch'
-import { getFilenameFromContentDisposition } from '@orpc/standard-server'
-
-const OVERRIDE_BODY_CONTEXT = Symbol('OVERRIDE_BODY_CONTEXT')
-
-interface OverrideBodyContext {
- fetchRequest: Request
-}
-
-const handler = new RPCHandler(router, {
- adapterInterceptors: [
- (options) => {
- return options.next({
- ...options,
- context: {
- ...options.context,
- [OVERRIDE_BODY_CONTEXT as any]: {
- fetchRequest: options.request,
- },
- },
- })
- },
- ],
- rootInterceptors: [
- (options) => {
- const { fetchRequest } = (options.context as any)[OVERRIDE_BODY_CONTEXT] as OverrideBodyContext
-
- return options.next({
- ...options,
- request: {
- ...options.request,
- async body() {
- const contentDisposition = fetchRequest.headers.get('content-disposition')
- const contentType = fetchRequest.headers.get('content-type')
-
- if (contentDisposition === null && contentType?.startsWith('multipart/form-data')) {
- // Custom handling for multipart/form-data
- // Example: use @mjackson/form-data-parser for streaming parsing
- return fetchRequest.formData()
- }
-
- // if has content-disposition always treat as file upload
- if (
- contentDisposition !== null || (
- !contentType?.startsWith('application/json')
- && !contentType?.startsWith('application/x-www-form-urlencoded')
- )
- ) {
- // Custom handling for file uploads
- // Example: streaming file into disk to reduce memory usage
- const fileName = getFilenameFromContentDisposition(contentDisposition ?? '') ?? 'blob'
- const blob = await fetchRequest.blob()
- return new File([blob], fileName, {
- type: blob.type,
- })
- }
-
- // fallback to default body parser
- return options.request.body()
- },
- },
- })
- },
- ],
-})
-```
-
-::: warning
-The `adapterInterceptors` can be different based on the adapter you are using. The example above is for the Fetch adapter.
-:::
diff --git a/apps/content/docs/advanced/publish-client-to-npm.md b/apps/content/docs/advanced/publish-client-to-npm.md
index 77e3fd3cd..c1f61202f 100644
--- a/apps/content/docs/advanced/publish-client-to-npm.md
+++ b/apps/content/docs/advanced/publish-client-to-npm.md
@@ -1,8 +1,3 @@
----
-title: Publish Client to NPM
-description: How to publish your oRPC client to NPM for users to consume your APIs as an SDK.
----
-
# Publish Client to NPM
Publishing your oRPC client to NPM allows users to easily consume your APIs as a software development kit (SDK).
@@ -13,7 +8,7 @@ Before you start, we recommend watching some [publish typescript library to npm
## Prerequisites
-You must have a project already set up with oRPC. [Contract First](/docs/contract-first/define-contract) is the preferred approach. If you haven't set one up yet, you can clone an [oRPC playground](/docs/playgrounds) and start from there.
+You must have a project already set up with oRPC. [Contract First](/docs/contract/router) is the preferred approach. If you haven't set one up yet, you can clone an [oRPC playground](/docs/playgrounds) and start from there.
::: info
In this guide, we'll use [pnpm](https://pnpm.io/) as the package manager and [tsdown](https://tsdown.dev/) for bundling the package. You can use other package managers and bundlers, but the commands may differ.
@@ -26,11 +21,12 @@ First, create a `src/index.ts` file to set up and export your client.
```ts [src/index.ts]
import { createORPCClient } from '@orpc/client'
import { RPCLink } from '@orpc/client/fetch'
-import type { ContractRouterClient } from '@orpc/contract'
+import type { RouterContractClient } from '@orpc/contract'
-export function createMyApi(apiKey: string): ContractRouterClient {
+export function createMyApi(apiKey: string): RouterContractClient {
const link = new RPCLink({
- url: 'https://example.com/rpc',
+ origin: 'https://example.com',
+ url: '/rpc',
headers: {
'x-api-key': apiKey,
}
@@ -41,7 +37,7 @@ export function createMyApi(apiKey: string): ContractRouterClient data instanceof User,
- serialize: data => data.toJSON(),
- deserialize: data => new User(data.id, data.name, data.email, data.age),
- }
- ```
-
- ::: warning
- Ensure the `type` is unique and greater than `20` to avoid conflicts with [built-in types](/docs/advanced/rpc-protocol#supported-types) in the future.
- :::
-
-2. **Use Your Custom Serializer**
-
- ```ts twoslash
- import type { StandardRPCCustomJsonSerializer } from '@orpc/client/standard'
- import { RPCHandler } from '@orpc/server/fetch'
- import { RPCLink } from '@orpc/client/fetch'
-
- declare const router: Record
- declare const userSerializer: StandardRPCCustomJsonSerializer
- // ---cut---
- const handler = new RPCHandler(router, {
- customJsonSerializers: [userSerializer], // [!code highlight]
- })
-
- const link = new RPCLink({
- url: 'https://example.com/rpc',
- customJsonSerializers: [userSerializer], // [!code highlight]
- })
- ```
-
-## Overriding Built-in Types
-
-You can override built-in types by matching their `type` with the [built-in types](/docs/advanced/rpc-protocol#supported-types).
-
-For example, oRPC represents `undefined` only in array items and ignores it in objects. To override this behavior:
-
-```ts twoslash
-import { StandardRPCCustomJsonSerializer } from '@orpc/client/standard'
-
-export const undefinedSerializer: StandardRPCCustomJsonSerializer = {
- type: 3, // Match the built-in undefined type. [!code highlight]
- condition: data => data === undefined,
- serialize: data => null, // JSON cannot represent undefined, so use null.
- deserialize: data => undefined,
-}
-```
diff --git a/apps/content/docs/advanced/rpc-protocol.md b/apps/content/docs/advanced/rpc-protocol.md
deleted file mode 100644
index 535db51e0..000000000
--- a/apps/content/docs/advanced/rpc-protocol.md
+++ /dev/null
@@ -1,150 +0,0 @@
----
-title: RPC Protocol
-description: Learn about the RPC protocol used by RPCHandler.
----
-
-# RPC Protocol
-
-The RPC protocol enables remote procedure calls over HTTP using JSON, supporting native data types. It is used by [RPCHandler](/docs/rpc-handler).
-
-## Routing
-
-The procedure to call is determined by the `pathname`.
-
-```bash
-curl https://example.com/rpc/planet/create
-```
-
-This example calls the `planet.create` procedure, with `/rpc` as the prefix:
-
-```ts
-const router = {
- planet: {
- create: os.handler(() => {}) // [!code highlight]
- }
-}
-```
-
-## Input
-
-Any HTTP method can be used. Input can be provided via URL query parameters or the request body, based on the HTTP method.
-
-::: warning
-By default, [RPCHandler](/docs/rpc-handler) in the [HTTP Adapter](/docs/adapters/http) enabled [StrictGetMethodPlugin](/docs/rpc-handler#default-plugins) which blocks GET requests except for procedures explicitly allowed. Please refer to [StrictGetMethodPlugin](/docs/plugins/strict-get-method) for more details.
-:::
-
-### Input in URL Query
-
-```ts
-const url = new URL('https://example.com/rpc/planet/create')
-
-url.searchParams.append('data', JSON.stringify({
- json: {
- name: 'Earth',
- detached_at: '2022-01-01T00:00:00.000Z'
- },
- meta: [[1, 'detached_at']]
-}))
-
-const response = await fetch(url)
-```
-
-### Input in Request Body
-
-```bash
-curl -X POST https://example.com/rpc/planet/create \
- -H 'Content-Type: application/json' \
- -d '{
- "json": {
- "name": "Earth",
- "detached_at": "2022-01-01T00:00:00.000Z"
- },
- "meta": [[1, "detached_at"]]
- }'
-```
-
-### Input with File
-
-```ts
-const form = new FormData()
-
-form.set('data', JSON.stringify({
- json: {
- name: 'Earth',
- thumbnail: {},
- images: [{}, {}]
- },
- meta: [[1, 'detached_at']],
- maps: [['images', 0], ['images', 1]]
-}))
-
-form.set('0', new Blob([''], { type: 'image/png' }))
-form.set('1', new Blob([''], { type: 'image/png' }))
-
-const response = await fetch('https://example.com/rpc/planet/create', {
- method: 'POST',
- body: form
-})
-```
-
-## Success Response
-
-```http
-HTTP/1.1 200 OK
-Content-Type: application/json
-
-{
- "json": {
- "id": "1",
- "name": "Earth",
- "detached_at": "2022-01-01T00:00:00.000Z"
- },
- "meta": [[0, "id"], [1, "detached_at"]]
-}
-```
-
-A success response has an HTTP status code between `200-299` and returns the procedure's output.
-
-## Error Response
-
-```http
-HTTP/1.1 500 Internal Server Error
-Content-Type: application/json
-
-{
- "json": {
- "defined": false,
- "code": "INTERNAL_SERVER_ERROR",
- "status": 500,
- "message": "Internal server error",
- "data": {}
- },
- "meta": []
-}
-```
-
-An error response has an HTTP status code between `400-599` and returns an `ORPCError` object.
-
-## Meta
-
-The `meta` field describes native data in the format `[type: number, ...path: (string | number)[]]`.
-
-- **type**: Data type (see [Supported Types](#supported-types)).
-- **path**: Path to the data inside `json`.
-
-### Supported Types
-
-| Type | Description |
-| ---- | ----------- |
-| 0 | bigint |
-| 1 | date |
-| 2 | nan |
-| 3 | undefined |
-| 4 | url |
-| 5 | regexp |
-| 6 | set |
-| 7 | map |
-
-## Maps
-
-The `maps` field is used with `FormData` to map a file or blob to a specific path in `json`.
diff --git a/apps/content/docs/advanced/scaling-large-projects.md b/apps/content/docs/advanced/scaling-large-projects.md
new file mode 100644
index 000000000..2ef26844b
--- /dev/null
+++ b/apps/content/docs/advanced/scaling-large-projects.md
@@ -0,0 +1,104 @@
+# Scaling Large Projects
+
+A single root [client](/docs/client/client-side) is a great way to get started. As your project grows, though, it can lead to type performance issues and tangled dependencies. Splitting the client into smaller service-level clients can help for a while, but very large codebases can still outgrow that approach.
+
+This guide shows an alternative pattern for large projects: import and use individual [procedure contracts](/docs/contract/procedure) directly.
+
+## Requirements
+
+This pattern depends on one consistency rule: every [procedure contract](/docs/contract/procedure) must define `meta.path`, and that path must exactly match the procedure's location in the root contract.
+
+```ts
+import { meta, oc } from '@orpc/contract'
+
+export const procedure = oc
+ .meta(meta.path(['real', 'path', 'to', 'procedure']))
+ .input(z.object({ name: z.string() }))
+ .output(z.object({ message: z.string() }))
+```
+
+If you use `['real', 'path', 'to', 'procedure']` as the path, the procedure must be mounted at `real.path.to.procedure` in the root contract. This is required for the pattern to work correctly:
+
+```ts
+import { procedure } from './path/to/procedure'
+
+const router = {
+ real: {
+ path: {
+ to: {
+ procedure,
+ },
+ },
+ }
+}
+```
+
+## Contract Caller
+
+This pattern does not require a single root client. Instead, you configure a caller that communicates with the server. `createContractCaller` accepts an [RPC Link](/docs/rpc/link), an [OpenAPI Link](/docs/openapi/link), or a custom link. It also accepts options similar to [`createORPCClient`](/docs/client/client-side), but with less typesafe because the full contract is not known up front:
+
+```ts
+import { createContractCaller } from '@orpc/contract'
+
+export const call = createContractCaller(link, { /** options */})
+```
+
+::: warning
+If you are using [OpenAPI Link](/docs/openapi/link), or any link that requires the client to be wrapped in `JsonifiedClient`, use `createContractJsonifiedCaller` from `@orpc/openapi` instead of `createContractCaller`.
+:::
+
+You can then call a procedure by importing its contract directly in the client:
+
+```ts
+import { procedure } from './path/to/procedure'
+
+const output = await call(procedure, input, {/** options */})
+```
+
+### `contractRef`
+
+Some integrations still need a root contract. For example, [OpenAPI Link](/docs/openapi/link) and some plugins depend on one. In those cases, `contractRef` can help:
+
+```ts
+import { RouterContract } from '@orpc/contract'
+
+const contractRef: RouterContract = {}
+
+const link = new OpenAPILink(contractRef, {
+ plugins: [
+ new PluginRequireContract(contractRef)
+ ]
+})
+
+export const call = createContractCaller(link, { contractRef })
+```
+
+The idea behind `contractRef` is simple: every time `call` is used, the caller automatically registers the called procedure contract into `contractRef` at the path defined by `meta.path`.
+
+::: info
+Some features may not support `contractRef` well. In those cases, import the root contract instead and cast it with `as any` when needed.
+:::
+
+## TanStack Query Integration
+
+[TanStack Query Integration](/docs/integrations/tanstack-query) also supports this pattern. First, create a factory that accepts a [contract caller](#contract-caller) and options similar to the [TanStack Query interceptor options](/docs/integrations/tanstack-query#interceptors), but with less type safety because the full contract is not known up front:
+
+```ts
+import { createContractUtilsFactory } from '@orpc/tanstack-query'
+
+export const createUtils = createContractUtilsFactory(call, { /** options */})
+```
+
+::: warning
+If you are using [OpenAPI Link](/docs/openapi/link), or any link that requires the client to be wrapped in `JsonifiedClient`, use `createContractJsonifiedUtilsFactory` from `@orpc/tanstack-query` instead of `createContractUtilsFactory`.
+:::
+
+You can then create utilities for each procedure contract:
+
+```ts
+import { procedure } from './path/to/procedure'
+
+const utils = createUtils(procedure)
+
+const query = useQuery(utils.queryOptions({/** options */}))
+```
diff --git a/apps/content/docs/advanced/superjson.md b/apps/content/docs/advanced/superjson.md
deleted file mode 100644
index 1002fa269..000000000
--- a/apps/content/docs/advanced/superjson.md
+++ /dev/null
@@ -1,143 +0,0 @@
----
-title: SuperJson
-description: Replace the default oRPC RPC serializer with SuperJson.
----
-
-# SuperJson
-
-This guide explains how to replace the default oRPC RPC serializer with [SuperJson](https://github.com/blitz-js/superjson).
-
-:::info
-While the default oRPC serializer is faster and more efficient, SuperJson is widely adopted and may be preferred for compatibility.
-:::
-
-## SuperJson Serializer
-
-:::warning
-The `SuperJsonSerializer` supports only the data types that SuperJson handles, plus `AsyncIteratorObject` at the root level for [Event Iterator](/docs/event-iterator). It does not support all [RPC supported types](/docs/rpc-handler#supported-data-types).
-:::
-
-```ts twoslash
-import { createORPCErrorFromJson, ErrorEvent, isORPCErrorJson, mapEventIterator, toORPCError } from '@orpc/client'
-import type { StandardRPCSerializer } from '@orpc/client/standard'
-import { isAsyncIteratorObject } from '@orpc/shared'
-import SuperJSON from 'superjson'
-
-export class SuperJSONSerializer implements Pick {
- serialize(data: unknown): object {
- if (isAsyncIteratorObject(data)) {
- return mapEventIterator(data, {
- value: async (value: unknown) => SuperJSON.serialize(value),
- error: async (e) => {
- return new ErrorEvent({
- data: SuperJSON.serialize(toORPCError(e).toJSON()),
- cause: e,
- })
- },
- })
- }
-
- return SuperJSON.serialize(data)
- }
-
- deserialize(data: any): unknown {
- if (isAsyncIteratorObject(data)) {
- return mapEventIterator(data, {
- value: async value => SuperJSON.deserialize(value),
- error: async (e) => {
- if (!(e instanceof ErrorEvent))
- return e
-
- const deserialized = SuperJSON.deserialize(e.data as any)
-
- if (isORPCErrorJson(deserialized)) {
- return createORPCErrorFromJson(deserialized, { cause: e })
- }
-
- return new ErrorEvent({
- data: deserialized,
- cause: e,
- })
- },
- })
- }
-
- return SuperJSON.deserialize(data)
- }
-}
-```
-
-## SuperJson Handler
-
-```ts twoslash
-declare class SuperJSONSerializer implements Pick {
- serialize(data: unknown): object
- deserialize(data: unknown): unknown
-}
-// ---cut---
-import type { StandardRPCSerializer } from '@orpc/client/standard'
-import type { Context, Router } from '@orpc/server'
-import type { FetchHandlerOptions } from '@orpc/server/fetch'
-import { FetchHandler } from '@orpc/server/fetch'
-import { StrictGetMethodPlugin } from '@orpc/server/plugins'
-import type { StandardHandlerOptions } from '@orpc/server/standard'
-import { StandardHandler, StandardRPCCodec, StandardRPCMatcher } from '@orpc/server/standard'
-
-export interface SuperJSONHandlerOptions
- extends FetchHandlerOptions, Omit, 'plugins'> {
- /**
- * Enable or disable the StrictGetMethodPlugin.
- *
- * @default true
- */
- strictGetMethodPluginEnabled?: boolean
-}
-
-export class SuperJSONHandler extends FetchHandler {
- constructor(router: Router, options: NoInfer> = {}) {
- options.plugins ??= []
-
- const strictGetMethodPluginEnabled = options.strictGetMethodPluginEnabled ?? true
-
- if (strictGetMethodPluginEnabled) {
- options.plugins.push(new StrictGetMethodPlugin())
- }
-
- const serializer = new SuperJSONSerializer()
- const matcher = new StandardRPCMatcher()
- const codec = new StandardRPCCodec(serializer as any)
-
- super(new StandardHandler(router, matcher, codec, options), options)
- }
-}
-```
-
-## SuperJson Link
-
-```ts twoslash
-declare class SuperJSONSerializer implements Pick {
- serialize(data: unknown): object
- deserialize(data: unknown): unknown
-}
-// ---cut---
-import type { ClientContext } from '@orpc/client'
-import { StandardLink, StandardRPCLinkCodec } from '@orpc/client/standard'
-import type { StandardLinkOptions, StandardRPCLinkCodecOptions, StandardRPCSerializer } from '@orpc/client/standard'
-import type { LinkFetchClientOptions } from '@orpc/client/fetch'
-import { LinkFetchClient } from '@orpc/client/fetch'
-
-export interface SuperJSONLinkOptions
- extends LinkFetchClientOptions,
- Omit, 'plugins'>,
- StandardRPCLinkCodecOptions { }
-
-export class SuperJSONLink extends StandardLink {
- constructor(options: SuperJSONLinkOptions) {
- const linkClient = new LinkFetchClient(options)
- const serializer = new SuperJSONSerializer()
- const linkCodec = new StandardRPCLinkCodec(serializer as any, options)
-
- super(linkCodec, linkClient, options)
- }
-}
-```
diff --git a/apps/content/docs/advanced/testing-and-mocking.md b/apps/content/docs/advanced/testing-and-mocking.md
new file mode 100644
index 000000000..2525e805d
--- /dev/null
+++ b/apps/content/docs/advanced/testing-and-mocking.md
@@ -0,0 +1,46 @@
+# Testing and Mocking
+
+Testing and mocking are essential for building reliable applications. In this section, we'll explore how to test your procedures and routers effectively, as well as how to create mock implementations for testing purposes.
+
+## Testing
+
+For fast, focused tests, use [Server-Side Clients](/docs/client/server-side) or call your procedures directly with `call`. This lets you verify validation, middleware, and handler logic without going through HTTP.
+
+```ts
+import { call } from '@orpc/server'
+
+it('lists planets', async () => {
+ await expect(
+ call(router.planet.list, { page: 1, size: 10 })
+ ).resolves.toEqual([
+ { id: '1', name: 'Earth' },
+ { id: '2', name: 'Mars' },
+ ])
+})
+```
+
+::: info
+For a production-like test setup, create [fetch-based internal clients](/docs/best-practices/optimizing-ssr#implementation).
+:::
+
+## Mocking
+
+Use the [Implementer](/docs/contract/implementation) to create test-specific versions of a [procedure](/docs/procedure) or [router](/docs/router). This is useful when one part of your system depends on another procedure, but your test should not execute the real implementation.
+
+```ts twoslash
+import { router } from './shared/planet'
+// ---cut---
+import { implement } from '@orpc/server'
+
+const fakeListPlanet = implement(router.planet.list).handler(() => [])
+```
+
+Use `fakeListPlanet` anywhere your test would normally use the real `listPlanet` procedure.
+
+::: info
+`implement` is also useful for building mock servers in frontend tests.
+:::
+
+::: warning
+`implement` does not support [lazy routers](/docs/router#lazy-router) directly. If you need to mock one, first [unlazy the router](/docs/contract/router#router-to-contract).
+:::
diff --git a/apps/content/docs/advanced/testing-mocking.md b/apps/content/docs/advanced/testing-mocking.md
deleted file mode 100644
index bcb041731..000000000
--- a/apps/content/docs/advanced/testing-mocking.md
+++ /dev/null
@@ -1,51 +0,0 @@
----
-title: Testing & Mocking
-description: How to test and mock oRPC routers and procedures?
----
-
-# Testing & Mocking
-
-Testing and mocking are essential parts of the development process, ensuring your oRPC routers and procedures work as expected. This guide covers strategies for testing and mocking in oRPC applications.
-
-## Testing
-
-Using [Server-Side Clients](/docs/client/server-side), you can directly invoke your procedures in tests without additional setup. This approach allows you to test procedures in isolation, ensuring they behave correctly.
-
-```ts
-import { call } from '@orpc/server'
-
-it('works', async () => {
- await expect(
- call(router.planet.list, { page: 1, size: 10 })
- ).resolves.toEqual([
- { id: '1', name: 'Earth' },
- { id: '2', name: 'Mars' },
- ])
-})
-```
-
-::: info
-You can also use the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to create production-like clients for testing purposes. [Learn more](/docs/best-practices/optimize-ssr#alternative-approach)
-:::
-
-## Mocking
-
-The [Implementer](/docs/contract-first/implement-contract#the-implementer) is designed for contract-first development, but it can also create alternative versions of your [router](/docs/router) or [procedure](/docs/procedure) for testing.
-
-```ts twoslash
-import { router } from './shared/planet'
-// ---cut---
-import { implement, unlazyRouter } from '@orpc/server'
-
-const fakeListPlanet = implement(router.planet.list).handler(() => [])
-```
-
-You can use `fakeListPlanet` to replace the actual `listPlanet` implementation during tests.
-
-::: info
-The `implement` function is also useful for creating mock servers for frontend testing scenarios.
-:::
-
-::: warning
-The `implement` function doesn't support [lazy routers](/docs/router#lazy-router) yet. Use the `unlazyRouter` utility to convert your lazy router before implementing. [Learn more](/docs/contract-first/router-to-contract#unlazy-the-router)
-:::
diff --git a/apps/content/docs/advanced/validation-errors.md b/apps/content/docs/advanced/validation-errors.md
index 29d545910..ae40b4786 100644
--- a/apps/content/docs/advanced/validation-errors.md
+++ b/apps/content/docs/advanced/validation-errors.md
@@ -1,117 +1,72 @@
----
-title: Validation Errors
-description: Learn about oRPC's built-in validation errors and how to customize them.
----
-
# Validation Errors
-oRPC provides built-in validation errors that work well by default. However, you might sometimes want to customize them.
+oRPC includes built-in validation errors that work well for most cases. Customize them when you need a different message or error shape.
-## Customizing with Client Interceptors
+## Customizing
-[Client Interceptors](/docs/rpc-handler#lifecycle) are preferred because they run before error validation, ensuring that your custom errors are properly validated.
+You can catch validation errors with [interceptors](/docs/rpc/handler#interceptors), [client interceptors](/docs/rpc/handler#client-interceptors), or [middleware](/docs/middleware) applied before `.input` or `.output`.
```ts twoslash
import { RPCHandler } from '@orpc/server/fetch'
import { router } from './shared/planet'
// ---cut---
-import { onError, ORPCError, ValidationError } from '@orpc/server'
import * as z from 'zod'
+import { ORPCError, ValidationError } from '@orpc/server'
const handler = new RPCHandler(router, {
- clientInterceptors: [
- onError((error) => {
- if (
- error instanceof ORPCError
- && error.code === 'BAD_REQUEST'
- && error.cause instanceof ValidationError
- ) {
- // If you only use Zod you can safely cast to ZodIssue[]
- const zodError = new z.ZodError(error.cause.issues as z.core.$ZodIssue[])
-
- throw new ORPCError('INPUT_VALIDATION_FAILED', {
- status: 422,
- message: z.prettifyError(zodError),
- data: z.flattenError(zodError),
- cause: error.cause,
- })
+ interceptors: [
+ async ({ next }) => {
+ try {
+ return await next()
}
-
- if (
- error instanceof ORPCError
- && error.code === 'INTERNAL_SERVER_ERROR'
- && error.cause instanceof ValidationError
- ) {
- throw new ORPCError('OUTPUT_VALIDATION_FAILED', {
- cause: error.cause,
- })
+ catch (error) {
+ if (
+ error instanceof ORPCError
+ && error.code === 'BAD_REQUEST'
+ && error.cause instanceof ValidationError
+ ) {
+ // If you only use Zod you can safely cast to ZodIssue[]
+ const zodError = new z.ZodError(error.cause.issues as z.core.$ZodIssue[])
+
+ throw new ORPCError('INPUT_VALIDATION_FAILED', {
+ message: z.prettifyError(zodError),
+ data: z.flattenError(zodError),
+ cause: error,
+ })
+ }
+
+ if (
+ error instanceof ORPCError
+ && error.code === 'INTERNAL_SERVER_ERROR'
+ && error.cause instanceof ValidationError
+ ) {
+ // do not expose validation details for output validation errors
+ throw new ORPCError('OUTPUT_VALIDATION_FAILED', {
+ cause: error,
+ })
+ }
+
+ throw error
}
- }),
+ },
],
})
```
-## Customizing with Middleware
-
-```ts twoslash
-import { onError, ORPCError, os, ValidationError } from '@orpc/server'
-import * as z from 'zod'
-
-const base = os.use(onError((error) => {
- if (
- error instanceof ORPCError
- && error.code === 'BAD_REQUEST'
- && error.cause instanceof ValidationError
- ) {
- // If you only use Zod you can safely cast to ZodIssue[]
- const zodError = new z.ZodError(error.cause.issues as z.core.$ZodIssue[])
-
- throw new ORPCError('INPUT_VALIDATION_FAILED', {
- status: 422,
- message: z.prettifyError(zodError),
- data: z.flattenError(zodError),
- cause: error.cause,
- })
- }
-
- if (
- error instanceof ORPCError
- && error.code === 'INTERNAL_SERVER_ERROR'
- && error.cause instanceof ValidationError
- ) {
- throw new ORPCError('OUTPUT_VALIDATION_FAILED', {
- cause: error.cause,
- })
- }
-}))
-
-const getting = base
- .input(z.object({ id: z.uuid() }))
- .output(z.object({ id: z.uuid(), name: z.string() }))
- .handler(async ({ input, context }) => {
- return { id: input.id, name: 'name' }
- })
-```
-
-Every [procedure](/docs/procedure) built from `base` now uses these customized validation errors.
+## Typesafe Validation Errors
-:::warning
-Middleware applied before `.input`/`.output` catches validation errors by default, but this behavior can be configured.
-:::
+As explained in the [error handling guide](/docs/error-handling#orpcerror-compatibility), if you throw an `ORPCError` whose `code` and `data` match an error defined with `.errors`, oRPC treats it the same as `errors.[code]`.
-## Type‑Safe Validation Errors
-
-As explained in the [error handling guide](/docs/error-handling#combining-both-approaches), when you throw an `ORPCError` instance, if the `code`, `status` and `data` match with the errors defined in the `.errors` method, oRPC will treat it exactly as if you had thrown `errors.[code]` using the type‑safe approach.
+This does not work in [interceptors](/docs/rpc/handler#interceptors). Use [client interceptors](/docs/rpc/handler#client-interceptors) or [middleware](/docs/middleware) applied before `.input` or `.output` instead.
```ts twoslash
import { RPCHandler } from '@orpc/server/fetch'
// ---cut---
-import { onError, ORPCError, os, ValidationError } from '@orpc/server'
+import { ORPCError, os, ValidationError } from '@orpc/server'
import * as z from 'zod'
const base = os.errors({
INPUT_VALIDATION_FAILED: {
- status: 422,
data: z.object({
formErrors: z.array(z.string()),
fieldErrors: z.record(z.string(), z.array(z.string()).optional()),
@@ -125,23 +80,29 @@ const example = base
const handler = new RPCHandler({ example }, {
clientInterceptors: [
- onError((error) => {
- if (
- error instanceof ORPCError
- && error.code === 'BAD_REQUEST'
- && error.cause instanceof ValidationError
- ) {
- // If you only use Zod you can safely cast to ZodIssue[]
- const zodError = new z.ZodError(error.cause.issues as z.core.$ZodIssue[])
-
- throw new ORPCError('INPUT_VALIDATION_FAILED', {
- status: 422,
- message: z.prettifyError(zodError),
- data: z.flattenError(zodError),
- cause: error.cause,
- })
+ async ({ next }) => {
+ try {
+ return await next()
}
- }),
+ catch (error) {
+ if (
+ error instanceof ORPCError
+ && error.code === 'BAD_REQUEST'
+ && error.cause instanceof ValidationError
+ ) {
+ // If you only use Zod you can safely cast to ZodIssue[]
+ const zodError = new z.ZodError(error.cause.issues as z.core.$ZodIssue[])
+
+ throw new ORPCError('INPUT_VALIDATION_FAILED', {
+ message: z.prettifyError(zodError),
+ data: z.flattenError(zodError),
+ cause: error,
+ })
+ }
+
+ throw error
+ }
+ },
],
})
```
diff --git a/apps/content/docs/best-practices/dedupe-middleware.md b/apps/content/docs/best-practices/dedupe-middleware.md
index b0edf1692..7f42c02c2 100644
--- a/apps/content/docs/best-practices/dedupe-middleware.md
+++ b/apps/content/docs/best-practices/dedupe-middleware.md
@@ -1,73 +1,70 @@
----
-title: Dedupe Middleware
-description: Enhance oRPC middleware performance by avoiding redundant executions.
----
-
# Dedupe Middleware
-This guide explains how to optimize your [middleware](/docs/middleware) for fast and efficient repeated execution.
+Use [context](/docs/context) to prevent the same [middleware](/docs/middleware) from repeating expensive work.
## Problem
-When a procedure [calls](/docs/client/server-side#using-the-call-utility) another procedure, overlapping middleware might be applied in both.
+The same middleware can run more than once during a single call. This often happens when:
-Similarly, when using `.use(auth).router(router)`, some procedures inside `router` might already include the `auth` middleware.
+- a procedure [calls](/docs/client/server-side#one-off-calls) another procedure that both use the same middleware
+- you use `.use(authProvider).router(router)`, and some procedures in `router` already use `authProvider`
:::warning
-Redundant middleware execution can hurt performance, especially if the middleware is resource-intensive.
+Repeated middleware work can hurt performance, especially for expensive operations such as opening a database connection.
:::
## Solution
-Use the `context` to track middleware execution and prevent duplication. For example:
+Store the computed value in `context` and reuse it when the middleware runs again.
+
+For example, this middleware loads auth at most once per call:
```ts twoslash
import { os } from '@orpc/server'
-declare function connectDb(): Promise<'a_fake_db'>
+declare function loadAuth(headers: Headers): Promise<{ id: string } | undefined>
// ---cut---
-const dbProvider = os
- .$context<{ db?: Awaited> }>()
+const authProvider = os
+ .$context<{ headers: Headers, auth?: { id: string } | undefined, authLoaded?: boolean | undefined }>()
.middleware(async ({ context, next }) => {
- /**
- * If db already exists, skip the connection.
- */
- const db = context.db ?? await connectDb() // [!code highlight]
+ // reuse the loaded auth value if it was already loaded
+ const auth = context.authLoaded
+ ? context.auth
+ : await loadAuth(context.headers)
- return next({ context: { db } })
+ return next({ context: { auth, authLoaded: true } })
})
```
-Now `dbProvider` middleware can be safely applied multiple times without duplicating the database connection:
+You can now apply `authProvider` multiple times without loading auth again:
```ts twoslash
import { call, os } from '@orpc/server'
-declare function connectDb(): Promise<'a_fake_db'>
-const dbProvider = os
- .$context<{ db?: Awaited> }>()
+declare function loadAuth(headers: Headers): Promise<{ id: string } | undefined>
+const authProvider = os
+ .$context<{ headers: Headers, auth?: { id: string } | undefined, authLoaded?: boolean | undefined }>()
.middleware(async ({ context, next }) => {
- const db = context.db ?? await connectDb()
+ // reuse the loaded auth value if it was already loaded
+ const auth = context.authLoaded
+ ? context.auth
+ : await loadAuth(context.headers)
- return next({ context: { db } })
+ return next({ context: { auth, authLoaded: true } })
})
// ---cut---
-const foo = os.use(dbProvider).handler(({ context }) => 'Hello World')
+const base = os.$context<{ headers: Headers }>()
-const bar = os.use(dbProvider).handler(({ context }) => {
- /**
- * Now when you call foo, the dbProvider middleware no need to connect to the database again.
- */
- const result = call(foo, 'input', { context }) // [!code highlight]
+const foo = base.use(authProvider).handler(({ context }) => 'Hello World')
- return 'Hello World'
+const bar = base.use(authProvider).handler(({ context }) => {
+ // Reuse the auth value that is already stored in context.
+ return call(foo, undefined, { context }) // [!code highlight]
})
-/**
- * Now even when `dbProvider` is applied multiple times, it still only connects to the database once.
- */
-const router = os
- .use(dbProvider) // [!code highlight]
+// Applying authProvider again does not load auth a second time.
+const router = base
+ .use(authProvider) // [!code highlight]
.use(({ next }) => {
// Additional middleware logic
return next()
@@ -77,49 +74,3 @@ const router = os
bar,
})
```
-
-## Built-in Dedupe Middleware
-
-oRPC can automatically dedupe some middleware under specific conditions.
-
-::: info
-Deduplication occurs only if the router middlewares is a **subset** of the **leading** procedure middlewares and appears in the **same order**.
-:::
-
-```ts
-const router = os.use(logging).use(dbProvider).router({
- // ✅ Deduplication occurs:
- ping: os.use(logging).use(dbProvider).use(auth).handler(({ context }) => 'ping'),
- pong: os.use(logging).use(dbProvider).handler(({ context }) => 'pong'),
-
- // ⛔ Deduplication does not occur:
- diff_subset: os.use(logging).handler(({ context }) => 'ping'),
- diff_order: os.use(dbProvider).use(logging).handler(({ context }) => 'pong'),
- diff_leading: os.use(monitor).use(logging).use(dbProvider).handler(({ context }) => 'bar'),
-})
-
-// --- equivalent to ---
-
-const router = {
- // ✅ Deduplication occurs:
- ping: os.use(logging).use(dbProvider).use(auth).handler(({ context }) => 'ping'),
- pong: os.use(logging).use(dbProvider).handler(({ context }) => 'pong'),
-
- // ⛔ Deduplication does not occur:
- diff_subset: os.use(logging).use(dbProvider).use(logging).handler(({ context }) => 'ping'),
- diff_order: os.use(logging).use(dbProvider).use(dbProvider).use(logging).handler(({ context }) => 'pong'),
- diff_leading: os.use(logging).use(dbProvider).use(monitor).use(logging).use(dbProvider).handler(({ context }) => 'bar'),
-}
-```
-
-### Configuration
-
-Disable middleware deduplication by setting `dedupeLeadingMiddlewares` to `false` in `.$config`:
-
-```ts
-const base = os.$config({ dedupeLeadingMiddlewares: false })
-```
-
-:::warning
-The deduplication behavior is safe unless you want to apply middleware multiple times.
-:::
diff --git a/apps/content/docs/best-practices/monorepo-setup.md b/apps/content/docs/best-practices/monorepo-setup.md
index f72197f68..9217b2de5 100644
--- a/apps/content/docs/best-practices/monorepo-setup.md
+++ b/apps/content/docs/best-practices/monorepo-setup.md
@@ -1,8 +1,3 @@
----
-title: Monorepo Setup
-description: The most efficient way to set up a monorepo with oRPC
----
-
# Monorepo Setup
A monorepo stores multiple related projects in a single repository, a common practice for managing interconnected projects like web applications and their APIs.
@@ -102,6 +97,7 @@ packages/
This is just a suggestion. You can structure your monorepo however you like.
:::
-## Related
+## Learn More
+- [Scaling Large Projects](/docs/advanced/scaling-large-projects)
- [Publish Client to NPM](/docs/advanced/publish-client-to-npm)
diff --git a/apps/content/docs/best-practices/no-throw-literal.md b/apps/content/docs/best-practices/no-throw-literal.md
index 051502f56..4dfa78696 100644
--- a/apps/content/docs/best-practices/no-throw-literal.md
+++ b/apps/content/docs/best-practices/no-throw-literal.md
@@ -1,8 +1,3 @@
----
-title: No Throw Literal
-description: Always throw `Error` instances instead of literal values.
----
-
# No Throw Literal
In JavaScript, you can throw any value, but it's best to throw only `Error` instances.
@@ -19,30 +14,31 @@ oRPC treats thrown `Error` instances as best practice by default, as recommended
## Configuration
-Customize oRPC's behavior by setting `throwableError` in the `Registry`:
+Customize oRPC's behavior by setting `ThrowableError` in the `Registry`:
```ts
declare module '@orpc/server' { // or '@orpc/contract', or '@orpc/client'
interface Registry {
- throwableError: Error // [!code highlight]
+ ThrowableError: Error // [!code highlight]
}
}
```
:::info
-Avoid using `any` or `unknown` for `throwableError` because doing so prevents the client from inferring [type-safe errors](/docs/client/error-handling#using-safe-and-isdefinederror). Instead, use `null | undefined | {}` (equivalent to `unknown`) for stricter error type inference.
+Avoid using `any` or `unknown` for `ThrowableError` because doing so prevents the client from inferring [typesafe errors](/docs/client/error-handling#using-safe-and-isinferableerror). Instead, use `null | undefined | {}` (equivalent to `unknown`) for stricter error type inference.
:::
-:::tip
-If you configure `throwableError` as `null | undefined | {}`, adjust your code to check the `isSuccess` property instead of `error`:
+::: warning
+If `ThrowableError` is configured as `null | undefined | {}`, check `isSuccess` instead of relying on `error`:
```ts
const { error, data, isSuccess } = await safe(client('input'))
if (!isSuccess) {
- if (isDefinedError(error)) {
- // handle type-safe error
+ if (isInferableError(error)) {
+ // handle typesafe errors
}
+
// handle other errors
}
else {
diff --git a/apps/content/docs/best-practices/optimize-ssr.md b/apps/content/docs/best-practices/optimize-ssr.md
deleted file mode 100644
index 6b1dae110..000000000
--- a/apps/content/docs/best-practices/optimize-ssr.md
+++ /dev/null
@@ -1,250 +0,0 @@
----
-title: Optimize Server-Side Rendering (SSR) for Fullstack Frameworks
-description: Optimize SSR performance in Next.js, SvelteKit, and other frameworks by using oRPC to make direct server-side API calls, avoiding unnecessary network requests.
----
-
-# Optimize Server-Side Rendering (SSR) for Fullstack Frameworks
-
-This guide demonstrates an optimized approach for setting up Server-Side Rendering (SSR) with oRPC in fullstack frameworks like Next.js, Nuxt, and SvelteKit. This method enhances performance by eliminating redundant network calls during the server rendering process.
-
-## The Problem with Standard SSR Data Fetching
-
-In a typical SSR setup within fullstack frameworks, data fetching often involves the server making an HTTP request back to its own API endpoints.
-
-
-
-This pattern works, but it introduces unnecessary overhead: the server needs to make an HTTP request to itself to fetch the data, which can add extra latency and consume resources.
-
-Ideally, during SSR, the server should fetch data by directly invoking the relevant API logic within the same process.
-
-
-
-Fortunately, oRPC provides both a [server-side client](/docs/client/server-side) and [client-side client](/docs/client/client-side), so you can leverage the former during SSR and automatically fall back to the latter in the browser.
-
-## Conceptual approach
-
-```ts
-// Use this for server-side calls
-const orpc = createRouterClient(router)
-
-// Fallback to this for client-side calls
-const orpc: RouterClient = createORPCClient(someLink)
-```
-
-But how? A naive `typeof window === 'undefined'` check works, but exposes your router logic to the client. We need a hack that ensures server‑only code never reaches the browser.
-
-## Implementation
-
-We'll use `globalThis` to share the server client without bundling it into client code.
-
-::: code-group
-
-```ts [lib/orpc.ts]
-import type { RouterClient } from '@orpc/server'
-import { RPCLink } from '@orpc/client/fetch'
-import { createORPCClient } from '@orpc/client'
-
-declare global {
- var $client: RouterClient | undefined
-}
-
-const link = new RPCLink({
- url: () => {
- if (typeof window === 'undefined') {
- throw new Error('RPCLink is not allowed on the server side.')
- }
-
- return `${window.location.origin}/rpc`
- },
-})
-
-/**
- * Fallback to client-side client if server-side client is not available.
- */
-export const client: RouterClient = globalThis.$client ?? createORPCClient(link)
-```
-
-```ts [lib/orpc.server.ts]
-import 'server-only'
-
-import { createRouterClient } from '@orpc/server'
-
-globalThis.$client = createRouterClient(router, {
- /**
- * Provide initial context if needed.
- *
- * Because this client instance is shared across all requests,
- * only include context that's safe to reuse globally.
- * For per-request context, use middleware context or pass a function as the initial context.
- */
- context: async () => ({
- headers: await headers(), // provide headers if initial context required
- }),
-})
-```
-
-:::
-
-::: details `OpenAPILink` support?
-When you use [OpenAPILink](/docs/openapi/client/openapi-link), its `JsonifiedClient` turns native values (like Date or URL) into plain JSON, so your client types no longer match the output of `createRouterClient`. To fix this, oRPC offers `createJsonifiedRouterClient`, which builds a router client that matches the output of OpenAPILink.
-
-::: code-group
-
-```ts [lib/orpc.ts]
-import type { RouterClient } from '@orpc/server'
-import type { JsonifiedClient } from '@orpc/openapi-client'
-import { OpenAPILink } from '@orpc/openapi-client/fetch'
-import { createORPCClient } from '@orpc/client'
-
-declare global {
- var $client: JsonifiedClient> | undefined
-}
-
-const link = new OpenAPILink(contract, {
- url: () => {
- if (typeof window === 'undefined') {
- throw new Error('OpenAPILink is not allowed on the server side.')
- }
-
- return `${window.location.origin}/api`
- },
-})
-
-/**
- * Fallback to client-side client if server-side client is not available.
- */
-export const client: JsonifiedClient> = globalThis.$client ?? createORPCClient(link)
-```
-
-```ts [lib/orpc.server.ts]
-import 'server-only'
-
-import { createJsonifiedRouterClient } from '@orpc/openapi'
-
-globalThis.$client = createJsonifiedRouterClient(router, {
- /**
- * Provide initial context if needed.
- *
- * Because this client instance is shared across all requests,
- * only include context that's safe to reuse globally.
- * For per-request context, use middleware context or pass a function as the initial context.
- */
- context: async () => ({
- headers: await headers(), // provide headers if initial context required
- }),
-})
-```
-
-:::
-
-Finally, ensure `lib/orpc.server.ts` is imported before any other code on the server. In Next.js, add it to both `instrumentation.ts` and `app/layout.tsx`:
-
-::: code-group
-
-```ts [instrumentation.ts]
-export async function register() {
- // Conditionally import if facing runtime compatibility issues
- // if (process.env.NEXT_RUNTIME === "nodejs") {
- await import('./lib/orpc.server')
- // }
-}
-```
-
-```ts [app/layout.tsx]
-import '../lib/orpc.server' // for pre-rendering
-
-// Rest of the code
-```
-
-:::
-
-Now, importing `client` from `lib/orpc.ts` gives you a server-side client during SSR and a client-side client on the client without leaking your router logic.
-
-## Alternative Approach
-
-The above approach is the most straightforward and performant, but you can also use a `fetch` adapter approach that enables plugins like `DedupeRequestsPlugin` and works with any `handler/link` pair that supports the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).
-
-::: info
-oRPC doesn't restrict you to any specific approach for optimizing SSR - you can choose whatever approach works best for your framework or requirements.
-:::
-
-```ts [lib/orpc.server.ts]
-import 'server-only'
-
-import { createORPCClient } from '@orpc/client'
-import { RPCLink } from '@orpc/client/fetch'
-import type { RouterClient } from '@orpc/server'
-import { handler } from '@/app/rpc/[[...rest]]/route'
-
-const link = new RPCLink({
- url: 'http://placeholder',
- method: inferRPCMethodFromRouter(router),
- plugins: [
- new DedupeRequestsPlugin({
- groups: [{
- condition: () => true,
- context: {},
- }],
- }),
- ],
- fetch: async (request) => {
- const { response } = await handler.handle(request, {
- context: {
- headers: await headers(), // Provide headers if needed
- },
- })
-
- return response ?? new Response('Not Found', { status: 404 })
- },
-})
-
-globalThis.$client = createORPCClient>(link)
-```
-
-## Using the client
-
-The `client` requires no special handling, just use it like regular clients.
-
-```tsx
-export default async function PlanetListPage() {
- const planets = await client.planet.list({ limit: 10 })
-
- return (
-
- {planets.map(planet => (
-
{planet.name}
- ))}
-
- )
-}
-```
-
-::: info
-This example uses Next.js, but you can apply the same pattern in SvelteKit, Nuxt, or any framework.
-:::
-
-## TanStack Query
-
-Combining this oRPC setup with TanStack Query (React Query, Solid Query, etc.) provides a powerful pattern for data fetching, and state management, especially with Suspense hooks. Refer to these details in [Tanstack Query Integration Guide](/docs/integrations/tanstack-query-old/basic) and [Tanstack Query SSR Guide](https://tanstack.com/query/latest/docs/framework/react/guides/ssr).
-
-```tsx
-export default function PlanetListPage() {
- const { data: planets } = useSuspenseQuery(
- orpc.planet.list.queryOptions({
- input: { limit: 10 },
- }),
- )
-
- return (
-
- {planets.map(planet => (
-
{planet.name}
- ))}
-
- )
-}
-```
-
-:::warning
-Above example uses suspense hooks, you might need to wrap your app within ` ` (or corresponding APIs) to make it work. In Next.js, maybe you need create `loading.tsx`.
-:::
diff --git a/apps/content/docs/best-practices/optimizing-ssr.md b/apps/content/docs/best-practices/optimizing-ssr.md
new file mode 100644
index 000000000..2336b8236
--- /dev/null
+++ b/apps/content/docs/best-practices/optimizing-ssr.md
@@ -0,0 +1,166 @@
+# Optimizing Server-Side Rendering (SSR) for Fullstack Frameworks
+
+This guide shows how to optimize Server-Side Rendering (SSR) with oRPC in fullstack frameworks such as Next.js, Nuxt, and SvelteKit. The goal is to avoid unnecessary network calls while the server renders a page.
+
+## The Problem with Standard SSR Data Fetching
+
+In many fullstack frameworks, SSR still fetches data by making an HTTP request from the server to its own API route.
+
+
+
+This works, but it adds avoidable overhead. The server has to go through the HTTP layer just to reach code that is already running in the same process. That extra hop can increase latency and waste resources.
+
+Ideally, SSR should fetch data by calling the relevant API logic directly in the same process.
+
+
+
+With [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) support, you can easily create an internal link that reaches your API logic without making a real network request. For even lower overhead, you can use the [server-side client](#using-server-side-client-directly) directly.
+
+## Conceptual approach
+
+```ts
+// During SSR, use an internal link
+const orpc: RouterClient = createORPCClient(internalLink)
+
+// In the browser, use a normal remote link
+const orpc: RouterClient = createORPCClient(remoteLink)
+```
+
+But how? A naive `typeof window === 'undefined'` check works, **but exposes your router logic to the client**. We need a hack that ensures server‑only code never reaches the browser.
+
+## Implementation
+
+We'll use `globalThis` to share an SSR client without bundling server-only code into the browser.
+
+::: info
+This setup is not limited to [RPC Link](/docs/rpc/link) or [Next.js](https://nextjs.org/). You can use [OpenAPI Link](/docs/openapi/link) or a custom one, and the same pattern works in SvelteKit, Nuxt, and other fullstack frameworks.
+:::
+
+::: code-group
+
+```ts [lib/orpc.ts]
+import type { RouterClient } from '@orpc/server'
+import { RPCLink } from '@orpc/client/fetch'
+import { createORPCClient } from '@orpc/client'
+
+declare global {
+ var $client: RouterClient | undefined
+}
+
+const link = new RPCLink({
+ origin: () => {
+ if (typeof window === 'undefined') {
+ throw new Error('This link is not allowed on the server side.')
+ }
+
+ return window.location.origin
+ },
+})
+
+/**
+ * Fall back to a browser client when no SSR client is registered.
+ */
+export const client: RouterClient = globalThis.$client ?? createORPCClient(link)
+```
+
+```ts [lib/orpc.server.ts]
+import 'server-only'
+
+import { createORPCClient } from '@orpc/client'
+import { RPCLink } from '@orpc/client/fetch'
+import type { RouterClient } from '@orpc/server'
+import { headers } from 'next/headers'
+
+const internalLink = new RPCLink({
+ origin: 'http://localhost',
+ fetch: async (url, init) => {
+ const request = new Request(url, init)
+
+ // Use a fetch handler here
+ const { response } = await handler.handle(request, {
+ context: { // provide initial context if needed
+ headers: await headers(),
+ },
+ })
+
+ return response ?? new Response('Not Found', { status: 404 })
+ },
+})
+
+globalThis.$client = createORPCClient(internalLink)
+```
+
+:::
+
+Import `lib/orpc.server.ts` before other server code so the SSR client is registered early. In Next.js, add it to both `instrumentation.ts` and `app/layout.tsx`:
+
+::: code-group
+
+```ts [instrumentation.ts]
+export async function register() {
+ // Conditionally import if facing runtime compatibility issues
+ // if (process.env.NEXT_RUNTIME === "nodejs") {
+ await import('./lib/orpc.server')
+ // }
+}
+```
+
+```ts [app/layout.tsx]
+import '../lib/orpc.server' // for pre-rendering
+
+// Rest of the code
+```
+
+:::
+
+With this setup, importing `client` from `lib/orpc.ts` uses the internal-link client during SSR and the remote client in the browser.
+
+## Using Server-Side Client Directly
+
+Alternatively, you can use the [server-side client](/docs/client/server-side) directly for SSR. This approach is more efficient and straightforward, as it eliminates serialization and deserialization overhead entirely.
+
+::: info
+Both a [fetch-based internal link](#implementation) and the [server-side client](/docs/client/server-side) are valid strategies for optimizing SSR. The fetch-based approach offers greater flexibility and plugin compatibility, while the server-side client is more efficient and easier to set up. Choose whichever best fits your needs.
+:::
+
+```ts
+import 'server-only'
+
+import { createRouterClient } from '@orpc/server'
+import { headers } from 'next/headers'
+
+globalThis.$client = createRouterClient(router, {
+ /**
+ * Provide initial context if needed.
+ *
+ * Because this client instance is shared across all requests,
+ * only include context that's safe to reuse globally.
+ * For per-request context, use middleware context or pass a function as the initial context.
+ */
+ context: async () => ({
+ headers: await headers(), // provide headers if initial context required
+ }),
+})
+```
+
+## Using the client
+
+The `client` needs no special handling. Use it like any other oRPC client.
+
+```tsx
+export default async function PlanetListPage() {
+ const planets = await client.planet.list({ limit: 10 })
+
+ return (
+
+ {planets.map(planet => (
+
{planet.name}
+ ))}
+
+ )
+}
+```
+
+::: info
+These examples use Next.js, but the same pattern also works in SvelteKit, Nuxt, and other fullstack frameworks.
+:::
diff --git a/apps/content/docs/binary-data.md b/apps/content/docs/binary-data.md
new file mode 100644
index 000000000..036b75b01
--- /dev/null
+++ b/apps/content/docs/binary-data.md
@@ -0,0 +1,60 @@
+# Binary Data
+
+[File](https://developer.mozilla.org/en-US/docs/Web/API/File), [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob), and [ReadableStream\](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) are supported by the [RPC Serializer](/docs/rpc/serializer) and [OpenAPI Serializer](/docs/openapi/serializer). Use them to handle binary data in your procedures.
+
+
+
+## `File` and `Blob`
+
+Procedures can accept `File` and `Blob` as input and return them directly or inside nested structures.
+
+::: warning
+`File` and `Blob` are usually buffered in memory by default. For large files, we recommend [extending the body parser](/docs/advanced/extend-body-parser) for better performance and reliability.
+:::
+
+```ts twoslash
+import { os } from '@orpc/server'
+import * as z from 'zod'
+// ---cut---
+const example = os
+ .input(z.file())
+ .output(z.object({ anyFieldName: z.instanceof(File) }))
+ .handler(async ({ input }) => {
+ const file = input
+
+ console.log(file.name)
+
+ return {
+ anyFieldName: new File(['Hello World'], 'hello.txt', { type: 'text/plain' }),
+ }
+ })
+```
+
+## `ReadableStream`
+
+Procedures can return `ReadableStream` to stream binary responses. The example below uses the [Response Headers Plugin](/docs/plugins/response-headers) to set the appropriate `Content-Type` header.
+
+```ts twoslash
+import { os } from '@orpc/server'
+import { ResponseHeadersHandlerPluginContext } from '@orpc/server/plugins'
+import * as z from 'zod'
+
+interface ServerContext extends ResponseHeadersHandlerPluginContext {}
+
+const base = os.$context()
+// ---cut---
+const example = base
+ .output(z.instanceof(ReadableStream))
+ .handler(async ({ context }) => {
+ context.resHeaders?.set('Content-Type', 'text/plain')
+
+ const stream = new ReadableStream({
+ start(controller) {
+ controller.enqueue(new TextEncoder().encode('Hello World'))
+ controller.close()
+ }
+ })
+
+ return stream
+ })
+```
diff --git a/apps/content/docs/client/client-side.md b/apps/content/docs/client/client-side.md
index 8c598d41a..c9df8edb4 100644
--- a/apps/content/docs/client/client-side.md
+++ b/apps/content/docs/client/client-side.md
@@ -1,11 +1,6 @@
----
-title: Client-Side Clients
-description: Call your oRPC procedures remotely as if they were local functions.
----
-
# Client-Side Clients
-Call your [procedures](/docs/procedure) remotely as if they were local functions.
+Client-side clients call procedures remotely, in a different process or on a different machine. They are useful in frontend applications, mobile apps, or any setup where the client and server run in different environments.
## Installation
@@ -35,35 +30,22 @@ deno add npm:@orpc/client@latest
## Creating a Client
-This guide uses [RPCLink](/docs/client/rpc-link), so make sure your server is set up with [RPCHandler](/docs/rpc-handler) or any API that follows the [RPC Protocol](/docs/advanced/rpc-protocol).
+To create a client, first set up a link that defines how the client communicates with the server. This can be an [RPC Link](/docs/rpc/link), an [OpenAPI Link](/docs/openapi/link), or any custom link. Then create a client for your [router](/docs/router) or [contract](/docs/contract/router) using `createORPCClient`.
```ts
-import { createORPCClient, onError } from '@orpc/client'
-import { RPCLink } from '@orpc/client/fetch'
+import { createORPCClient } from '@orpc/client'
+import { RouterContractClient } from '@orpc/contract'
import { RouterClient } from '@orpc/server'
-import { ContractRouterClient } from '@orpc/contract'
-
-const link = new RPCLink({
- url: 'http://localhost:3000/rpc',
- headers: () => ({
- authorization: 'Bearer token',
- }),
- // fetch: <-- provide fetch polyfill fetch if needed
- interceptors: [
- onError((error) => {
- console.error(error)
- })
- ],
-})
-// Create a client for your router
-const client: RouterClient = createORPCClient(link)
-// Or, create a client using a contract
-const client: ContractRouterClient = createORPCClient(link)
+// if you are following contract-first approach
+const contractClient: RouterContractClient = createORPCClient(link)
+
+// if you are following normal approach
+const normalClient: RouterClient = createORPCClient(link)
```
:::tip
-You can export `RouterClient` and `ContractRouterClient` from server instead.
+You can export `RouterClient` or `RouterContractClient` from the server to avoid importing the contract or router in the client.
:::
## Calling Procedures
@@ -71,20 +53,88 @@ You can export `RouterClient` and `ContractRouterClient 'pong'),
+ pong: os.handler(() => 'ping'),
+}
-const client = {} as RouterClient
+declare const client: RouterClient
// ---cut---
-const planet = await client.planet.find({ id: 1 })
+const pong = await client.ping()
-client.planet.create
-// ^|
+client.ping
+// ^|
```
-## Merge Clients
+## Client Context
+
+Client context lets you pass values with each call, such as auth tokens or cache hints.
+
+```ts
+interface ClientContext {
+ token?: string
+}
+
+// if you are following contract-first approach
+const client: RouterContractClient = createORPCClient(link)
+
+// if you are following normal approach
+const client: RouterClient = createORPCClient(link)
+
+const output = await client.someProcedure(input, {
+ context: {
+ token: 'abc123',
+ },
+})
+```
+
+## Interceptors
+
+Interceptors let you wrap client calls. They are similar to interceptors in links, but are more typesafe because the exact input, output, and error types of each client are known. You can provide per-client interceptors with `scoped`.
+
+```ts
+import { isInferableError, safe } from '@orpc/client'
+
+const client: RouterClient = createORPCClient(link, {
+ interceptors: [
+ async ({ context, path, next }) => {
+ const [error, data] = await safe(next())
+
+ if (error) {
+ if (isInferableError(error)) {
+ // handle typesafe errors
+ }
+
+ throw error
+ }
+
+ return data
+ }
+ ],
+ scoped: {
+ planet: {
+ find: {
+ interceptors: [ // <- these interceptors only apply to client.planet.find
+ async ({ context, path, next }) => {
+ return next()
+ }
+ ]
+ }
+ }
+ }
+})
+```
+
+::: info
+You can use [`safe` and `isInferableError`](/docs/client/error-handling#using-safe-and-isinferableerror) together for typesafe error handling in interceptors.
+:::
+
+## Merging Clients
-In oRPC, a client is a simple object-like structure. To merge multiple clients, you simply assign each client to a property in a new object:
+In oRPC, a client is just an object-like structure. To merge multiple clients, assign each client to a property on a new object:
```ts
const clientA: RouterClient = createORPCClient(linkA)
@@ -101,14 +151,14 @@ export const orpc = {
## Utilities
::: info
-These utilities can be used for any kind of oRPC client.
+These utilities can also be used for [server-side clients](/docs/client/server-side) and are not specific to client-side clients.
:::
### Infer Client Inputs
-```ts twoslash
-import type { orpc as client } from './shared/planet'
-// ---cut---
+Infers input types for each procedure in a client.
+
+```ts
import type { InferClientInputs } from '@orpc/client'
type Inputs = InferClientInputs
@@ -116,13 +166,11 @@ type Inputs = InferClientInputs
type FindPlanetInput = Inputs['planet']['find']
```
-Recursively infers the **input types** from a client. Produces a nested map where each endpoint's input type is preserved.
-
### Infer Client Body Inputs
-```ts twoslash
-import type { orpc as client } from './shared/planet'
-// ---cut---
+Infers body input types for each procedure in a client. If an endpoint's input includes `{ body: ... }`, only the `body` portion is extracted. Otherwise, the entire input type is used.
+
+```ts
import type { InferClientBodyInputs } from '@orpc/client'
type BodyInputs = InferClientBodyInputs
@@ -130,13 +178,11 @@ type BodyInputs = InferClientBodyInputs
type FindPlanetBodyInput = BodyInputs['planet']['find']
```
-Recursively infers the **body input types** from a client. If an endpoint's input includes `{ body: ... }`, only the `body` portion is extracted. Produces a nested map of body input types.
-
### Infer Client Outputs
-```ts twoslash
-import type { orpc as client } from './shared/planet'
-// ---cut---
+Infers output types for each procedure in a client.
+
+```ts
import type { InferClientOutputs } from '@orpc/client'
type Outputs = InferClientOutputs
@@ -144,13 +190,11 @@ type Outputs = InferClientOutputs
type FindPlanetOutput = Outputs['planet']['find']
```
-Recursively infers the **output types** from a client. Produces a nested map where each endpoint's output type is preserved.
-
### Infer Client Body Outputs
-```ts twoslash
-import type { orpc as client } from './shared/planet'
-// ---cut---
+Infers body output types for each procedure in a client. If an endpoint's output includes `{ body: ... }`, only the `body` portion is extracted. Otherwise, the entire output type is used.
+
+```ts
import type { InferClientBodyOutputs } from '@orpc/client'
type BodyOutputs = InferClientBodyOutputs
@@ -158,13 +202,11 @@ type BodyOutputs = InferClientBodyOutputs
type FindPlanetBodyOutput = BodyOutputs['planet']['find']
```
-Recursively infers the **body output types** from a client. If an endpoint's output includes `{ body: ... }`, only the `body` portion is extracted. Produces a nested map of body output types.
-
### Infer Client Errors
-```ts twoslash
-import type { orpc as client } from './shared/planet'
-// ---cut---
+Infers the errors each procedure in a client can throw when using [type-safe error handling](/docs/error-handling#typesafe-errors).
+
+```ts
import type { InferClientErrors } from '@orpc/client'
type Errors = InferClientErrors
@@ -172,28 +214,22 @@ type Errors = InferClientErrors
type FindPlanetError = Errors['planet']['find']
```
-Recursively infers the **error types** from a client when using [type-safe error handling](/docs/error-handling#type‐safe-error-handling). Produces a nested map where each endpoint's error type is preserved.
+### Infer Client Error
-### Infer Client Error Union
+Infers all possible errors the entire client can throw. This is useful with [type-safe error handling](/docs/error-handling#typesafe-errors).
-```ts twoslash
-import type { orpc as client } from './shared/planet'
-// ---cut---
-import type { InferClientErrorUnion } from '@orpc/client'
+```ts
+import type { InferClientError } from '@orpc/client'
-type AllErrors = InferClientErrorUnion
+type ClientError = InferClientError
```
-Recursively infers a **union of all error types** from a client when using [type-safe error handling](/docs/error-handling#type‐safe-error-handling). Useful when you want to handle all possible errors from any endpoint at once.
-
### Infer Client Context
-```ts twoslash
-import type { orpc as client } from './shared/planet'
-// ---cut---
+Infers the [client context](#client-context) type from a client.
+
+```ts
import type { InferClientContext } from '@orpc/client'
type Context = InferClientContext
```
-
-Infers the client context type from a client.
diff --git a/apps/content/docs/client/dynamic-link.md b/apps/content/docs/client/dynamic-link.md
index ef888b81b..642f58bd7 100644
--- a/apps/content/docs/client/dynamic-link.md
+++ b/apps/content/docs/client/dynamic-link.md
@@ -1,20 +1,17 @@
----
-title: DynamicLink
-description: Dynamically switch between multiple oRPC's links.
----
-
# DynamicLink
-`DynamicLink` lets you dynamically choose between different oRPC's links based on your client context. This capability enables flexible routing of RPC requests.
+`DynamicLink` lets you choose a link at runtime. Use it when different requests should be routed through different links.
## Example
-This example shows how the client dynamically selects between two [RPCLink](/docs/client/rpc-link) instances based on the client context: one dedicated to cached requests and another for non-cached requests.
-
```ts twoslash
-import { router } from './shared/planet'
-import { RouterClient } from '@orpc/server'
+import { os, RouterClient } from '@orpc/server'
import { RPCLink } from '@orpc/client/fetch'
+
+const router = {
+ ping: os.handler(() => 'pong'),
+ pong: os.handler(() => 'ping'),
+}
// ---cut---
import { createORPCClient, DynamicLink } from '@orpc/client'
@@ -23,11 +20,11 @@ interface ClientContext {
}
const cacheLink = new RPCLink({
- url: 'https://cache.example.com/rpc',
+ origin: 'https://cache.example.com',
})
const noCacheLink = new RPCLink({
- url: 'https://example.com/rpc',
+ origin: 'https://example.com',
})
const link = new DynamicLink((options, path, input) => {
@@ -41,6 +38,6 @@ const link = new DynamicLink((options, path, input) => {
const client: RouterClient = createORPCClient(link)
```
-:::info
-Any oRPC's link is supported, not strictly limited to `RPCLink`.
+::: info
+This example uses two [RPC Link](/docs/rpc/link) instances, but `DynamicLink` works with any other link.
:::
diff --git a/apps/content/docs/client/error-handling.md b/apps/content/docs/client/error-handling.md
index cd23f542e..c52f0f43b 100644
--- a/apps/content/docs/client/error-handling.md
+++ b/apps/content/docs/client/error-handling.md
@@ -1,21 +1,31 @@
----
-title: Error Handling in oRPC Clients
-description: Learn how to handle errors in a type-safe way in oRPC clients.
----
+# Client Error Handling
-# Error Handling in oRPC Clients
+oRPC supports several ways to handle client-side errors. In most cases, `try/catch` is enough. If you use [Typesafe Errors](/docs/error-handling#typesafe-errors), `safe` and `createSafeClient` let you handle them with full type inference.
-This guide explains how to handle type-safe errors in oRPC clients using [type-safe error handling](/docs/error-handling#type‐safe-error-handling). Both [server-side](/docs/client/server-side) and [client-side](/docs/client/client-side) clients are supported.
+## Using `try/catch`
-## Using `safe` and `isDefinedError`
+For most calls, use regular `try/catch`.
+
+```ts
+try {
+ const data = await client.doSomething({ id: '123' })
+}
+catch (error) {
+ // handle error
+}
+```
+
+## Using `safe` and `isInferableError`
+
+When working with [Typesafe Errors](/docs/error-handling#typesafe-errors), use `safe` to preserve error type inference. It behaves like `try/catch`, but returns the typesafe result instead of throwing.
```ts twoslash
-import { os } from '@orpc/server'
+import { call, os } from '@orpc/server'
import * as z from 'zod'
// ---cut---
-import { isDefinedError, safe } from '@orpc/client'
+import { isInferableError, safe } from '@orpc/client'
-const doSomething = os
+const exampleProcedure = os
.input(z.object({ id: z.string() }))
.errors({
RATE_LIMIT_EXCEEDED: {
@@ -24,16 +34,17 @@ const doSomething = os
})
.handler(async ({ input, errors }) => {
throw errors.RATE_LIMIT_EXCEEDED({ data: { retryAfter: 1000 } })
-
- return { id: input.id }
})
- .callable()
-const [error, data, isDefined] = await safe(doSomething({ id: '123' }))
-// or const { error, data, isDefined } = await safe(doSomething({ id: '123' }))
+// or { error, data, inferableError }
+const [error, data, inferableError] = await safe(
+ call(exampleProcedure, { id: '123' })
+)
+
+if (isInferableError(error)) { // or inferableError
+ // handle inferable error
-if (isDefinedError(error)) { // or isDefined
- // handle known error
+ // or inferableError.data.retryAfter
console.log(error.data.retryAfter)
}
else if (error) {
@@ -45,18 +56,18 @@ else {
}
```
-:::info
+::: info
+`safe` supports both tuple and object forms:
-- `safe` works like `try/catch`, but can infer error types.
-- `safe` supports both tuple `[error, data, isDefined]` and object `{ error, data, isDefined }` styles.
-- `isDefinedError` checks if an error originates from `.errors`.
-- `isDefined` can replace `isDefinedError`
+- `[error, data, inferableError]`
+- `{ error, data, inferableError }`
+`inferableError` is the same value as `error` when `isInferableError(error)` returns `true`; otherwise it is `null`.
:::
## Safe Client
-If you often use `safe` for error handling, `createSafeClient` can simplify your code by automatically wrapping all procedure calls with `safe`. It works with both [server-side](/docs/client/server-side) and [client-side](/docs/client/client-side) clients.
+If you use `safe` often, `createSafeClient` can reduce repetition by wrapping entire client calls with `safe`.
```ts
import { createSafeClient } from '@orpc/client'
diff --git a/apps/content/docs/client/event-iterator.md b/apps/content/docs/client/event-iterator.md
index 82cffede9..b4cde24ac 100644
--- a/apps/content/docs/client/event-iterator.md
+++ b/apps/content/docs/client/event-iterator.md
@@ -1,24 +1,18 @@
----
-title: Event Iterator in oRPC Clients
-description: Learn how to use event iterators in oRPC clients.
----
+# Event Iterator in Client
-# Event Iterator in oRPC Clients
-
-An [Event Iterator](/docs/event-iterator) in oRPC behaves like an [AsyncGenerator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator).
-Simply iterate over it and await each event.
+Consume an [Event Iterator](/docs/event-iterator) like an [AsyncGenerator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator). Await the call, then iterate over events as they arrive.
## Basic Usage
```ts twoslash
-import { ContractRouterClient, eventIterator, oc } from '@orpc/contract'
-import * as z from 'zod'
+import { eventIterator, oc, RouterContractClient } from '@orpc/contract'
+import { z } from 'zod'
const contract = {
streaming: oc.output(eventIterator(z.object({ message: z.string() })))
}
-declare const client: ContractRouterClient
+declare const client: RouterContractClient
// ---cut---
const iterator = await client.streaming()
@@ -27,9 +21,9 @@ for await (const event of iterator) {
}
```
-## Stopping the Stream Manually
+## Stopping the Stream
-You can rely on `signal` or `.return` to stop the iterator.
+Use an `AbortSignal` or call `.return` to stop the iterator.
```ts
const controller = new AbortController()
@@ -38,8 +32,8 @@ const iterator = await client.streaming(undefined, { signal: controller.signal }
// Stop the stream after 1 second
setTimeout(async () => {
controller.abort()
- // or
- await iterator.return()
+
+ // Or call `await iterator.return()` if you already have the iterator instance.
}, 1000)
for await (const event of iterator) {
@@ -50,7 +44,7 @@ for await (const event of iterator) {
## Error Handling
::: info
-Unlike traditional SSE, the Event Iterator does not automatically retry on error. To enable automatic retries, refer to the [Client Retry Plugin](/docs/plugins/client-retry).
+Unlike traditional SSE, Event Iterators do not retry automatically after an error. To add retries, use the [Retry Plugin](/docs/plugins/retry#event-source-simulation).
:::
```ts
@@ -68,13 +62,24 @@ catch (error) {
}
```
-::: info
-Errors thrown by the server can be instances of `ORPCError`.
-:::
+## Event Metadata
+
+Use `getEventMeta` to read [event metadata](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#event_stream_format) for each item, such as the event ID and retry interval.
+
+```ts
+import { getEventMeta } from '@orpc/client'
+
+const iterator = await client.streaming()
+
+for await (const event of iterator) {
+ const meta = getEventMeta(event)
+ console.log(event.message, meta?.id, meta?.retry)
+}
+```
## Using `consumeEventIterator`
-oRPC provides a utility function `consumeEventIterator` to consume an event iterator with lifecycle callbacks.
+Use `consumeEventIterator` to consume an event iterator with lifecycle callbacks. It accepts either an event iterator or a promise that resolves to one.
```ts
import { consumeEventIterator } from '@orpc/client'
@@ -99,7 +104,3 @@ setTimeout(async () => {
await cancel()
}, 1000)
```
-
-:::info
-This utility accepts both promises and event iterators. Passing a promise directly lets it infer correct error type.
-:::
diff --git a/apps/content/docs/client/rpc-link.md b/apps/content/docs/client/rpc-link.md
deleted file mode 100644
index bb0495911..000000000
--- a/apps/content/docs/client/rpc-link.md
+++ /dev/null
@@ -1,181 +0,0 @@
----
-title: RPCLink
-description: Details on using RPCLink in oRPC clients.
----
-
-# RPCLink
-
-RPCLink enables communication with an [RPCHandler](/docs/rpc-handler) or any API that follows the [RPC Protocol](/docs/advanced/rpc-protocol) using HTTP/Fetch.
-
-:::warning
-This documentation is focused on the [HTTP Adapter](/docs/adapters/http).
-Other adapters may remove or change options to keep things simple.
-:::
-
-## Overview
-
-Before using RPCLink, make sure your server is set up with [RPCHandler](/docs/rpc-handler) or any API that follows the [RPC Protocol](/docs/advanced/rpc-protocol).
-
-```ts
-import { onError } from '@orpc/client'
-import { RPCLink } from '@orpc/client/fetch'
-
-const link = new RPCLink({
- url: 'http://localhost:3000/rpc',
- headers: () => ({
- 'x-api-key': 'my-api-key'
- }),
- fetch: (request, init) => {
- return globalThis.fetch(request, {
- ...init,
- credentials: 'include', // Include cookies for cross-origin requests
- })
- },
- interceptors: [
- onError((error) => {
- console.error(error)
- })
- ],
-})
-
-export const client: RouterClient = createORPCClient(link)
-```
-
-## Using Client Context
-
-Client context lets you pass extra information when calling procedures and dynamically modify RPCLink's behavior.
-
-```ts twoslash
-import { router } from './shared/planet'
-import { RouterClient } from '@orpc/server'
-import { createORPCClient } from '@orpc/client'
-import { RPCLink } from '@orpc/client/fetch'
-
-interface ClientContext {
- something?: string
-}
-
-const link = new RPCLink({
- url: 'http://localhost:3000/rpc',
- headers: async ({ context }) => ({
- 'x-api-key': context?.something ?? ''
- })
-})
-
-const client: RouterClient = createORPCClient(link)
-
-const result = await client.planet.list(
- { limit: 10 },
- { context: { something: 'value' } }
-)
-```
-
-:::info
-If a property in `ClientContext` is required, oRPC enforces its inclusion when calling procedures.
-:::
-
-## Custom Request Method
-
-By default, RPCLink sends requests via `POST`. You can override this to use methods like `GET` (for browser or CDN caching) based on your requirements.
-
-::: warning
-By default, [RPCHandler](/docs/rpc-handler) in the [HTTP Adapter](/docs/adapters/http) enabled [StrictGetMethodPlugin](/docs/rpc-handler#default-plugins) which blocks GET requests except for procedures explicitly allowed. Please refer to [StrictGetMethodPlugin](/docs/plugins/strict-get-method) for more details.
-:::
-
-```ts twoslash
-import { RPCLink } from '@orpc/client/fetch'
-
-interface ClientContext {
- cache?: RequestCache
-}
-
-const link = new RPCLink({
- url: 'http://localhost:3000/rpc',
- method: ({ context }, path) => {
- // Use GET for cached responses
- if (context?.cache) {
- return 'GET'
- }
-
- // Use GET for rendering requests
- if (typeof window === 'undefined') {
- return 'GET'
- }
-
- // Use GET for read-like operations
- if (path.at(-1)?.match(/^(?:get|find|list|search)(?:[A-Z].*)?$/)) {
- return 'GET'
- }
-
- return 'POST'
- },
- fetch: (request, init, { context }) => globalThis.fetch(request, {
- ...init,
- cache: context?.cache,
- }),
-})
-```
-
-::: details Automatically use method specified in contract?
-
-By using `inferRPCMethodFromContractRouter`, the `RPCLink` automatically uses the method specified in the contract when sending requests.
-
-```ts
-import { inferRPCMethodFromContractRouter } from '@orpc/contract'
-
-const link = new RPCLink({
- url: 'http://localhost:3000/rpc',
- method: inferRPCMethodFromContractRouter(contract),
-})
-```
-
-::: info
-A normal [router](/docs/router) works as a contract router as long as it does not include a [lazy router](/docs/router#lazy-router). For more advanced use cases, refer to the [Router to Contract](/docs/contract-first/router-to-contract) guide.
-:::
-
-## Lazy URL
-
-You can define `url` as a function, ensuring compatibility with environments that may lack certain runtime APIs.
-
-```ts
-const link = new RPCLink({
- url: () => {
- if (typeof window === 'undefined') {
- throw new Error('RPCLink is not allowed on the server side.')
- }
-
- return `${window.location.origin}/rpc`
- },
-})
-```
-
-## SSE Like Behavior
-
-Unlike traditional SSE, the [Event Iterator](/docs/event-iterator) does not automatically retry on error. To enable automatic retries, refer to the [Client Retry Plugin](/docs/plugins/client-retry).
-
-## Lifecycle
-
-```mermaid
-sequenceDiagram
- actor A1 as Client
- participant P1 as Input/Output/Error Encoder
- participant P2 as Client Sender
- participant P3 as Adapter
-
- A1 ->> P1: input, signal, lastEventId, ...
- Note over P1: interceptors
- P1 ->> P1: encode request
- P1 ->> P2: standard request
- Note over P2: clientInterceptors
- P2 ->> P3: adapter request
- Note over P3: adapterInterceptors
- P3 ->> P3: send
- P3 ->> P2: adapter response
- P2 ->> P1: standard response
- P1 ->> P1: decode response
- P1 ->> A1: error/output
-```
-
-::: tip
-Interceptors can be used to intercept and modify the lifecycle at various stages.
-:::
diff --git a/apps/content/docs/client/server-side.md b/apps/content/docs/client/server-side.md
index 1b1d7f64e..92c2790a5 100644
--- a/apps/content/docs/client/server-side.md
+++ b/apps/content/docs/client/server-side.md
@@ -1,65 +1,58 @@
----
-title: Server-Side Clients
-description: Call your oRPC procedures in the same environment as your server like native functions.
----
-
# Server-Side Clients
-Call your [procedures](/docs/procedure) in the same environment as your server, no proxies required like native functions.
-
-## Calling Procedures
-
-oRPC offers multiple methods to invoke a [procedure](/docs/procedure).
+Server-side clients call procedures locally, within the same process. They are useful in microservices, serverless functions, or any setup where the caller and procedures run in the same environment.
-### Using `.callable`
+## One-Off Calls
-Define your procedure and turn it into a callable procedure:
+Use `call` when you need to invoke a single procedure without creating a client instance.
```ts twoslash
-import { os } from '@orpc/server'
import * as z from 'zod'
-const getProcedure = os
- .input(z.object({ id: z.string() }))
- .handler(async ({ input }) => ({ id: input.id }))
- .callable({
- context: {} // Provide initial context if needed
- })
-
-const result = await getProcedure({ id: '123' })
-```
-
-### Using the `call` Utility
-
-Alternatively, call your procedure using the `call` helper:
-
-```ts twoslash
-import * as z from 'zod'
+const exampleProcedure = os
+ .input(z.string())
+ .handler(async ({ input }) => ({ id: input }))
+// ---cut---
import { call, os } from '@orpc/server'
-const getProcedure = os
- .input(z.object({ id: z.string() }))
- .handler(async ({ input }) => ({ id: input.id }))
-
-const result = await call(getProcedure, { id: '123' }, {
- context: {} // Provide initial context if needed
+const result = await call(exampleProcedure, 'input', {
+ context: {} // <- provide initial context if needed
})
```
-## Router Client
+## Router Clients
-Create a [router](/docs/router) based client to access multiple procedures:
+Use `createRouterClient` to create a client for your [router](/docs/router). This is useful when you want to call multiple procedures.
```ts twoslash
import * as z from 'zod'
-// ---cut---
-import { createRouterClient, os } from '@orpc/server'
-
-const ping = os.handler(() => 'pong')
-const pong = os.handler(() => 'ping')
+import { os } from '@orpc/server'
-const client = createRouterClient({ ping, pong }, {
- context: {} // Provide initial context if needed
+const router = {
+ ping: os.handler(() => 'pong'),
+ pong: os.handler(() => 'ping'),
+}
+// ---cut---
+import { createRouterClient } from '@orpc/server'
+
+const client = createRouterClient(router, {
+ context: {}, // <- provide initial context if needed, can be async function
+ interceptors: [
+ async ({ next, path }) => {
+ console.time(path.join('.'))
+
+ try {
+ return await next()
+ }
+ catch (err) {
+ console.error(`${path.join('.')}:`, err)
+ throw err
+ }
+ finally {
+ console.timeEnd(path.join('.'))
+ }
+ }
+ ]
})
const result = await client.ping()
@@ -67,73 +60,92 @@ const result = await client.ping()
### Client Context
-You can define a client context to pass additional information when calling procedures. This is useful for modifying procedure behavior dynamically.
+Client context is passed with each call. Use it to switch between contexts, such as different users or tenants, without creating multiple client instances.
```ts twoslash
import * as z from 'zod'
import { createRouterClient, os } from '@orpc/server'
+
+const router = {
+ ping: os.handler(() => 'pong'),
+ pong: os.handler(() => 'ping'),
+}
// ---cut---
interface ClientContext {
cache?: boolean
}
-const ping = os.handler(() => 'pong')
-const pong = os.handler(() => 'ping')
-
-const client = createRouterClient({ ping, pong }, {
+const client = createRouterClient(router, {
context: ({ cache }: ClientContext) => { // [!code highlight]
if (cache) {
- return {} // <-- context when cache enabled
+ return {} // <- context when cache enabled
}
- return {} // <-- context when cache disabled
+ return {}
}
})
const result = await client.ping(undefined, { context: { cache: true } })
```
-:::info
-If `ClientContext` contains a required property, oRPC enforces that the client provides it when calling a procedure.
-:::
+### Interceptors
-## Lifecycle
+Interceptors let you observe or modify an entire call. Common use cases include logging, error handling, and metrics collection.
-```mermaid
-sequenceDiagram
- actor A1 as Client
- participant P1 as Error Validator
- participant P2 as Input/Output Validator
- participant P3 as Handler
-
- A1 ->> P2: input, signal, lastEventId, ...
- Note over P2: interceptors
- Note over P2: middlewares before .input
- P2 ->> P2: Validate Input
- P2 ->> P1: if invalid input
- P1 ->> P1: validate error
- P1 ->> A1: invalid input error
- Note over P2: middlewares after .input
- P2 ->> P3: validated input, signal, lastEventId, ...
- P3 ->> P3: handle
- P3 ->> P2: error/output
- P2 ->> P2: validate output
- P2 ->> P1: error/validated output
- P1 ->> P1: validate error
- P1 ->> A1: validated error/output
+```ts
+const client = createRouterClient(router, {
+ interceptors: [
+ async ({ next, path, context }) => {
+ console.time(path.join('.'))
+
+ try {
+ const output = await next()
+ return output
+ }
+ catch (err) {
+ console.error(`${path.join('.')}:`, err)
+ throw err
+ }
+ finally {
+ console.timeEnd(path.join('.'))
+ }
+ }
+ ]
+})
```
-### Middlewares Order
+## `.callable` extension
-To ensure that all middlewares run after input validation and before output validation, apply the following configuration:
+Import `@orpc/server/extensions/callable` from a module that always runs during initialization, such as the file where you define your base builder or create your server. This adds a `.callable` method to the decorated procedure, allowing you to call it directly like a regular function while still using it as a regular procedure.
-```ts
-const base = os.$config({
- initialInputValidationIndex: Number.NEGATIVE_INFINITY,
- initialOutputValidationIndex: Number.NEGATIVE_INFINITY,
-})
+::: code-group
+
+```ts [usage]
+const ping = base
+ .input(z.object({ name: z.string(), }))
+ .handler(async ({ input }) => `Hello ${input.name}!`)
+ .callable({
+ context: async () => ({}), // <- provide initial context if needed, can be async function
+ interceptors: [], // <- client interceptors
+ })
+
+const router = {
+ ping, // <- still use it as a regular procedure
+}
+
+const message = await ping({ name: 'World' }) // <- or call it directly
+```
+
+```ts [setup]
+import '@orpc/server/extensions/callable'
+
+import { os } from '@orpc/server'
+
+export const base = os
```
-:::info
-By default, oRPC executes middlewares based on their registration order relative to validation steps. Middlewares registered before `.input` run before input validation, and those registered after `.output` run before output validation.
:::
+
+## Lifecycle
+
+TODO: add lifecycle diagram
diff --git a/apps/content/docs/comparison.md b/apps/content/docs/comparison.md
deleted file mode 100644
index a07ed5272..000000000
--- a/apps/content/docs/comparison.md
+++ /dev/null
@@ -1,41 +0,0 @@
----
-title: Comparison
-description: How is oRPC different from other RPC or REST solutions?
----
-
-# Comparison
-
-This comparison table helps you understand how oRPC differs from other popular TypeScript RPC and REST solutions.
-
-- ✅ First-class, built-in support
-- 🟡 Lacks features, or requires third-party integrations
-- 🛑 Not supported or not documented
-
-| Feature | oRPC docs | oRPC | tRPC | ts-rest | Hono |
-| ---------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | ---- | ---- | ------- | ---- |
-| End-to-end Typesafe Input/Output | | ✅ | ✅ | ✅ | ✅ |
-| End-to-end Typesafe Errors | [1](/docs/client/error-handling), [2](/docs/error-handling#type%E2%80%90safe-error-handling) | ✅ | 🟡 | ✅ | ✅ |
-| End-to-end Typesafe File/Blob | [1](/docs/file-upload-download) | ✅ | 🟡 | 🛑 | 🛑 |
-| End-to-end Typesafe Streaming | [1](/docs/event-iterator) | ✅ | ✅ | 🛑 | 🛑 |
-| Tanstack Query Integration (React) | [1](/docs/integrations/tanstack-query) | ✅ | ✅ | 🟡 | 🛑 |
-| Tanstack Query Integration (Vue) | [1](/docs/integrations/tanstack-query) | ✅ | 🛑 | 🟡 | 🛑 |
-| Tanstack Query Integration (Solid) | [1](/docs/integrations/tanstack-query) | ✅ | 🛑 | 🟡 | 🛑 |
-| Tanstack Query Integration (Svelte) | [1](/docs/integrations/tanstack-query) | ✅ | 🛑 | 🛑 | 🛑 |
-| Tanstack Query Integration (Angular) | [1](/docs/integrations/tanstack-query) | ✅ | 🛑 | 🛑 | 🛑 |
-| Vue Pinia Colada Integration | [1](/docs/integrations/pinia-colada) | ✅ | 🛑 | 🛑 | 🛑 |
-| With Contract-First Approach | [1](/docs/contract-first/define-contract) | ✅ | 🛑 | ✅ | ✅ |
-| Without Contract-First Approach | | ✅ | ✅ | 🛑 | ✅ |
-| OpenAPI Support | [1](/docs/openapi/openapi-handler) | ✅ | 🟡 | 🟡 | ✅ |
-| OpenAPI Support for multiple schema | [1](/docs/openapi/openapi-handler) | ✅ | 🛑 | 🛑 | ✅ |
-| OpenAPI Bracket Notation Support | [1](/docs/openapi/bracket-notation) | ✅ | 🛑 | 🛑 | 🛑 |
-| Server Actions Support | [1](/docs/server-action) | ✅ | ✅ | 🛑 | 🛑 |
-| Lazy Router | [1](/docs/router#lazy-router) | ✅ | ✅ | 🛑 | 🛑 |
-| Native Types (Date, URL, Set, Maps, ...) | [1](/docs/rpc-handler#supported-data-types) | ✅ | 🟡 | 🛑 | 🛑 |
-| Streaming response (SSE) | [1](/docs/event-iterator) | ✅ | ✅ | 🛑 | ✅ |
-| Standard Schema (Zod, Valibot, ArkType, ...) | | ✅ | ✅ | 🛑 | 🟡 |
-| Built-in Plugins (CORS, CSRF, Retry, ...) | | ✅ | 🛑 | 🛑 | ✅ |
-| Batch Requests | [1](/docs/plugins/batch-requests) | ✅ | ✅ | 🛑 | 🛑 |
-| WebSockets | [1](/docs/adapters/websocket) | ✅ | ✅ | 🛑 | 🛑 |
-| [Cloudflare Websocket Hibernation](https://developers.cloudflare.com/durable-objects/examples/websocket-hibernation-server/) | [1](/docs/plugins/hibernation) | ✅ | 🛑 | 🛑 | 🛑 |
-| Nest.js integration | [1](/docs/openapi/integrations/implement-contract-in-nest) | ✅ | 🟡 | ✅ | 🛑 |
-| Message Port (Electron, Browser, Workers, ...) | [1](/docs/adapters/message-port) | ✅ | 🟡 | 🛑 | 🛑 |
diff --git a/apps/content/docs/context.md b/apps/content/docs/context.md
index 4d78a68fa..49784c60c 100644
--- a/apps/content/docs/context.md
+++ b/apps/content/docs/context.md
@@ -1,156 +1,122 @@
----
-title: Context
-description: Understanding context in oRPC
----
+# Context
-# Context in oRPC
-
-oRPC's context mechanism provides a type-safe dependency injection pattern. It lets you supply required dependencies either explicitly or dynamically through middleware. There are two types:
-
-- **Initial Context:** Provided explicitly when invoking a procedure.
-- **Execution Context:** Generated during procedure execution, typically by middleware.
+The context mechanism provides a type-safe dependency injection pattern. It lets you provide required dependencies explicitly or inject them dynamically through middleware.
## Initial Context
-Initial context is used to define required dependencies (usually environment-specific) that must be passed when calling a procedure.
+Use initial context for values that come from the environment. Declare it with `.$context`, then provide it when executing the procedure:
```ts twoslash
import { os } from '@orpc/server'
// ---cut---
-const base = os.$context<{ headers: Headers, env: { DB_URL: string } }>()
+const base = os.$context<{ env: { DB_URL: string } }>()
-const getting = base
+export const getting = base
.handler(async ({ context }) => {
console.log(context.env)
})
-
-export const router = { getting }
```
-When calling that requires initial context, pass it explicitly:
+::: info
+When a procedure requires initial context when calling, you must manually pass it:
```ts twoslash
-import { os } from '@orpc/server'
+import { call, os } from '@orpc/server'
+
+const base = os.$context<{ env: { DB_URL: string } }>()
+const getting = base.handler(async ({ context }) => {})
+// ---cut---
+const output = await call(getting, undefined, {
+ context: { // <- initial context must be passed when calling
+ env: { DB_URL: 'postgres://...' },
+ },
+})
+```
-const base = os.$context<{ headers: Headers, env: { DB_URL: string } }>()
+:::
-const getting = base
- .handler(async ({ context }) => {
+### Default Initial Context
- })
+To avoid repeating `.$context` declarations, you can define a default initial context type globally.
-export const router = { getting }
-// ---cut---
-import { RPCHandler } from '@orpc/server/fetch'
-
-const handler = new RPCHandler(router)
-
-export default function fetch(request: Request) {
- handler.handle(request, {
- context: { // <-- you must pass initial context here
- headers: request.headers,
- env: {
- DB_URL: '***'
- }
- }
- })
+```ts
+declare module '@orpc/server' {
+ export interface DefaultInitialContext {
+ env: { DB_URL: string }
+ }
}
```
-## Execution context
+## Injected Context
-Execution context is computed during the process lifecycle, usually via [middleware](/docs/middleware). It can be used independently or combined with initial context.
+Injected context is injected at runtime through [middleware](/docs/middleware#middleware-context):
```ts twoslash
import { os } from '@orpc/server'
-// ---cut---
-import { cookies, headers } from 'next/headers'
+declare const env: { DB_URL: string }
+// ---cut---
const base = os.use(async ({ next }) => next({
context: {
- headers: await headers(),
- cookies: await cookies(),
+ env: { DB_URL: env.DB_URL },
},
}))
-const getting = base.handler(async ({ context }) => {
- context.cookies.set('key', 'value')
+export const getting = base.handler(async ({ context }) => {
+ console.log(context.env)
})
-
-export const router = { getting }
```
-When using execution context, you don't need to pass any context manually:
+::: info
+When you use middleware context, you do not need to pass context manually when calling:
```ts twoslash
-import { os } from '@orpc/server'
-import { cookies, headers } from 'next/headers'
+import { call, os } from '@orpc/server'
+
+declare const env: { DB_URL: string }
const base = os.use(async ({ next }) => next({
context: {
- headers: await headers(),
- cookies: await cookies(),
+ env: { DB_URL: env.DB_URL },
},
}))
-const getting = base.handler(async ({ context }) => {
- context.cookies.set('key', 'value')
-})
-
-export const router = { getting }
+const getting = base.handler(async ({ context }) => {})
// ---cut---
-import { RPCHandler } from '@orpc/server/fetch'
-
-const handler = new RPCHandler(router)
-
-export default function fetch(request: Request) {
- handler.handle(request) // <-- no need to pass anything more
-}
+// no need to pass context manually when calling
+const output = await call(getting)
```
-## Combining Initial and Execution Context
+:::
+
+## Combining Initial and Injected Context
-Often you need both static and dynamic dependencies. Use initial context for environment-specific values (e.g., database URLs) and middleware (execution context) for runtime data (e.g., user authentication).
+In many cases, you will use both. Use initial context for environment-specific values, such as database URLs, and injected context for runtime data, such as authenticated users.
```ts twoslash
import { ORPCError, os } from '@orpc/server'
+
+declare function parseJWT(token: string | undefined, secret: string): { userId: number } | null
// ---cut---
-const base = os.$context<{ headers: Headers, env: { DB_URL: string } }>()
+const base = os.$context<{ headers: Headers, env: { JWT_SECRET: string } }>()
const requireAuth = base.middleware(async ({ context, next }) => {
- const user = parseJWT(context.headers.get('authorization')?.split(' ')[1])
+ const user = parseJWT(
+ context.headers.get('authorization')?.split(' ')[1],
+ context.env.JWT_SECRET
+ )
- if (user) {
- return next({ context: { user } })
+ if (!user) {
+ throw new ORPCError('UNAUTHORIZED')
}
- throw new ORPCError('UNAUTHORIZED')
-})
-
-const dbProvider = base.middleware(async ({ context, next }) => {
- const client = new Client(context.env.DB_URL)
-
- try {
- await client.connect()
- return next({ context: { db: client } })
- }
- finally {
- await client.disconnect()
- }
+ return next({ context: { user } })
})
const getting = base
- .use(dbProvider)
.use(requireAuth)
.handler(async ({ context }) => {
- console.log(context.db)
+ console.log(context.env)
console.log(context.user)
})
-// ---cut-after---
-declare function parseJWT(token: string | undefined): { userId: number } | null
-declare class Client {
- constructor(url: string)
- connect(): Promise
- disconnect(): Promise
-}
```
diff --git a/apps/content/docs/contract-first/define-contract.md b/apps/content/docs/contract-first/define-contract.md
deleted file mode 100644
index c01b9d827..000000000
--- a/apps/content/docs/contract-first/define-contract.md
+++ /dev/null
@@ -1,144 +0,0 @@
----
-title: Define Contract
-description: Learn how to define a contract for contract-first development in oRPC
----
-
-# Define Contract
-
-**Contract-first development** is a design pattern where you define the API contract before writing any implementation code. This methodology promotes a well-structured codebase that adheres to best practices and facilitates easier maintenance and evolution over time.
-
-In oRPC, a **contract** specifies the rules and expectations for a procedure. It details the input, output, errors,... types and can include constraints or validations to ensure that both client and server share a clear, consistent interface.
-
-## Installation
-
-::: code-group
-
-```sh [npm]
-npm install @orpc/contract@latest
-```
-
-```sh [yarn]
-yarn add @orpc/contract@latest
-```
-
-```sh [pnpm]
-pnpm add @orpc/contract@latest
-```
-
-```sh [bun]
-bun add @orpc/contract@latest
-```
-
-```sh [deno]
-deno add npm:@orpc/contract@latest
-```
-
-:::
-
-## Procedure Contract
-
-A procedure contract in oRPC is similar to a standard [procedure](/docs/procedure) definition, but with extraneous APIs removed to better support contract-first development.
-
-```ts twoslash
-import * as z from 'zod'
-// ---cut---
-import { oc } from '@orpc/contract'
-
-export const exampleContract = oc
- .input(
- z.object({
- name: z.string(),
- age: z.number().int().min(0),
- }),
- )
- .output(
- z.object({
- id: z.number().int().min(0),
- name: z.string(),
- age: z.number().int().min(0),
- }),
- )
-```
-
-## Contract Router
-
-Similar to the standard [router](/docs/router) in oRPC, the contract router organizes your defined contracts into a structured hierarchy. The contract router is streamlined by removing APIs that are not essential for contract-first development.
-
-```ts
-export const routerContract = {
- example: exampleContract,
- nested: {
- example: exampleContract,
- },
-}
-```
-
-## Full Example
-
-Below is a complete example demonstrating how to define a contract for a simple "Planet" service. This example extracted from our [Getting Started](/docs/getting-started) guide.
-
-```ts twoslash
-import * as z from 'zod'
-import { oc } from '@orpc/contract'
-// ---cut---
-export const PlanetSchema = z.object({
- id: z.number().int().min(1),
- name: z.string(),
- description: z.string().optional(),
-})
-
-export const listPlanetContract = oc
- .input(
- z.object({
- limit: z.number().int().min(1).max(100).optional(),
- cursor: z.number().int().min(0).default(0),
- }),
- )
- .output(z.array(PlanetSchema))
-
-export const findPlanetContract = oc
- .input(PlanetSchema.pick({ id: true }))
- .output(PlanetSchema)
-
-export const createPlanetContract = oc
- .input(PlanetSchema.omit({ id: true }))
- .output(PlanetSchema)
-
-export const contract = {
- planet: {
- list: listPlanetContract,
- find: findPlanetContract,
- create: createPlanetContract,
- },
-}
-```
-
-## Utilities
-
-### Infer Contract Router Input
-
-```ts twoslash
-import type { contract } from './shared/planet'
-// ---cut---
-import type { InferContractRouterInputs } from '@orpc/contract'
-
-export type Inputs = InferContractRouterInputs
-
-type FindPlanetInput = Inputs['planet']['find']
-```
-
-This snippet automatically extracts the expected input types for each procedure in the router.
-
-### Infer Contract Router Output
-
-```ts twoslash
-import type { contract } from './shared/planet'
-// ---cut---
-import type { InferContractRouterOutputs } from '@orpc/contract'
-
-export type Outputs = InferContractRouterOutputs
-
-type FindPlanetOutput = Outputs['planet']['find']
-```
-
-Similarly, this utility infers the output types, ensuring that your application correctly handles the results from each procedure.
diff --git a/apps/content/docs/contract-first/implement-contract.md b/apps/content/docs/contract-first/implement-contract.md
deleted file mode 100644
index da414aafe..000000000
--- a/apps/content/docs/contract-first/implement-contract.md
+++ /dev/null
@@ -1,111 +0,0 @@
----
-title: Implement Contract
-description: Learn how to implement a contract for contract-first development in oRPC
----
-
-# Implement Contract
-
-After defining your contract, the next step is to implement it in your server code. oRPC enforces your contract at runtime, ensuring that your API consistently adheres to its specifications.
-
-## Installation
-
-::: code-group
-
-```sh [npm]
-npm install @orpc/server@latest
-```
-
-```sh [yarn]
-yarn add @orpc/server@latest
-```
-
-```sh [pnpm]
-pnpm add @orpc/server@latest
-```
-
-```sh [bun]
-bun add @orpc/server@latest
-```
-
-```sh [deno]
-deno add npm:@orpc/server@latest
-```
-
-:::
-
-## The Implementer
-
-The `implement` function converts your contract into an implementer instance. This instance compatible with the original `os` from `@orpc/server` provides a type-safe interface to define your procedures and supports features like [Middleware](/docs/middleware) and [Context](/docs/context).
-
-```ts twoslash
-import { contract } from './shared/planet'
-// ---cut---
-import { implement } from '@orpc/server'
-
-const os = implement(contract) // fully replaces the os from @orpc/server
-```
-
-## Implementing Procedures
-
-Define a procedure by attaching a `.handler` to its corresponding contract, ensuring it adheres to the contract's specifications.
-
-```ts twoslash
-import { contract } from './shared/planet'
-import { implement } from '@orpc/server'
-
-const os = implement(contract)
-// ---cut---
-export const listPlanet = os.planet.list
- .handler(({ input }) => {
- // Your logic for listing planets
- return []
- })
-```
-
-## Building the Router
-
-To assemble your API, create a router at the root level using `.router`. This ensures that the entire router is type-checked and enforces the contract at runtime.
-
-```ts
-const router = os.router({ // <-- Essential for full contract enforcement
- planet: {
- list: listPlanet,
- find: findPlanet,
- create: createPlanet,
- },
-})
-```
-
-## Full Implementation Example
-
-Below is a complete implementation of the contract defined in the [previous section](/docs/contract-first/define-contract).
-
-```ts twoslash
-import { contract } from './shared/planet'
-import { implement } from '@orpc/server'
-// ---cut---
-const os = implement(contract)
-
-export const listPlanet = os.planet.list
- .handler(({ input }) => {
- return []
- })
-
-export const findPlanet = os.planet.find
- .handler(({ input }) => {
- return { id: 123, name: 'Planet X' }
- })
-
-export const createPlanet = os.planet.create
- .handler(({ input }) => {
- return { id: 123, name: 'Planet X' }
- })
-
-export const router = os.router({
- planet: {
- list: listPlanet,
- find: findPlanet,
- create: createPlanet,
- },
-})
-```
diff --git a/apps/content/docs/contract-first/router-to-contract.md b/apps/content/docs/contract-first/router-to-contract.md
deleted file mode 100644
index 994e27e4d..000000000
--- a/apps/content/docs/contract-first/router-to-contract.md
+++ /dev/null
@@ -1,55 +0,0 @@
----
-title: Router to Contract
-description: Learn how to convert a router into a contract, safely export it, and prevent exposing internal details to the client.
----
-
-# Router to Contract
-
-A normal [router](/docs/router) works as a contract router as long as it does not include a [lazy router](/docs/router#lazy-router). This guide not only shows you how to **unlazy** a router to make it compatible with contracts, but also how to **minify** it and **prevent internal business logic from being exposed to the client**.
-
-## Unlazy the Router
-
-If your router includes a [lazy router](/docs/router#lazy-router), you need to fully resolve it to make it compatible with contract.
-
-```ts
-import { unlazyRouter } from '@orpc/server'
-
-const resolvedRouter = await unlazyRouter(router)
-```
-
-## Minify & Export the Contract Router for the Client
-
-Sometimes, you'll need to import the contract on the client - for example, to use [OpenAPILink](/docs/openapi/client/openapi-link) or define request methods in [RPCLink](/docs/client/rpc-link#custom-request-method).
-
-If you're using [Contract First](/docs/contract-first/define-contract), this is safe: your contract is already lightweight and free of business logic.
-
-However, if you're deriving the contract from a [router](/docs/router), importing it directly can be heavy and may leak internal logic. To prevent this, follow the steps below to safely minify and export your contract.
-
-1. **Minify the Contract Router and Export to JSON**
-
- ```ts
- import fs from 'node:fs'
- import { minifyContractRouter } from '@orpc/contract'
-
- const minifiedRouter = minifyContractRouter(router)
-
- fs.writeFileSync('./contract.json', JSON.stringify(minifiedRouter))
- ```
-
- ::: warning
- `minifyContractRouter` preserves only the metadata and routing information necessary for the client, all other data will be stripped out.
- :::
-
-2. **Import the Contract JSON on the Client Side**
-
- ```ts
- import contract from './contract.json' // [!code highlight]
-
- const link = new OpenAPILink(contract as typeof router, {
- url: 'http://localhost:3000/api',
- })
- ```
-
- ::: warning
- Cast `contract` to `typeof router` to ensure type safety, since standard schema types cannot be serialized to JSON so we must manually cast them.
- :::
diff --git a/apps/content/docs/contract/implementation.md b/apps/content/docs/contract/implementation.md
new file mode 100644
index 000000000..0bb8341c2
--- /dev/null
+++ b/apps/content/docs/contract/implementation.md
@@ -0,0 +1,140 @@
+# Contract Implementation
+
+Implementing a contract means adding business logic to each procedure defined in that contract. It ensures every implementation stays consistent by verifying that each handler matches the procedure's expected shape.
+
+## Implementer
+
+The `implement` function turns a contract into an implementer. Use it to build procedures, routers, and create middleware with full type safety.
+
+```ts twoslash
+import { contract } from './shared/planet'
+// ---cut---
+import { implement } from '@orpc/server'
+
+const implementer = implement(contract)
+ .$context<{ something?: string }>() // <- define initial context
+
+implementer.planet.list
+// ^|
+
+//
+
+//
+
+//
+//
+```
+
+### Initial Context
+
+Use `.$context` to declare the initial context required for a procedure to execute.
+Learn more in the [Context Documentation](/docs/context).
+
+## Implementing Procedures
+
+Define a `.handler` for a procedure contract to provide its business logic.
+
+```ts twoslash
+import { contract } from './shared/planet'
+import { implement } from '@orpc/server'
+
+const implementer = implement(contract)
+const requireAuth = implementer.middleware(({ next }) => next())
+// ---cut---
+const listPlanet = implementer.planet.list
+ .use(requireAuth) // <- Apply authentication middleware
+ .handler(({ input }) => {
+ // Your logic for listing planets
+ return []
+ })
+```
+
+::: info
+If middleware needs to wrap validation, apply it at the router level instead. In this example, use `implementer.use` to apply it globally or `implementer.planet.use` to apply it to the `planet` router before `.list`.
+
+```ts
+const listPlanet = implementer
+ .planet
+ .use(requireAuth) // <- middleware wraps validation
+ .list
+ .handler(({ input }) => {
+ // Your logic for listing planets
+ return []
+ })
+```
+
+:::
+
+## Implementing Routers
+
+Create the root router with `.router` to assemble your API. This enables full type-checking and runtime contract enforcement.
+
+```ts
+const router = implementer.router({
+ planet: {
+ list: listPlanet,
+ find: findPlanet,
+ create: createPlanet,
+ },
+})
+```
+
+### Extending Router
+
+Like a normal [router](/docs/router), an implementer router can also be extended with shared behavior. For example, you can apply authentication middleware to every procedure:
+
+```ts
+const router = implementer.use(requireAuth).router({
+ planet: {
+ list: listPlanet,
+ find: findPlanet,
+ create: createPlanet,
+ },
+})
+```
+
+::: danger
+If you apply middleware with `.use` at both the router and procedure levels, it may run more than once. That duplication can hurt performance. To avoid redundant middleware execution, see our [best practices for middleware deduplication](/docs/best-practices/dedupe-middleware).
+:::
+
+## Creating Middleware
+
+The implementer can also create [middleware](/docs/middleware). Middleware created this way can infer the contract's [typesafe errors](/docs/error-handling#typesafe-errors). If not all contracts define the same errors, use the `in` operator to check that an error exists before using it.
+
+```ts
+const ratelimit = implementer.middleware(async ({ next, errors }) => {
+ if ('TOO_MANY_REQUESTS' in errors) {
+ // Apply rate limiting only when TOO_MANY_REQUESTS is defined by the contract.
+ if (isRatelimitReached) {
+ throw errors.TOO_MANY_REQUESTS()
+ }
+ }
+
+ return next()
+})
+```
+
+::: info
+You do not have to create middleware from the implementer. Any type-compatible middleware can be used.
+:::
+
+## Reusability
+
+Each implementer call creates a new instance, which avoids reference issues and makes contracts easy to reuse and extend.
+
+```ts
+const pub = implementer // Base setup for procedures that publish
+const authed = implementer.use(requireAuth) // Extends 'pub' with authentication
+
+const listPlanets = pub.planet.list.handler(({ input }) => {
+ // Your logic for listing planets without authentication
+ return []
+})
+
+const createPlanet = authed.planet.create.handler(({ input }) => {
+ // Your logic for creating planets with authentication
+ return { }
+})
+```
+
+This pattern helps prevent duplication while maintaining flexibility.
diff --git a/apps/content/docs/contract/procedure.md b/apps/content/docs/contract/procedure.md
new file mode 100644
index 000000000..7a9b0a06b
--- /dev/null
+++ b/apps/content/docs/contract/procedure.md
@@ -0,0 +1,85 @@
+# Procedure Contract
+
+Procedure contracts define the expected shape of a [procedure](/docs/procedure) without including any business logic. They are useful for documentation, testing, and keeping multiple implementations of the same procedure aligned.
+
+## Overview
+
+```ts twoslash
+import { z } from 'zod'
+import type { AnyMetaPlugin } from '@orpc/contract'
+
+declare const someMeta: AnyMetaPlugin
+// ---cut---
+import { oc } from '@orpc/contract'
+
+const example = oc
+ .meta(someMeta) // <- attach metadata
+ .errors({ NOT_FOUND: {} }) // <- define errors
+ .input(z.object({ id: z.number(), name: z.string() })) // <- input validation
+ .output(z.object({ id: z.number(), name: z.string() })) // <- output validation
+```
+
+:::info
+All of these chains are optional. You can create an empty contract with just `oc`.
+:::
+
+## Metadata
+
+Use `.meta` to attach metadata to a contract. Middleware and plugins can read it later when you implement the contract. Learn more in the [Metadata documentation](/docs/metadata).
+
+## Typesafe Errors
+
+Use `.errors` to define the errors a contract can produce. These errors can be thrown from handlers or middleware when you implement the contract and remain properly typed on the client. Learn more in the [Typesafe Error Handling documentation](/docs/error-handling#typesafe-errors).
+
+## Input/Output Validation
+
+oRPC supports [Zod](https://zod.dev/), [Valibot](https://valibot.dev/), [Arktype](https://arktype.io/), and any other [Standard Schema](https://standardschema.dev/schema#what-schema-libraries-implement-the-spec) library for validation.
+
+::: info
+Unlike a [procedure](/docs/procedure), a contract has no `.handler` chain. If you want the client to infer the output type correctly, define `.output`. Otherwise, the output type will be `unknown`.
+:::
+
+### Multiple Schemas
+
+`.input` and `.output` can be called multiple times. Each call adds another schema instead of replacing an earlier one.
+
+```ts
+const example = oc
+ .input(z.looseObject({ name: z.string() }))
+ .input(z.looseObject({ id: z.number() }))
+ .output(z.looseObject({ name: z.string() }))
+ .output(z.looseObject({ id: z.number() }))
+```
+
+::: warning
+When you stack schemas, the input or output must satisfy all of them, so the schemas need to be compatible. For example, with Zod, prefer `z.looseObject` over `z.object` to allow unknown properties.
+:::
+
+### `type` Utility
+
+For simple use cases without external libraries, use oRPC's built-in `type` utility. It takes a mapping function as its first argument:
+
+```ts
+import { type } from '@orpc/contract'
+
+const example = oc
+ .input(type<{ value: number }>())
+ .output(type<{ value: number }, number>(({ value }) => value))
+```
+
+## Reusability
+
+Each builder call creates a new instance, which avoids reference issues and makes contracts easy to reuse and extend.
+
+```ts
+const pub = oc // Base setup for procedures that publish
+const authed = pub.meta(requireAuthMeta) // Extends 'pub' with authentication
+
+const pubExample = pub
+ .input(z.object({ name: z.string() }))
+
+const authedExample = authed
+ .input(z.object({ id: z.number() }))
+```
+
+This pattern helps prevent duplication while maintaining flexibility.
diff --git a/apps/content/docs/contract/router.md b/apps/content/docs/contract/router.md
new file mode 100644
index 000000000..474248532
--- /dev/null
+++ b/apps/content/docs/contract/router.md
@@ -0,0 +1,158 @@
+# Router Contract
+
+Router contracts define the shape of a [router](/docs/router) without including any business logic. Use them for documentation, testing, and keeping multiple implementations of the same router aligned.
+
+::: info
+A standalone [procedure contract](/docs/contract/procedure) is also a router contract, so you can use the same features with individual procedure contracts.
+:::
+
+## Overview
+
+Define a router contract as a plain JavaScript object where each key maps to a procedure contract:
+
+```ts twoslash
+import { z } from 'zod'
+// ---cut---
+import { oc } from '@orpc/contract'
+
+const ping = oc.output(z.string())
+const pong = oc.output(z.string())
+
+export const router = {
+ ping,
+ pong,
+ nested: { ping, pong }
+}
+```
+
+
+
+## Extending Router
+
+You can extend a router contract with shared configuration, such as attaching metadata to every procedure:
+
+```ts
+const router = oc.meta(requireAuthMeta).router({
+ ping,
+ pong,
+ nested: {
+ ping,
+ pong,
+ }
+})
+```
+
+## Router to Contract
+
+A normal [router](/docs/router) can be used as a contract router as long as it does not include a [lazy router](/docs/router#lazy-router). If necessary, use `unlazyRouter` to fully resolve it and make it contract-compatible.
+
+```ts
+import { unlazyRouter } from '@orpc/server'
+
+const compatibleContract = await unlazyRouter(router)
+```
+
+### Safely Importing Router on the Client
+
+Sometimes you need to import the contract on the client, for example when using [OpenAPI Link](/docs/openapi/link). If you derive the contract from a [router](/docs/router), importing it directly can be heavy and may expose internal logic. To avoid this, follow the steps below to safely minify and export the contract.
+
+1. **Minify the Contract Router and Export to JSON**
+
+ ```ts
+ import fs from 'node:fs'
+ import { unlazyRouter } from '@orpc/server'
+ import { minifyRouterContract } from '@orpc/contract'
+
+ const compatibleContract = await unlazyRouter(router)
+ const minifiedRouter = minifyRouterContract(compatibleContract)
+
+ fs.writeFileSync('./contract.json', JSON.stringify(minifiedRouter))
+ ```
+
+ ::: info
+ `minifyRouterContract` preserves only the metadata needed by the client; all other data is stripped out.
+ :::
+
+2. **Import the Contract JSON on the Client Side**
+
+ ```ts
+ import contract from './contract.json' // [!code highlight]
+
+ const link = new OpenAPILink(contract as typeof router)
+ ```
+
+ ::: info
+ Cast `contract` to `typeof router` to preserve type safety, since standard schema types cannot be serialized to JSON and must be cast manually.
+ :::
+
+## Utilities
+
+::: info
+A standalone [procedure contract](/docs/contract/procedure) is also a router contract, so these utilities work with individual procedure contracts too.
+:::
+
+### Infer Router Contract Inputs
+
+Infers the input type of each procedure contract in a router contract.
+
+```ts twoslash
+import type { contract } from './shared/planet'
+// ---cut---
+import type { InferRouterContractInputs } from '@orpc/contract'
+
+export type Inputs = InferRouterContractInputs
+
+type FindPlanetInput = Inputs['planet']['find']
+```
+
+### Infer Router Contract Outputs
+
+Infers the output type of each procedure contract in a router contract.
+
+```ts twoslash
+import type { contract } from './shared/planet'
+// ---cut---
+import type { InferRouterContractOutputs } from '@orpc/contract'
+
+export type Outputs = InferRouterContractOutputs
+
+type FindPlanetOutput = Outputs['planet']['find']
+```
+
+### Infer Router Contract Error Map
+
+Collects the error maps from every procedure contract in a router contract into a single type.
+
+```ts twoslash
+import type { contract } from './shared/planet'
+// ---cut---
+import type { InferRouterContractErrorMap } from '@orpc/contract'
+
+export type ErrorMap = InferRouterContractErrorMap
+```
+
+### Infer Router Contract Errors
+
+Infers the throwable errors each procedure contract in a router contract can describe.
+
+```ts twoslash
+import type { contract } from './shared/planet'
+// ---cut---
+import type { InferRouterContractErrors } from '@orpc/contract'
+
+export type Errors = InferRouterContractErrors
+
+type FindPlanetError = Errors['planet']['find']
+```
+
+### Infer Router Contract Error
+
+Infers all possible throwable errors the entire router contract can describe. This is useful when you want a single type for contract-wide error handling.
+
+```ts twoslash
+import type { contract } from './shared/planet'
+// ---cut---
+import type { InferRouterContractError } from '@orpc/contract'
+
+export type ContractError = InferRouterContractError
+```
diff --git a/apps/content/docs/ecosystem.md b/apps/content/docs/ecosystem.md
deleted file mode 100644
index dd0924685..000000000
--- a/apps/content/docs/ecosystem.md
+++ /dev/null
@@ -1,48 +0,0 @@
----
-title: Ecosystem
-description: oRPC ecosystem & community resources
----
-
-# Ecosystem
-
-:::info
-If your project is missing here, please [open a PR](https://github.com/middleapi/orpc/edit/main/apps/content/docs/ecosystem.md) to add it.
-:::
-
-## Starter Kits
-
-| Name | Stars | Description |
-| --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| [Zap.ts](https://github.com/zap-studio/monorepo) | [](https://github.com/zap-studio/monorepo) | Next.js boilerplate designed to help you build applications faster using a modern set of tools. |
-| [Better-T-Stack](https://github.com/AmanVarshney01/create-better-t-stack) | [](https://github.com/AmanVarshney01/create-better-t-stack) | A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations |
-| [Vazen](https://github.com/stack-found/vazen) | [](https://github.com/stack-found/vazen) | A production-grade monorepo starter for building full-stack TypeScript apps with scalable architecture and developer-first tooling. |
-| [create-start-app](https://github.com/AmanVarshney01/create-better-t-stack) | [](https://github.com/TanStack/create-tsrouter-app) | Quickly scaffold a new React project with TanStack Router and oRPC |
-| [create-o3-app](https://github.com/Tony-ArtZ/create-o3-app) | [](https://github.com/Tony-ArtZ/create-o3-app) | The O3 Stack is a "bleeding-edge" full-stack TypeScript framework that uses experimental technologies like oRPC, Drizzle ORM, and ArkType, positioning itself as T3 Stack's more adventurous sibling that prioritizes newest tools over stability. |
-| [RT Stack](https://github.com/nktnet1/rt-stack) | [](https://github.com/nktnet1/rt-stack) | Lightweight fullstack turborepo with modular components, shared configs, containerized deployments and 100% type-safety. Features React + Vite, TanStack Router, oRPC + Valibot, Better Auth, and Drizzle ORM. |
-| [Start UI](https://github.com/BearStudio/start-ui-web) | [](https://github.com/BearStudio/start-ui-web) | 🚀 Start UI [web] is an opinionated UI starter from the 🐻 Beastudio Team with ⚙️ Node.js, 🟦 TypeScript, ⚛️ React, 📦 TanStack Start, 💨 Tailwind CSS, 🧩 shadcn/ui, 📋 React Hook Form, 🔌 oRPC, 🛠 Prisma, 🔐 Better Auth, 📚 Storybook, 🧪 Vitest, 🎭 Playwright |
-| [ShipFullStack](https://github.com/sunshineLixun/ShipFullStack) | [](https://github.com/sunshineLixun/ShipFullStack) | A modern TypeScript stack that combines React, TanStack Start, Hono, ORPC, Expo, and more. |
-| [WXT Starter](https://github.com/mefengl/wxt-starter) | [](https://github.com/mefengl/wxt-starter) | Maybe the best template based on wxt. |
-| [Start Kit](https://github.com/CarlosZiegler/start-kit.dev) | [](https://github.com/CarlosZiegler/start-kit.dev) | The production-ready SaaS starter kit for the modern TypeScript stack. |
-| [tsu!stack](https://github.com/tsu-moe/tsu-stack) | [](https://github.com/tsu-moe/tsu-stack) | Batteries-included TanStack Start Vite+ Monorepo Template with Hono + oRPC + Drizzle ORM + Better Auth. 🐋 Dockerized and ⛅ Cloudflare Workers ready. shadcn/ui, Paraglide-js (i18n), Feature-Sliced Design, evlog, @t3-oss/env, AGENTS.md, and many more features -- out of the box! |
-
-## Tools
-
-| Name | Stars | Description |
-| ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
-| [orpc-file-based-router](https://github.com/zeeeeby/orpc-file-based-router) | [](https://github.com/zeeeeby/orpc-file-based-router) | Automatically creates an oRPC router configuration based on your file structure, similar to Next.js, express-file-routing |
-| [Vertrag](https://github.com/Quatton/vertrag) | [](https://github.com/Quatton/vertrag) | A spec-first API development tool (oRPC contract + any backend language) |
-| [Prisma oRPC Generator](https://github.com/omar-dulaimi/prisma-orpc-generator) | [](https://github.com/omar-dulaimi/prisma-orpc-generator) | Prisma generator that creates fully-featured ORPC routers |
-| [DRZL](https://github.com/use-drzl/drzl) | [](https://github.com/use-drzl/drzl) | Zero‑friction codegen for Drizzle ORM. Analyze your schema. Generate validation, services, and routers — fast. |
-| [orpc-msw](https://github.com/DanSnow/orpc-msw) | [](https://github.com/DanSnow/orpc-msw) | A utility library for type-safe mocking of OpenAPI-based oRPC contracts using Mock Service Worker (MSW) for robust testing and development. |
-
-## Libraries
-
-| Name | Stars | Description |
-| --------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| [Permix](https://permix.letstri.dev/) | [](https://github.com/letstri/permix) | lightweight, framework-agnostic, type-safe permissions management library |
-| [trpc-cli](https://github.com/mmkal/trpc-cli?tab=readme-ov-file#orpc) | [](https://github.com/mmkal/trpc-cli) | Turn a oRPC router into a type-safe, fully-functional, documented CLI |
-| [@reliverse/rempts](https://github.com/reliverse/rempts) | [](https://github.com/reliverse/rempts) | 🐦🔥 a modern, type-safe toolkit for building delightful cli experiences. it's fast, flexible, and made for developer happiness. file-based commands keep things simple—no clutter, just clean and easy workflows. this is how cli should feel. |
-| [oRPC Shield](https://github.com/omar-dulaimi/orpc-shield) | [](https://github.com/omar-dulaimi/orpc-shield) | Type-safe authorization for modern oRPC apps — lightweight, composable, fast. |
-| [Every Plugin](https://github.com/near-everything/every-plugin) | [](https://github.com/near-everything/every-plugin) | A composable plugin runtime for loading, initializing, and executing remote plugins |
-| [orpc-json-diff](https://github.com/NeilTheFisher/orpc-json-diff) | [](https://github.com/NeilTheFisher/orpc-json-diff) | Apply json patches for oRPC event iterators to save bandwidth |
-| [effect-orpc](https://github.com/utopyin/effect-orpc) | [](https://github.com/utopyin/effect-orpc) | Effect-TS integration for oRPC |
diff --git a/apps/content/docs/error-handling.md b/apps/content/docs/error-handling.md
index cdf382fc3..2b056eef0 100644
--- a/apps/content/docs/error-handling.md
+++ b/apps/content/docs/error-handling.md
@@ -1,128 +1,175 @@
----
-title: Error Handling
-description: Manage errors in oRPC using both traditional and type‑safe strategies.
----
+# Error Handling
-# Error Handling in oRPC
+Error handling in oRPC is flexible and consistent. You can use the `ORPCError` class, define typesafe errors, and adapt custom error classes while still returning meaningful feedback to clients.
-oRPC offers a robust error handling system. You can either throw standard JavaScript errors or, preferably, use the specialized `ORPCError` class to utilize oRPC features.
+## `ORPCError` Class
-There are two primary approaches:
+`ORPCError` is the standard error type in oRPC. It includes a `code`, plus optional `message` and `data` fields.
-- **Normal Approach:** Throw errors directly (using `ORPCError` is recommended for clarity).
-- **Type‑Safe Approach:** Predefine error types so that clients can infer and handle errors in a type‑safe manner.
-
-:::warning
-The `ORPCError.data` property is sent to the client. Avoid including sensitive information.
+::: danger
+`message` and `data` are sent to the client. Do not include sensitive information in either field.
:::
-## Normal Approach
-
-In the traditional approach you may throw any JavaScript error. However, using the `ORPCError` class improves consistency and ensures that error codes and optional data are handled appropriately.
-
-**Key Points:**
-
-- The first argument is the error code.
-- You may optionally include a message, additional error data, or any standard error options.
+```ts twoslash
+declare const notFound: boolean
+// ---cut---
+import { ORPCError, os } from '@orpc/server'
-```ts
-const rateLimit = os.middleware(async ({ next }) => {
+const rateLimitMiddleware = os.middleware(async ({ next }) => {
throw new ORPCError('RATE_LIMITED', {
message: 'You are being rate limited',
data: { retryAfter: 60 }
})
+
return next()
})
const example = os
- .use(rateLimit)
+ .use(rateLimitMiddleware)
.handler(async ({ input }) => {
- throw new ORPCError('NOT_FOUND')
- throw new Error('Something went wrong') // <-- will be converted to INTERNAL_SERVER_ERROR
+ if (notFound) {
+ throw new ORPCError('NOT_FOUND')
+ }
})
```
-::: danger
-Do not pass sensitive data in the `ORPCError.data` field.
-:::
+## Typesafe Errors
-## Type‑Safe Error Handling
+For end-to-end type safety, define your errors with `.errors` or [return `ORPCError`](#returning-an-orpcerror). This lets the client infer each error's shape and handle it safely. You can use any [Standard Schema](https://standardschema.dev/schema#what-schema-libraries-implement-the-spec) library to validate error data.
-For a fully type‑safe error management experience, define your error types using the `.errors` method. This lets the client infer the error's structure and handle it accordingly. You can use any [Standard Schema](https://github.com/standard-schema/standard-schema?tab=readme-ov-file#what-schema-libraries-implement-the-spec) library to validate error data.
+::: danger
+`message` and `data` are sent to the client. Do not include sensitive information in either field.
+:::
```ts twoslash
import { os } from '@orpc/server'
import * as z from 'zod'
+
+declare const notFound: boolean
// ---cut---
-const base = os.errors({ // <-- common errors
- RATE_LIMITED: {
- data: z.object({
- retryAfter: z.number(),
- }),
- },
- UNAUTHORIZED: {},
-})
+const rateLimitMiddleware = os
+ .errors({
+ RATE_LIMITED: {
+ data: z.object({
+ retryAfter: z.number(),
+ }),
+ },
+ })
+ .middleware(async ({ next, errors }) => {
+ throw errors.RATE_LIMITED({
+ message: 'You are being rate limited',
+ data: { retryAfter: 60 }
+ })
-const rateLimit = base.middleware(async ({ next, errors }) => {
- throw errors.RATE_LIMITED({
- message: 'You are being rate limited',
- data: { retryAfter: 60 }
+ return next()
})
- return next()
-})
-const example = base
- .use(rateLimit)
+const exampleProcedure = os
+ .use(rateLimitMiddleware)
.errors({
NOT_FOUND: {
- message: 'The resource was not found', // <-- default message
+ message: 'The resource was not found', // <- default message
},
})
.handler(async ({ input, errors }) => {
- throw errors.NOT_FOUND()
+ if (notFound) {
+ throw errors.NOT_FOUND()
+ }
})
```
-:::danger
-Again, avoid including any sensitive data in the error data since it will be exposed to the client.
+::: tip
+You can use typesafe errors across your entire project, but we recommend reserving them for application-specific cases. For common errors like `UNAUTHORIZED` or `RATE_LIMITED`, the client usually already understands the meaning. Skipping explicit schemas for those errors can also reduce type complexity and improve TypeScript performance.
:::
-Learn more about [Client Error Handling](/docs/client/error-handling).
-
-## Combining Both Approaches
+### ORPCError Compatibility
-You can combine both strategies seamlessly. When you throw an `ORPCError` instance, if the `code`, `status` and `data` match with the errors defined in the `.errors` method, oRPC will treat it exactly as if you had thrown `errors.[code]` using the type‑safe approach.
+If you cannot access the `errors` object, for example in a utility function or another module, you can still throw `ORPCError`. oRPC will try to convert it to the matching typesafe error when its `code` and `data` match a defined error. If no match is found, it is treated as an unknown error.
```ts
-const base = os.errors({ // <-- common errors
- RATE_LIMITED: {
- data: z.object({
- retryAfter: z.number().int().min(1).default(1),
- }),
- },
- UNAUTHORIZED: {},
-})
-
-const rateLimit = base.middleware(async ({ next, errors }) => {
- throw errors.RATE_LIMITED({
- message: 'You are being rate limited',
- data: { retryAfter: 60 }
+const exampleProcedure = os
+ .errors({
+ NOT_FOUND: {
+ message: 'The resource was not found',
+ },
})
- // OR --- both are equivalent
- throw new ORPCError('RATE_LIMITED', {
- message: 'You are being rate limited',
- data: { retryAfter: 60 }
+ .handler(async ({ errors }) => {
+ throw errors.NOT_FOUND()
+
+ // Treated as errors.NOT_FOUND because the code and data match
+ throw new ORPCError('NOT_FOUND')
+
+ // Treated as an unknown error because it does not match any defined error
+ throw new ORPCError('BAD_REQUEST')
})
- return next()
-})
+```
-const example = base
- .use(rateLimit)
- .handler(async ({ input }) => {
- throw new ORPCError('BAD_REQUEST') // <-- unknown error
+### Returning an `ORPCError`
+
+As an alternative to `.errors`, you can return an `ORPCError` directly from your handler or middleware to achieve end-to-end type safety.
+
+::: warning
+When [implementing a contract](/docs/contract/implementation), returning an `ORPCError` is equivalent to throwing one.
+:::
+
+```ts
+const exampleProcedure = os
+ .handler(async ({ errors }) => {
+ if (reachRateLimit) {
+ return new ORPCError('RATE_LIMITED', {
+ message: 'You are being rate limited',
+ data: { retryAfter: 60 }
+ })
+ }
+
+ return 'Success'
})
```
-:::danger
-Remember: Since `ORPCError.data` is transmitted to the client, do not include any sensitive information.
+::: danger
+`message` and `data` are sent to the client. Do not include sensitive information in either field.
+:::
+
+## ORPC Error Codes
+
+By default, oRPC allows any string as an error code and suggests common HTTP codes like `NOT_FOUND` and `UNAUTHORIZED`. You can override this with your own set of allowed error codes for better type safety and consistency.
+
+```ts
+declare module '@orpc/server' { // or '@orpc/client'
+ interface Registry {
+ ORPCErrorCode: 'NOT_FOUND' | 'UNAUTHORIZED' | 'RATE_LIMITED' | 'MY_CUSTOM_ERROR' | (string & {})
+ }
+}
+```
+
+With this configuration, only `NOT_FOUND`, `UNAUTHORIZED`, `RATE_LIMITED`, and `MY_CUSTOM_ERROR` will be suggested as error codes. The `(string & {})` fallback ensures you can still use any string value when needed.
+
+## Using Custom Error Classes
+
+You do not have to use `ORPCError` directly in your business logic. You can throw your own error classes and convert them to `ORPCError` in middleware or interceptors.
+
+::: info
+By default, oRPC can convert non-`ORPCError` into an `ORPCError` with code `INTERNAL_SERVER_ERROR`, or leave them unchanged depending on the client you are using.
:::
+
+```ts
+class MyCustomError extends Error {
+}
+
+const customErrorConverterMiddleware = os.middleware(async ({ next }) => {
+ try {
+ return await next()
+ }
+ catch (err) {
+ if (err instanceof MyCustomError) {
+ throw new ORPCError('MY_CUSTOM_ERROR', { message: err.message, cause: err })
+ }
+
+ throw err
+ }
+})
+```
+
+## Client Error Handling
+
+To learn how to handle errors on the client side, see the [Client Error Handling documentation](/docs/client/error-handling).
diff --git a/apps/content/docs/event-iterator.md b/apps/content/docs/event-iterator.md
index 3a01e4687..a83635ca0 100644
--- a/apps/content/docs/event-iterator.md
+++ b/apps/content/docs/event-iterator.md
@@ -1,39 +1,38 @@
----
-title: Event Iterator (SSE)
-description: Learn how to streaming responses, real-time updates, and server-sent events using oRPC.
----
-
# Event Iterator (SSE)
-oRPC provides built‑in support for streaming responses, real‑time updates, and server-sent events (SSE) without any extra configuration. This functionality is ideal for applications that require live updates, such as AI chat responses, live sports scores, or stock market data.
+Event Iterator enables **typesafe**, **realtime data streaming**. It is the recommended approach for building features like live notifications, chat messages, progress updates, and data feeds.
## Overview
-The event iterator is defined by an asynchronous generator function. In the example below, the handler continuously yields a new event every second:
+An event iterator is implemented as an [asynchronous generator function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function*) (or a compatible implementation). In the example below, the handler emits a new event every second:
```ts
const example = os
- .handler(async function* ({ input, lastEventId }) {
+ .handler(async function* ({ input, signal, lastEventId }) {
while (true) {
+ signal?.throwIfAborted()
yield { message: 'Hello, world!' }
await new Promise(resolve => setTimeout(resolve, 1000))
}
})
```
-Learn how to consume the event iterator on the client [here](/docs/client/event-iterator)
+::: info
+Learn how to consume event iterators from the client in the [client guide](/docs/client/event-iterator).
+:::
-## Validate Event Iterator
+## Validating Events
-oRPC includes a built‑in `eventIterator` helper that works with any [Standard Schema](https://github.com/standard-schema/standard-schema?tab=readme-ov-file#what-schema-libraries-implement-the-spec) library to validate events.
+Use the built‑in `eventIterator` helper that works with any [Standard Schema](https://standardschema.dev/schema#what-schema-libraries-implement-the-spec) library to validate events.
```ts
import { eventIterator } from '@orpc/server'
const example = os
.output(eventIterator(z.object({ message: z.string() })))
- .handler(async function* ({ input, lastEventId }) {
+ .handler(async function* ({ input, signal, lastEventId }) {
while (true) {
+ signal?.throwIfAborted()
yield { message: 'Hello, world!' }
await new Promise(resolve => setTimeout(resolve, 1000))
}
@@ -42,23 +41,27 @@ const example = os
## Last Event ID & Event Metadata
-Using the `withEventMeta` helper, you can attach [additional event meta](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#event_stream_format) (such as an event ID or a retry interval) to each event.
+Using the `withEventMeta` helper, you can attach [additional event metadata](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#event_stream_format) (such as an event ID or retry interval) to each event. When the client reconnects properly, the last received event ID is sent back to the server in `lastEventId`, allowing the stream to resume from where it left off.
::: info
-When used with [Client Retry Plugin](/docs/plugins/client-retry) or [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource), the client will reconnect with the last event ID. This value is made available to your handler as `lastEventId`, allowing you to resume the stream seamlessly.
+When used with the [Retry Plugin](/docs/plugins/retry) or [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource), reconnection with the last event ID is handled automatically.
:::
```ts
import { withEventMeta } from '@orpc/server'
const example = os
- .handler(async function* ({ input, lastEventId }) {
+ .handler(async function* ({ input, signal, lastEventId }) {
if (lastEventId) {
// Resume streaming from lastEventId
}
else {
while (true) {
- yield withEventMeta({ message: 'Hello, world!' }, { id: 'some-id', retry: 10_000 })
+ signal?.throwIfAborted()
+ yield withEventMeta(
+ { message: 'Hello, world!' },
+ { id: 'some-id', retry: 10_000 }
+ )
await new Promise(resolve => setTimeout(resolve, 1000))
}
}
@@ -67,16 +70,18 @@ const example = os
## Stop Event Iterator
-To signal the end of the stream, simply use a `return` statement. When the handler returns, oRPC marks the stream as successfully completed.
+To end the stream, use either a `return` or `throw` statement. oRPC marks the stream as completed when the handler returns.
:::warning
-This behavior is exclusive to oRPC. Standard [SSE](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events) clients, such as those using [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) will automatically reconnect when the connection closes.
+This behavior is specific to oRPC. Standard [SSE](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events) clients, such as [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource), do not recognize this completion signal and will automatically attempt to reconnect. For details, see the [Standard Server documentation](https://github.com/middleapi/standardserver#event-stream-body).
:::
```ts
const example = os
- .handler(async function* ({ input, lastEventId }) {
+ .handler(async function* ({ input, signal, lastEventId }) {
while (true) {
+ signal?.throwIfAborted()
+
if (done) {
return
}
@@ -87,15 +92,16 @@ const example = os
})
```
-## Cleanup Side-Effects
+## Signal and Side-Effects
-If the client closes the connection or an unexpected error occurs, you can use a `finally` block to clean up any side effects (for example, closing database connections or stopping background tasks):
+When the client closes the connection or an unexpected error occurs, oRPC aborts the provided `signal`. Use it to exit loops and avoid resource leaks. Put cleanup logic in a `finally` block so it runs whether the stream ends normally, errors, or is cancelled.
```ts
const example = os
- .handler(async function* ({ input, lastEventId }) {
+ .handler(async function* ({ input, signal, lastEventId }) {
try {
while (true) {
+ signal?.throwIfAborted()
yield { message: 'Hello, world!' }
await new Promise(resolve => setTimeout(resolve, 1000))
}
@@ -118,8 +124,8 @@ const publisher = new MemoryPublisher<{
}>()
const live = os
- .handler(async function* ({ input, signal }) {
- const iterator = publisher.subscribe('something-updated', { signal })
+ .handler(async function* ({ input, signal, lastEventId }) {
+ const iterator = publisher.subscribe('something-updated', { signal, lastEventId })
for await (const payload of iterator) {
// Handle payload here or yield directly to client
yield payload
@@ -132,54 +138,3 @@ const publish = os
await publisher.publish('something-updated', { id: input.id })
})
```
-
-## Event Publisher
-
-Unlike the [Publisher Helper](/docs/helpers/publisher), the `EventPublisher` is more lightweight with synchronous publishing and no resume support.
-
-::: code-group
-
-```ts [Static Events]
-import { EventPublisher } from '@orpc/server'
-
-const publisher = new EventPublisher<{
- 'something-updated': {
- id: string
- }
-}>()
-
-const livePlanet = os
- .handler(async function* ({ input, signal }) {
- for await (const payload of publisher.subscribe('something-updated', { signal })) { // [!code highlight]
- // handle payload here and yield something to client
- }
- })
-
-const update = os
- .input(z.object({ id: z.string() }))
- .handler(({ input }) => {
- publisher.publish('something-updated', { id: input.id }) // [!code highlight]
- })
-```
-
-```ts [Dynamic Events]
-import { EventPublisher } from '@orpc/server'
-
-const publisher = new EventPublisher>()
-
-const onMessage = os
- .input(z.object({ channel: z.string() }))
- .handler(async function* ({ input, signal }) {
- for await (const payload of publisher.subscribe(input.channel, { signal })) { // [!code highlight]
- yield payload.message
- }
- })
-
-const sendMessage = os
- .input(z.object({ channel: z.string(), message: z.string() }))
- .handler(({ input }) => {
- publisher.publish(input.channel, { message: input.message }) // [!code highlight]
- })
-```
-
-:::
diff --git a/apps/content/docs/examples/openai-streaming.md b/apps/content/docs/examples/openai-streaming.md
deleted file mode 100644
index 57d2b575d..000000000
--- a/apps/content/docs/examples/openai-streaming.md
+++ /dev/null
@@ -1,53 +0,0 @@
----
-title: OpenAI Streaming Example
-description: Combine oRPC with the OpenAI Streaming API to build a chatbot
----
-
-# OpenAI Streaming Example
-
-This example shows how to integrate oRPC with the OpenAI Streaming API to build a chatbot.
-
-## Basic Example
-
-```ts twoslash
-import { createORPCClient } from '@orpc/client'
-import { RPCLink } from '@orpc/client/fetch'
-import { os, RouterClient } from '@orpc/server'
-import * as z from 'zod'
-// ---cut---
-import OpenAI from 'openai'
-
-const openai = new OpenAI()
-
-const complete = os
- .input(z.object({ content: z.string() }))
- .handler(async function* ({ input }) {
- const stream = await openai.chat.completions.create({
- model: 'gpt-4o',
- messages: [{ role: 'user', content: input.content }],
- stream: true,
- })
-
- yield* stream
- })
-
-const router = { complete }
-
-// --------------- CLIENT ---------------
-
-const link = new RPCLink({
- url: 'https://example.com/rpc',
-})
-
-const client: RouterClient = createORPCClient(link)
-
-const stream = await client.complete({ content: 'Hello, world!' })
-
-for await (const chunk of stream) {
- console.log(chunk.choices[0]?.delta?.content || '')
-}
-```
-
-::: info
-Learn more about [RPCLink](/docs/client/rpc-link) and [Event Iterator](/docs/client/event-iterator).
-:::
diff --git a/apps/content/docs/file-upload-download.md b/apps/content/docs/file-upload-download.md
deleted file mode 100644
index dc3b3ecf8..000000000
--- a/apps/content/docs/file-upload-download.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-title: File Upload and Download
-description: Learn how to upload and download files using oRPC.
----
-
-# File Operations in oRPC
-
-oRPC natively supports standard [File](https://developer.mozilla.org/en-US/docs/Web/API/File) and [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) objects. You can even combine files with complex data structures like arrays and objects for upload and download operations.
-
-:::tip File Uploads
-For uploading files larger than 100 MB, we recommend using a dedicated upload solution or [extending the body parser](/docs/advanced/extend-body-parser) for better performance and reliability, as oRPC does not support chunked or resumable uploads.
-:::
-
-:::tip File Downloads
-For downloading files, we recommend using **lazy file** libraries like [@mjackson/lazy-file](https://www.npmjs.com/package/@mjackson/lazy-file) or [Bun.file](https://bun.com/docs/api/file-io#reading-files-bun-file) to reduce memory usage.
-:::
-
-## Example
-
-```ts twoslash
-import { os } from '@orpc/server'
-import * as z from 'zod'
-// ---cut---
-const example = os
- .input(z.file())
- .output(z.object({ anyFieldName: z.instanceof(File) }))
- .handler(async ({ input }) => {
- const file = input
-
- console.log(file.name)
-
- return {
- anyFieldName: new File(['Hello World'], 'hello.txt', { type: 'text/plain' }),
- }
- })
-```
diff --git a/apps/content/docs/getting-started.md b/apps/content/docs/getting-started.md
index 97a83b6b1..28e147520 100644
--- a/apps/content/docs/getting-started.md
+++ b/apps/content/docs/getting-started.md
@@ -1,184 +1,3 @@
----
-title: Getting Started
-description: Quick guide to oRPC
----
-
# Getting Started
-oRPC (OpenAPI Remote Procedure Call) combines RPC (Remote Procedure Call) with OpenAPI, allowing you to define and call remote (or local) procedures through a type-safe API while adhering to the OpenAPI specification.
-
-oRPC simplifies RPC service definition, making it easy to build scalable applications, from simple scripts to complex microservices.
-
-This guide covers the basics: defining procedures, handling errors, and integrating with popular frameworks.
-
-## Prerequisites
-
-- Node.js 18+ (20+ recommended) | Bun | Deno | Cloudflare Workers
-- A package manager: npm | pnpm | yarn | bun | deno
-- A TypeScript project (strict mode recommended)
-
-## Installation
-
-::: code-group
-
-```sh [npm]
-npm install @orpc/server@latest @orpc/client@latest
-```
-
-```sh [yarn]
-yarn add @orpc/server@latest @orpc/client@latest
-```
-
-```sh [pnpm]
-pnpm add @orpc/server@latest @orpc/client@latest
-```
-
-```sh [bun]
-bun add @orpc/server@latest @orpc/client@latest
-```
-
-```sh [deno]
-deno add npm:@orpc/server@latest npm:@orpc/client@latest
-```
-
-:::
-
-## Define App Router
-
-We'll use [Zod](https://github.com/colinhacks/zod) for schema validation (optional, any [standard schema](https://github.com/standard-schema/standard-schema) is supported).
-
-```ts twoslash
-import type { IncomingHttpHeaders } from 'node:http'
-import { ORPCError, os } from '@orpc/server'
-import * as z from 'zod'
-
-const PlanetSchema = z.object({
- id: z.number().int().min(1),
- name: z.string(),
- description: z.string().optional(),
-})
-
-export const listPlanet = os
- .input(
- z.object({
- limit: z.number().int().min(1).max(100).optional(),
- cursor: z.number().int().min(0).default(0),
- }),
- )
- .handler(async ({ input }) => {
- // your list code here
- return [{ id: 1, name: 'name' }]
- })
-
-export const findPlanet = os
- .input(PlanetSchema.pick({ id: true }))
- .handler(async ({ input }) => {
- // your find code here
- return { id: 1, name: 'name' }
- })
-
-export const createPlanet = os
- .$context<{ headers: IncomingHttpHeaders }>()
- .use(({ context, next }) => {
- const user = parseJWT(context.headers.authorization?.split(' ')[1])
-
- if (user) {
- return next({ context: { user } })
- }
-
- throw new ORPCError('UNAUTHORIZED')
- })
- .input(PlanetSchema.omit({ id: true }))
- .handler(async ({ input, context }) => {
- // your create code here
- return { id: 1, name: 'name' }
- })
-
-export const router = {
- planet: {
- list: listPlanet,
- find: findPlanet,
- create: createPlanet
- }
-}
-// ---cut-after---
-
-declare function parseJWT(token: string | undefined): { userId: number } | null
-```
-
-## Create Server
-
-Using [Node.js](/docs/adapters/http) as the server runtime, but oRPC also supports other runtimes like Bun, Deno, Cloudflare Workers, etc.
-
-```ts twoslash
-import { router } from './shared/planet'
-// ---cut---
-import { createServer } from 'node:http'
-import { RPCHandler } from '@orpc/server/node'
-import { CORSPlugin } from '@orpc/server/plugins'
-import { onError } from '@orpc/server'
-
-const handler = new RPCHandler(router, {
- plugins: [new CORSPlugin()],
- interceptors: [
- onError((error) => {
- console.error(error)
- }),
- ],
-})
-
-const server = createServer(async (req, res) => {
- const result = await handler.handle(req, res, {
- context: { headers: req.headers }
- })
-
- if (!result.matched) {
- res.statusCode = 404
- res.end('No procedure matched')
- }
-})
-
-server.listen(
- 3000,
- '127.0.0.1',
- () => console.log('Listening on 127.0.0.1:3000')
-)
-```
-
-Learn more about [RPCHandler](/docs/rpc-handler).
-
-## Create Client
-
-```ts twoslash
-import { router } from './shared/planet'
-// ---cut---
-import type { RouterClient } from '@orpc/server'
-import { createORPCClient } from '@orpc/client'
-import { RPCLink } from '@orpc/client/fetch'
-
-const link = new RPCLink({
- url: 'http://127.0.0.1:3000',
- headers: { Authorization: 'Bearer token' },
-})
-
-export const orpc: RouterClient = createORPCClient(link)
-```
-
-Supports both [client-side clients](/docs/client/client-side) and [server-side clients](/docs/client/server-side).
-
-## Call Procedure
-
-End-to-end type-safety and auto-completion out of the box.
-
-```ts twoslash
-import { orpc } from './shared/planet'
-// ---cut---
-const planet = await orpc.planet.find({ id: 1 })
-
-orpc.planet.create
-// ^|
-```
-
-## Next Steps
-
-This guide introduced the RPC aspects of oRPC. To explore OpenAPI integration, visit the [OpenAPI Guide](/docs/openapi/getting-started).
+// TODO
diff --git a/apps/content/docs/helpers/base64url.md b/apps/content/docs/helpers/base64url.md
index af5d5d93a..0ea9b666a 100644
--- a/apps/content/docs/helpers/base64url.md
+++ b/apps/content/docs/helpers/base64url.md
@@ -1,12 +1,9 @@
----
-title: Base64Url Helpers
-description: Functions to encode and decode base64url strings, a URL-safe variant of base64 encoding.
----
-
# Base64Url Helpers
Base64Url helpers provide functions to encode and decode base64url strings, a URL-safe variant of base64 encoding used in web tokens, data serialization, and APIs.
+## Basic Usage
+
```ts twoslash
import { decodeBase64url, encodeBase64url } from '@orpc/server/helpers'
diff --git a/apps/content/docs/helpers/cookie.md b/apps/content/docs/helpers/cookie.md
index bb5e2b099..e74bdfd92 100644
--- a/apps/content/docs/helpers/cookie.md
+++ b/apps/content/docs/helpers/cookie.md
@@ -1,11 +1,8 @@
----
-title: Cookie Helpers
-description: Functions for managing HTTP cookies in web applications.
----
-
# Cookie Helpers
-The Cookie helpers provide functions to set and get HTTP cookies.
+Cookie helpers provide utilities for setting and reading HTTP cookies from fetch headers.
+
+## Basic Usage
```ts twoslash
import { deleteCookie, getCookie, setCookie } from '@orpc/server/helpers'
diff --git a/apps/content/docs/helpers/encryption.md b/apps/content/docs/helpers/encryption.md
index eae94e3cf..87eab10b2 100644
--- a/apps/content/docs/helpers/encryption.md
+++ b/apps/content/docs/helpers/encryption.md
@@ -1,8 +1,3 @@
----
-title: Encryption Helpers
-description: Functions to encrypt and decrypt sensitive data using AES-GCM.
----
-
# Encryption Helpers
Encryption helpers provide functions to encrypt and decrypt sensitive data using AES-GCM with PBKDF2 key derivation.
@@ -11,6 +6,8 @@ Encryption helpers provide functions to encrypt and decrypt sensitive data using
Encryption secures data content but has performance trade-offs compared to [signing](/docs/helpers/signing). It requires more CPU resources and processing time. For edge runtimes like [Cloudflare Workers](https://developers.cloudflare.com/workers/), ensure you have sufficient CPU time budget (recommend >200ms per request) for encryption operations.
:::
+## Basic Usage
+
```ts twoslash
import { decrypt, encrypt } from '@orpc/server/helpers'
diff --git a/apps/content/docs/helpers/form-data.md b/apps/content/docs/helpers/form-data.md
index 7d2638126..29088c0f4 100644
--- a/apps/content/docs/helpers/form-data.md
+++ b/apps/content/docs/helpers/form-data.md
@@ -1,8 +1,3 @@
----
-title: Form Data Helpers
-description: Utilities for parsing form data and handling validation errors with bracket notation support.
----
-
# Form Data Helpers
Form data helpers provide utilities for parsing HTML form data and extracting validation error messages, with full support for [bracket notation](/docs/openapi/bracket-notation) to handle complex nested structures.
@@ -12,7 +7,7 @@ Form data helpers provide utilities for parsing HTML form data and extracting va
Parses HTML form data using [bracket notation](/docs/openapi/bracket-notation) to deserialize complex nested objects and arrays.
```ts twoslash
-import { parseFormData } from '@orpc/openapi-client/helpers'
+import { parseFormData } from '@orpc/openapi/helpers'
const form = new FormData()
form.append('name', 'John')
@@ -33,10 +28,10 @@ const parsed = parseFormData(form)
## `getIssueMessage`
-Extracts validation error messages from [standard schema](https://github.com/standard-schema/standard-schema) issues using [bracket notation](/docs/openapi/bracket-notation) paths.
+Extracts validation error messages from [standard schema](https://standardschema.dev/) issues using [bracket notation](/docs/openapi/bracket-notation) paths.
```ts twoslash
-import { getIssueMessage } from '@orpc/openapi-client/helpers'
+import { getIssueMessage } from '@orpc/openapi/helpers'
const error = {
data: {
@@ -60,13 +55,13 @@ const anyError = getIssueMessage('anything', 'path')
```
::: warning
-The `getIssueMessage` utility works with any data type but requires validation errors to follow the [standard schema issue format](https://github.com/standard-schema/standard-schema?tab=readme-ov-file#the-interface). It looks for issues in the `data.issues` property. If you use custom [validation errors](/docs/advanced/validation-errors), store them elsewhere, or modify the issue format, `getIssueMessage` may not work as expected.
+The `getIssueMessage` utility works with any data type but requires validation errors to follow the [standard schema issue format](https://standardschema.dev/#the-specifications). It looks for issues in the `data.issues` property. If you use custom [validation errors](/docs/advanced/validation-errors), store them elsewhere, or modify the issue format, `getIssueMessage` may not work as expected.
:::
## Usage Example
```tsx
-import { getIssueMessage, parseFormData } from '@orpc/openapi-client/helpers'
+import { getIssueMessage, parseFormData } from '@orpc/openapi/helpers'
export function ContactForm() {
const [error, setError] = useState()
diff --git a/apps/content/docs/helpers/publisher.md b/apps/content/docs/helpers/publisher.md
index cea90ee3e..0449aea1f 100644
--- a/apps/content/docs/helpers/publisher.md
+++ b/apps/content/docs/helpers/publisher.md
@@ -1,42 +1,39 @@
----
-title: Publisher
-description: Listen and publish events with resuming support in oRPC
----
+# Publisher Helpers
-# Publisher
-
-The Publisher is a helper that enables you to listen to and publish events to subscribers. Combined with the [Event Iterator](/docs/client/event-iterator), it allows you to build streaming responses, real-time updates, and server-sent events with minimal requirements.
+Publisher helpers provide a unified way to publish and subscribe to events across different storage backends in oRPC applications. They support both static and dynamic event names, along with optional replay of missed events for subscribers.
## Installation
::: code-group
```sh [npm]
-npm install @orpc/experimental-publisher@latest
+npm install @orpc/publisher@latest
```
```sh [yarn]
-yarn add @orpc/experimental-publisher@latest
+yarn add @orpc/publisher@latest
```
```sh [pnpm]
-pnpm add @orpc/experimental-publisher@latest
+pnpm add @orpc/publisher@latest
```
```sh [bun]
-bun add @orpc/experimental-publisher@latest
+bun add @orpc/publisher@latest
```
```sh [deno]
-deno add npm:@orpc/experimental-publisher@latest
+deno add npm:@orpc/publisher@latest
```
:::
## Basic Usage
+The core concept is the `Publisher` interface, which defines a standard way to publish events and subscribe to them. You can create your own publisher or use one of the provided adapters for popular storage backends. The `publish` method accepts an event name and payload, while `subscribe` lets you listen to specific events using either callback or iterator styles.
+
```ts twoslash
-import { MemoryPublisher } from '@orpc/experimental-publisher/memory'
+import { MemoryPublisher } from '@orpc/publisher/memory'
import { os } from '@orpc/server'
import * as z from 'zod'
// ---cut---
@@ -47,8 +44,8 @@ const publisher = new MemoryPublisher<{
}>()
const live = os
- .handler(async function* ({ input, signal }) {
- const iterator = publisher.subscribe('something-updated', { signal })
+ .handler(async function* ({ input, signal, lastEventId }) {
+ const iterator = publisher.subscribe('something-updated', { signal, lastEventId })
for await (const payload of iterator) {
// Handle payload here or yield directly to client
yield payload
@@ -71,33 +68,74 @@ const publisher = new MemoryPublisher>()
:::
-## Resume Feature
+## Adapters
-The resume feature uses `lastEventId` to determine where to resume from after a disconnection.
+| Name | Replay Support | Adapter for |
+| ------------------ | -------------- | ---------------------------------------------------- |
+| `MemoryPublisher` | ✅ | In-memory storage |
+| `RedisPublisher` | ✅ | [Redis](https://github.com/redis/redis) |
+| `UpstashPublisher` | ✅ | [Upstash Redis](https://github.com/upstash/redis-js) |
+
+::: code-group
+
+```ts [memory]
+import { MemoryPublisher } from '@orpc/publisher/memory'
+```
+
+```ts [redis]
+import { createClient } from 'redis'
+import { RedisPublisher } from '@orpc/publisher/redis'
+
+const client = createClient({ url: 'redis://localhost:6379' })
+
+// RedisRateLimiter lazily connects to Redis when needed.
+// You can still call `client.connect()` manually, but it is optional.
+await client.connect()
+
+const publisher = new RedisPublisher(client, {
+ subscriber: client.duplicate(), // Redis client for subscribing to pub/sub (default: client.duplicate())
+ prefix: 'orpc:', // Optional Redis key prefix
+ serializer: undefined, // Optional custom serializer
+})
+```
+
+```ts [upstash]
+import { Redis } from '@upstash/redis'
+import { UpstashPublisher } from '@orpc/publisher/upstash'
+
+const redis = Redis.fromEnv()
+
+const publisher = new UpstashPublisher(redis, {
+ prefix: 'orpc:', // Optional Redis key prefix
+ serializer: undefined, // Optional custom serializer
+})
+```
-::: warning
-By default, most adapters have this feature disabled.
:::
-### Server Implementation
+## Replay Missing Events
-When subscribing, you must forward the `lastEventId` to the publisher to enable resuming:
+Some adapters can replay events missed while a subscriber is offline. This feature is usually disabled by default, but you can enable it when creating the publisher. When enabled, the publisher automatically manages event ids and attempts to replay events since the last event id provided by the subscriber.
```ts
-const live = os
- .handler(async function* ({ input, signal, lastEventId }) {
- const iterator = publisher.subscribe('something-updated', { signal, lastEventId })
- for await (const payload of iterator) {
- yield payload
- }
- })
+const publisher = new MemoryPublisher({
+ replay: {
+ enabled: true, // Enable replaying missed events
+ seconds: 60 * 5, // TTL in seconds
+ }
+})
+
+const iterator = publisher.subscribe('something-updated', {
+ signal,
+ lastEventId, // The publisher will attempt to replay missed events since this event id
+})
```
-::: warning Event ID Management
-The publisher automatically manages event ids when resume is enabled. This means:
+::: warning
+When replay is enabled, the publisher manages event ids automatically. This means:
-- Event ids you provide when publishing will be ignored
-- When subscribing, you must forward the event id when yielding custom payloads
+- Any event id provided during publishing is ignored
+- When subscribing, you must preserve and forward the event id when yielding custom payloads
```ts
import { getEventMeta, withEventMeta } from '@orpc/server'
@@ -106,8 +144,9 @@ const live = os
.handler(async function* ({ input, signal, lastEventId }) {
const iterator = publisher.subscribe('something-updated', { signal, lastEventId })
for await (const payload of iterator) {
- // Preserve event id when yielding custom data
- yield withEventMeta({ custom: 'value' }, { ...getEventMeta(payload) })
+ // Preserve event id when yielding custom payloads
+ const id = getEventMeta(payload)?.id
+ yield withEventMeta({ custom: 'value' }, { id })
}
})
@@ -115,15 +154,18 @@ const publish = os
.input(z.object({ id: z.string() }))
.handler(async ({ input }) => {
// The event id 'this-will-be-ignored' will be replaced by the publisher
- await publisher.publish('something-updated', withEventMeta({ id: input.id }, { id: 'this-will-be-ignored' }))
+ await publisher.publish(
+ 'something-updated',
+ withEventMeta({ id: input.id }, { id: 'this-will-be-ignored' })
+ )
})
```
:::
-### Client Implementation
+### Client Reconnection
-On the client, you can use the [Client Retry Plugin](/docs/plugins/client-retry), which automatically controls and passes `lastEventId` to the server when reconnecting. Alternatively, you can manage `lastEventId` manually:
+On the client, you can use the [Retry Plugin](/docs/plugins/retry), which automatically controls and passes `lastEventId` to the server when reconnecting. Alternatively, you can manage `lastEventId` manually:
```ts
import { getEventMeta } from '@orpc/client'
@@ -145,129 +187,3 @@ while (true) {
}
}
```
-
-## Available Adapters
-
-| Name | Resume Support | Description |
-| ------------------------ | -------------- | -------------------------------------------------------------------------------------------- |
-| `MemoryPublisher` | ✅ | A simple in-memory publisher |
-| `IORedisPublisher` | ✅ | Adapter for [ioredis](https://github.com/redis/ioredis) |
-| `UpstashRedisPublisher` | ✅ | Adapter for [Upstash Redis](https://github.com/upstash/redis-js) |
-| `PublisherDurableObject` | ✅ | Adapter for [Cloudflare Durable Objects](https://developers.cloudflare.com/durable-objects/) |
-
-::: info
-If you'd like to add a new publisher adapter, please open an issue.
-:::
-
-### Memory Publisher
-
-```ts
-import { MemoryPublisher } from '@orpc/experimental-publisher/memory'
-
-const publisher = new MemoryPublisher<{
- 'something-updated': {
- id: string
- }
-}>({
- resumeRetentionSeconds: 60 * 2, // Retain events for 2 minutes to support resume
-})
-```
-
-::: info
-Resume support is disabled by default in `MemoryPublisher`. Enable it by setting `resumeRetentionSeconds` to an appropriate value.
-:::
-
-### IORedis Publisher
-
-```ts
-import { Redis } from 'ioredis'
-import { IORedisPublisher } from '@orpc/experimental-publisher/ioredis'
-
-const publisher = new IORedisPublisher<{
- 'something-updated': {
- id: string
- }
-}>({
- commander: new Redis(), // For executing short-lived commands
- listener: new Redis(), // For subscribing to events
- resumeRetentionSeconds: 60 * 2, // Retain events for 2 minutes to support resume
- prefix: 'orpc:publisher:', // avoid conflict with other keys
- customJsonSerializers: [] // optional custom serializers
-})
-```
-
-This adapter requires two Redis instances: one for executing short-lived commands and another for subscribing to events.
-
-::: info
-Resume support is disabled by default in `IORedisPublisher`. Enable it by setting `resumeRetentionSeconds` to an appropriate value.
-:::
-
-### Upstash Redis Publisher
-
-```ts
-import { Redis } from '@upstash/redis'
-import { UpstashRedisPublisher } from '@orpc/experimental-publisher/upstash-redis'
-
-const redis = Redis.fromEnv()
-
-const publisher = new UpstashRedisPublisher<{
- 'something-updated': {
- id: string
- }
-}>(redis, {
- resumeRetentionSeconds: 60 * 2, // Retain events for 2 minutes to support resume
- prefix: 'orpc:publisher:', // avoid conflict with other keys
- customJsonSerializers: [] // optional custom serializers
-})
-```
-
-::: info
-Resume support is disabled by default in `UpstashRedisPublisher`. Enable it by setting `resumeRetentionSeconds` to an appropriate value.
-:::
-
-### Cloudflare Durable Object
-
-```ts
-import { DurablePublisher, PublisherDurableObject } from '@orpc/experimental-publisher-durable-object'
-
-export class PublisherDO extends PublisherDurableObject {
- constructor(ctx: DurableObjectState, env: Env) {
- super(ctx, env, {
- resume: {
- retentionSeconds: 60 * 2, // Retain events for 2 minutes to support resume
- cleanupIntervalSeconds: 12 * 60 * 60, // Interval for inactivity checks; if inactive, the DO is cleaned up (default: 12 hours)
- },
- })
- }
-}
-
-export default {
- async fetch(request, env) {
- const publisher = new DurablePublisher<{
- 'something-updated': {
- id: string
- }
- }>(env.PUBLISHER_DO, {
- prefix: 'publisher1', // avoid conflict with other keys
- customJsonSerializers: [] // optional custom serializers
- })
- },
-}
-```
-
-::: warning
-You must enable the [`enable_request_signal`](https://developers.cloudflare.com/workers/configuration/compatibility-flags/#enable-requestsignal-for-incoming-requests) compatibility flag in your workers to support request abort signals, which are necessary for properly cleaning up subscriptions.
-
-```json
-{
- "compatibility_flags": [
- "enable_request_signal"
- ]
-}
-```
-
-:::
-
-::: info
-Resume support is disabled by default in `PublisherDurableObject`. Enable it by setting `resume.retentionSeconds` to an appropriate value.
-:::
diff --git a/apps/content/docs/helpers/ratelimit.md b/apps/content/docs/helpers/ratelimit.md
index 40deb9d88..415df7b7f 100644
--- a/apps/content/docs/helpers/ratelimit.md
+++ b/apps/content/docs/helpers/ratelimit.md
@@ -1,220 +1,202 @@
----
-title: Rate Limit
-description: Rate limiting features for oRPC with multiple adapters support.
----
+# Rate Limit Helpers
-# Rate Limit
-
-The Rate Limit package provides flexible rate limiting for oRPC with multiple storage backend support. It includes adapters for in-memory, Redis, and Upstash, along with middleware and plugin helpers for seamless integration.
+Rate Limit helpers provide a unified set of adapters, middleware, and handler plugins for adding rate limiting to oRPC applications. They are flexible and composable, so you can use different rate-limiting strategies and storage backends without changing your procedure code.
## Installation
::: code-group
```sh [npm]
-npm install @orpc/experimental-ratelimit@latest
+npm install @orpc/ratelimit@latest
```
```sh [yarn]
-yarn add @orpc/experimental-ratelimit@latest
+yarn add @orpc/ratelimit@latest
```
```sh [pnpm]
-pnpm add @orpc/experimental-ratelimit@latest
+pnpm add @orpc/ratelimit@latest
```
```sh [bun]
-bun add @orpc/experimental-ratelimit@latest
+bun add @orpc/ratelimit@latest
```
```sh [deno]
-deno add npm:@orpc/experimental-ratelimit@latest
+deno add npm:@orpc/ratelimit@latest
```
:::
-## Available Adapters
+## Basic Usage
-### Memory Adapter
+The core concept is the `RateLimiter` interface, which defines a standard way to check and enforce rate limits. You can create your own custom limiter or use one of the provided adapters for popular storage backends. The `limit` method accepts a key and an optional `weight` value, which defaults to `1`, so a single request can consume multiple points.
-A simple in-memory rate limiter using a sliding window log algorithm. Ideal for single-instance applications or development.
+```ts twoslash
+import { MemoryRateLimiter } from '@orpc/ratelimit/memory'
+// ---cut---
+import { ORPCError } from '@orpc/server'
-```ts
-import { MemoryRatelimiter } from '@orpc/experimental-ratelimit/memory'
+const limiter = new MemoryRateLimiter({
+ maxRequests: 5,
+ window: 60000,
+})
+
+const result = await limiter.limit('user:123', { weight: 2 })
+
+if (!result.success) {
+ throw new ORPCError('TOO_MANY_REQUESTS', {
+ data: {
+ limit: result.limit,
+ remaining: result.remaining,
+ reset: result.reset,
+ },
+ })
+}
+```
+
+## Adapters
+
+The package includes adapters for multiple storage backends and runtimes.
+Each adapter might require `maxRequests` and `window` to configure the limit, along with adapter specific options.
-const limiter = new MemoryRatelimiter({
+| Name | Blocking Mode | Adapter for |
+| ----------------------- | ------------- | ----------------------------------------------------------------------------------------------------------- |
+| `MemoryRateLimiter` | ✅ | In-memory storage |
+| `RedisRateLimiter` | ✅ | [Redis](https://github.com/redis/redis) |
+| `UpstashRateLimiter` | ✅ | [Upstash Rate Limit](https://www.npmjs.com/package/@upstash/ratelimit) |
+| `CloudflareRateLimiter` | | [Cloudflare RateLimit Binding](https://developers.cloudflare.com/workers/runtime-apis/bindings/rate-limit/) |
+
+::: code-group
+
+```ts [memory]
+import { MemoryRateLimiter } from '@orpc/ratelimit/memory'
+
+const limiter = new MemoryRateLimiter({
maxRequests: 10, // Maximum requests allowed
window: 60000, // Time window in milliseconds (60 seconds)
})
```
-### Redis Adapter
-
-Redis-based rate limiter using atomic Lua scripts for distributed rate limiting.
+```ts [redis]
+import { RedisRateLimiter } from '@orpc/ratelimit/redis'
+import { createClient } from 'redis'
-```ts
-import { RedisRatelimiter } from '@orpc/experimental-ratelimit/redis'
-import { Redis } from 'ioredis'
+const client = createClient({ url: 'redis://localhost:6379' })
-const redis = new Redis('redis://localhost:6379')
+// RedisRateLimiter lazily connects to Redis when needed.
+// You can still call `client.connect()` manually, but it is optional.
+await client.connect()
-const limiter = new RedisRatelimiter({
- eval: async (script, numKeys, ...rest) => {
- return redis.eval(script, numKeys, ...rest)
- },
- maxRequests: 100,
- window: 60000,
- prefix: 'orpc:ratelimit:', // Optional key prefix
+const limiter = new RedisRateLimiter(client, {
+ prefix: 'orpc:', // Optional Redis key prefix
+ maxRequests: 10, // Maximum requests allowed
+ window: 60000, // Time window in milliseconds (60 seconds)
})
```
-::: info
-You can use any Redis client that supports Lua script evaluation by providing an `eval` function.
-:::
+```ts [cloudflare]
+import { CloudflareRateLimiter } from '@orpc/ratelimit/cloudflare'
-### Upstash Ratelimit Adapter
+export default {
+ async fetch(request, env) {
+ // env.MY_RATE_LIMITER is a Cloudflare Workers Rate Limiting binding
+ // https://developers.cloudflare.com/workers/runtime-apis/bindings/rate-limit/
-Adapter for [@upstash/ratelimit](https://www.npmjs.com/package/@upstash/ratelimit), optimized for serverless environments like Vercel Edge and Cloudflare Workers.
+ const limiter = new CloudflareRateLimiter(env.MY_RATE_LIMITER, {
+ prefix: 'orpc:', // Optional key prefix
+ })
+ }
+}
+```
-```ts
+```ts [upstash]
import { Ratelimit } from '@upstash/ratelimit'
import { Redis } from '@upstash/redis'
-import { UpstashRatelimiter } from '@orpc/experimental-ratelimit/upstash-ratelimit'
+import { UpstashRateLimiter } from '@orpc/ratelimit/upstash'
const redis = Redis.fromEnv()
-
const ratelimit = new Ratelimit({
redis,
limiter: Ratelimit.slidingWindow(10, '60 s'),
- prefix: 'my-app:',
+ prefix: 'orpc:', // Optional key prefix
})
-const limiter = new UpstashRatelimiter(ratelimit)
-```
-
-::: tip Edge Runtime Support
-For Edge runtime like Vercel Edge or Cloudflare Workers, pass the `waitUntil` function to better handle background tasks:
-
-```ts
-const limiter = new UpstashRatelimiter(ratelimit, {
- waitUntil: ctx.waitUntil.bind(ctx),
+const limiter = new UpstashRateLimiter(ratelimit, {
+ waitUntil: ctx.waitUntil.bind(ctx), // Pass waitUntil for Edge runtime support
})
```
:::
-### Cloudflare Ratelimit Adapter
-
-Adapter for [Cloudflare Workers Ratelimit](https://developers.cloudflare.com/workers/runtime-apis/bindings/rate-limit/).
-
-```ts
-import { CloudflareRatelimiter } from '@orpc/experimental-ratelimit/cloudflare-ratelimit'
-
-export default {
- async fetch(request, env) {
- const limiter = new CloudflareRatelimiter(env.MY_RATE_LIMITER)
-
- return new Response(`Hello World!`)
- }
-}
-```
-
-## Blocking Mode
+### Blocking Mode
-Some adapters support blocking mode, which waits for the rate limit to reset instead of immediately rejecting requests.
+Some adapters support blocking mode, which waits until capacity becomes available instead of rejecting requests immediately.
```ts
-const limiter = new MemoryRatelimiter({
+const limiter = new MemoryRateLimiter({
maxRequests: 10,
window: 60000,
blockingUntilReady: {
- enabled: true,
+ enabled: true, // Disabled by default
timeout: 5000, // Wait up to 5 seconds
},
})
```
-## Manual Usage
-
-You can use adapters directly without middleware for custom rate limiting logic:
-
-```ts twoslash
-import { MemoryRatelimiter } from '@orpc/experimental-ratelimit/memory'
-import { ORPCError } from '@orpc/server'
-
-const limiter = new MemoryRatelimiter({
- maxRequests: 5,
- window: 60000,
-})
-
-const result = await limiter.limit('user:123')
-
-if (!result.success) {
- throw new ORPCError('TOO_MANY_REQUESTS', {
- data: {
- limit: result.limit,
- remaining: result.remaining,
- reset: result.reset,
- },
- })
-}
-```
-
-## `createRatelimitMiddleware`
+## Ratelimit Middleware
-The `createRatelimitMiddleware` helper creates middleware for oRPC procedures to enforce rate limits.
+The `ratelimit` helper creates middleware that enforces rate limits for [procedures](/docs/procedure).
-```ts twoslash
-import { call, os } from '@orpc/server'
-import { MemoryRatelimiter } from '@orpc/experimental-ratelimit/memory'
-import { createRatelimitMiddleware, Ratelimiter } from '@orpc/experimental-ratelimit'
-import { z } from 'zod'
+```ts
+import { ratelimit, RateLimiter } from '@orpc/ratelimit'
-const loginProcedure = os
- .$context<{ ratelimiter: Ratelimiter }>()
+const procedure = os
+ .$context<{ ratelimiter: RateLimiter }>()
.input(z.object({ email: z.email() }))
.use(
- createRatelimitMiddleware({
+ ratelimit({
limiter: ({ context }) => context.ratelimiter,
key: ({ context }, input) => `login:${input.email}`,
+ weight: 1, // Optional weight for each request, default is 1
}),
)
.handler(({ input }) => {
return { success: true }
})
-const ratelimiter = new MemoryRatelimiter({
+const ratelimiter = new MemoryRateLimiter({
maxRequests: 10,
window: 60000,
})
const result = await call(
- loginProcedure,
+ procedure,
{ email: 'user@example.com' },
{ context: { ratelimiter } }
)
```
::: info Automatic Deduplication
-The `createRatelimitMiddleware` automatically deduplicates rate limit checks when the same `limiter` and `key` combination is used multiple times in a request chain. This behavior follows the [Dedupe Middleware Best Practice](/docs/best-practices/dedupe-middleware). To disable deduplication, set the `dedupe: false` option.
+When the same `limiter` and `key` combination is used multiple times in a single request chain, the `ratelimit` middleware performs the rate limit check only once. This behavior follows the [Dedupe Middleware Best Practice](/docs/best-practices/dedupe-middleware). To disable deduplication, set `dedupe: false`.
:::
::: tip Conditional Limiter
-You can dynamically choose different limiters based on context:
+You can choose different limiters dynamically based on the request context:
```ts
-const premiumLimiter = new MemoryRatelimiter({
+const premiumLimiter = new MemoryRateLimiter({
maxRequests: 100,
window: 60000,
})
-const standardLimiter = new MemoryRatelimiter({
+const standardLimiter = new MemoryRateLimiter({
maxRequests: 10,
window: 60000,
})
const result = await call(
- loginProcedure,
+ procedure,
{ email: 'user@example.com' },
{
context: {
@@ -228,22 +210,20 @@ const result = await call(
## Handler Plugin
-The `RatelimitHandlerPlugin` automatically adds HTTP rate-limiting headers (`RateLimit-*` and `Retry-After`) to responses when used with middleware created by [`createRatelimitMiddleware`](#createratelimitmiddleware).
+The `RateLimitHandlerPlugin` automatically adds HTTP rate limiting headers (`RateLimit-*` and `Retry-After`) to responses when used with [Ratelimit Middleware](#ratelimit-middleware). This lets clients inspect the current limit state and know when they can retry after hitting a limit.
```ts
-import { RatelimitHandlerPlugin } from '@orpc/experimental-ratelimit'
+import { RateLimitHandlerPlugin } from '@orpc/ratelimit'
const handler = new RPCHandler(router, {
plugins: [
- new RatelimitHandlerPlugin(),
+ new RateLimitHandlerPlugin(),
],
})
```
::: info
-You can combine this plugin with [Retry After Plugin](/docs/plugins/retry-after) to enable automatic client-side retries based on server rate-limiting headers.
+You can combine this plugin with [Retry After Plugin](/docs/plugins/retry-after) to enable automatic client-side retries based on server rate limiting headers.
:::
-::: info
-The `handler` can be any supported oRPC handler, such as [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or other custom handlers.
-:::
+
diff --git a/apps/content/docs/helpers/signing.md b/apps/content/docs/helpers/signing.md
index f2675d35b..c7d27b0b0 100644
--- a/apps/content/docs/helpers/signing.md
+++ b/apps/content/docs/helpers/signing.md
@@ -1,8 +1,3 @@
----
-title: Signing Helpers
-description: Functions to cryptographically sign and verify data using HMAC-SHA256.
----
-
# Signing Helpers
Signing helpers provide functions to cryptographically sign and verify data using HMAC-SHA256.
@@ -11,6 +6,8 @@ Signing helpers provide functions to cryptographically sign and verify data usin
Signing is faster than [encryption](/docs/helpers/encryption) but users can view the original data.
:::
+## Basic Usage
+
```ts twoslash
import { getSignedValue, sign, unsign } from '@orpc/server/helpers'
diff --git a/apps/content/docs/integrations/ai-sdk.md b/apps/content/docs/integrations/ai-sdk.md
deleted file mode 100644
index 2ffce341f..000000000
--- a/apps/content/docs/integrations/ai-sdk.md
+++ /dev/null
@@ -1,220 +0,0 @@
----
-title: AI SDK Integration
-description: Seamlessly use AI SDK inside your oRPC projects without any extra overhead.
----
-
-# AI SDK Integration
-
-[AI SDK](https://ai-sdk.dev/) is a free open-source library for building AI-powered products. You can seamlessly integrate it with oRPC without any extra overhead.
-
-::: warning
-This documentation requires AI SDK v5.0.0 or later. For a refresher, review the [AI SDK documentation](https://ai-sdk.dev/docs).
-:::
-
-## Server
-
-Use `streamToEventIterator` to convert AI SDK streams to [oRPC Event Iterators](/docs/event-iterator).
-
-```ts twoslash
-import { os, streamToEventIterator, type } from '@orpc/server'
-import { convertToModelMessages, streamText, UIMessage } from 'ai'
-import { google } from '@ai-sdk/google'
-
-export const chat = os
- .input(type<{ chatId: string, messages: UIMessage[] }>())
- .handler(async ({ input }) => {
- const result = streamText({
- model: google('gemini-1.5-flash'),
- system: 'You are a helpful assistant.',
- messages: await convertToModelMessages(input.messages),
- })
-
- return streamToEventIterator(result.toUIMessageStream())
- })
-```
-
-## Client
-
-On the client side, convert the event iterator back to a stream using `eventIteratorToStream` or `eventIteratorToUnproxiedDataStream`.
-
-```tsx twoslash
-import React, { useState } from 'react'
-import { os, streamToEventIterator, type } from '@orpc/server'
-import { convertToModelMessages, streamText, UIMessage } from 'ai'
-import { google } from '@ai-sdk/google'
-
-export const chat = os
- .input(type<{ chatId: string, messages: UIMessage[] }>())
- .handler(async ({ input }) => {
- const result = streamText({
- model: google('gemini-1.5-flash'),
- system: 'You are a helpful assistant.',
- messages: await convertToModelMessages(input.messages),
- })
-
- return streamToEventIterator(result.toUIMessageStream())
- })
- .callable()
-
-const client = { chat }
-// ---cut---
-import { useChat } from '@ai-sdk/react'
-import { eventIteratorToUnproxiedDataStream } from '@orpc/client'
-
-export function Example() {
- const { messages, sendMessage, status } = useChat({
- transport: {
- async sendMessages(options) {
- return eventIteratorToUnproxiedDataStream(await client.chat({
- chatId: options.chatId,
- messages: options.messages,
- }, { signal: options.abortSignal }))
- },
- reconnectToStream(options) {
- throw new Error('Unsupported')
- },
- },
- })
- const [input, setInput] = useState('')
-
- return (
- <>
- {messages.map(message => (
-
- {message.role === 'user' ? 'User: ' : 'AI: '}
- {message.parts.map((part, index) =>
- part.type === 'text' ? {part.text} : null,
- )}
-
- ))}
-
-
- >
- )
-}
-```
-
-::: info
-The `reconnectToStream` function is not supported by default, which is fine for most use cases. If you need reconnection support, implement it similar to `sendMessages` with custom reconnection logic. See this [reconnect example]().
-:::
-
-::: info
-Prefer `eventIteratorToUnproxiedDataStream` over `eventIteratorToStream`.
-AI SDK internally uses `structuredClone`, which doesn't support proxied data.
-oRPC may proxy events for [metadata](/docs/event-iterator#last-event-id-event-metadata), so unproxy before passing to AI SDK.
-:::
-
-## `implementTool` helper
-
-Implements [procedure contract](/docs/contract-first/define-contract) as an [AI SDK tools](https://ai-sdk.dev/docs/foundations/tools) by leveraging existing contract definitions.
-
-```ts twoslash
-import { oc } from '@orpc/contract'
-import {
- AI_SDK_TOOL_META_SYMBOL,
- AiSdkToolMeta,
- implementTool
-} from '@orpc/ai-sdk'
-import { z } from 'zod'
-
-interface ORPCMeta extends AiSdkToolMeta {} // optional extend meta
-const base = oc.$meta({})
-
-const getWeatherContract = base
- .meta({
- [AI_SDK_TOOL_META_SYMBOL]: {
- title: 'Get Weather', // AI SDK tool title
- },
- })
- .route({
- summary: 'Get the weather in a location', // AI SDK tool description
- })
- .input(z.object({
- location: z.string().describe('The location to get the weather for'),
- }))
- .output(z.object({
- location: z.string().describe('The location the weather is for'),
- temperature: z.number().describe('The temperature in Celsius'),
- }))
-
-const getWeatherTool = implementTool(getWeatherContract, {
- execute: async ({ location }) => ({
- location,
- temperature: 72 + Math.floor(Math.random() * 21) - 10,
- }),
- // ...add any additional configuration or overrides here
-})
-```
-
-::: warning
-The `implementTool` helper requires a contract with an `input` schema defined
-:::
-
-::: info
-Standard [procedures](/docs/procedure) are also compatible with [procedure contracts](/docs/contract-first/define-contract).
-:::
-
-## `createTool` helper
-
-Converts a [procedure](/docs/procedure) into an [AI SDK Tool](https://ai-sdk.dev/docs/foundations/tools) by leveraging existing procedure definitions.
-
-```ts twoslash
-import { os } from '@orpc/server'
-import {
- AI_SDK_TOOL_META_SYMBOL,
- AiSdkToolMeta,
- createTool
-} from '@orpc/ai-sdk'
-import { z } from 'zod'
-
-interface ORPCMeta extends AiSdkToolMeta {} // optional extend meta
-const base = os.$meta({})
-
-const getWeatherProcedure = base
- .meta({
- [AI_SDK_TOOL_META_SYMBOL]: {
- title: 'Get Weather', // AI SDK tool title
- },
- })
- .route({
- summary: 'Get the weather in a location',
- })
- .input(z.object({
- location: z.string().describe('The location to get the weather for'),
- }))
- .output(z.object({
- location: z.string().describe('The location the weather is for'),
- temperature: z.number().describe('The temperature in Celsius'),
- }))
- .handler(async ({ input }) => ({
- location: input.location,
- temperature: 72 + Math.floor(Math.random() * 21) - 10,
- }))
-
-const getWeatherTool = createTool(getWeatherProcedure, {
- context: {}, // provide initial context if needed
- // ...add any additional configuration or overrides here
-})
-```
-
-::: warning
-The `createTool` helper requires a procedure with an `input` schema defined
-:::
diff --git a/apps/content/docs/integrations/better-auth.md b/apps/content/docs/integrations/better-auth.md
deleted file mode 100644
index ba8db9e2d..000000000
--- a/apps/content/docs/integrations/better-auth.md
+++ /dev/null
@@ -1,81 +0,0 @@
----
-title: Better Auth Integration
-description: Seamlessly use Better Auth inside your oRPC projects without any extra overhead.
----
-
-# Better Auth Integration
-
-[Better Auth](https://better-auth.com/) is a framework-agnostic, universal authentication and authorization framework for TypeScript.
-
-::: warning
-This documentation assumes you are already familiar with [Better Auth](https://better-auth.com/). If you need a refresher, please review the official Better Auth documentation before proceeding.
-:::
-
-## Step 1: Define Context Headers
-
-First, you need to access request headers in your context. You can do this either manually or by using the [Request Headers Plugin](/docs/plugins/request-headers).
-
-### Option A: Manual Context Definition
-
-```typescript
-import { os } from '@orpc/server'
-
-export const base = os.$context<{ headers: Headers }>()
-```
-
-::: tip
-Don't forget to provide the `headers` when creating the context. This is typically done in your server adapter.
-:::
-
-### Option B: Using Request Headers Plugin
-
-Follow the setup instructions on the [Request Headers Plugin](/docs/plugins/request-headers) page.
-
-## Step 2: Create Auth Middleware
-
-Create a middleware that fetches the session and user from Better Auth, validates authentication, and adds them to the context.
-
-```typescript
-import { auth } from './auth' // Your Better Auth instance
-import { base } from './context'
-import { ORPCError } from '@orpc/server'
-
-export const authMiddleware = base.middleware(async ({ context, next }) => {
- const sessionData = await auth.api.getSession({
- headers: context.headers, // or reqHeaders if you're using the plugin
- })
-
- if (!sessionData?.session || !sessionData?.user) {
- throw new ORPCError('UNAUTHORIZED')
- }
-
- // Adds session and user to the context
- return next({
- context: {
- session: sessionData.session,
- user: sessionData.user
- },
- })
-})
-```
-
-## Usage
-
-Instead of using `.use(authMiddleware)` every time you create a protected procedure, you can create an `authorized` base that already includes the auth middleware:
-
-```typescript
-import { base } from './context'
-import { authMiddleware } from './middlewares/auth'
-
-export const authorized = base.use(authMiddleware)
-```
-
-Now you can use `authorized` to create procedures that require authentication:
-
-```typescript
-import { authorized } from './authorized'
-
-export const getMessages = authorized.handler(({ context }) => {
- // context.session and context.user are guaranteed to be defined
-})
-```
diff --git a/apps/content/docs/integrations/durable-iterator.md b/apps/content/docs/integrations/durable-iterator.md
deleted file mode 100644
index 1a3dda83a..000000000
--- a/apps/content/docs/integrations/durable-iterator.md
+++ /dev/null
@@ -1,444 +0,0 @@
----
-title: Durable Iterator Integration
-description: Extends Event Iterator with durable event streams, automatic reconnections, and event recovery through a separate streaming service.
----
-
-# Durable Iterator Integration
-
-Durable Iterator extends [Event Iterator](/docs/event-iterator) by offloading streaming to a separate service that provides durable event streams, automatic reconnections, and event recovery.
-
-::: info
-See the complete example in our [Cloudflare Worker Playground](/docs/playgrounds).
-:::
-
-::: info
-While not limited to [Cloudflare Durable Objects](https://developers.cloudflare.com/durable-objects/), it's currently the only supported implementation.
-:::
-
-## Installation
-
-::: code-group
-
-```sh [npm]
-npm install @orpc/experimental-durable-iterator@latest
-```
-
-```sh [yarn]
-yarn add @orpc/experimental-durable-iterator@latest
-```
-
-```sh [pnpm]
-pnpm add @orpc/experimental-durable-iterator@latest
-```
-
-```sh [bun]
-bun add @orpc/experimental-durable-iterator@latest
-```
-
-```sh [deno]
-deno add npm:@orpc/experimental-durable-iterator@latest
-```
-
-:::
-
-::: warning
-The `experimental-` prefix indicates that this feature is still in development and may change in the future.
-:::
-
-## Durable Object
-
-::: warning
-This section requires you to be familiar with [Cloudflare Durable Objects](https://developers.cloudflare.com/durable-objects/). Please learn it first before continuing.
-:::
-
-### Define your Durable Object
-
-Simply extend the `DurableIteratorObject` class:
-
-```ts
-import { DurableIteratorObject } from '@orpc/experimental-durable-iterator/durable-object'
-
-export class ChatRoom extends DurableIteratorObject<{ message: string }> {
- constructor(ctx: DurableObjectState, env: Env) {
- super(ctx, env, {
- signingKey: 'secret-key', // Replace with your actual signing key
- interceptors: [
- onError(e => console.error(e)), // log error thrown from rpc calls
- ],
- onSubscribed: (websocket, lastEventId) => {
- console.log(`WebSocket Ready id=${websocket['~orpc'].deserializeId()}`)
- }
- })
- }
-
- someMethod() {
- // publishEvent method inherited from DurableIteratorObject
- this.publishEvent({ message: 'Hello, world!' })
- }
-}
-```
-
-::: info
-How to use `DurableIteratorObject` without extending it: [see here](https://github.com/middleapi/orpc/tree/main/packages/durable-iterator/src/durable-object/object.ts)
-:::
-
-### Upgrade Durable Iterator Request
-
-Upgrade and validate WebSocket requests to your Durable Object by providing a signing key and the corresponding namespace:
-
-```ts
-import { upgradeDurableIteratorRequest } from '@orpc/experimental-durable-iterator/durable-object'
-
-export default {
- async fetch(request, env) {
- const url = new URL(request.url)
-
- if (url.pathname === '/chat-room') {
- return upgradeDurableIteratorRequest(request, {
- signingKey: 'secret-key', // Replace with your actual signing key
- namespace: env.CHAT_ROOM,
- })
- }
-
- return new Response('Not Found', { status: 404 })
- },
-} satisfies ExportedHandler
-
-export { ChatRoom }
-```
-
-### Publish Events
-
-Use `publishEvent` to send events to connected clients. Three filtering options are available:
-
-- **`tags`**: Send events only to clients with matching tags
-- **`targets`**: Send events to specific clients (accepts array or filter callback)
-- **`exclude`**: Exclude specific clients from receiving events (accepts array or filter callback)
-
-```ts
-this.publishEvent({ message: 'Hello, world!' }, {
- tags: ['tag1', 'tag2'],
- targets: ws => ws['~orpc'].deserializeTokenPayload().att.role === 'admin',
- exclude: [senderWs],
-})
-```
-
-::: info
-When using [Resume Events After Connection Loss](#resume-events-after-connection-loss) feature, prefer `tags` or `targets` filtering over `exclude` for security. Since clients control their own identity, `exclude` should only be used for UI convenience, not security enforcement.
-:::
-
-### Resume Events After Connection Loss
-
-Event resumption is disabled by default. Enable it by configuring `resumeRetentionSeconds` to specify how long events are persisted for recovery:
-
-```ts
-export class YourDurableObject extends DurableIteratorObject<{ message: string }> {
- constructor(
- ctx: DurableObjectState,
- env: Env,
- ) {
- super(ctx, env, {
- signingKey: 'secret-key',
- resumeRetentionSeconds: 60 * 2, // 2 minutes [!code highlight]
- })
- }
-}
-```
-
-::: warning
-This feature controls event IDs automatically, so custom event IDs will be ignored:
-
-```ts
-import { withEventMeta } from '@orpc/experimental-durable-iterator'
-
-this.publishEvent(withEventMeta({ message: 'Hello, world!' }, { id: 'this-will-not-take-effect' }))
-```
-
-:::
-
-## Server Side
-
-Define two procedures: one for listening to chat room messages, and another for sending messages to all connected clients:
-
-::: info
-This example assumes your server and Durable Object run in the same environment. For different environments, send a fetch request to your Durable Object instead of invoking methods directly.
-:::
-
-```ts
-import { DurableIterator } from '@orpc/experimental-durable-iterator'
-
-export const router = {
- onMessage: base.handler(({ context }) => {
- return new DurableIterator('some-room', {
- tags: ['tag1', 'tag2'],
- signingKey: 'secret-key', // Replace with your actual signing key
- })
- }),
-
- sendMessage: base
- .input(z.object({ message: z.string() }))
- .handler(async ({ context, input }) => {
- const id = context.env.CHAT_ROOM.idFromName('some-room')
- const stub = context.env.CHAT_ROOM.get(id)
-
- await stub.publishEvent(input)
- }),
-}
-```
-
-Enable Durable Iterator support by adding `DurableIteratorHandlerPlugin` to your handler:
-
-```ts
-import { DurableIteratorHandlerPlugin } from '@orpc/experimental-durable-iterator'
-
-const handler = new RPCHandler(router, {
- plugins: [
- new DurableIteratorHandlerPlugin(),
- ],
-})
-```
-
-::: warning CORS Policy
-The `DurableIteratorHandlerPlugin` adds an `x-orpc-durable-iterator` header to responses, indicating that the response contains a durable iterator. For cross-origin requests, you must configure CORS to expose this header to clients.
-
-```ts
-const handler = new RPCHandler(router, {
- plugins: [
- new CORSPlugin({
- exposeHeaders: ['x-orpc-durable-iterator'], // [!code highlight]
- }),
- new DurableIteratorHandlerPlugin(),
- ],
-})
-```
-
-:::
-
-## Client Side
-
-On the client side, simply configure the plugin. Usage is identical to [Event Iterator](/docs/client/event-iterator). The `url` in `DurableIteratorLinkPlugin` points to your Durable Object upgrade endpoint:
-
-```ts
-import { DurableIteratorLinkPlugin } from '@orpc/experimental-durable-iterator/client'
-
-const link = new RPCLink({
- url: 'http://localhost:3000/rpc',
- plugins: [
- new DurableIteratorLinkPlugin({
- url: 'ws://localhost:3000/chat-room',
- interceptors: [
- onError(e => console.error(e)), // log error thrown from rpc calls
- ],
- }),
- ],
-})
-```
-
-::: info
-`DurableIteratorLinkPlugin` establishes a WebSocket connection to the Durable Object for each durable iterator and automatically reconnects if the connection is lost.
-:::
-
-### Example
-
-```ts
-const iterator = await client.onMessage()
-
-for await (const { message } of iterator) {
- console.log('Received message:', message)
-}
-
-await client.sendMessage({ message: 'Hello, world!' })
-```
-
-### Auto Refresh Token Before Expiration
-
-Token auto-refresh is disabled by default. Enable it by configuring `refreshTokenBeforeExpireInSeconds`:
-
-```ts
-const link = new RPCLink({
- url: 'http://localhost:3000/rpc',
- plugins: [
- new DurableIteratorLinkPlugin({
- url: 'ws://localhost:3000/chat-room',
- refreshTokenBeforeExpireInSeconds: 10 * 60, // 10 minutes [!code highlight]
- }),
- ],
-})
-```
-
-::: warning
-Token refresh reuses the existing WebSocket connection if the refreshed token has identical `chn` (channel) and `tags`. Otherwise, the connection closes and a new one is established.
-:::
-
-### Stopping the Durable Iterator
-
-Like [Event Iterator](/docs/client/event-iterator), you can rely on `signal` or `.return` to stop the iterator.
-
-```ts
-const controller = new AbortController()
-const iterator = await client.onMessage(undefined, { signal: controller.signal })
-
-// Stop the iterator after 1 second
-setTimeout(() => {
- controller.abort()
- // or
- iterator.return()
-}, 1000)
-
-for await (const { message } of iterator) {
- console.log('Received message:', message)
-}
-```
-
-## Method RPC
-
-Unlike [Cloudflare Durable Objects RPC](https://developers.cloudflare.com/durable-objects/best-practices/create-durable-object-stubs-and-send-requests/) (server-side only), this RPC uses oRPC's built-in system over the same WebSocket connection for fast client-to-Durable Object communication. Define methods that accept a `DurableIteratorWebsocket` instance as the first argument and return an [oRPC Client](/docs/client/server-side):
-
-```ts
-import { DurableIteratorWebsocket } from '@orpc/experimental-durable-iterator/durable-object'
-
-export class ChatRoom extends DurableIteratorObject<{ message: string }> {
- singleClient(ws: DurableIteratorWebsocket) {
- return base
- .input(z.object({ message: z.string() }))
- .handler(({ input, context }) => {
- const tokenPayload = ws['~orpc'].deserializeTokenPayload()
-
- this.publishEvent(input, {
- exclude: [ws], // exclude the sender
- })
- })
- .callable()
- }
-
- routerClient(ws: DurableIteratorWebsocket) {
- return {
- ping: base.handler(() => 'pong').callable(),
- echo: base
- .input(z.object({ text: z.string() }))
- .handler(({ input }) => `Echo: ${input.text}`)
- .callable(),
- }
- }
-}
-```
-
-### Server Side Usage
-
-```ts
-import { DurableIterator } from '@orpc/experimental-durable-iterator'
-
-export const onMessage = base.handler(({ context }) => {
- return new DurableIterator('some-room', {
- signingKey: 'secret-key', // Replace with your actual signing key
- att: { // Attach additional data to token
- userId: 'user-123',
- },
- }).rpc('singleClient', 'routerClient') // Allowed methods
-})
-```
-
-::: info
-Clients can only call methods defined in the `rpc` method, providing fine-grained access control.
-:::
-
-::: warning
-The `att` (attachment) data is visible to clients. Only include non-sensitive metadata like user IDs or preferences.
-:::
-
-### Client Side Usage
-
-Invoke methods defined in `rpc` directly from the client iterator:
-
-```ts
-const iterator = await client.onMessage()
-
-// Listen for events
-for await (const { message } of iterator) {
- console.log('Received message:', message)
-}
-
-// Call RPC methods
-await iterator.singleClient({ message: 'Hello, world!' })
-
-// Call nested router methods
-const response = await iterator.routerClient.ping()
-console.log(response) // "pong"
-
-const echoResponse = await iterator.routerClient.echo({ text: 'Hello' })
-console.log(echoResponse) // "Echo: Hello"
-```
-
-::: info
-[Retry Plugin](/docs/plugins/client-retry) is enabled for all RPC methods. Configure retry attempts using the context:
-
-```ts
-await iterator.singleClient({ message: 'Hello, world!' }, { context: { retry: 3 } })
-```
-
-:::
-
-## Contract First
-
-This integration supports [Contract First](/docs/contract-first/define-contract). Define an interface that extends `DurableIteratorObject`:
-
-```ts
-import type { ContractRouterClient } from '@orpc/contract'
-import { oc, type } from '@orpc/contract'
-import type { ClientDurableIterator } from '@orpc/experimental-durable-iterator/client'
-import type { DurableIteratorObject } from '@orpc/experimental-durable-iterator'
-
-export const publishMessageContract = oc.input(z.object({ message: z.string() }))
-
-export interface ChatRoom extends DurableIteratorObject<{ message: string }> {
- publishMessage(...args: any[]): ContractRouterClient
-}
-
-export const contract = {
- onMessage: oc.output(type>()),
-}
-```
-
-## Advanced
-
-Durable Iterator is built on top of the [Hibernation Plugin](/docs/plugins/hibernation), essentially providing an oRPC instance within another oRPC. This architecture gives you access to the full oRPC ecosystem, including interceptors and plugins for both server and client sides.
-
-### Server-Side Customization
-
-```ts
-export class YourDurableObject extends DurableIteratorObject<{ message: string }> {
- constructor(
- ctx: DurableObjectState,
- env: Env,
- ) {
- super(ctx, env, {
- signingKey: 'secret-key',
- customJsonSerializers: [], // Custom JSON serializers
- interceptors: [], // Handler interceptors
- plugins: [], // Handler plugins
- })
- }
-}
-```
-
-### Client-Side Customization
-
-```ts
-declare module '@orpc/experimental-durable-iterator/client' {
- interface ClientDurableIteratorRpcContext {
- // Custom client context
- }
-}
-
-const link = new RPCLink({
- url: 'http://localhost:3000/rpc',
- plugins: [
- new DurableIteratorLinkPlugin({
- url: 'ws://localhost:3000/chat-room',
- customJsonSerializers: [], // Custom JSON serializers
- interceptors: [], // Link interceptors
- plugins: [], // Link plugins
- }),
- ],
-})
-```
diff --git a/apps/content/docs/integrations/effect.md b/apps/content/docs/integrations/effect.md
new file mode 100644
index 000000000..9f72ea4df
--- /dev/null
+++ b/apps/content/docs/integrations/effect.md
@@ -0,0 +1,272 @@
+# Effect Integration
+
+[Effect](https://effect.website/) integration lets you seamlessly use Effect's powerful features, such as its effect system, concurrency model, and schema library, within oRPC.
+
+::: warning
+This guide assumes familiarity with [Effect](https://effect.website/). Review the official documentation if needed.
+:::
+
+## Installation
+
+::: code-group
+
+```sh [npm]
+npm install @orpc/experimental-effect@latest effect@latest
+```
+
+```sh [yarn]
+yarn add @orpc/experimental-effect@latest effect@latest
+```
+
+```sh [pnpm]
+pnpm add @orpc/experimental-effect@latest effect@latest
+```
+
+```sh [bun]
+bun add @orpc/experimental-effect@latest effect@latest
+```
+
+```sh [deno]
+deno add npm:@orpc/experimental-effect@latest npm:effect@latest
+```
+
+:::
+
+## Effectful Handlers
+
+`handlerGen` allows you to write effectful handlers using generator functions. Inside the generator, you can yield Effect operations, and `handlerGen` will handle the execution and error handling for you.
+
+```ts twoslash
+import { os } from '@orpc/server'
+// ---cut---
+import { handlerGen } from '@orpc/experimental-effect'
+import { Effect } from 'effect'
+
+const procedure = os.handler(handlerGen(function* ({ input, context }) {
+ // You can use Effect's features here, such as concurrency, error handling, etc.
+ const result = yield* Effect.promise(() => Promise.resolve(5))
+ return result
+}))
+```
+
+### `.effect` extension
+
+Import `@orpc/experimental-effect/extensions/effect` from a module that always runs during initialization, such as the file where you define your base builder or create your server. This adds an `.effect` method to the builder so you can write effectful handlers directly.
+
+::: code-group
+
+```ts [usage]
+const procedure = base.effect(function* ({ input, context }) {
+ // You can use Effect's features here, such as concurrency, error handling, etc.
+ const result = yield* Effect.promise(() => Promise.resolve(5))
+ return result
+})
+```
+
+```ts [setup]
+import '@orpc/experimental-effect/extensions/effect'
+
+import { os } from '@orpc/server'
+
+export const base = os
+```
+
+:::
+
+### Effect Services
+
+You can provide Effect services through the oRPC context in a typesafe way with `WithEffectContext` and `~effect/context`:
+
+```ts twoslash
+import { call, os } from '@orpc/server'
+// ---cut---
+import { handlerGen, WithEffectContext } from '@orpc/experimental-effect'
+import { Context, Effect } from 'effect'
+
+class Random extends Context.Tag('MyRandomService')<
+ Random,
+ {
+ readonly next: Effect.Effect
+ }
+>() {}
+
+interface ServerContext extends WithEffectContext {}
+
+const procedure = os
+ .$context()
+ .handler(handlerGen(function* ({ input, context }) {
+ const random = yield* Random
+ const result = yield* random.next
+ return result
+ }))
+
+const random = await call(procedure, undefined, {
+ context: {
+ '~effect/context': Context.empty().pipe(
+ Context.add(Random, {
+ next: Effect.succeed(Math.random()),
+ }),
+ )
+ }
+})
+```
+
+::: info
+You can also extend the Effect context with [middleware](/docs/middleware):
+
+```ts
+const procedure = os
+ .$context()
+ .use(({ context, next }) => {
+ return next({
+ context: {
+ '~effect/context': context['~effect/context'].pipe(
+ Context.add(AdditionService, {}),
+ )
+ }
+ })
+ })
+ .handler(handlerGen(function* ({ input, context }) {
+ const additionService = yield* AdditionService
+ }))
+```
+
+:::
+
+### Error Handling
+
+This integration preserves the original error whenever possible. If you call `Effect.fail(error)`, the error is forwarded to [middleware](/docs/middleware) and interceptors, just like a regular thrown error.
+
+To customize this behavior, wrap the effect before execution using `~effect/wrap` in the context:
+
+```ts
+import { Context, Effect } from 'effect'
+
+interface ServerContext extends WithEffectContext {}
+
+export async function fetch(request: Request) {
+ const { response } = await handler.fetch(request, {
+ context: {
+ '~effect/context': Context.empty(),
+ '~effect/wrap': (effect, opts) => effect.pipe(
+ Effect.catchAllCause((cause) => {
+
+ })
+ ),
+ }
+ })
+
+ return response ?? new Response('Not Found', { status: 404 })
+}
+```
+
+::: info
+For app level error handling, we recommend [middleware](/docs/middleware) or interceptors.
+:::
+
+### Typesafe Errors
+
+When you `yield* Effect.fail(new ORPCError(...))` or `return new ORPCError(...)`, oRPC treats it as a [returned ORPCError](/docs/error-handling#returning-an-orpcerror). On the client, you can handle these errors in a typesafe way:
+
+```ts
+const procedure = os.handler(handlerGen(function* ({ errors }) {
+ if (resourceNotFound) {
+ yield* Effect.fail(new ORPCError('NOT_FOUND', {
+ message: 'The resource you are looking for does not exist',
+ }))
+ // -- or -
+ return new ORPCError('NOT_FOUND', {
+ message: 'The resource you are looking for does not exist',
+ })
+ }
+
+ return 'Success'
+}))
+
+const [error, result] = await call(procedure)
+
+if (isInferableError(error)) {
+ // typesafe error handling
+}
+```
+
+## Effect Schema
+
+oRPC natively supports [Standard Schema](https://standardschema.dev/schema#what-schema-libraries-implement-the-spec), and [Effect Schema](https://effect.website/docs/schema/introduction/) implements that spec through [Schema.standardSchemaV1](https://effect.website/docs/schema/standard-schema/):
+
+```ts
+import { Schema } from 'effect'
+
+const procedure = os
+ .input(Schema.standardSchemaV1(Schema.Struct({ name: Schema.String })))
+ .handler(handlerGen(function* ({ input, context }) {
+ return `Hello ${input.name}!`
+ }))
+```
+
+### `.input` and `.output` Extensions
+
+Import `@orpc/experimental-effect/extensions/input-output` from a module that always runs during initialization, such as the file where you define your base builder or create your server. This lets you define `.input` and `.output` directly with Effect Schema:
+
+::: code-group
+
+```ts [usage]
+const procedure = base
+ .input(Schema.Struct({ name: Schema.String }))
+ .output(Schema.Struct({ greeting: Schema.String }))
+ .handler(handlerGen(function* ({ input, context }) {
+ return { greeting: `Hello ${input.name}!` }
+ }))
+```
+
+```ts [setup]
+import '@orpc/experimental-effect/extensions/input-output'
+
+import { os } from '@orpc/server'
+
+export const base = os
+```
+
+:::
+
+::: info
+You can also use these extensions with the [contract builder](/docs/contract/procedure).
+:::
+
+### JSON Schema Converter
+
+This integration also provides `EffectSchemaToJsonSchemaConverter`, built on top of [Effect Schema to JSON Schema](https://effect.website/docs/schema/json-schema/). You can use it with tools such as the [OpenAPI Generator](/docs/openapi/specification#openapi-generator):
+
+```ts
+import { EffectSchemaToJsonSchemaConverter } from '@orpc/experimental-effect'
+
+const generator = new OpenAPIGenerator({
+ converters: [new EffectSchemaToJsonSchemaConverter()],
+})
+```
+
+## OpenTelemetry Integration
+
+First, set up the [oRPC OpenTelemetry integration](/docs/integrations/opentelemetry). Then instrument your Effect to work seamlessly with OpenTelemetry by providing `TracingLive` through `~effect/wrap` in the context. This makes Effect tracing equivalent to OpenTelemetry tracing:
+
+```ts
+import { Resource, Tracer } from '@effect/opentelemetry'
+import { Context, Effect, Layer } from 'effect'
+
+interface ServerContext extends WithEffectContext {}
+
+const TracingLive = Tracer.layerGlobal.pipe(
+ Layer.provide(Resource.layerFromEnv()),
+)
+
+export async function fetch(request: Request) {
+ const { response } = await handler.fetch(request, {
+ context: {
+ '~effect/context': Context.empty(),
+ '~effect/wrap': (effect, opts) => effect.pipe(Effect.provide(TracingLive)),
+ }
+ })
+
+ return response ?? new Response('Not Found', { status: 404 })
+}
+```
diff --git a/apps/content/docs/integrations/evlog.md b/apps/content/docs/integrations/evlog.md
new file mode 100644
index 000000000..21ed26423
--- /dev/null
+++ b/apps/content/docs/integrations/evlog.md
@@ -0,0 +1,117 @@
+# Evlog Integration
+
+[Evlog](https://evlog.dev/) integration for oRPC adds structured logging so you can trace requests, monitor errors, and inspect application behavior.
+
+::: warning
+This guide assumes familiarity with [Evlog](https://evlog.dev/). Review the official documentation if needed.
+:::
+
+## Installation
+
+::: code-group
+
+```sh [npm]
+npm install @orpc/evlog@latest evlog@latest
+```
+
+```sh [yarn]
+yarn add @orpc/evlog@latest evlog@latest
+```
+
+```sh [pnpm]
+pnpm add @orpc/evlog@latest evlog@latest
+```
+
+```sh [bun]
+bun add @orpc/evlog@latest evlog@latest
+```
+
+```sh [deno]
+deno add npm:@orpc/evlog@latest npm:evlog@latest
+```
+
+:::
+
+## Setup
+
+Use `EvlogHandlerPlugin` to instrument your handler with structured logs, request tracking, and error monitoring.
+
+```ts twoslash
+import { RPCHandler } from '@orpc/server/fetch'
+import { router } from './shared/planet'
+// ---cut---
+import { EvlogHandlerPlugin } from '@orpc/evlog'
+
+const handler = new RPCHandler(router, {
+ plugins: [
+ new EvlogHandlerPlugin({
+ drain: undefined, // <- custom Evlog drain (optional)
+ plugins: [], // <- additional Evlog plugins (optional)
+ logAbort: true, // <- log when requests are aborted (disabled by default)
+ }),
+ ],
+})
+```
+
+
+
+## Using the Logger in Your Code
+
+This plugin supports using [AsyncLocalStorage](https://nodejs.org/api/async_context.html#class-asynclocalstorage) to access the logger throughout a request and enrich the final [wide event](https://www.evlog.dev/learn/wide-events#uselogger-retrieving-the-request-logger). It is the most convenient way to use Evlog's full feature set. If your runtime does not support AsyncLocalStorage, you can still [access the logger from the context](#without-asynclocalstorage).
+
+::: code-group
+
+```ts [business logic]
+import { createLoggerStorage } from '@orpc/evlog/node'
+
+/**
+ * Pass `storage` to the plugin configuration.
+ * Call `useLogger` inside a procedure to access the request logger.
+ */
+export const { storage, useLogger } = createLoggerStorage()
+
+const procedure = os
+ .handler(async () => {
+ const logger = useLogger() // [!code highlight]
+
+ logger?.set({ user: { id: 123, name: 'John Doe' } }) // [!code highlight]
+
+ await logger.fork('child-procedure', () => {
+ const logger = useLogger() // [!code highlight]
+ })
+
+ return { success: true }
+ })
+```
+
+```ts [handler setup]
+const handler = new RPCHandler(router, {
+ plugins: [
+ new EvlogHandlerPlugin({
+ storage, // <- pass the storage to the plugin
+ }),
+ ],
+})
+```
+
+:::
+
+### Without AsyncLocalStorage
+
+If you do not want to use AsyncLocalStorage, or your runtime does not support it, you can still read the logger from the context.
+
+```ts
+import { getLogger, LoggerContext } from '@orpc/evlog'
+
+interface ServerContext extends LoggerContext {} // [!code highlight]
+
+const procedure = os
+ .$context()
+ .handler(({ context }) => {
+ const logger = getLogger(context) // [!code highlight]
+
+ logger?.set({ user: { id: 123, name: 'John Doe' } }) // [!code highlight]
+
+ return { success: true }
+ })
+```
diff --git a/apps/content/docs/integrations/next.md b/apps/content/docs/integrations/next.md
new file mode 100644
index 000000000..ab2e21b09
--- /dev/null
+++ b/apps/content/docs/integrations/next.md
@@ -0,0 +1,324 @@
+# Next.js Integration
+
+[Next.js](https://nextjs.org/) integration provides utilities for using oRPC in Next.js applications, including support for [server functions](https://nextjs.org/docs/app/api-reference/directives/use-server) and form actions.
+
+## Installation
+
+::: code-group
+
+```sh [npm]
+npm install @orpc/next@latest
+```
+
+```sh [yarn]
+yarn add @orpc/next@latest
+```
+
+```sh [pnpm]
+pnpm add @orpc/next@latest
+```
+
+```sh [bun]
+bun add @orpc/next@latest
+```
+
+```sh [deno]
+deno add npm:@orpc/next@latest
+```
+
+:::
+
+## Server Functions
+
+Use `createServerFunction` to turn a [procedure](/docs/procedure) into a [server function](https://nextjs.org/docs/app/api-reference/directives/use-server). It accepts the same options as [server-side clients](/docs/client/server-side#router-clients), and the returned function accepts the same input as the original procedure.
+
+```ts twoslash
+'use server'
+
+import { os } from '@orpc/server'
+import { createServerFunction } from '@orpc/next'
+
+const procedure = os.handler(async () => 'Hello from oRPC + Next.js!')
+
+export const serverFunction = createServerFunction(procedure, {
+ context: async () => { // <- provide initial context if needed
+ return { user: { id: '123', name: 'Alice' } }
+ },
+ interceptors: [] // <- add interceptors if needed
+})
+```
+
+You can call the returned `serverFunction` from a client component.
+
+```tsx
+'use client'
+
+import { serverFunction } from './path/to/server/function'
+
+export default function Page() {
+ const handleClick = async () => {
+ const [error, message] = await serverFunction()
+
+ if (!error) {
+ console.log({ message })
+ }
+ }
+
+ return (
+
+ Call Server Function
+
+ )
+}
+```
+
+Special Next.js errors such as [redirect](https://nextjs.org/docs/app/api-reference/functions/redirect) and [notFound](https://nextjs.org/docs/app/api-reference/functions/not-found) are rethrown so Next.js handles them normally. All other errors are serialized to `ORPCErrorJSON` and returned as the first element of the tuple.
+
+### Typesafe Errors
+
+[Typesafe errors](/docs/error-handling#typesafe-errors) are supported as well. Because errors are serialized before they reach the client, use the `inferable` field to distinguish errors.
+
+::: code-group
+
+```tsx [client]
+'use client'
+
+import { serverFunction } from './path/to/server/function'
+
+export default function Page() {
+ const handleClick = async () => {
+ const [error, message] = await serverFunction()
+
+ if (error) {
+ if (error.inferable) {
+ // handle typesafe error
+ }
+ else {
+ // handle unknown error
+ }
+ }
+ else {
+ // handle success case
+ }
+ }
+
+ return (
+
+ Call Server Function
+
+ )
+}
+```
+
+```ts [server]
+'use server'
+
+const procedure = os
+ .errors({
+ NOT_FOUND: {
+ message: 'The resource was not found',
+ },
+ })
+ .handler(async ({ errors }) => {
+ throw errors.NOT_FOUND()
+ })
+
+export const serverFunction = createServerFunction(procedure)
+```
+
+:::
+
+### `createServerFunctionable`
+
+If you reuse the same options across multiple server functions, `createServerFunctionable` creates a preconfigured helper. The helper takes a procedure and returns a value that works as both a server function and the original [procedure](/docs/procedure) on the server.
+
+```ts
+import { createServerFunctionable } from '@orpc/next'
+
+const functionable = createServerFunctionable({
+ context: async () => { // <- provide initial context if needed
+ return { user: { id: '123', name: 'Alice' } }
+ },
+})
+
+// Works as both a server function and a procedure.
+export const functionableProcedure = functionable(
+ os.handler(async () => 'Hello from oRPC + Next.js!')
+)
+```
+
+### `.actionable` Extension
+
+Import `@orpc/next/extensions/actionable` from a module that always runs during initialization, such as the file where you define your base builder. This adds an `.actionable` method to decorated procedures. Like `createServerFunctionable`, it returns a value that works as both a server function and a [procedure](/docs/procedure).
+
+::: code-group
+
+```ts [usage]
+export const functionableProcedure = base
+ .handler(async () => 'Hello from oRPC + Next.js!')
+ .actionable({
+ context: async () => { // <- provide initial context if needed
+ return { user: { id: '123', name: 'Alice' } }
+ },
+ })
+```
+
+```ts [setup]
+import '@orpc/next/extensions/actionable'
+
+import { os } from '@orpc/server'
+
+export const base = os
+```
+
+:::
+
+### Hooks
+
+This integration also includes React hooks for server functions. `useServerFunction` executes a server function and tracks its status. `useOptimisticServerFunction` does the same, with optimistic updates. Unlike direct server function calls, hook errors are deserialized into native `ORPCError` instances instead of plain JSON (`ORPCErrorJSON`) for a more natural developer experience.
+
+::: code-group
+
+```tsx [useServerFunction]
+'use client'
+
+import { useServerFunction } from '@orpc/next/hooks'
+import {
+ getIssueMessage,
+ isInferableError,
+ onErrorDeferred,
+ parseFormData,
+} from '@orpc/next/hooks'
+
+export function MyComponent() {
+ const { execute, data, error, status } = useServerFunction(serverFunction, {
+ interceptors: [
+ onErrorDeferred((error) => {
+ if (isInferableError(error)) {
+ console.error(error.data)
+ // ^ Typed error data
+ }
+ }),
+ ],
+ })
+
+ return (
+
+ )
+}
+```
+
+```tsx [useOptimisticServerFunction]
+'use client'
+
+import { useOptimisticServerAction } from '@orpc/next/hooks'
+import {
+ getIssueMessage,
+ onSuccessDeferred,
+ parseFormData,
+} from '@orpc/next'
+
+export function MyComponent() {
+ const [todos, setTodos] = useState([])
+ const { execute, optimisticState } = useOptimisticServerAction(someAction, {
+ optimisticPassthrough: todos,
+ optimisticReducer: (currentState, newTodo) => [...currentState, newTodo],
+ interceptors: [
+ onSuccessDeferred(({ data }) => {
+ setTodos(prevTodos => [...prevTodos, data])
+ }),
+ ],
+ })
+
+ return (
+
+
+ {optimisticState.map(todo => (
+ {todo.todo}
+ ))}
+
+
+
+ )
+}
+```
+
+:::
+
+::: info
+Besides hooks, this integration also re-exports [form-data helpers](/docs/helpers/form-data) for working with `FormData`, as well as deferred interceptors for updating UI states: `onStartDeferred`, `onSuccessDeferred`, `onErrorDeferred`, and `onFinishDeferred`.
+:::
+
+::: info
+You can use [`safe` and `isInferableError`](/docs/client/error-handling#using-safe-and-isinferableerror) together for typesafe error handling in interceptors.
+:::
+
+## Server Form Functions
+
+Use `createServerFormFunction` to turn a procedure into a form action for `
+ )
+}
+```
+
+```ts [server]
+'use server'
+
+import { redirect } from 'next/navigation'
+
+const procedure = os
+ .input(z.object({ name: z.string() }))
+ .handler(async ({ input }) => {
+ // do something
+ })
+
+export const serverFormFunction = createServerFormFunction(procedure, {
+ interceptors: [
+ async ({ next }) => {
+ await next()
+ redirect('/thank-you') // redirect on success
+ }
+ ]
+})
+```
+
+:::
+
+### `createServerFormFunctionable`
+
+If you reuse the same options across multiple form actions, `createServerFormFunctionable` creates a preconfigured helper. Like [`createServerFunctionable`](#createserverfunctionable), it takes a procedure and returns a value that works as both a server form function and the original [procedure](/docs/procedure).
+
+```ts
+import { createServerFormFunctionable } from '@orpc/next'
+
+const formFunctionable = createServerFormFunctionable({
+ context: async () => { // <- provide initial context if needed
+ return { user: { id: '123', name: 'Alice' } }
+ },
+})
+
+// Works as both a server form function and a procedure.
+export const formFunctionableProcedure = formFunctionable(
+ os.handler(async () => 'Hello from oRPC + Next.js!')
+)
+```
diff --git a/apps/content/docs/integrations/opentelemetry.md b/apps/content/docs/integrations/opentelemetry.md
index 8f465fc0f..63fbd2dfd 100644
--- a/apps/content/docs/integrations/opentelemetry.md
+++ b/apps/content/docs/integrations/opentelemetry.md
@@ -1,11 +1,6 @@
----
-title: OpenTelemetry Integration
-description: Seamlessly integrate oRPC with OpenTelemetry for distributed tracing
----
-
# OpenTelemetry Integration
-[OpenTelemetry](https://opentelemetry.io/) provides observability APIs and instrumentation for applications. oRPC integrates seamlessly with OpenTelemetry to instrument your APIs for distributed tracing.
+[OpenTelemetry](https://opentelemetry.io/) integration adds automatic instrumentation to oRPC applications, enabling distributed tracing and performance monitoring with minimal setup.
::: warning
This guide assumes familiarity with [OpenTelemetry](https://opentelemetry.io/). Review the official documentation if needed.
@@ -22,36 +17,36 @@ See the complete example in our [Bun WebSocket + OpenTelemetry Playground](/docs
::: code-group
```sh [npm]
-npm install @orpc/otel@latest
+npm install @orpc/opentelemetry@latest
```
```sh [yarn]
-yarn add @orpc/otel@latest
+yarn add @orpc/opentelemetry@latest
```
```sh [pnpm]
-pnpm add @orpc/otel@latest
+pnpm add @orpc/opentelemetry@latest
```
```sh [bun]
-bun add @orpc/otel@latest
+bun add @orpc/opentelemetry@latest
```
```sh [deno]
-deno add npm:@orpc/otel@latest
+deno add npm:@orpc/opentelemetry@latest
```
:::
## Setup
-To set up OpenTelemetry with oRPC, use the `ORPCInstrumentation` class. This class automatically instruments your oRPC client and server for distributed tracing.
+To integrate OpenTelemetry with oRPC, use `ORPCInstrumentation`. It automatically instruments both client and server for distributed tracing.
::: code-group
```ts twoslash [server]
import { NodeSDK } from '@opentelemetry/sdk-node'
-import { ORPCInstrumentation } from '@orpc/otel'
+import { ORPCInstrumentation } from '@orpc/opentelemetry'
const sdk = new NodeSDK({
instrumentations: [
@@ -65,7 +60,7 @@ sdk.start()
```ts twoslash [client]
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web'
import { registerInstrumentations } from '@opentelemetry/instrumentation'
-import { ORPCInstrumentation } from '@orpc/otel'
+import { ORPCInstrumentation } from '@orpc/opentelemetry'
const provider = new WebTracerProvider()
@@ -81,7 +76,21 @@ registerInstrumentations({
:::
::: info
-While OpenTelemetry can be used on both server and client sides, using it on the server only is sufficient in most cases.
+You can configure OpenTelemetry for your server, client, or both, depending on your needs.
+:::
+
+## Context Propagation
+
+By default, `ORPCInstrumentation` enables [context propagation](https://opentelemetry.io/docs/concepts/context-propagation/) between the client and server. You can disable it by setting `propagationEnabled` to `false` if you do not need it or if another instrumentation already handles it.
+
+```ts
+const instrumentation = new ORPCInstrumentation({
+ propagationEnabled: false,
+})
+```
+
+::: warning
+Popular instrumentations that already handle context propagation include [@hono/otel](https://www.npmjs.com/package/@hono/otel), [@opentelemetry/instrumentation-http](https://www.npmjs.com/package/@opentelemetry/instrumentation-http), and [@opentelemetry/instrumentation-fetch](https://www.npmjs.com/package/@opentelemetry/instrumentation-fetch).
:::
## Middleware Span
@@ -109,41 +118,6 @@ Object.defineProperty(someMiddleware, 'name', {
Define the `name` property on your middleware to improve span naming and make traces easier to read.
:::
-## Handling Uncaught Exceptions
-
-oRPC may throw errors before they reach the error handling layer, such as invalid WebSocket messages or adapter interceptor errors. We recommend capturing these errors:
-
-```ts
-import { SpanStatusCode, trace } from '@opentelemetry/api'
-
-const tracer = trace.getTracer('uncaught-errors')
-
-function recordError(eventName: string, reason: unknown) {
- const span = tracer.startSpan(eventName)
- const message = String(reason)
-
- if (reason instanceof Error) {
- span.recordException(reason)
- }
- else {
- span.recordException({ message })
- }
-
- span.setStatus({ code: SpanStatusCode.ERROR, message })
- span.end()
-}
-
-process.on('uncaughtException', (reason) => {
- recordError('uncaughtException', reason)
- // process.exit(1) // uncomment to restore default Node.js behavior
-})
-
-process.on('unhandledRejection', (reason) => {
- recordError('unhandledRejection', reason)
- // process.exit(1) // uncomment to restore default Node.js behavior
-})
-```
-
## Capture Abort Signals
If your application heavily uses [Event Iterator](/docs/event-iterator) or similar streaming patterns, we recommend capturing an event when the `signal` is aborted to properly track and detach unexpected long-running operations:
@@ -165,11 +139,3 @@ const handler = new RPCHandler(router, {
],
})
```
-
-## Context Propagation
-
-When using oRPC with HTTP/fetch adapters, you should set up proper HTTP instrumentation for [context propagation](https://opentelemetry.io/docs/concepts/context-propagation/) on both client and server. This ensures trace context propagates between services, maintaining distributed tracing integrity.
-
-::: info
-Common libraries for HTTP instrumentation include [@hono/otel](https://www.npmjs.com/package/@hono/otel), [@opentelemetry/instrumentation-http](https://www.npmjs.com/package/@opentelemetry/instrumentation-http), [@opentelemetry/instrumentation-fetch](https://www.npmjs.com/package/@opentelemetry/instrumentation-fetch), etc.
-:::
diff --git a/apps/content/docs/integrations/pinia-colada.md b/apps/content/docs/integrations/pinia-colada.md
deleted file mode 100644
index c8be463b7..000000000
--- a/apps/content/docs/integrations/pinia-colada.md
+++ /dev/null
@@ -1,171 +0,0 @@
----
-title: Pinia Colada Integration
-description: Seamlessly integrate oRPC with Pinia Colada
----
-
-# Pinia Colada Integration
-
-[Pinia Colada](https://pinia-colada.esm.dev/) is the data fetching layer for Pinia and Vue. oRPC's integration with Pinia Colada is lightweight and straightforward - there's no extra overhead.
-
-::: warning
-This documentation assumes you are already familiar with [Pinia Colada](https://pinia-colada.esm.dev/). If you need a refresher, please review the official Pinia Colada documentation before proceeding.
-:::
-
-::: warning
-[Pinia Colada](https://pinia-colada.esm.dev/) is still in an unstable stage. As a result, this integration may introduce breaking changes in the future to keep up with its ongoing development.
-:::
-
-## Installation
-
-::: code-group
-
-```sh [npm]
-npm install @orpc/vue-colada@latest @pinia/colada@latest
-```
-
-```sh [yarn]
-yarn add @orpc/vue-colada@latest @pinia/colada@latest
-```
-
-```sh [pnpm]
-pnpm add @orpc/vue-colada@latest @pinia/colada@latest
-```
-
-```sh [bun]
-bun add @orpc/vue-colada@latest @pinia/colada@latest
-```
-
-```sh [deno]
-deno add npm:@orpc/vue-colada@latest npm:@pinia/colada@latest
-```
-
-:::
-
-## Setup
-
-Before you begin, ensure you have already configured a [server-side client](/docs/client/server-side) or a [client-side client](/docs/client/client-side).
-
-```ts twoslash
-import { router } from './shared/planet'
-import { RouterClient } from '@orpc/server'
-
-declare const client: RouterClient
-// ---cut---
-import { createORPCVueColadaUtils } from '@orpc/vue-colada'
-
-export const orpc = createORPCVueColadaUtils(client)
-
-orpc.planet.find.queryOptions({ input: { id: 123 } })
-// ^|
-
-//
-```
-
-## Avoiding Query/Mutation Key Conflicts
-
-Prevent key conflicts by passing a unique base key when creating your utils:
-
-```ts
-const userORPC = createORPCVueColadaUtils(userClient, {
- path: ['user']
-})
-const postORPC = createORPCVueColadaUtils(postClient, {
- path: ['post']
-})
-```
-
-## Query Options Utility
-
-Use `.queryOptions` to configure queries. Use it with hooks like `useQuery`, `useSuspenseQuery`, or `prefetchQuery`.
-
-```ts twoslash
-import { router } from './shared/planet'
-import { RouterClient } from '@orpc/server'
-import { RouterUtils } from '@orpc/vue-colada'
-import { useQuery } from '@pinia/colada'
-
-declare const orpc: RouterUtils>
-// ---cut---
-const query = useQuery(orpc.planet.find.queryOptions({
- input: { id: 123 }, // Specify input if needed
- context: { cache: true }, // Provide client context if needed
- // additional options...
-}))
-```
-
-## Mutation Options
-
-Use `.mutationOptions` to create options for mutations. Use it with hooks like `useMutation`.
-
-```ts twoslash
-import { router } from './shared/planet'
-import { RouterClient } from '@orpc/server'
-import { RouterUtils } from '@orpc/vue-colada'
-import { useMutation } from '@pinia/colada'
-
-declare const orpc: RouterUtils>
-// ---cut---
-const mutation = useMutation(orpc.planet.create.mutationOptions({
- context: { cache: true }, // Provide client context if needed
- // additional options...
-}))
-
-mutation.mutate({ name: 'Earth' })
-```
-
-## Query/Mutation Key
-
-Use `.key` to generate a `QueryKey` or `MutationKey`. This is useful for tasks such as revalidating queries, checking mutation status, etc.
-
-```ts twoslash
-import { router } from './shared/planet'
-import { RouterClient } from '@orpc/server'
-import { RouterUtils } from '@orpc/vue-colada'
-import { useQueryCache } from '@pinia/colada'
-
-declare const orpc: RouterUtils>
-// ---cut---
-const queryCache = useQueryCache()
-
-// Invalidate all planet queries
-queryCache.invalidateQueries({
- key: orpc.planet.key(),
-})
-
-// Invalidate the planet find query with id 123
-queryCache.invalidateQueries({
- key: orpc.planet.find.key({ input: { id: 123 } })
-})
-```
-
-## Calling Procedure Clients
-
-Use `.call` to call a procedure client directly. It's an alias for corresponding procedure client.
-
-```ts
-const result = orpc.planet.find.call({ id: 123 })
-```
-
-## Error Handling
-
-Easily manage type-safe errors using our built-in `isDefinedError` helper.
-
-```ts
-import { isDefinedError } from '@orpc/client'
-
-const mutation = useMutation(orpc.planet.create.mutationOptions({
- onError: (error) => {
- if (isDefinedError(error)) {
- // Handle the error here
- }
- },
-}))
-
-mutation.mutate({ name: 'Earth' })
-
-if (mutation.error.value && isDefinedError(mutation.error.value)) {
- // Handle the error here
-}
-```
-
-For more details, see our [type-safe error handling guide](/docs/error-handling#type‐safe-error-handling).
diff --git a/apps/content/docs/integrations/pino.md b/apps/content/docs/integrations/pino.md
index e0d0e5f09..4f2eb2139 100644
--- a/apps/content/docs/integrations/pino.md
+++ b/apps/content/docs/integrations/pino.md
@@ -1,11 +1,6 @@
----
-title: Pino Integration
-description: Integrate oRPC with Pino for structured logging and request tracking.
----
-
# Pino Integration
-[Pino](https://getpino.io/) is a fast and lightweight JSON logger. This guide explains how to integrate oRPC with Pino to add structured logging, request tracking, and error monitoring to your applications.
+[Pino](https://getpino.io/) integration for oRPC provides structured logging capabilities, allowing you to easily track requests, monitor errors, and gain insights into your application's behavior.
::: warning
This guide assumes familiarity with [Pino](https://getpino.io/). Review the official documentation if needed.
@@ -16,52 +11,53 @@ This guide assumes familiarity with [Pino](https://getpino.io/). Review the offi
::: code-group
```sh [npm]
-npm install @orpc/experimental-pino@latest pino@latest
+npm install @orpc/pino@latest pino@latest
```
```sh [yarn]
-yarn add @orpc/experimental-pino@latest pino@latest
+yarn add @orpc/pino@latest pino@latest
```
```sh [pnpm]
-pnpm add @orpc/experimental-pino@latest pino@latest
+pnpm add @orpc/pino@latest pino@latest
```
```sh [bun]
-bun add @orpc/experimental-pino@latest pino@latest
+bun add @orpc/pino@latest pino@latest
```
```sh [deno]
-deno add npm:@orpc/experimental-pino@latest npm:pino@latest
+deno add npm:@orpc/pino@latest npm:pino@latest
```
:::
## Setup
-To set up Pino with oRPC, use the `LoggingHandlerPlugin` class. This plugin automatically instruments your handler with structured logging, request tracking, and error monitoring.
+To set up Pino with oRPC, use the `PinoHandlerPlugin` class. This plugin automatically instruments your handler with structured logging, request tracking, and error monitoring.
-```ts
-import { LoggingHandlerPlugin } from '@orpc/experimental-pino'
+```ts twoslash
+import { RPCHandler } from '@orpc/server/fetch'
+import { router } from './shared/planet'
+// ---cut---
+import { PinoHandlerPlugin } from '@orpc/pino'
import pino from 'pino'
const logger = pino()
const handler = new RPCHandler(router, {
plugins: [
- new LoggingHandlerPlugin({
- logger, // Custom logger instance
- generateId: ({ request }) => crypto.randomUUID(), // Custom ID generator
- logRequestResponse: true, // Log request start/end (disabled by default)
- logRequestAbort: true, // Log when requests are aborted (disabled by default)
+ new PinoHandlerPlugin({
+ logger, // <- custom logger instance
+ generateRequestId: ({ request }) => crypto.randomUUID(), // <- custom request id generator
+ logLifecycle: true, // <- log information about request lifecycle (disabled by default)
+ logAbort: true, // <- log information when requests are aborted (disabled by default)
}),
],
})
```
-::: info
-The `handler` can be any supported oRPC handler, such as [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or another custom handler.
-:::
+
::: tip
For improved log readability during development, consider using [pino-pretty](https://github.com/pinojs/pino-pretty) to format your logs in a human-friendly way.
@@ -77,12 +73,12 @@ npm run dev | npx pino-pretty
You can access the logger from the context object using the `getLogger` function:
```ts
-import { getLogger, LoggerContext } from '@orpc/experimental-pino'
+import { getLogger, LoggerContext } from '@orpc/pino'
-interface ORPCContext extends LoggerContext {} // [!code highlight]
+interface ServerContext extends LoggerContext {} // [!code highlight]
const procedure = os
- .$context()
+ .$context()
.handler(({ context }) => {
const logger = getLogger(context) // [!code highlight]
@@ -99,23 +95,23 @@ You can provide a custom logger instance for specific requests by passing it thr
```ts
import {
- CONTEXT_LOGGER_SYMBOL,
+ LOGGER_CONTEXT_SYMBOL,
LoggerContext,
- LoggingHandlerPlugin
-} from '@orpc/experimental-pino'
+ PinoHandlerPlugin
+} from '@orpc/pino'
const logger = pino()
const httpLogger = pinoHttp({ logger })
-interface ORPCContext extends LoggerContext {} // [!code highlight]
+interface ServerContext extends LoggerContext {} // [!code highlight]
const router = {
- ping: os.$context().handler(() => 'pong')
+ ping: os.$context().handler(() => 'pong')
}
const handler = new RPCHandler(router, {
plugins: [
- new LoggingHandlerPlugin({ logger }), // [!code highlight]
+ new PinoHandlerPlugin({ logger }), // [!code highlight]
],
})
@@ -125,7 +121,7 @@ const server = createServer(async (req, res) => {
const { matched } = await handler.handle(req, res, {
prefix: '/api',
context: {
- [CONTEXT_LOGGER_SYMBOL]: req.log, // [!code highlight]
+ [LOGGER_CONTEXT_SYMBOL]: req.log, // [!code highlight]
},
})
diff --git a/apps/content/docs/integrations/react-swr.md b/apps/content/docs/integrations/react-swr.md
deleted file mode 100644
index a5ec5ebcf..000000000
--- a/apps/content/docs/integrations/react-swr.md
+++ /dev/null
@@ -1,204 +0,0 @@
----
-title: React SWR Integration
-description: Integrate oRPC with React SWR for efficient data fetching and caching.
----
-
-# React SWR Integration
-
-[SWR](https://swr.vercel.app/) is a React Hooks library for data fetching that provides features like caching, revalidation, and more. oRPC SWR integration is very lightweight and straightforward - there's no extra overhead.
-
-::: warning
-This documentation assumes you are already familiar with [SWR](https://swr.vercel.app/). If you need a refresher, please review the official SWR documentation before proceeding.
-:::
-
-## Installation
-
-::: code-group
-
-```sh [npm]
-npm install @orpc/experimental-react-swr@latest
-```
-
-```sh [yarn]
-yarn add @orpc/experimental-react-swr@latest
-```
-
-```sh [pnpm]
-pnpm add @orpc/experimental-react-swr@latest
-```
-
-```sh [bun]
-bun add @orpc/experimental-react-swr@latest
-```
-
-```sh [deno]
-deno add npm:@orpc/experimental-react-swr@latest
-```
-
-:::
-
-::: warning
-The `experimental-` prefix indicates that this integration is still in development and may change in the future.
-:::
-
-## Setup
-
-Before you begin, ensure you have already configured a [server-side client](/docs/client/server-side) or a [client-side client](/docs/client/client-side).
-
-```ts twoslash
-import { router } from './shared/planet'
-import { RouterClient } from '@orpc/server'
-
-declare const client: RouterClient