Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
d17d646
wip
dinwwwh Dec 14, 2024
37440e4
wip
dinwwwh Dec 14, 2024
abc387a
procedure builder tests
dinwwwh Dec 14, 2024
88ce38a
procedure implementer tests
dinwwwh Dec 14, 2024
ec79af7
wip
dinwwwh Dec 14, 2024
b3a0d91
refactor and 100% coverage for procedure caller
dinwwwh Dec 14, 2024
658a31b
fix middleware types
dinwwwh Dec 15, 2024
b434818
tests for middleware with output is typed
dinwwwh Dec 15, 2024
c6c449d
tests for procedure decorated
dinwwwh Dec 15, 2024
0916f3a
router
dinwwwh Dec 15, 2024
c472305
typed for router builder
dinwwwh Dec 15, 2024
a60ef96
context restriction for router builder
dinwwwh Dec 16, 2024
c4d81de
typesafe and prevent duplicate on unshift method
dinwwwh Dec 16, 2024
e9a1dde
router builder tests partial
dinwwwh Dec 16, 2024
ee127d5
lazy
dinwwwh Dec 16, 2024
363ab50
lazy decorated
dinwwwh Dec 16, 2024
1d22963
improve
dinwwwh Dec 17, 2024
c6cd3e3
sync
dinwwwh Dec 17, 2024
680dbf7
improve middleware types
dinwwwh Dec 17, 2024
f9dd4f2
improve merging middleware on unshiftMiddleware
dinwwwh Dec 17, 2024
226ef47
remove lazy method
dinwwwh Dec 17, 2024
74859cd
improve at context
dinwwwh Dec 17, 2024
103e5cb
router builder
dinwwwh Dec 17, 2024
50eca8a
router caller
dinwwwh Dec 18, 2024
d005b75
router implementer
dinwwwh Dec 18, 2024
b0a3383
builder
dinwwwh Dec 18, 2024
03935d1
reindex
dinwwwh Dec 18, 2024
a53f2b9
separate middleware decorated
dinwwwh Dec 18, 2024
d6a668e
procedure can be a router
dinwwwh Dec 18, 2024
54c8c1e
improve dedupe in unshiftMiddleware
dinwwwh Dec 18, 2024
c1d90e7
improve
dinwwwh Dec 18, 2024
5664122
tests for procedure works as a router
dinwwwh Dec 18, 2024
57f6953
safe object callable
dinwwwh Dec 18, 2024
6ac0f1b
group hidden mechanism
dinwwwh Dec 18, 2024
9c85981
router caller now works with procedure as router, and more
dinwwwh Dec 19, 2024
612ddfa
fix
dinwwwh Dec 19, 2024
de6138a
fetch - handle request
dinwwwh Dec 19, 2024
a04d95d
fetch, and some improvement on caller
dinwwwh Dec 19, 2024
4e4b869
rename caller to client, and some improvements
dinwwwh Dec 20, 2024
8802237
hidden tests
dinwwwh Dec 20, 2024
345d8d0
rename client
dinwwwh Dec 20, 2024
a75fc57
Merge branch 'main' into feat/rewrite-server
dinwwwh Dec 20, 2024
393e2a8
merge types on client
dinwwwh Dec 20, 2024
cad921c
react-query sync
dinwwwh Dec 20, 2024
4d8bb06
vue-query sync
dinwwwh Dec 20, 2024
0f429bd
sync openapi
dinwwwh Dec 20, 2024
61ce849
sync next
dinwwwh Dec 20, 2024
f704931
sync react
dinwwwh Dec 20, 2024
ea1333e
sync rest
dinwwwh Dec 20, 2024
1be1bc6
sync playground
dinwwwh Dec 20, 2024
72c8579
fix lazy-decorated tests
dinwwwh Dec 20, 2024
3fc0b29
sync docs
dinwwwh Dec 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions apps/content/content/docs/client/react-query.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ description: Simplify React Query usage with minimal integration using ORPC and

```ts twoslash
import { createORPCReactQueryUtils } from '@orpc/react-query';
import { createORPCClient } from '@orpc/client';
import { createORPCFetchClient } from '@orpc/client';
import type { router } from 'examples/server';

// Create an ORPC client
export const client = createORPCClient<typeof router>({
export const client = createORPCFetchClient<typeof router>({
baseURL: 'http://localhost:3000/api',
});

Expand All @@ -35,12 +35,13 @@ orpc.getting.

```tsx twoslash
import { createORPCReactQueryUtils, RouterUtils } from '@orpc/react-query';
import { createORPCClient } from '@orpc/client';
import { createORPCFetchClient } from '@orpc/client';
import { RouterClient } from '@orpc/server';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import type { router } from 'examples/server';
import * as React from 'react';

const ORPCContext = React.createContext<RouterUtils<typeof router> | undefined>(undefined);
const ORPCContext = React.createContext<RouterUtils<RouterClient<typeof router>> | undefined>(undefined);

export function useORPC() {
const orpc = React.useContext(ORPCContext);
Expand All @@ -54,7 +55,7 @@ export function useORPC() {

export function ORPCProvider({ children }: { children: React.ReactNode }) {
const [client] = React.useState(() =>
createORPCClient<typeof router>({
createORPCFetchClient<typeof router>({
baseURL: 'http://localhost:3000/api',
})
);
Expand Down
7 changes: 4 additions & 3 deletions apps/content/content/docs/client/react.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@ npm i @orpc/client @orpc/react @tanstack/react-query

```tsx twoslash
import { createORPCReact } from '@orpc/react'
import { createORPCClient } from '@orpc/client'
import { createORPCFetchClient } from '@orpc/client'
import { RouterClient } from '@orpc/server'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { useState } from 'react'
import type { router } from 'examples/server'
import * as React from 'react'

export const { orpc, ORPCContext } = createORPCReact<typeof router /** or contract router */>()
export const { orpc, ORPCContext } = createORPCReact<RouterClient<typeof router /** or contract router */>>()

export function ORPCProvider({ children }: { children: React.ReactNode }) {
const [client] = useState(() => createORPCClient<typeof router /** must match with createORPCReact*/>({
const [client] = useState(() => createORPCFetchClient<typeof router /** must match with createORPCReact*/>({
baseURL: 'http://localhost:3000/api',
}))
const [queryClient] = useState(() => new QueryClient())
Expand Down
4 changes: 2 additions & 2 deletions apps/content/content/docs/client/vanilla.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ npm i @orpc/client
To create a fully typed client, you need either the type of the [router](/docs/server/router) you intend to use or the [contract](/docs/contract/builder).

```ts twoslash
import { createORPCClient, ORPCError } from '@orpc/client'
import { createORPCFetchClient, ORPCError } from '@orpc/client'
import type { router } from 'examples/server'

const client = createORPCClient<typeof router /* or contract router */>({
const client = createORPCFetchClient<typeof router /* or contract router */>({
baseURL: 'http://localhost:3000/api',
// fetch: optional override for the default fetch function
// headers: provide additional headers
Expand Down
4 changes: 2 additions & 2 deletions apps/content/content/docs/client/vue-query.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ description: Simplify Vue Query usage with minimal integration using ORPC and Ta

```ts twoslash
import { createORPCVueQueryUtils } from '@orpc/vue-query';
import { createORPCClient } from '@orpc/client';
import { createORPCFetchClient } from '@orpc/client';
import type { router } from 'examples/server';

// Create an ORPC client
export const client = createORPCClient<typeof router>({
export const client = createORPCFetchClient<typeof router>({
baseURL: 'http://localhost:3000/api',
});

Expand Down
4 changes: 2 additions & 2 deletions apps/content/content/docs/contract-first.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ That's it! The contract definition and implementation are now completely separat
Create a fully typed client using just the contract definition:

```ts twoslash
import { createORPCClient, ORPCError } from '@orpc/client'
import { createORPCFetchClient, ORPCError } from '@orpc/client'
import type { contract } from 'examples/contract'

const client = createORPCClient<typeof contract /* or server router */>({
const client = createORPCFetchClient<typeof contract /* or server router */>({
baseURL: 'http://localhost:3000/prefix',
// fetch: optional override for the default fetch function
// headers: provide additional headers
Expand Down
4 changes: 2 additions & 2 deletions apps/content/content/docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,10 @@ Start the server and visit http://localhost:3000/api/getting?name=yourname to se
Use the fully typed client in any environment:

```ts twoslash
import { createORPCClient, ORPCError } from '@orpc/client'
import { createORPCFetchClient, ORPCError } from '@orpc/client'
import type { router } from 'examples/server'

const client = createORPCClient<typeof router /* or contract router */>({
const client = createORPCFetchClient<typeof router /* or contract router */>({
baseURL: 'http://localhost:3000/api',
// fetch: optional override for the default fetch function
// headers: provide additional headers
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Caller
title: Caller/Client
description: Make your procedures callable in oRPC.
---

Expand All @@ -9,7 +9,7 @@ You can directly call a procedure if its [Global Context](/docs/server/global-co
For security reasons, context cannot be passed when invoking such procedures directly.

```ts twoslash
import { os, createProcedureCaller } from '@orpc/server'
import { os, createProcedureClient } from '@orpc/server'
import { z } from 'zod'

// ❌ Cannot call this procedure directly because undefined is not assignable to 'Context'
Expand All @@ -36,53 +36,53 @@ const output_ = await router.getting({ name: 'World' }) // output is 'Hello, Wor

## Calling Procedures with Context

For context-sensitive calls, use a Procedure Caller.
A Procedure Caller securely provides the required context during invocation.
For context-sensitive calls, use a Procedure Client.
A Procedure Client securely provides the required context during invocation.

```ts twoslash
import { os, createProcedureCaller } from '@orpc/server'
import { os, createProcedureClient } from '@orpc/server'

type Context = { user?: { id: string } }

const getting = os.context<Context>().func(() => 'pong')

const gettingCaller = createProcedureCaller({
const gettingClient = createProcedureClient({
procedure: getting,
context: async () => {
// you can access headers, cookies, etc. here to create context
return { user: { id: 'example' } }
},
})

const output = await gettingCaller() // output is 'pong'
const output = await gettingClient() // output is 'pong'
```

Now, you can provide context when invoking a procedure.
Additionally, you can use `gettingCaller` as a [Server Action](/docs/server/server-action).
Additionally, you can use `gettingClient` as a [Server Action](/docs/server/server-action).

## Calling Routers with Shared Context

To call multiple procedures with shared context, use a `Router Caller`.
To call multiple procedures with shared context, use a `Router Client`.

```ts twoslash
import { os, createRouterCaller } from '@orpc/server'
import { os, createRouterClient } from '@orpc/server'

const router = os.router({
ping: os.func(() => 'pong')
})

const caller = createRouterCaller({
const client = createRouterClient({
router: router,
context: {},
})

const result = await caller.ping() // result is 'pong'
const result = await client.ping() // result is 'pong'
```

## Summary

- **Direct Calls:** Use when no context is required, or the context accepts `undefined`.
- **Procedure Caller:** Use for securely calling a single procedure with a specific context.
- **Router Caller:** Use for securely calling multiple procedures with shared context.
- **Procedure Client:** Use for securely calling a single procedure with a specific context.
- **Router Client:** Use for securely calling multiple procedures with shared context.

oRPC provides flexible and secure ways to invoke procedures tailored to your application needs.
10 changes: 5 additions & 5 deletions apps/content/content/docs/server/context.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const router = pub.router({

Middleware context is the context that is created or modified by middleware.
If your procedure only depends on `Middleware Context`, you can
[call it](/docs/server/caller) or use it as a [Server Action](/docs/server/server-action) directly.
[call it](/docs/server/client) or use it as a [Server Action](/docs/server/server-action) directly.

```ts twoslash
import { os, ORPCError } from '@orpc/server'
Expand Down Expand Up @@ -105,7 +105,7 @@ This pattern is useful for server-side applications where dependencies can be in
rather than relying on global mechanisms like `headers` or `cookies` in Next.js.

```ts twoslash
import { os, ORPCError, createProcedureCaller } from '@orpc/server'
import { os, ORPCError, createProcedureClient } from '@orpc/server'
import { handleFetchRequest, createORPCHandler } from '@orpc/server/fetch'
import { createOpenAPIServerlessHandler, createOpenAPIServerHandler } from '@orpc/openapi/fetch'

Expand Down Expand Up @@ -147,8 +147,8 @@ export function fetch(request: Request) {
}

// If you want to call this procedure or use as server action
// you must create another caller with context by using `createProcedureCaller` or `createRouterCaller`
const caller = createProcedureCaller({
// you must create another client with context by using `createProcedureClient` or `createRouterClient`
const client = createProcedureClient({
procedure: router.getting,
context: async () => {
// some logic to create context
Expand All @@ -159,7 +159,7 @@ const caller = createProcedureCaller({
},
})

const output = await caller()
const output = await client()
```

## Summary
Expand Down
4 changes: 2 additions & 2 deletions apps/content/content/docs/server/file-upload.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ To upload files with oRPC from the client, set up an oRPC client
and pass a `File` object directly to the upload endpoint.

```typescript
import { createORPCClient } from '@orpc/client'
import { createORPCFetchClient } from '@orpc/client'

const client = createORPCClient<typeof appRouter>({
const client = createORPCFetchClient<typeof appRouter>({
baseURL: 'http://localhost:3000',
})

Expand Down
2 changes: 1 addition & 1 deletion apps/content/content/docs/server/lazy.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Here's how you can set up and use them:
```typescript twoslash
import { os } from '@orpc/server'

const pub = os.context<{ user?: { id: string } }>()
const pub = os.context<{ user?: { id: string } } | undefined>()

// Define a router with lazy loading
const router = pub.router({
Expand Down
2 changes: 1 addition & 1 deletion apps/content/content/docs/server/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"file-upload",
"lazy",
"server-action",
"caller",
"client",
"error-handling",
"data-types",
"integrations",
Expand Down
16 changes: 8 additions & 8 deletions apps/content/content/docs/server/server-action.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ oRPC makes it simple to implement server actions, offering a robust and type-saf
Server actions are supported out of the box and are powered by several key features:

- [Middleware](/docs/server/middleware),
- [Procedure Caller](/docs/server/caller)
- [Procedure Client](/docs/server/client)
- [Smart Conversion](/docs/openapi/smart-conversion)
- [Bracket Notation](/docs/openapi/bracket-notation),

## Requirements

To use a procedure as a server action, the procedure must either:

1. Be [directly callable](/docs/server/caller#direct-procedure-calls), or
2. Use [Calling Procedures with Context](/docs/server/caller#calling-procedures-with-context) to create a callable procedure with context.
1. Be [directly callable](/docs/server/client#direct-procedure-calls), or
2. Use [Calling Procedures with Context](/docs/server/client#calling-procedures-with-context) to create a callable procedure with context.

## Usage

Expand Down Expand Up @@ -172,13 +172,13 @@ automatically convert `1992` into a `bigint` and seamlessly parse objects like `

Some procedures cannot be used as server actions directly. This is typically because they
require additional context, such as user information or other runtime data.
In such cases, you can use [createProcedureCaller](/docs/server/caller#calling-procedures-with-context)
or `createSafeAction` and `createFormAction` (built on top of `createProcedureCaller`)
In such cases, you can use [createProcedureClient](/docs/server/client#calling-procedures-with-context)
or `createSafeAction` and `createFormAction` (built on top of `createProcedureClient`)
to provide the required context dynamically, making the procedure callable and usable as a server action.

```ts twoslash
import { createSafeAction, createFormAction } from '@orpc/next'
import { createProcedureCaller, os } from '@orpc/server'
import { createProcedureClient, os } from '@orpc/server'
import { z } from 'zod'

type Context = { user?: { id: string } }
Expand All @@ -191,15 +191,15 @@ const getting = os
// @errors: 2349
getting({ name: 'Unnoq' }) // ❌ cannot call this procedure directly, and cannot be used as a server action

export const caller = createProcedureCaller({ // or createSafeAction or createFormAction
export const client = createProcedureClient({ // or createSafeAction or createFormAction
procedure: getting,
context: async () => {
// you can access headers, cookies, etc. here to create context
return { user: { id: 'example' } }
},
})

caller({ name: 'Unnoq' }) // ✅ can call this procedure directly, and can be used as a server action
client({ name: 'Unnoq' }) // ✅ can call this procedure directly, and can be used as a server action
```

This flexibility ensures you can adapt server actions to scenarios requiring runtime information, enhancing usability across diverse use cases.
11 changes: 6 additions & 5 deletions apps/content/content/home/client.mdx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<Tabs items={['Client', 'React', 'React Query', 'Vue Query', 'CURL']}>
<Tab value="Client">
```ts twoslash
import { createORPCClient, ORPCError } from '@orpc/client'
import { createORPCFetchClient, ORPCError } from '@orpc/client'
import type { router } from 'examples/server'

const client = createORPCClient<typeof router /* or contract router */>({
const client = createORPCFetchClient<typeof router /* or contract router */>({
baseURL: 'http://localhost:3000/api',
// fetch: optional override for the default fetch function
// headers: provide additional headers
Expand Down Expand Up @@ -44,13 +44,14 @@ try {
<Tab value="React">
```tsx twoslash
import { createORPCReact } from '@orpc/react'
import { createORPCClient } from '@orpc/client'
import { createORPCFetchClient } from '@orpc/client'
import { RouterClient } from '@orpc/server'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { useState } from 'react'
import type { router } from 'examples/server'
import * as React from 'react'

export const { orpc, ORPCContext } = createORPCReact<typeof router /** or contract router */>()
export const { orpc, ORPCContext } = createORPCReact<RouterClient<typeof router /** or contract router */>>()

// ------------------ Example ------------------

Expand Down Expand Up @@ -117,7 +118,7 @@ const queries = orpc.useQueries(o => [
// ------------------ Provider ------------------

export function ORPCProvider({ children }: { children: React.ReactNode }) {
const [client] = useState(() => createORPCClient<typeof router /** must match with createORPCReact*/>({
const [client] = useState(() => createORPCFetchClient<typeof router /** must match with createORPCReact*/>({
baseURL: 'http://localhost:3000/api',
}))
const [queryClient] = useState(() => new QueryClient())
Expand Down
4 changes: 2 additions & 2 deletions apps/content/content/home/landing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
export const getting = os
.use(authMiddleware) // require auth
.use(cache('5m')) // cache the output
.use(canMiddleware, (i) => i.id) // permission check by id
.route({
path: '/getting/{id}' // dynamic params support
method: 'POST' // custom OpenAPI method
Expand All @@ -16,6 +15,7 @@ export const getting = os
avatar: oz.file().type('image/*')
})
}))
.use(canMiddleware, (i) => i.id) // permission check by id
.output(z.string()) // validate output
.func(async (input) => 'Name and Avatar has been updated')
```
Expand All @@ -38,7 +38,7 @@ const text = await getting({
})
```

The [Procedure Caller](/docs/server/caller) feature lets your procedures behave like regular TypeScript functions.
The [Procedure Client](/docs/server/client) feature lets your procedures behave like regular TypeScript functions.

## Expose It Online with a Fully Typed Client

Expand Down
3 changes: 2 additions & 1 deletion apps/content/examples/react-query.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { RouterClient } from '@orpc/server'
import type { router } from 'examples/server'
import { createORPCReactQueryUtils } from '@orpc/react-query'

export const orpc = createORPCReactQueryUtils<typeof router /** or contract router */>('fake-client' as any)
export const orpc = createORPCReactQueryUtils({} as RouterClient<typeof router /** or contract router */>)
5 changes: 2 additions & 3 deletions apps/content/examples/react.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { RouterClient } from '@orpc/server'
import type { router } from 'examples/server'
import { createORPCReact } from '@orpc/react'
// biome-ignore lint/correctness/noUnusedImports: <explanation>

export const { orpc, ORPCContext }
= createORPCReact<typeof router /** or contract router */>()
export const { orpc, ORPCContext } = createORPCReact<RouterClient<typeof router /** or contract router */>>()
Loading