Skip to content

Commit d7b5662

Browse files
authored
feat(client)!: client context mechanism and rewrite (#62)
* improve & tests * fixed * sync @orpc/react * sync @orpc/react-query * sync @orpc/vue-query * fix global fetch problem * type fixed * lint fixed * fixes * rename createClient -> createORPCClient * docs * dynamic link * improve cast type * client context + dynamic link docs * fix docs * improve docs * improve docs * improve docs
1 parent 2a66984 commit d7b5662

76 files changed

Lines changed: 1367 additions & 545 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/content/content/docs/client/react-query.mdx

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,17 @@ description: Simplify React Query usage with minimal integration using ORPC and
1515

1616
```ts twoslash
1717
import { createORPCReactQueryUtils } from '@orpc/react-query';
18-
import { createORPCFetchClient } from '@orpc/client';
18+
import { createORPCClient } from '@orpc/client';
19+
import { ORPCLink } from '@orpc/client/fetch';
1920
import type { router } from 'examples/server';
2021

21-
// Create an ORPC client
22-
export const client = createORPCFetchClient<typeof router>({
23-
baseURL: 'http://localhost:3000/api',
24-
});
22+
const orpcLink = new ORPCLink({
23+
url: 'http://localhost:3000/api',
24+
// fetch: optional override for the default fetch function
25+
// headers: provide additional headers
26+
})
27+
28+
const client = createORPCClient<typeof router /* or contract router */>(orpcLink)
2529

2630
// Create React Query utilities for ORPC
2731
export const orpc = createORPCReactQueryUtils(client);
@@ -35,13 +39,14 @@ orpc.getting.
3539

3640
```tsx twoslash
3741
import { createORPCReactQueryUtils, RouterUtils } from '@orpc/react-query';
38-
import { createORPCFetchClient } from '@orpc/client';
42+
import { createORPCClient } from '@orpc/client';
43+
import { ORPCLink } from '@orpc/client/fetch';
3944
import { RouterClient } from '@orpc/server';
4045
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
4146
import type { router } from 'examples/server';
4247
import * as React from 'react';
4348

44-
const ORPCContext = React.createContext<RouterUtils<RouterClient<typeof router>> | undefined>(undefined);
49+
const ORPCContext = React.createContext<RouterUtils<RouterClient<typeof router, unknown>> | undefined>(undefined);
4550

4651
export function useORPC() {
4752
const orpc = React.useContext(ORPCContext);
@@ -54,11 +59,15 @@ export function useORPC() {
5459
}
5560

5661
export function ORPCProvider({ children }: { children: React.ReactNode }) {
57-
const [client] = React.useState(() =>
58-
createORPCFetchClient<typeof router>({
59-
baseURL: 'http://localhost:3000/api',
60-
})
61-
);
62+
const [client] = React.useState(() => {
63+
const orpcLink = new ORPCLink({
64+
url: 'http://localhost:3000/api',
65+
// fetch: optional override for the default fetch function
66+
// headers: provide additional headers
67+
});
68+
69+
return createORPCClient<typeof router>(orpcLink);
70+
});
6271
const [queryClient] = React.useState(() => new QueryClient());
6372

6473
const orpc = React.useMemo(() => createORPCReactQueryUtils(client), [client]);

apps/content/content/docs/client/react.mdx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,26 @@ npm i @orpc/client @orpc/react @tanstack/react-query
1313

1414
```tsx twoslash
1515
import { createORPCReact } from '@orpc/react'
16-
import { createORPCFetchClient } from '@orpc/client'
16+
import { createORPCClient } from '@orpc/client'
17+
import { ORPCLink } from '@orpc/client/fetch'
1718
import { RouterClient } from '@orpc/server'
1819
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
1920
import { useState } from 'react'
2021
import type { router } from 'examples/server'
2122
import * as React from 'react'
2223

23-
export const { orpc, ORPCContext } = createORPCReact<RouterClient<typeof router /** or contract router */>>()
24+
export const { orpc, ORPCContext } = createORPCReact<RouterClient<typeof router /** or contract router */, unknown>>()
2425

2526
export function ORPCProvider({ children }: { children: React.ReactNode }) {
26-
const [client] = useState(() => createORPCFetchClient<typeof router /** must match with createORPCReact*/>({
27-
baseURL: 'http://localhost:3000/api',
28-
}))
27+
const [client] = useState(() => {
28+
const orpcLink = new ORPCLink({
29+
url: 'http://localhost:3000/api',
30+
// fetch: optional override for the default fetch function
31+
// headers: provide additional headers
32+
})
33+
34+
return createORPCClient<typeof router>(orpcLink)
35+
})
2936
const [queryClient] = useState(() => new QueryClient())
3037

3138
return (

apps/content/content/docs/client/vanilla.mdx

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,17 @@ npm i @orpc/client
1414
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).
1515

1616
```ts twoslash
17-
import { createORPCFetchClient, ORPCError } from '@orpc/client'
17+
import { createORPCClient, ORPCError } from '@orpc/client'
18+
import { ORPCLink } from '@orpc/client/fetch'
1819
import type { router } from 'examples/server'
1920

20-
const client = createORPCFetchClient<typeof router /* or contract router */>({
21-
baseURL: 'http://localhost:3000/api',
21+
const orpcLink = new ORPCLink({
22+
url: 'http://localhost:3000/api',
2223
// fetch: optional override for the default fetch function
2324
// headers: provide additional headers
2425
})
26+
27+
const client = createORPCClient<typeof router /* or contract router */>(orpcLink)
2528

2629
// File upload out of the box
2730
const output = await client.post.create({
@@ -34,3 +37,62 @@ const output = await client.post.create({
3437
client.post.
3538
// ^|
3639
```
40+
41+
## Client Context
42+
43+
The `Client Context` feature allows you to pass additional contextual information (like caching policies) to your client calls.
44+
45+
```ts twoslash
46+
import type { router } from 'examples/server'
47+
import { createORPCClient, ORPCError } from '@orpc/client'
48+
import { ORPCLink } from '@orpc/client/fetch'
49+
50+
type ClientContext = { cache?: RequestCache } | undefined
51+
// if context is not undefinable, it will require you pass context in every call
52+
53+
const orpcLink = new ORPCLink<ClientContext>({
54+
url: 'http://localhost:3000/api',
55+
// headers: provide additional headers
56+
fetch: (input, init, context) => globalThis.fetch(input, {
57+
...init,
58+
cache: context?.cache,
59+
}),
60+
})
61+
62+
const client = createORPCClient<typeof router, ClientContext>(orpcLink)
63+
64+
client.getting({ name: 'unnoq' }, { context: { cache: 'force-cache' } })
65+
```
66+
67+
> **Note**: This works seamlessly with [Vue Query](/docs/client/vue-query) and [React Query](/docs/client/react-query).
68+
69+
## Dynamic Link
70+
71+
With the **Dynamic Link** mechanism, you can define custom logic to dynamically choose between different links based on the request's context, path, or input.
72+
73+
```ts twoslash
74+
import type { router } from 'examples/server'
75+
import { createORPCClient, DynamicLink, ORPCError } from '@orpc/client'
76+
import { ORPCLink } from '@orpc/client/fetch'
77+
78+
const orpcLink1 = new ORPCLink({
79+
url: 'http://localhost:3000/api',
80+
// headers: provide additional headers
81+
})
82+
83+
const orpcLink2 = new ORPCLink({
84+
url: 'http://localhost:8000/api',
85+
// headers: provide additional headers
86+
})
87+
88+
const dynamicLink = new DynamicLink((path, input, options) => { // can be async
89+
// const clientContext = options.context
90+
if (path.includes('post')) {
91+
return orpcLink1
92+
}
93+
94+
return orpcLink2
95+
})
96+
97+
const client = createORPCClient<typeof router>(dynamicLink)
98+
```

apps/content/content/docs/client/vue-query.mdx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,19 @@ description: Simplify Vue Query usage with minimal integration using ORPC and Ta
1313

1414
```ts twoslash
1515
import { createORPCVueQueryUtils } from '@orpc/vue-query';
16-
import { createORPCFetchClient } from '@orpc/client';
16+
import { createORPCClient } from '@orpc/client';
17+
import { ORPCLink } from '@orpc/client/fetch';
1718
import type { router } from 'examples/server';
1819

19-
// Create an ORPC client
20-
export const client = createORPCFetchClient<typeof router>({
21-
baseURL: 'http://localhost:3000/api',
20+
const orpcLink = new ORPCLink({
21+
url: 'http://localhost:3000/api',
22+
// fetch: optional override for the default fetch function
23+
// headers: provide additional headers
2224
});
2325

26+
// Create an ORPC client
27+
export const client = createORPCClient<typeof router>(orpcLink);
28+
2429
// Create Vue Query utilities for ORPC
2530
export const orpc = createORPCVueQueryUtils(client);
2631

apps/content/content/docs/contract-first.mdx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,17 @@ That's it! The contract definition and implementation are now completely separat
129129
Create a fully typed client using just the contract definition:
130130

131131
```ts twoslash
132-
import { createORPCFetchClient, ORPCError } from '@orpc/client'
132+
import { createORPCClient, ORPCError } from '@orpc/client'
133+
import { ORPCLink } from '@orpc/client/fetch'
133134
import type { contract } from 'examples/contract'
134135

135-
const client = createORPCFetchClient<typeof contract /* or server router */>({
136-
baseURL: 'http://localhost:3000/prefix',
136+
const orpcLink = new ORPCLink({
137+
url: 'http://localhost:3000/prefix',
137138
// fetch: optional override for the default fetch function
138139
// headers: provide additional headers
139140
})
141+
142+
const client = createORPCClient<typeof contract /* or server router */>(orpcLink)
140143

141144
// File upload out of the box
142145
const output = await client.post.create({

apps/content/content/docs/index.mdx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,14 +187,17 @@ Start the server and visit http://localhost:3000/api/getting?name=yourname to se
187187
Use the fully typed client in any environment:
188188

189189
```ts twoslash
190-
import { createORPCFetchClient, ORPCError } from '@orpc/client'
190+
import { createORPCClient, ORPCError } from '@orpc/client'
191+
import { ORPCLink } from '@orpc/client/fetch'
191192
import type { router } from 'examples/server'
192193

193-
const client = createORPCFetchClient<typeof router /* or contract router */>({
194-
baseURL: 'http://localhost:3000/api',
194+
const orpcLink = new ORPCLink({
195+
url: 'http://localhost:3000/api',
195196
// fetch: optional override for the default fetch function
196197
// headers: provide additional headers
197198
})
199+
200+
const client = createORPCClient<typeof router /* or contract router */>(orpcLink)
198201

199202
// File upload out of the box
200203
const output = await client.post.create({

apps/content/content/docs/server/file-upload.mdx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,17 @@ To upload files with oRPC from the client, set up an oRPC client
6363
and pass a `File` object directly to the upload endpoint.
6464

6565
```typescript
66-
import { createORPCFetchClient } from '@orpc/client'
66+
import { createORPCClient } from '@orpc/client'
67+
import { ORPCLink } from '@orpc/client/fetch'
6768

68-
const client = createORPCFetchClient<typeof appRouter>({
69-
baseURL: 'http://localhost:3000',
69+
const orpcLink = new ORPCLink({
70+
url: 'http://localhost:3000/api',
71+
// fetch: optional override for the default fetch function
72+
// headers: provide additional headers
7073
})
7174

75+
const client = createORPCClient<typeof appRouter>(orpcLink)
76+
7277
// Example: Upload a file from an HTML file input
7378
const fileInput = document.getElementById('file-input') as HTMLInputElement
7479
fileInput.onchange = async () => {

apps/content/content/home/client.mdx

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
<Tabs items={['Client', 'React', 'React Query', 'Vue Query', 'CURL']}>
22
<Tab value="Client">
33
```ts twoslash
4-
import { createORPCFetchClient, ORPCError } from '@orpc/client'
4+
import { createORPCClient, ORPCError } from '@orpc/client'
5+
import { ORPCLink } from '@orpc/client/fetch'
56
import type { router } from 'examples/server'
67

7-
const client = createORPCFetchClient<typeof router /* or contract router */>({
8-
baseURL: 'http://localhost:3000/api',
8+
const orpcLink = new ORPCLink({
9+
url: 'http://localhost:3000/api',
910
// fetch: optional override for the default fetch function
1011
// headers: provide additional headers
1112
})
13+
14+
const client = createORPCClient<typeof router /* or contract router */>(orpcLink)
1215

1316
// File upload out of the box
1417
const output = await client.post.create({
@@ -44,14 +47,15 @@ try {
4447
<Tab value="React">
4548
```tsx twoslash
4649
import { createORPCReact } from '@orpc/react'
47-
import { createORPCFetchClient } from '@orpc/client'
50+
import { createORPCClient } from '@orpc/client'
51+
import { ORPCLink } from '@orpc/client/fetch'
4852
import { RouterClient } from '@orpc/server'
4953
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
5054
import { useState } from 'react'
5155
import type { router } from 'examples/server'
5256
import * as React from 'react'
5357

54-
export const { orpc, ORPCContext } = createORPCReact<RouterClient<typeof router /** or contract router */>>()
58+
export const { orpc, ORPCContext } = createORPCReact<RouterClient<typeof router /** or contract router */, unknown>>()
5559

5660
// ------------------ Example ------------------
5761

@@ -118,9 +122,15 @@ const queries = orpc.useQueries(o => [
118122
// ------------------ Provider ------------------
119123

120124
export function ORPCProvider({ children }: { children: React.ReactNode }) {
121-
const [client] = useState(() => createORPCFetchClient<typeof router /** must match with createORPCReact*/>({
122-
baseURL: 'http://localhost:3000/api',
123-
}))
125+
const [client] = useState(() => {
126+
const orpcLink = new ORPCLink({
127+
url: 'http://localhost:3000/api',
128+
// fetch: optional override for the default fetch function
129+
// headers: provide additional headers
130+
})
131+
132+
return createORPCClient<typeof router>(orpcLink)
133+
})
124134
const [queryClient] = useState(() => new QueryClient())
125135

126136
return (

apps/content/examples/react-query.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ import type { RouterClient } from '@orpc/server'
22
import type { router } from 'examples/server'
33
import { createORPCReactQueryUtils } from '@orpc/react-query'
44

5-
export const orpc = createORPCReactQueryUtils({} as RouterClient<typeof router /** or contract router */>)
5+
export const orpc = createORPCReactQueryUtils({} as RouterClient<typeof router /** or contract router */, unknown>)

apps/content/examples/react.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ import type { RouterClient } from '@orpc/server'
22
import type { router } from 'examples/server'
33
import { createORPCReact } from '@orpc/react'
44

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

0 commit comments

Comments
 (0)