@trpc/client 9.20.1 → 10.0.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/TRPCClientError-17b117e1.mjs +81 -0
- package/dist/TRPCClientError-ec6bd2ca.js +94 -0
- package/dist/{declarations/src/TRPCClientError.d.ts → TRPCClientError.d.ts} +29 -33
- package/dist/TRPCClientError.d.ts.map +1 -0
- package/dist/createChain-3b458753.js +27 -0
- package/dist/createChain-b7cb1f5a.mjs +25 -0
- package/dist/{declarations/src/createTRPCClient.d.ts → createTRPCClient.d.ts} +5 -6
- package/dist/createTRPCClient.d.ts.map +1 -0
- package/dist/{declarations/src/getFetch.d.ts → getFetch.d.ts} +1 -1
- package/dist/getFetch.d.ts.map +1 -0
- package/dist/httpUtils-1f9e4e3c.js +97 -0
- package/dist/httpUtils-c09d7b79.mjs +91 -0
- package/dist/{declarations/src/index.d.ts → index.d.ts} +4 -4
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +243 -0
- package/dist/index.mjs +233 -0
- package/dist/index.ts.js +1 -0
- package/dist/{declarations/src/internals → internals}/TRPCClient.d.ts +62 -61
- package/dist/internals/TRPCClient.d.ts.map +1 -0
- package/dist/{declarations/src/internals → internals}/dataLoader.d.ts +16 -16
- package/dist/internals/dataLoader.d.ts.map +1 -0
- package/dist/{declarations/src/internals → internals}/fetchHelpers.d.ts +2 -2
- package/dist/internals/fetchHelpers.d.ts.map +1 -0
- package/dist/{declarations/src/internals → internals}/retryDelay.d.ts +1 -1
- package/dist/internals/retryDelay.d.ts.map +1 -0
- package/dist/links/dedupeLink.d.ts +4 -0
- package/dist/links/dedupeLink.d.ts.map +1 -0
- package/dist/{declarations/src/links → links}/httpBatchLink.d.ts +7 -6
- package/dist/links/httpBatchLink.d.ts.map +1 -0
- package/dist/links/httpBatchLink.js +195 -0
- package/dist/links/httpBatchLink.mjs +191 -0
- package/dist/links/httpBatchLink.ts.js +1 -0
- package/dist/{declarations/src/links → links}/httpLink.d.ts +4 -3
- package/dist/links/httpLink.d.ts.map +1 -0
- package/dist/links/httpLink.js +44 -0
- package/dist/links/httpLink.mjs +40 -0
- package/dist/links/httpLink.ts.js +1 -0
- package/dist/links/httpUtils.d.ts +22 -0
- package/dist/links/httpUtils.d.ts.map +1 -0
- package/dist/links/internals/createChain.d.ts +8 -0
- package/dist/links/internals/createChain.d.ts.map +1 -0
- package/dist/links/internals/transformOperationResult.d.ts +16 -0
- package/dist/links/internals/transformOperationResult.d.ts.map +1 -0
- package/dist/{declarations/src/links → links}/loggerLink.d.ts +38 -37
- package/dist/links/loggerLink.d.ts.map +1 -0
- package/dist/links/loggerLink.js +107 -0
- package/dist/links/loggerLink.mjs +98 -0
- package/dist/links/loggerLink.ts.js +1 -0
- package/dist/links/retryLink.d.ts +6 -0
- package/dist/links/retryLink.d.ts.map +1 -0
- package/dist/links/splitLink.d.ts +14 -0
- package/dist/links/splitLink.d.ts.map +1 -0
- package/dist/links/splitLink.js +32 -0
- package/dist/links/splitLink.mjs +28 -0
- package/dist/links/splitLink.ts.js +1 -0
- package/dist/links/transformerLink.d.ts +4 -0
- package/dist/links/transformerLink.d.ts.map +1 -0
- package/dist/links/transformerLink.js +79 -0
- package/dist/links/transformerLink.mjs +71 -0
- package/dist/links/transformerLink.ts.js +1 -0
- package/dist/links/types.d.ts +39 -0
- package/dist/links/types.d.ts.map +1 -0
- package/dist/links/wsLink.d.ts +21 -0
- package/dist/links/wsLink.d.ts.map +1 -0
- package/dist/links/wsLink.js +385 -0
- package/dist/links/wsLink.mjs +370 -0
- package/dist/links/wsLink.ts.js +1 -0
- package/dist/rx.d.ts +11 -0
- package/dist/rx.d.ts.map +1 -0
- package/dist/rx.js +88 -0
- package/dist/rx.mjs +73 -0
- package/dist/rx.ts.js +1 -0
- package/links/httpBatchLink/index.d.ts +1 -0
- package/links/httpBatchLink/index.js +1 -0
- package/links/httpLink/index.d.ts +1 -0
- package/links/httpLink/index.js +1 -0
- package/links/loggerLink/index.d.ts +1 -0
- package/links/loggerLink/index.js +1 -0
- package/links/splitLink/index.d.ts +1 -0
- package/links/splitLink/index.js +1 -0
- package/links/transformerLink/index.d.ts +1 -0
- package/links/transformerLink/index.js +1 -0
- package/links/wsLink/index.d.ts +1 -0
- package/links/wsLink/index.js +1 -0
- package/package.json +53 -18
- package/src/TRPCClientError.ts +17 -21
- package/src/createTRPCClient.ts +4 -3
- package/src/index.ts +1 -1
- package/src/internals/TRPCClient.ts +78 -92
- package/src/internals/dataLoader.ts +1 -1
- package/src/links/dedupeLink.test.ts +134 -0
- package/src/links/dedupeLink.ts +54 -0
- package/src/links/httpBatchLink.ts +36 -46
- package/src/links/httpLink.ts +26 -37
- package/src/{internals/httpRequest.ts → links/httpUtils.ts} +30 -21
- package/src/links/internals/createChain.test.ts +132 -0
- package/src/links/internals/createChain.ts +31 -0
- package/src/links/internals/transformOperationResult.ts +25 -0
- package/src/links/loggerLink.ts +39 -22
- package/src/links/retryLink.ts +44 -14
- package/src/links/splitLink.test.ts +56 -0
- package/src/links/splitLink.ts +23 -38
- package/src/links/transformerLink.ts +74 -0
- package/src/links/types.ts +64 -0
- package/src/links/wsLink.ts +57 -77
- package/src/rx.ts +50 -0
- package/dist/TRPCClientError-09b8a26b.esm.js +0 -77
- package/dist/TRPCClientError-bfee2bf5.cjs.dev.js +0 -79
- package/dist/TRPCClientError-e9bf96e9.cjs.prod.js +0 -79
- package/dist/declarations/src/TRPCClientError.d.ts.map +0 -1
- package/dist/declarations/src/createTRPCClient.d.ts.map +0 -1
- package/dist/declarations/src/getFetch.d.ts.map +0 -1
- package/dist/declarations/src/index.d.ts.map +0 -1
- package/dist/declarations/src/internals/TRPCAbortError.d.ts +0 -4
- package/dist/declarations/src/internals/TRPCAbortError.d.ts.map +0 -1
- package/dist/declarations/src/internals/TRPCClient.d.ts.map +0 -1
- package/dist/declarations/src/internals/dataLoader.d.ts.map +0 -1
- package/dist/declarations/src/internals/executeChain.d.ts +0 -9
- package/dist/declarations/src/internals/executeChain.d.ts.map +0 -1
- package/dist/declarations/src/internals/fetchHelpers.d.ts.map +0 -1
- package/dist/declarations/src/internals/httpRequest.d.ts +0 -14
- package/dist/declarations/src/internals/httpRequest.d.ts.map +0 -1
- package/dist/declarations/src/internals/observable.d.ts +0 -18
- package/dist/declarations/src/internals/observable.d.ts.map +0 -1
- package/dist/declarations/src/internals/retryDelay.d.ts.map +0 -1
- package/dist/declarations/src/internals/transformRPCResponse.d.ts +0 -15
- package/dist/declarations/src/internals/transformRPCResponse.d.ts.map +0 -1
- package/dist/declarations/src/links/core.d.ts +0 -45
- package/dist/declarations/src/links/core.d.ts.map +0 -1
- package/dist/declarations/src/links/httpBatchLink.d.ts.map +0 -1
- package/dist/declarations/src/links/httpLink.d.ts.map +0 -1
- package/dist/declarations/src/links/loggerLink.d.ts.map +0 -1
- package/dist/declarations/src/links/splitLink.d.ts +0 -24
- package/dist/declarations/src/links/splitLink.d.ts.map +0 -1
- package/dist/declarations/src/links/wsLink.d.ts +0 -30
- package/dist/declarations/src/links/wsLink.d.ts.map +0 -1
- package/dist/transformRPCResponse-57e80136.cjs.dev.js +0 -133
- package/dist/transformRPCResponse-739c13d0.cjs.prod.js +0 -133
- package/dist/transformRPCResponse-f7f8b0e1.esm.js +0 -129
- package/dist/trpc-client.cjs.d.ts +0 -1
- package/dist/trpc-client.cjs.dev.js +0 -379
- package/dist/trpc-client.cjs.js +0 -7
- package/dist/trpc-client.cjs.prod.js +0 -379
- package/dist/trpc-client.esm.js +0 -374
- package/links/httpBatchLink/package.json +0 -4
- package/links/httpLink/package.json +0 -4
- package/links/loggerLink/package.json +0 -4
- package/links/splitLink/package.json +0 -4
- package/links/wsLink/package.json +0 -4
- package/src/internals/TRPCAbortError.ts +0 -7
- package/src/internals/executeChain.ts +0 -67
- package/src/internals/observable.ts +0 -89
- package/src/internals/transformRPCResponse.ts +0 -25
- package/src/links/core.ts +0 -71
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trpc/client",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "10.0.0-alpha.10",
|
|
4
4
|
"description": "tRPC Client lib",
|
|
5
5
|
"author": "KATT",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,37 +10,72 @@
|
|
|
10
10
|
"url": "git+https://github.com/trpc/trpc.git",
|
|
11
11
|
"directory": "packages/client"
|
|
12
12
|
},
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
|
|
13
|
+
"main": "dist/index.js",
|
|
14
|
+
"module": "dist/index.mjs",
|
|
15
|
+
"typings": "dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"import": "./dist/index.mjs",
|
|
19
|
+
"require": "./dist/index.js",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./rx": {
|
|
23
|
+
"import": "./dist/rx.mjs",
|
|
24
|
+
"require": "./dist/rx.js",
|
|
25
|
+
"default": "./dist/rx.js"
|
|
26
|
+
},
|
|
27
|
+
"./links/httpBatchLink": {
|
|
28
|
+
"import": "./dist/links/httpBatchLink.mjs",
|
|
29
|
+
"require": "./dist/links/httpBatchLink.js",
|
|
30
|
+
"default": "./dist/links/httpBatchLink.js"
|
|
31
|
+
},
|
|
32
|
+
"./links/httpLink": {
|
|
33
|
+
"import": "./dist/links/httpLink.mjs",
|
|
34
|
+
"require": "./dist/links/httpLink.js",
|
|
35
|
+
"default": "./dist/links/httpLink.js"
|
|
36
|
+
},
|
|
37
|
+
"./links/loggerLink": {
|
|
38
|
+
"import": "./dist/links/loggerLink.mjs",
|
|
39
|
+
"require": "./dist/links/loggerLink.js",
|
|
40
|
+
"default": "./dist/links/loggerLink.js"
|
|
41
|
+
},
|
|
42
|
+
"./links/splitLink": {
|
|
43
|
+
"import": "./dist/links/splitLink.mjs",
|
|
44
|
+
"require": "./dist/links/splitLink.js",
|
|
45
|
+
"default": "./dist/links/splitLink.js"
|
|
46
|
+
},
|
|
47
|
+
"./links/transformerLink": {
|
|
48
|
+
"import": "./dist/links/transformerLink.mjs",
|
|
49
|
+
"require": "./dist/links/transformerLink.js",
|
|
50
|
+
"default": "./dist/links/transformerLink.js"
|
|
51
|
+
},
|
|
52
|
+
"./links/wsLink": {
|
|
53
|
+
"import": "./dist/links/wsLink.mjs",
|
|
54
|
+
"require": "./dist/links/wsLink.js",
|
|
55
|
+
"default": "./dist/links/wsLink.js"
|
|
56
|
+
}
|
|
22
57
|
},
|
|
23
|
-
"scripts": {},
|
|
24
|
-
"main": "dist/trpc-client.cjs.js",
|
|
25
|
-
"module": "dist/trpc-client.esm.js",
|
|
26
|
-
"typings": "dist/trpc-client.cjs.d.ts",
|
|
27
58
|
"files": [
|
|
28
59
|
"README.md",
|
|
29
60
|
"dist",
|
|
30
61
|
"links",
|
|
31
62
|
"src"
|
|
32
63
|
],
|
|
64
|
+
"scripts": {
|
|
65
|
+
"build": "rollup -c"
|
|
66
|
+
},
|
|
33
67
|
"dependencies": {
|
|
34
|
-
"@babel/runtime": "^7.9.0"
|
|
68
|
+
"@babel/runtime": "^7.9.0",
|
|
69
|
+
"rxjs": "^7.0.0"
|
|
35
70
|
},
|
|
36
71
|
"peerDependencies": {
|
|
37
|
-
"@trpc/server": "
|
|
72
|
+
"@trpc/server": "10.0.0-alpha.10"
|
|
38
73
|
},
|
|
39
74
|
"devDependencies": {
|
|
40
|
-
"@trpc/server": "
|
|
75
|
+
"@trpc/server": "10.0.0-alpha.10"
|
|
41
76
|
},
|
|
42
77
|
"publishConfig": {
|
|
43
78
|
"access": "public"
|
|
44
79
|
},
|
|
45
|
-
"gitHead": "
|
|
80
|
+
"gitHead": "a1de7cd99bc36e26da285ed1cfdf8cb24dd5fd0b"
|
|
46
81
|
}
|
package/src/TRPCClientError.ts
CHANGED
|
@@ -18,58 +18,54 @@ export class TRPCClientError<TRouter extends AnyRouter>
|
|
|
18
18
|
public readonly cause;
|
|
19
19
|
public readonly shape: Maybe<inferRouterError<TRouter>>;
|
|
20
20
|
public readonly data: Maybe<inferRouterError<TRouter>['data']>;
|
|
21
|
-
|
|
22
|
-
* Fatal error - expect no more results after this error
|
|
23
|
-
* Used for when WebSockets disconnect prematurely.
|
|
24
|
-
*/
|
|
25
|
-
public readonly isDone: boolean;
|
|
21
|
+
public readonly meta;
|
|
26
22
|
|
|
27
23
|
constructor(
|
|
28
24
|
message: string,
|
|
29
|
-
opts
|
|
25
|
+
opts?: {
|
|
30
26
|
result: Maybe<TRPCErrorResponse<inferRouterError<TRouter>>>;
|
|
31
27
|
/**
|
|
32
|
-
* @deprecated use cause
|
|
28
|
+
* @deprecated use `cause`
|
|
33
29
|
**/
|
|
34
30
|
originalError?: Maybe<Error>;
|
|
35
31
|
cause?: Maybe<Error>;
|
|
36
|
-
|
|
32
|
+
meta?: Record<string, unknown>;
|
|
37
33
|
},
|
|
38
34
|
) {
|
|
39
|
-
const cause = opts
|
|
35
|
+
const cause = opts?.cause ?? opts?.originalError;
|
|
40
36
|
|
|
41
37
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
42
38
|
// @ts-ignore https://github.com/tc39/proposal-error-cause
|
|
43
39
|
super(message, { cause });
|
|
44
40
|
|
|
45
|
-
this.
|
|
41
|
+
this.meta = opts?.meta;
|
|
46
42
|
|
|
47
43
|
this.cause = this.originalError = cause;
|
|
48
|
-
this.shape = opts
|
|
49
|
-
this.data = opts
|
|
44
|
+
this.shape = opts?.result?.error;
|
|
45
|
+
this.data = opts?.result?.error.data;
|
|
50
46
|
this.name = 'TRPCClientError';
|
|
51
47
|
|
|
52
48
|
Object.setPrototypeOf(this, TRPCClientError.prototype);
|
|
53
49
|
}
|
|
54
50
|
|
|
55
51
|
public static from<TRouter extends AnyRouter>(
|
|
56
|
-
|
|
57
|
-
opts: {
|
|
52
|
+
cause: Error | TRPCErrorResponse<any>,
|
|
53
|
+
opts: { meta?: Record<string, unknown> } = {},
|
|
58
54
|
): TRPCClientError<TRouter> {
|
|
59
|
-
if (!(
|
|
60
|
-
return new TRPCClientError<TRouter>((
|
|
55
|
+
if (!(cause instanceof Error)) {
|
|
56
|
+
return new TRPCClientError<TRouter>((cause.error as any).message ?? '', {
|
|
61
57
|
...opts,
|
|
62
58
|
cause: null,
|
|
63
|
-
result:
|
|
59
|
+
result: cause,
|
|
64
60
|
});
|
|
65
61
|
}
|
|
66
|
-
if (
|
|
67
|
-
return
|
|
62
|
+
if (cause.name === 'TRPCClientError') {
|
|
63
|
+
return cause as TRPCClientError<any>;
|
|
68
64
|
}
|
|
69
65
|
|
|
70
|
-
return new TRPCClientError<TRouter>(
|
|
66
|
+
return new TRPCClientError<TRouter>(cause.message, {
|
|
71
67
|
...opts,
|
|
72
|
-
cause
|
|
68
|
+
cause,
|
|
73
69
|
result: null,
|
|
74
70
|
});
|
|
75
71
|
}
|
package/src/createTRPCClient.ts
CHANGED
|
@@ -11,8 +11,9 @@ export function createTRPCClient<TRouter extends AnyRouter>(
|
|
|
11
11
|
return new Client<TRouter>(opts);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export type { CreateTRPCClientOptions } from './internals/TRPCClient';
|
|
15
|
-
|
|
16
14
|
export type TRPCClient<TRouter extends AnyRouter> = Client<TRouter>;
|
|
17
15
|
|
|
18
|
-
export type {
|
|
16
|
+
export type {
|
|
17
|
+
TRPCRequestOptions,
|
|
18
|
+
CreateTRPCClientOptions,
|
|
19
|
+
} from './internals/TRPCClient';
|
package/src/index.ts
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AnyRouter,
|
|
3
|
-
ClientDataTransformerOptions,
|
|
4
|
-
DataTransformer,
|
|
5
3
|
inferHandlerInput,
|
|
6
4
|
inferProcedureInput,
|
|
7
5
|
inferProcedureOutput,
|
|
8
6
|
inferSubscriptionOutput,
|
|
9
7
|
} from '@trpc/server';
|
|
10
8
|
import { TRPCResult } from '@trpc/server/rpc';
|
|
11
|
-
import {
|
|
12
|
-
import { getAbortController } from './fetchHelpers';
|
|
9
|
+
import { CancelFn } from '..';
|
|
13
10
|
import { getFetch } from '../getFetch';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
11
|
+
import { httpBatchLink } from '../links/httpBatchLink';
|
|
12
|
+
import { createChain } from '../links/internals/createChain';
|
|
13
|
+
import { transformOperationResult } from '../links/internals/transformOperationResult';
|
|
16
14
|
import {
|
|
17
|
-
CancelFn,
|
|
18
15
|
HTTPHeaders,
|
|
19
|
-
|
|
16
|
+
LinkRuntime,
|
|
20
17
|
OperationContext,
|
|
21
18
|
OperationLink,
|
|
22
19
|
TRPCLink,
|
|
23
|
-
} from '../links/
|
|
24
|
-
import {
|
|
20
|
+
} from '../links/types';
|
|
21
|
+
import { inferObservableValue, observableToPromise } from '../rx';
|
|
22
|
+
import { share } from 'rxjs/operators';
|
|
23
|
+
import { Observer, Subscription } from 'rxjs';
|
|
25
24
|
import { TRPCClientError } from '../TRPCClientError';
|
|
25
|
+
import { getAbortController } from './fetchHelpers';
|
|
26
26
|
|
|
27
27
|
type CancellablePromise<T = unknown> = Promise<T> & {
|
|
28
28
|
cancel: CancelFn;
|
|
@@ -39,8 +39,7 @@ let idCounter = 0;
|
|
|
39
39
|
function getRequestId() {
|
|
40
40
|
return ++idCounter;
|
|
41
41
|
}
|
|
42
|
-
|
|
43
|
-
export type CreateTRPCClientOptions<TRouter extends AnyRouter> = {
|
|
42
|
+
interface CreateTRPCClientBaseOptions {
|
|
44
43
|
/**
|
|
45
44
|
* Add ponyfill for fetch
|
|
46
45
|
*/
|
|
@@ -53,25 +52,26 @@ export type CreateTRPCClientOptions<TRouter extends AnyRouter> = {
|
|
|
53
52
|
* headers to be set on outgoing requests / callback that of said headers
|
|
54
53
|
*/
|
|
55
54
|
headers?: HTTPHeaders | (() => HTTPHeaders | Promise<HTTPHeaders>);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** @internal */
|
|
58
|
+
export interface CreateTRPCClientWithURLOptions
|
|
59
|
+
extends CreateTRPCClientBaseOptions {
|
|
56
60
|
/**
|
|
57
|
-
*
|
|
58
|
-
* @link http://localhost:3000/docs/data-transformers
|
|
61
|
+
* HTTP URL of API
|
|
59
62
|
**/
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
links: TRPCLink<TRouter>[];
|
|
73
|
-
}
|
|
74
|
-
);
|
|
63
|
+
url: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** @internal */
|
|
67
|
+
export interface CreateTRPCClientWithLinksOptions<TRouter extends AnyRouter>
|
|
68
|
+
extends CreateTRPCClientBaseOptions {
|
|
69
|
+
/**
|
|
70
|
+
* @link http://localhost:3000/docs/links
|
|
71
|
+
**/
|
|
72
|
+
links: TRPCLink<TRouter>[];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
75
|
type TRPCType = 'subscription' | 'query' | 'mutation';
|
|
76
76
|
export interface TRPCRequestOptions {
|
|
77
77
|
/**
|
|
@@ -79,27 +79,20 @@ export interface TRPCRequestOptions {
|
|
|
79
79
|
*/
|
|
80
80
|
context?: OperationContext;
|
|
81
81
|
}
|
|
82
|
+
|
|
83
|
+
/** @internal */
|
|
84
|
+
export type CreateTRPCClientOptions<TRouter extends AnyRouter> =
|
|
85
|
+
| CreateTRPCClientWithLinksOptions<TRouter>
|
|
86
|
+
| CreateTRPCClientWithURLOptions;
|
|
82
87
|
export class TRPCClient<TRouter extends AnyRouter> {
|
|
83
88
|
private readonly links: OperationLink<TRouter>[];
|
|
84
|
-
public readonly runtime:
|
|
89
|
+
public readonly runtime: LinkRuntime;
|
|
85
90
|
|
|
86
91
|
constructor(opts: CreateTRPCClientOptions<TRouter>) {
|
|
87
|
-
const transformer: DataTransformer = opts.transformer
|
|
88
|
-
? 'input' in opts.transformer
|
|
89
|
-
? {
|
|
90
|
-
serialize: opts.transformer.input.serialize,
|
|
91
|
-
deserialize: opts.transformer.output.deserialize,
|
|
92
|
-
}
|
|
93
|
-
: opts.transformer
|
|
94
|
-
: {
|
|
95
|
-
serialize: (data) => data,
|
|
96
|
-
deserialize: (data) => data,
|
|
97
|
-
};
|
|
98
|
-
|
|
99
92
|
const _fetch = getFetch(opts?.fetch);
|
|
100
93
|
const AC = getAbortController(opts?.AbortController);
|
|
101
94
|
|
|
102
|
-
function getHeadersFn():
|
|
95
|
+
function getHeadersFn(): LinkRuntime['headers'] {
|
|
103
96
|
if (opts.headers) {
|
|
104
97
|
const headers = opts.headers;
|
|
105
98
|
return typeof headers === 'function' ? headers : () => headers;
|
|
@@ -107,7 +100,6 @@ export class TRPCClient<TRouter extends AnyRouter> {
|
|
|
107
100
|
return () => ({});
|
|
108
101
|
}
|
|
109
102
|
this.runtime = {
|
|
110
|
-
transformer,
|
|
111
103
|
AbortController: AC as any,
|
|
112
104
|
fetch: _fetch,
|
|
113
105
|
headers: getHeadersFn(),
|
|
@@ -135,8 +127,8 @@ export class TRPCClient<TRouter extends AnyRouter> {
|
|
|
135
127
|
path: string;
|
|
136
128
|
context?: OperationContext;
|
|
137
129
|
}) {
|
|
138
|
-
const $
|
|
139
|
-
links: this.links as any,
|
|
130
|
+
const chain$ = createChain<TRouter, TInput, TOutput>({
|
|
131
|
+
links: this.links as OperationLink<any, any, any>[],
|
|
140
132
|
op: {
|
|
141
133
|
id: getRequestId(),
|
|
142
134
|
type,
|
|
@@ -145,8 +137,7 @@ export class TRPCClient<TRouter extends AnyRouter> {
|
|
|
145
137
|
context,
|
|
146
138
|
},
|
|
147
139
|
});
|
|
148
|
-
|
|
149
|
-
return $result;
|
|
140
|
+
return chain$.pipe(share());
|
|
150
141
|
}
|
|
151
142
|
private requestAsPromise<TInput = unknown, TOutput = unknown>(opts: {
|
|
152
143
|
type: TRPCType;
|
|
@@ -154,38 +145,29 @@ export class TRPCClient<TRouter extends AnyRouter> {
|
|
|
154
145
|
path: string;
|
|
155
146
|
context?: OperationContext;
|
|
156
147
|
}): CancellablePromise<TOutput> {
|
|
157
|
-
const $
|
|
158
|
-
|
|
159
|
-
const promise =
|
|
160
|
-
const res = $result.get();
|
|
161
|
-
if (res?.type === 'data') {
|
|
162
|
-
resolve(res.data);
|
|
163
|
-
$result.done();
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
$result.subscribe({
|
|
167
|
-
onNext: (result) => {
|
|
168
|
-
if (result?.type !== 'data') {
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
resolve(result.data);
|
|
148
|
+
const req$ = this.$request<TInput, TOutput>(opts);
|
|
149
|
+
type TValue = inferObservableValue<typeof req$>;
|
|
150
|
+
const { promise, abort } = observableToPromise<TValue>(req$);
|
|
172
151
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
152
|
+
const cancellablePromise: CancellablePromise<any> = new Promise<TOutput>(
|
|
153
|
+
(resolve, reject) => {
|
|
154
|
+
promise
|
|
155
|
+
.then((result) => {
|
|
156
|
+
const transformed = transformOperationResult(result);
|
|
157
|
+
if (transformed.ok) {
|
|
158
|
+
resolve(transformed.data as any);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
reject(transformed.error);
|
|
162
|
+
})
|
|
163
|
+
.catch((err) => {
|
|
164
|
+
reject(TRPCClientError.from(err));
|
|
165
|
+
});
|
|
166
|
+
},
|
|
167
|
+
) as any;
|
|
168
|
+
cancellablePromise.cancel = abort;
|
|
187
169
|
|
|
188
|
-
return
|
|
170
|
+
return cancellablePromise;
|
|
189
171
|
}
|
|
190
172
|
public query<
|
|
191
173
|
TQueries extends TRouter['_def']['queries'],
|
|
@@ -232,28 +214,32 @@ export class TRPCClient<TRouter extends AnyRouter> {
|
|
|
232
214
|
>(
|
|
233
215
|
path: TPath,
|
|
234
216
|
input: TInput,
|
|
235
|
-
opts: TRPCRequestOptions &
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
const $res = this.$request<TInput, TOutput>({
|
|
217
|
+
opts: TRPCRequestOptions & Partial<Observer<TRPCResult<TOutput>>>,
|
|
218
|
+
): Subscription {
|
|
219
|
+
const observable$ = this.$request<TInput, TOutput>({
|
|
239
220
|
type: 'subscription',
|
|
240
221
|
path,
|
|
241
222
|
input,
|
|
242
223
|
context: opts.context,
|
|
243
224
|
});
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
if (
|
|
247
|
-
|
|
225
|
+
return observable$.subscribe({
|
|
226
|
+
next(result) {
|
|
227
|
+
if ('error' in result.data) {
|
|
228
|
+
const err = TRPCClientError.from(result.data, {
|
|
229
|
+
meta: result.context,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
opts.error?.(err);
|
|
233
|
+
return;
|
|
248
234
|
}
|
|
235
|
+
opts.next?.(result.data.result);
|
|
236
|
+
},
|
|
237
|
+
error(err) {
|
|
238
|
+
opts.error?.(err);
|
|
249
239
|
},
|
|
250
|
-
|
|
251
|
-
opts.
|
|
240
|
+
complete() {
|
|
241
|
+
opts.complete?.();
|
|
252
242
|
},
|
|
253
|
-
onDone: opts.onDone,
|
|
254
243
|
});
|
|
255
|
-
return () => {
|
|
256
|
-
$res.done();
|
|
257
|
-
};
|
|
258
244
|
}
|
|
259
245
|
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { waitFor } from '@testing-library/dom';
|
|
2
|
+
import { AnyRouter } from '@trpc/server';
|
|
3
|
+
import { OperationLink } from '..';
|
|
4
|
+
import { Observable } from 'rxjs';
|
|
5
|
+
import { dedupeLink } from './dedupeLink';
|
|
6
|
+
import { createChain } from './internals/createChain';
|
|
7
|
+
|
|
8
|
+
test('dedupeLink', async () => {
|
|
9
|
+
const endingLinkTriggered = jest.fn();
|
|
10
|
+
const timerTriggered = jest.fn();
|
|
11
|
+
const links: OperationLink<AnyRouter, any, any>[] = [
|
|
12
|
+
// "dedupe link"
|
|
13
|
+
dedupeLink()(null as any),
|
|
14
|
+
({ op }) => {
|
|
15
|
+
return new Observable((subscribe) => {
|
|
16
|
+
endingLinkTriggered();
|
|
17
|
+
const timer = setTimeout(() => {
|
|
18
|
+
timerTriggered();
|
|
19
|
+
subscribe.next({
|
|
20
|
+
data: {
|
|
21
|
+
id: null,
|
|
22
|
+
result: {
|
|
23
|
+
type: 'data',
|
|
24
|
+
data: {
|
|
25
|
+
input: op.input,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
subscribe.complete();
|
|
31
|
+
}, 1);
|
|
32
|
+
return () => clearTimeout(timer);
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
{
|
|
37
|
+
const call1 = createChain<AnyRouter, unknown, unknown>({
|
|
38
|
+
links,
|
|
39
|
+
op: {
|
|
40
|
+
type: 'query',
|
|
41
|
+
id: 1,
|
|
42
|
+
input: 'world',
|
|
43
|
+
path: 'hello',
|
|
44
|
+
context: {},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const call2 = createChain<AnyRouter, unknown, unknown>({
|
|
49
|
+
links,
|
|
50
|
+
op: {
|
|
51
|
+
type: 'query',
|
|
52
|
+
id: 1,
|
|
53
|
+
input: 'world',
|
|
54
|
+
path: 'hello',
|
|
55
|
+
context: {},
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
const next = jest.fn();
|
|
59
|
+
call1.subscribe({ next });
|
|
60
|
+
call2.subscribe({ next });
|
|
61
|
+
|
|
62
|
+
expect(endingLinkTriggered).toHaveBeenCalledTimes(1);
|
|
63
|
+
await waitFor(() => {
|
|
64
|
+
expect(timerTriggered).toHaveBeenCalledTimes(1);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
expect(next).toHaveBeenCalledTimes(2);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('dedupe - cancel one does not cancel the other', async () => {
|
|
72
|
+
const endingLinkTriggered = jest.fn();
|
|
73
|
+
const timerTriggered = jest.fn();
|
|
74
|
+
const links: OperationLink<AnyRouter, any, any>[] = [
|
|
75
|
+
// "dedupe link"
|
|
76
|
+
dedupeLink()(null as any),
|
|
77
|
+
({ op }) => {
|
|
78
|
+
return new Observable((subscribe) => {
|
|
79
|
+
endingLinkTriggered();
|
|
80
|
+
const timer = setTimeout(() => {
|
|
81
|
+
timerTriggered();
|
|
82
|
+
subscribe.next({
|
|
83
|
+
data: {
|
|
84
|
+
id: null,
|
|
85
|
+
result: {
|
|
86
|
+
type: 'data',
|
|
87
|
+
data: {
|
|
88
|
+
input: op.input,
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
subscribe.complete();
|
|
94
|
+
}, 1);
|
|
95
|
+
return () => clearTimeout(timer);
|
|
96
|
+
});
|
|
97
|
+
},
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
{
|
|
101
|
+
const call1 = createChain<AnyRouter, unknown, unknown>({
|
|
102
|
+
links,
|
|
103
|
+
op: {
|
|
104
|
+
type: 'query',
|
|
105
|
+
id: 1,
|
|
106
|
+
input: 'world',
|
|
107
|
+
path: 'hello',
|
|
108
|
+
context: {},
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const call2 = createChain<AnyRouter, unknown, unknown>({
|
|
113
|
+
links,
|
|
114
|
+
op: {
|
|
115
|
+
type: 'query',
|
|
116
|
+
id: 1,
|
|
117
|
+
input: 'world',
|
|
118
|
+
path: 'hello',
|
|
119
|
+
context: {},
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
const next = jest.fn();
|
|
123
|
+
const call1$ = call1.subscribe({ next });
|
|
124
|
+
call2.subscribe({ next });
|
|
125
|
+
call1$.unsubscribe();
|
|
126
|
+
|
|
127
|
+
expect(endingLinkTriggered).toHaveBeenCalledTimes(1);
|
|
128
|
+
await waitFor(() => {
|
|
129
|
+
expect(timerTriggered).toHaveBeenCalledTimes(1);
|
|
130
|
+
|
|
131
|
+
expect(next).toHaveBeenCalledTimes(1);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { AnyRouter } from '@trpc/server';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { share } from 'rxjs';
|
|
4
|
+
import { OperationResult, TRPCLink } from './types';
|
|
5
|
+
|
|
6
|
+
export function dedupeLink<
|
|
7
|
+
TRouter extends AnyRouter = AnyRouter,
|
|
8
|
+
>(): TRPCLink<TRouter> {
|
|
9
|
+
// initialized config
|
|
10
|
+
return () => {
|
|
11
|
+
// initialized in app
|
|
12
|
+
const pending: Record<string, Observable<any>> = {};
|
|
13
|
+
return ({ op, next }) => {
|
|
14
|
+
// initialized for request
|
|
15
|
+
|
|
16
|
+
if (op.type !== 'query') {
|
|
17
|
+
// pass through
|
|
18
|
+
return next(op);
|
|
19
|
+
}
|
|
20
|
+
const key = JSON.stringify([op.path, op.input]);
|
|
21
|
+
if (pending[key]) {
|
|
22
|
+
// console.log('hooking into pending', { op });
|
|
23
|
+
return new Observable((observer) => pending[key].subscribe(observer));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const shared$ = new Observable<OperationResult<TRouter, unknown>>(
|
|
27
|
+
(observer) => {
|
|
28
|
+
function reset() {
|
|
29
|
+
delete pending[key];
|
|
30
|
+
}
|
|
31
|
+
const next$ = next(op).subscribe({
|
|
32
|
+
next(v) {
|
|
33
|
+
observer.next(v);
|
|
34
|
+
},
|
|
35
|
+
error(e) {
|
|
36
|
+
reset();
|
|
37
|
+
observer.error(e);
|
|
38
|
+
},
|
|
39
|
+
complete() {
|
|
40
|
+
reset();
|
|
41
|
+
observer.complete();
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
return () => {
|
|
45
|
+
reset();
|
|
46
|
+
next$.unsubscribe();
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
).pipe(share());
|
|
50
|
+
pending[key] = shared$;
|
|
51
|
+
return shared$;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
}
|