Skip to content

Commit 6b06c96

Browse files
authored
feat(client)!: update standard link interceptors and plugins options (#333)
This update change options related to `RPCLink` and `OpenAPILink` from receive 3 args like this `options, input, path` to this `{ context, input, path }` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Refactor** - Consolidated parameters across client calls and interceptors into a unified object structure. - Updated options and type definitions to enforce required properties, enhancing clarity and type safety. - Streamlined retry operations for clearer error handling and more consistent behavior. - **Tests** - Revised test cases to align with the new parameter structure, ensuring a reliable and maintainable validation process. - Updated fetch function signatures in test cases to accept a single `request` parameter, simplifying the interface. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 85cc28f commit 6b06c96

12 files changed

Lines changed: 160 additions & 163 deletions

File tree

apps/content/docs/client/rpc-link.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ interface ClientContext {
7171

7272
const link = new RPCLink<ClientContext>({
7373
url: 'http://localhost:3000/rpc',
74-
method: ({ context }, path) => {
74+
method: ({ context, path }) => {
7575
if (context?.cache) {
7676
return 'GET'
7777
}

apps/content/docs/plugins/client-retry.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const link = new RPCLink<ORPCClientContext>({
2626
plugins: [
2727
new ClientRetryPlugin({
2828
default: { // Optional override for default options
29-
retry: (options, path) => {
29+
retry: ({ path }) => {
3030
if (path.join('.') === 'planet.list') {
3131
return 2
3232
}

packages/client/src/adapters/fetch/link-fetch-client.test.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,7 @@ describe('linkFetchClient', () => {
4141
expect(fetch).toBeCalledWith(
4242
toFetchRequestSpy.mock.results[0]!.value,
4343
{ redirect: 'manual' },
44-
options,
45-
['example'],
46-
{ body: true },
44+
{ ...options, path: ['example'], input: { body: true } },
4745
)
4846
})
4947
})

packages/client/src/adapters/fetch/link-fetch-client.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
import type { StandardLazyResponse, StandardRequest } from '@orpc/standard-server'
22
import type { ToFetchRequestOptions } from '@orpc/standard-server-fetch'
33
import type { ClientContext, ClientOptions } from '../../types'
4-
import type { StandardLinkClient } from '../standard'
4+
import type { StandardLinkClient, StandardLinkInterceptorOptions } from '../standard'
55
import { toFetchRequest, toStandardLazyResponse } from '@orpc/standard-server-fetch'
66

77
export interface LinkFetchClientOptions<T extends ClientContext> extends ToFetchRequestOptions {
88
fetch?: (
99
request: Request,
1010
init: { redirect?: Request['redirect'] },
11-
options: ClientOptions<T>,
12-
path: readonly string[],
13-
input: unknown
11+
options: StandardLinkInterceptorOptions<T>,
1412
) => Promise<Response>
1513
}
1614

@@ -26,7 +24,7 @@ export class LinkFetchClient<T extends ClientContext> implements StandardLinkCli
2624
async call(request: StandardRequest, options: ClientOptions<T>, path: readonly string[], input: unknown): Promise<StandardLazyResponse> {
2725
const fetchRequest = toFetchRequest(request, this.toFetchRequestOptions)
2826

29-
const fetchResponse = await this.fetch(fetchRequest, { redirect: 'manual' }, options, path, input)
27+
const fetchResponse = await this.fetch(fetchRequest, { redirect: 'manual' }, { ...options, path, input })
3028

3129
const lazyResponse = toStandardLazyResponse(fetchResponse)
3230

packages/client/src/adapters/fetch/rpc-link.test.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ describe.each(supportedDataTypes)('rpcLink: $name', ({ value, expected }) => {
1818
const rpcLink = new RPCLink({
1919
url: 'http://api.example.com',
2020
method,
21-
fetch: async (url, init) => {
22-
const request = new Request(url, init)
21+
fetch: async (request) => {
2322
const { matched, response } = await rpcHandler.handle(request)
2423

2524
if (matched) {
@@ -51,8 +50,7 @@ describe.each(supportedDataTypes)('rpcLink: $name', ({ value, expected }) => {
5150
const rpcLink = new RPCLink({
5251
url: 'http://api.example.com',
5352
method,
54-
fetch: async (url, init) => {
55-
const request = new Request(url, init)
53+
fetch: async (request) => {
5654
const { matched, response } = await rpcHandler.handle(request)
5755

5856
if (matched) {

packages/client/src/adapters/standard/link.test.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,20 @@ describe('standardLink', () => {
4343
next: expect.any(Function),
4444
path: ['planet', 'create'],
4545
input: { name: 'Earth' },
46-
options: { context, signal, lastEventId },
46+
context,
47+
signal,
48+
lastEventId,
4749
})
4850

4951
expect(clientInterceptor).toHaveBeenCalledTimes(1)
5052
expect(clientInterceptor).toHaveBeenCalledWith({
5153
next: expect.any(Function),
5254
request: '__standard_request__',
55+
path: ['planet', 'create'],
56+
input: { name: 'Earth' },
57+
context,
58+
signal,
59+
lastEventId,
5360
})
5461
})
5562

packages/client/src/adapters/standard/link.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,18 @@ export interface StandardLinkPlugin<T extends ClientContext> {
1010
init?(options: StandardLinkOptions<T>): void
1111
}
1212

13+
export interface StandardLinkInterceptorOptions<T extends ClientContext> extends ClientOptions<T> {
14+
path: readonly string[]
15+
input: unknown
16+
}
17+
18+
export interface StandardLinkClientInterceptorOptions<T extends ClientContext> extends StandardLinkInterceptorOptions<T> {
19+
request: StandardRequest
20+
}
21+
1322
export interface StandardLinkOptions<T extends ClientContext> {
14-
interceptors?: Interceptor<{ path: readonly string[], input: unknown, options: ClientOptions<T> }, unknown, ThrowableError>[]
15-
clientInterceptors?: Interceptor<{ request: StandardRequest }, StandardLazyResponse, ThrowableError>[]
23+
interceptors?: Interceptor<StandardLinkInterceptorOptions<T>, unknown, ThrowableError>[]
24+
clientInterceptors?: Interceptor<StandardLinkClientInterceptorOptions<T>, StandardLazyResponse, ThrowableError>[]
1625
plugins?: StandardLinkPlugin<T>[]
1726
}
1827

@@ -34,7 +43,7 @@ export class StandardLink<T extends ClientContext> implements ClientLink<T> {
3443
}
3544

3645
call(path: readonly string[], input: unknown, options: ClientOptions<T>): Promise<unknown> {
37-
return intercept(this.interceptors, { path, input, options }, async ({ path, input, options }) => {
46+
return intercept(this.interceptors, { ...options, path, input }, async ({ path, input, ...options }) => {
3847
const output = await this.#call(path, input, options)
3948

4049
return output
@@ -46,8 +55,8 @@ export class StandardLink<T extends ClientContext> implements ClientLink<T> {
4655

4756
const response = await intercept(
4857
this.clientInterceptors,
49-
{ request },
50-
({ request }) => this.sender.call(request, options, path, input),
58+
{ ...options, input, path, request },
59+
({ input, path, request, ...options }) => this.sender.call(request, options, path, input),
5160
)
5261

5362
const output = await this.codec.decode(response, options, path, input)

packages/client/src/adapters/standard/rpc-link-codec.ts

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { ClientContext, ClientOptions, HTTPMethod } from '../../types'
2+
import type { StandardLinkInterceptorOptions } from './link'
23
import type { StandardRPCSerializer } from './rpc-serializer'
34
import type { StandardLinkCodec } from './types'
45
import { isAsyncIteratorObject, stringifyJSON, value, type Value } from '@orpc/shared'
@@ -10,33 +11,21 @@ export interface StandardRPCLinkCodecOptions<T extends ClientContext> {
1011
/**
1112
* Base url for all requests.
1213
*/
13-
url: Value<string | URL, [
14-
options: ClientOptions<T>,
15-
path: readonly string[],
16-
input: unknown,
17-
]>
14+
url: Value<string | URL, [StandardLinkInterceptorOptions<T>]>
1815

1916
/**
2017
* The maximum length of the URL.
2118
*
2219
* @default 2083
2320
*/
24-
maxUrlLength?: Value<number, [
25-
options: ClientOptions<T>,
26-
path: readonly string[],
27-
input: unknown,
28-
]>
21+
maxUrlLength?: Value<number, [StandardLinkInterceptorOptions<T>]>
2922

3023
/**
3124
* The method used to make the request.
3225
*
3326
* @default 'POST'
3427
*/
35-
method?: Value<HTTPMethod, [
36-
options: ClientOptions<T>,
37-
path: readonly string[],
38-
input: unknown,
39-
]>
28+
method?: Value<HTTPMethod, [StandardLinkInterceptorOptions<T>]>
4029

4130
/**
4231
* The method to use when the payload cannot safely pass to the server with method return from method function.
@@ -49,11 +38,7 @@ export interface StandardRPCLinkCodecOptions<T extends ClientContext> {
4938
/**
5039
* Inject headers to the request.
5140
*/
52-
headers?: Value<StandardHeaders, [
53-
options: ClientOptions<T>,
54-
path: readonly string[],
55-
input: unknown,
56-
]>
41+
headers?: Value<StandardHeaders, [StandardLinkInterceptorOptions<T>]>
5742
}
5843

5944
export class StandardRPCLinkCodec<T extends ClientContext> implements StandardLinkCodec<T> {
@@ -75,9 +60,11 @@ export class StandardRPCLinkCodec<T extends ClientContext> implements StandardLi
7560
}
7661

7762
async encode(path: readonly string[], input: unknown, options: ClientOptions<T>): Promise<StandardRequest> {
78-
const expectedMethod = await value(this.expectedMethod, options, path, input)
79-
let headers = await value(this.headers, options, path, input)
80-
const baseUrl = await value(this.baseUrl, options, path, input)
63+
const generalOptions = { ...options, path, input }
64+
65+
const expectedMethod = await value(this.expectedMethod, generalOptions)
66+
let headers = await value(this.headers, generalOptions)
67+
const baseUrl = await value(this.baseUrl, generalOptions)
8168
const url = new URL(baseUrl)
8269
url.pathname = `${url.pathname.replace(/\/$/, '')}${toHttpPath(path)}`
8370

@@ -92,7 +79,7 @@ export class StandardRPCLinkCodec<T extends ClientContext> implements StandardLi
9279
&& !(serialized instanceof FormData)
9380
&& !isAsyncIteratorObject(serialized)
9481
) {
95-
const maxUrlLength = await value(this.maxUrlLength, options, path, input)
82+
const maxUrlLength = await value(this.maxUrlLength, generalOptions)
9683
const getUrl = new URL(url)
9784

9885
getUrl.searchParams.append('data', stringifyJSON(serialized))

0 commit comments

Comments
 (0)