@trpc/client 10.0.0-alpha.4 → 10.0.0-alpha.40

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.
Files changed (174) hide show
  1. package/README.md +58 -1
  2. package/dist/TRPCClientError.d.ts +3 -11
  3. package/dist/TRPCClientError.d.ts.map +1 -1
  4. package/dist/createTRPCClient.d.ts +2 -3
  5. package/dist/createTRPCClient.d.ts.map +1 -1
  6. package/dist/createTRPCClientProxy.d.ts +24 -0
  7. package/dist/createTRPCClientProxy.d.ts.map +1 -0
  8. package/dist/{httpUtils-c09d7b79.mjs → httpUtils-089853f6.mjs} +38 -30
  9. package/dist/{httpUtils-1f9e4e3c.js → httpUtils-a0169eef.js} +38 -29
  10. package/dist/index.d.ts +2 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +240 -102
  13. package/dist/index.mjs +228 -94
  14. package/dist/internals/TRPCClient.d.ts +14 -17
  15. package/dist/internals/TRPCClient.d.ts.map +1 -1
  16. package/dist/internals/dataLoader.d.ts +7 -4
  17. package/dist/internals/dataLoader.d.ts.map +1 -1
  18. package/dist/links/dedupeLink.d.ts.map +1 -1
  19. package/dist/links/httpBatchLink.d.ts +5 -2
  20. package/dist/links/httpBatchLink.d.ts.map +1 -1
  21. package/dist/links/httpBatchLink.js +197 -69
  22. package/dist/links/httpBatchLink.mjs +197 -69
  23. package/dist/links/httpLink.d.ts +1 -1
  24. package/dist/links/httpLink.d.ts.map +1 -1
  25. package/dist/links/httpLink.js +5 -5
  26. package/dist/links/httpLink.mjs +5 -5
  27. package/dist/links/index.d.ts +9 -0
  28. package/dist/links/index.d.ts.map +1 -0
  29. package/dist/links/internals/createChain.d.ts.map +1 -1
  30. package/dist/links/internals/httpUtils.d.ts +30 -0
  31. package/dist/links/internals/httpUtils.d.ts.map +1 -0
  32. package/dist/links/internals/transformOperationResult.d.ts +17 -3
  33. package/dist/links/internals/transformOperationResult.d.ts.map +1 -1
  34. package/dist/links/loggerLink.d.ts.map +1 -1
  35. package/dist/links/loggerLink.js +2 -3
  36. package/dist/links/loggerLink.mjs +1 -2
  37. package/dist/links/retryLink.d.ts.map +1 -1
  38. package/dist/links/splitLink.d.ts +1 -1
  39. package/dist/links/splitLink.d.ts.map +1 -1
  40. package/dist/links/splitLink.js +3 -25
  41. package/dist/links/splitLink.mjs +2 -28
  42. package/dist/links/types.d.ts +12 -9
  43. package/dist/links/types.d.ts.map +1 -1
  44. package/dist/links/wsLink.d.ts +3 -3
  45. package/dist/links/wsLink.d.ts.map +1 -1
  46. package/dist/links/wsLink.js +12 -376
  47. package/dist/links/wsLink.mjs +10 -369
  48. package/dist/splitLink-0202cd7b.mjs +54 -0
  49. package/dist/splitLink-23c5ce5c.js +57 -0
  50. package/dist/wsLink-11ee4922.mjs +439 -0
  51. package/dist/wsLink-807f4ad9.js +455 -0
  52. package/links/httpBatchLink/dist/trpc-client-links-httpBatchLink.cjs.dev.js +4 -4
  53. package/links/httpBatchLink/dist/trpc-client-links-httpBatchLink.cjs.prod.js +4 -4
  54. package/links/httpBatchLink/dist/trpc-client-links-httpBatchLink.esm.js +4 -4
  55. package/links/httpBatchLink/index.d.ts +1 -1
  56. package/links/httpBatchLink/index.js +1 -1
  57. package/links/httpLink/dist/trpc-client-links-httpLink.cjs.dev.js +1 -1
  58. package/links/httpLink/dist/trpc-client-links-httpLink.cjs.prod.js +1 -1
  59. package/links/httpLink/dist/trpc-client-links-httpLink.esm.js +1 -1
  60. package/links/httpLink/index.d.ts +1 -1
  61. package/links/httpLink/index.js +1 -1
  62. package/links/loggerLink/index.d.ts +1 -1
  63. package/links/loggerLink/index.js +1 -1
  64. package/links/splitLink/index.d.ts +1 -1
  65. package/links/splitLink/index.js +1 -1
  66. package/links/wsLink/dist/trpc-client-links-wsLink.cjs.dev.js +3 -1
  67. package/links/wsLink/dist/trpc-client-links-wsLink.cjs.prod.js +3 -1
  68. package/links/wsLink/dist/trpc-client-links-wsLink.esm.js +3 -1
  69. package/links/wsLink/index.d.ts +1 -1
  70. package/links/wsLink/index.js +1 -1
  71. package/package.json +23 -30
  72. package/src/TRPCClientError.ts +5 -13
  73. package/src/createTRPCClient.ts +7 -3
  74. package/src/createTRPCClientProxy.ts +59 -0
  75. package/src/index.ts +2 -1
  76. package/src/internals/TRPCClient.ts +52 -36
  77. package/src/internals/dataLoader.ts +120 -45
  78. package/src/links/dedupeLink.test.ts +1 -1
  79. package/src/links/dedupeLink.ts +6 -7
  80. package/src/links/httpBatchLink.ts +64 -31
  81. package/src/links/httpLink.ts +4 -4
  82. package/src/links/index.ts +8 -0
  83. package/src/links/internals/createChain.test.ts +5 -5
  84. package/src/links/internals/createChain.ts +8 -3
  85. package/src/links/internals/httpUtils.ts +116 -0
  86. package/src/links/internals/transformOperationResult.ts +40 -12
  87. package/src/links/loggerLink.ts +1 -2
  88. package/src/links/retryLink.ts +1 -2
  89. package/src/links/splitLink.test.ts +3 -3
  90. package/src/links/splitLink.ts +5 -5
  91. package/src/links/types.ts +14 -9
  92. package/src/links/wsLink.ts +17 -16
  93. package/dist/TRPCClientError-17b117e1.mjs +0 -81
  94. package/dist/TRPCClientError-ec6bd2ca.js +0 -94
  95. package/dist/createChain-389cc116.mjs +0 -25
  96. package/dist/createChain-864dbb30.js +0 -27
  97. package/dist/internals/transformRPCResponse.d.ts +0 -15
  98. package/dist/internals/transformRPCResponse.d.ts.map +0 -1
  99. package/dist/links/httpUtils.d.ts +0 -22
  100. package/dist/links/httpUtils.d.ts.map +0 -1
  101. package/dist/links/transformerLink.d.ts +0 -4
  102. package/dist/links/transformerLink.d.ts.map +0 -1
  103. package/dist/links/transformerLink.js +0 -75
  104. package/dist/links/transformerLink.mjs +0 -67
  105. package/dist/links/transformerLink.ts.js +0 -1
  106. package/dist/observable-7e66cb56.mjs +0 -102
  107. package/dist/observable-85669100.js +0 -104
  108. package/dist/rx/index.d.ts +0 -3
  109. package/dist/rx/index.d.ts.map +0 -1
  110. package/dist/rx/index.js +0 -9
  111. package/dist/rx/index.mjs +0 -1
  112. package/dist/rx/index.ts.js +0 -1
  113. package/dist/rx/observable.d.ts +0 -4
  114. package/dist/rx/observable.d.ts.map +0 -1
  115. package/dist/rx/operators/index.d.ts +0 -4
  116. package/dist/rx/operators/index.d.ts.map +0 -1
  117. package/dist/rx/operators/index.js +0 -38
  118. package/dist/rx/operators/index.mjs +0 -32
  119. package/dist/rx/operators/index.ts.js +0 -1
  120. package/dist/rx/operators/map.d.ts +0 -3
  121. package/dist/rx/operators/map.d.ts.map +0 -1
  122. package/dist/rx/operators/share.d.ts +0 -6
  123. package/dist/rx/operators/share.d.ts.map +0 -1
  124. package/dist/rx/operators/tap.d.ts +0 -3
  125. package/dist/rx/operators/tap.d.ts.map +0 -1
  126. package/dist/rx/types.d.ts +0 -29
  127. package/dist/rx/types.d.ts.map +0 -1
  128. package/dist/rx/util/identity.d.ts +0 -2
  129. package/dist/rx/util/identity.d.ts.map +0 -1
  130. package/dist/rx/util/observableToPromise.d.ts +0 -10
  131. package/dist/rx/util/observableToPromise.d.ts.map +0 -1
  132. package/dist/rx/util/pipe.d.ts +0 -4
  133. package/dist/rx/util/pipe.d.ts.map +0 -1
  134. package/dist/share-4d79dc49.js +0 -110
  135. package/dist/share-671b63fa.mjs +0 -108
  136. package/dist/tap-538fa07f.mjs +0 -30
  137. package/dist/tap-799a2d33.js +0 -32
  138. package/links/transformerLink/dist/trpc-client-links-transformerLink.cjs.d.ts +0 -1
  139. package/links/transformerLink/dist/trpc-client-links-transformerLink.cjs.dev.js +0 -67
  140. package/links/transformerLink/dist/trpc-client-links-transformerLink.cjs.js +0 -7
  141. package/links/transformerLink/dist/trpc-client-links-transformerLink.cjs.prod.js +0 -67
  142. package/links/transformerLink/dist/trpc-client-links-transformerLink.esm.js +0 -63
  143. package/links/transformerLink/index.d.ts +0 -1
  144. package/links/transformerLink/index.js +0 -1
  145. package/rx/dist/trpc-client-rx.cjs.d.ts +0 -1
  146. package/rx/dist/trpc-client-rx.cjs.dev.js +0 -9
  147. package/rx/dist/trpc-client-rx.cjs.js +0 -7
  148. package/rx/dist/trpc-client-rx.cjs.prod.js +0 -9
  149. package/rx/dist/trpc-client-rx.esm.js +0 -1
  150. package/rx/index.d.ts +0 -1
  151. package/rx/index.js +0 -1
  152. package/rx/operators/dist/trpc-client-rx-operators.cjs.d.ts +0 -1
  153. package/rx/operators/dist/trpc-client-rx-operators.cjs.dev.js +0 -39
  154. package/rx/operators/dist/trpc-client-rx-operators.cjs.js +0 -7
  155. package/rx/operators/dist/trpc-client-rx-operators.cjs.prod.js +0 -39
  156. package/rx/operators/dist/trpc-client-rx-operators.esm.js +0 -33
  157. package/rx/operators/index.d.ts +0 -1
  158. package/rx/operators/index.js +0 -1
  159. package/src/internals/transformRPCResponse.ts +0 -25
  160. package/src/links/httpUtils.ts +0 -94
  161. package/src/links/transformerLink.ts +0 -70
  162. package/src/rx/index.ts +0 -2
  163. package/src/rx/observable.test.ts +0 -83
  164. package/src/rx/observable.ts +0 -70
  165. package/src/rx/operators/index.ts +0 -3
  166. package/src/rx/operators/map.test.ts +0 -92
  167. package/src/rx/operators/map.ts +0 -25
  168. package/src/rx/operators/share.test.ts +0 -60
  169. package/src/rx/operators/share.ts +0 -67
  170. package/src/rx/operators/tap.ts +0 -26
  171. package/src/rx/types.ts +0 -69
  172. package/src/rx/util/identity.ts +0 -3
  173. package/src/rx/util/observableToPromise.ts +0 -49
  174. package/src/rx/util/pipe.ts +0 -22
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trpc/client",
3
- "version": "10.0.0-alpha.4",
3
+ "version": "10.0.0-alpha.40",
4
4
  "description": "tRPC Client lib",
5
5
  "author": "KATT",
6
6
  "license": "MIT",
@@ -10,6 +10,14 @@
10
10
  "url": "git+https://github.com/trpc/trpc.git",
11
11
  "directory": "packages/client"
12
12
  },
13
+ "eslintConfig": {
14
+ "rules": {
15
+ "no-restricted-imports": [
16
+ "error",
17
+ "@trpc/client"
18
+ ]
19
+ }
20
+ },
13
21
  "main": "dist/index.js",
14
22
  "module": "dist/index.mjs",
15
23
  "typings": "dist/index.d.ts",
@@ -19,68 +27,53 @@
19
27
  "require": "./dist/index.js",
20
28
  "default": "./dist/index.js"
21
29
  },
22
- "./links/httpBatchLink": {
23
- "import": "./dist/links/httpBatchLink.mjs",
24
- "require": "./dist/links/httpBatchLink.js",
25
- "default": "./dist/links/httpBatchLink.js"
26
- },
27
30
  "./links/httpLink": {
28
31
  "import": "./dist/links/httpLink.mjs",
29
32
  "require": "./dist/links/httpLink.js",
30
33
  "default": "./dist/links/httpLink.js"
31
34
  },
32
- "./links/loggerLink": {
33
- "import": "./dist/links/loggerLink.mjs",
34
- "require": "./dist/links/loggerLink.js",
35
- "default": "./dist/links/loggerLink.js"
35
+ "./links/httpBatchLink": {
36
+ "import": "./dist/links/httpBatchLink.mjs",
37
+ "require": "./dist/links/httpBatchLink.js",
38
+ "default": "./dist/links/httpBatchLink.js"
36
39
  },
37
40
  "./links/splitLink": {
38
41
  "import": "./dist/links/splitLink.mjs",
39
42
  "require": "./dist/links/splitLink.js",
40
43
  "default": "./dist/links/splitLink.js"
41
44
  },
42
- "./links/transformerLink": {
43
- "import": "./dist/links/transformerLink.mjs",
44
- "require": "./dist/links/transformerLink.js",
45
- "default": "./dist/links/transformerLink.js"
45
+ "./links/loggerLink": {
46
+ "import": "./dist/links/loggerLink.mjs",
47
+ "require": "./dist/links/loggerLink.js",
48
+ "default": "./dist/links/loggerLink.js"
46
49
  },
47
50
  "./links/wsLink": {
48
51
  "import": "./dist/links/wsLink.mjs",
49
52
  "require": "./dist/links/wsLink.js",
50
53
  "default": "./dist/links/wsLink.js"
51
- },
52
- "./rx": {
53
- "import": "./dist/rx/index.mjs",
54
- "require": "./dist/rx/index.js",
55
- "default": "./dist/rx/index.js"
56
- },
57
- "./rx/operators": {
58
- "import": "./dist/rx/operators/index.mjs",
59
- "require": "./dist/rx/operators/index.js",
60
- "default": "./dist/rx/operators/index.js"
61
54
  }
62
55
  },
63
56
  "files": [
64
57
  "README.md",
65
58
  "dist",
66
59
  "links",
67
- "src",
68
- "rx"
60
+ "src"
69
61
  ],
70
62
  "scripts": {
71
- "build": "rollup -c"
63
+ "build": "rollup -c",
64
+ "ts-watch": "tsc --project tsconfig.watch.json"
72
65
  },
73
66
  "dependencies": {
74
67
  "@babel/runtime": "^7.9.0"
75
68
  },
76
69
  "peerDependencies": {
77
- "@trpc/server": "10.0.0-alpha.4"
70
+ "@trpc/server": "10.0.0-alpha.40"
78
71
  },
79
72
  "devDependencies": {
80
- "@trpc/server": "10.0.0-alpha.4"
73
+ "@trpc/server": "10.0.0-alpha.40"
81
74
  },
82
75
  "publishConfig": {
83
76
  "access": "public"
84
77
  },
85
- "gitHead": "ef9f7f1d36a26339b96069bba001ea0fe5768bb3"
78
+ "gitHead": "2af7a0070f3bc01b81fe6f14f591e77c549520a7"
86
79
  }
@@ -1,4 +1,4 @@
1
- import { AnyRouter, inferRouterError, Maybe } from '@trpc/server';
1
+ import { AnyRouter, Maybe, inferRouterError } from '@trpc/server';
2
2
  import { TRPCErrorResponse } from '@trpc/server/rpc';
3
3
 
4
4
  export interface TRPCClientErrorLike<TRouter extends AnyRouter> {
@@ -11,10 +11,6 @@ export class TRPCClientError<TRouter extends AnyRouter>
11
11
  extends Error
12
12
  implements TRPCClientErrorLike<TRouter>
13
13
  {
14
- /**
15
- * @deprecated use `cause`
16
- */
17
- public readonly originalError;
18
14
  public readonly cause;
19
15
  public readonly shape: Maybe<inferRouterError<TRouter>>;
20
16
  public readonly data: Maybe<inferRouterError<TRouter>['data']>;
@@ -24,15 +20,11 @@ export class TRPCClientError<TRouter extends AnyRouter>
24
20
  message: string,
25
21
  opts?: {
26
22
  result: Maybe<TRPCErrorResponse<inferRouterError<TRouter>>>;
27
- /**
28
- * @deprecated use `cause`
29
- **/
30
- originalError?: Maybe<Error>;
31
- cause?: Maybe<Error>;
23
+ cause?: Error;
32
24
  meta?: Record<string, unknown>;
33
25
  },
34
26
  ) {
35
- const cause = opts?.cause ?? opts?.originalError;
27
+ const cause = opts?.cause;
36
28
 
37
29
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
38
30
  // @ts-ignore https://github.com/tc39/proposal-error-cause
@@ -40,7 +32,7 @@ export class TRPCClientError<TRouter extends AnyRouter>
40
32
 
41
33
  this.meta = opts?.meta;
42
34
 
43
- this.cause = this.originalError = cause;
35
+ this.cause = cause;
44
36
  this.shape = opts?.result?.error;
45
37
  this.data = opts?.result?.error.data;
46
38
  this.name = 'TRPCClientError';
@@ -55,7 +47,7 @@ export class TRPCClientError<TRouter extends AnyRouter>
55
47
  if (!(cause instanceof Error)) {
56
48
  return new TRPCClientError<TRouter>((cause.error as any).message ?? '', {
57
49
  ...opts,
58
- cause: null,
50
+ cause: undefined,
59
51
  result: cause,
60
52
  });
61
53
  }
@@ -1,19 +1,23 @@
1
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
+
1
3
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
4
  import type { AnyRouter } from '@trpc/server';
3
5
  import {
4
- CreateTRPCClientOptions,
5
6
  TRPCClient as Client,
7
+ CreateTRPCClientOptions,
6
8
  } from './internals/TRPCClient';
7
9
 
8
10
  export function createTRPCClient<TRouter extends AnyRouter>(
9
11
  opts: CreateTRPCClientOptions<TRouter>,
10
12
  ) {
11
- return new Client<TRouter>(opts);
13
+ const client = new Client<TRouter>(opts);
14
+ return client;
12
15
  }
13
16
 
14
- export type TRPCClient<TRouter extends AnyRouter> = Client<TRouter>;
17
+ // Also the client created above needs to somehow be like `TRPCClient<Router> & Omit<Router, 'createCaller' | 'createProcedure' | '_def' | 'transformer' | 'errorFormatter' | 'getErrorShape>`
15
18
 
16
19
  export type {
17
20
  TRPCRequestOptions,
18
21
  CreateTRPCClientOptions,
22
+ TRPCClient,
19
23
  } from './internals/TRPCClient';
@@ -0,0 +1,59 @@
1
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
+
3
+ /* eslint-disable @typescript-eslint/no-explicit-any */
4
+ import type {
5
+ AnyRouter,
6
+ OmitNeverKeys,
7
+ Procedure,
8
+ ProcedureArgs,
9
+ ProcedureRouterRecord,
10
+ ProcedureType,
11
+ inferProcedureOutput,
12
+ } from '@trpc/server';
13
+ import { createProxy } from '@trpc/server/shared';
14
+ import { TRPCClient as Client } from './internals/TRPCClient';
15
+
16
+ type Resolver<TProcedure extends Procedure<any>> = (
17
+ ...args: ProcedureArgs<TProcedure['_def']>
18
+ ) => Promise<inferProcedureOutput<TProcedure>>;
19
+
20
+ type DecorateProcedure<TProcedure extends Procedure<any>> = OmitNeverKeys<{
21
+ query: TProcedure extends { _query: true } ? Resolver<TProcedure> : never;
22
+
23
+ mutate: TProcedure extends { _mutation: true } ? Resolver<TProcedure> : never;
24
+
25
+ subscribe: TProcedure extends { _subscription: true }
26
+ ? Resolver<TProcedure>
27
+ : never;
28
+ }>;
29
+
30
+ type assertProcedure<T> = T extends Procedure<any> ? T : never;
31
+
32
+ /**
33
+ * @internal
34
+ */
35
+ type DecoratedProcedureRecord<TProcedures extends ProcedureRouterRecord> = {
36
+ [TKey in keyof TProcedures]: TProcedures[TKey] extends AnyRouter
37
+ ? DecoratedProcedureRecord<TProcedures[TKey]['_def']['record']>
38
+ : DecorateProcedure<assertProcedure<TProcedures[TKey]>>;
39
+ };
40
+
41
+ const clientCallTypeMap: Record<keyof DecorateProcedure<any>, ProcedureType> = {
42
+ query: 'query',
43
+ mutate: 'mutation',
44
+ subscribe: 'subscription',
45
+ };
46
+
47
+ export function createTRPCClientProxy<TRouter extends AnyRouter>(
48
+ client: Client<TRouter>,
49
+ ) {
50
+ const proxy = createProxy(({ path, args }) => {
51
+ const pathCopy = [...path];
52
+ const clientCallType = pathCopy.pop()! as keyof DecorateProcedure<any>;
53
+ const procedureType = clientCallTypeMap[clientCallType];
54
+
55
+ const fullPath = pathCopy.join('.');
56
+ return (client as any)[procedureType](fullPath, ...args);
57
+ });
58
+ return proxy as DecoratedProcedureRecord<TRouter['_def']['record']>;
59
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './createTRPCClient';
2
+ export * from './createTRPCClientProxy';
2
3
  export * from './getFetch';
3
- export * from './links/types';
4
4
  export * from './TRPCClientError';
5
+ export * from './links';
@@ -1,42 +1,42 @@
1
1
  import {
2
2
  AnyRouter,
3
+ ClientDataTransformerOptions,
4
+ DataTransformer,
3
5
  inferHandlerInput,
4
6
  inferProcedureInput,
5
7
  inferProcedureOutput,
6
8
  inferSubscriptionOutput,
7
9
  } from '@trpc/server';
8
- import { TRPCResult } from '@trpc/server/rpc';
10
+ import {
11
+ Observer,
12
+ Unsubscribable,
13
+ inferObservableValue,
14
+ observableToPromise,
15
+ share,
16
+ } from '@trpc/server/observable';
17
+ import { TRPCResultMessage } from '@trpc/server/rpc';
9
18
  import { CancelFn } from '..';
19
+ import { TRPCClientError } from '../TRPCClientError';
10
20
  import { getFetch } from '../getFetch';
11
- import { httpBatchLink } from '../links/httpBatchLink';
21
+ import { httpBatchLink } from '../links';
12
22
  import { createChain } from '../links/internals/createChain';
13
- import { transformOperationResult } from '../links/internals/transformOperationResult';
23
+ import {
24
+ transformOperationResult,
25
+ transformSubscriptionOperationResult,
26
+ } from '../links/internals/transformOperationResult';
14
27
  import {
15
28
  HTTPHeaders,
16
- LinkRuntime,
17
29
  OperationContext,
18
30
  OperationLink,
31
+ TRPCClientRuntime,
19
32
  TRPCLink,
20
33
  } from '../links/types';
21
- import { UnsubscribeFn } from '../rx';
22
- import { inferObservableValue } from '../rx/observable';
23
- import { share } from '../rx/operators';
24
- import { Observer } from '../rx/types';
25
- import { observableToPromise } from '../rx/util/observableToPromise';
26
- import { TRPCClientError } from '../TRPCClientError';
27
34
  import { getAbortController } from './fetchHelpers';
28
35
 
29
36
  type CancellablePromise<T = unknown> = Promise<T> & {
30
37
  cancel: CancelFn;
31
38
  };
32
39
 
33
- /**
34
- * @deprecated no longer used
35
- */
36
- export interface FetchOptions {
37
- fetch?: typeof fetch;
38
- AbortController?: typeof AbortController;
39
- }
40
40
  let idCounter = 0;
41
41
  function getRequestId() {
42
42
  return ++idCounter;
@@ -54,6 +54,11 @@ interface CreateTRPCClientBaseOptions {
54
54
  * headers to be set on outgoing requests / callback that of said headers
55
55
  */
56
56
  headers?: HTTPHeaders | (() => HTTPHeaders | Promise<HTTPHeaders>);
57
+ /**
58
+ * Data transformer
59
+ * @link https://trpc.io/docs/data-transformers
60
+ **/
61
+ transformer?: ClientDataTransformerOptions;
57
62
  }
58
63
 
59
64
  /** @internal */
@@ -69,7 +74,7 @@ export interface CreateTRPCClientWithURLOptions
69
74
  export interface CreateTRPCClientWithLinksOptions<TRouter extends AnyRouter>
70
75
  extends CreateTRPCClientBaseOptions {
71
76
  /**
72
- * @link http://localhost:3000/docs/links
77
+ * @link https://trpc.io/docs/links
73
78
  **/
74
79
  links: TRPCLink<TRouter>[];
75
80
  }
@@ -88,23 +93,37 @@ export type CreateTRPCClientOptions<TRouter extends AnyRouter> =
88
93
  | CreateTRPCClientWithURLOptions;
89
94
  export class TRPCClient<TRouter extends AnyRouter> {
90
95
  private readonly links: OperationLink<TRouter>[];
91
- public readonly runtime: LinkRuntime;
96
+ public readonly runtime: TRPCClientRuntime;
92
97
 
93
98
  constructor(opts: CreateTRPCClientOptions<TRouter>) {
94
99
  const _fetch = getFetch(opts?.fetch);
95
100
  const AC = getAbortController(opts?.AbortController);
96
101
 
97
- function getHeadersFn(): LinkRuntime['headers'] {
102
+ function getHeadersFn(): TRPCClientRuntime['headers'] {
98
103
  if (opts.headers) {
99
104
  const headers = opts.headers;
100
105
  return typeof headers === 'function' ? headers : () => headers;
101
106
  }
102
107
  return () => ({});
103
108
  }
109
+
110
+ const transformer: DataTransformer = opts.transformer
111
+ ? 'input' in opts.transformer
112
+ ? {
113
+ serialize: opts.transformer.input.serialize,
114
+ deserialize: opts.transformer.output.deserialize,
115
+ }
116
+ : opts.transformer
117
+ : {
118
+ serialize: (data) => data,
119
+ deserialize: (data) => data,
120
+ };
121
+
104
122
  this.runtime = {
105
123
  AbortController: AC as any,
106
124
  fetch: _fetch,
107
125
  headers: getHeadersFn(),
126
+ transformer,
108
127
  };
109
128
 
110
129
  if ('links' in opts) {
@@ -155,9 +174,9 @@ export class TRPCClient<TRouter extends AnyRouter> {
155
174
  (resolve, reject) => {
156
175
  promise
157
176
  .then((result) => {
158
- const transformed = transformOperationResult(result);
177
+ const transformed = transformOperationResult(result, this.runtime);
159
178
  if (transformed.ok) {
160
- resolve(transformed.data as any);
179
+ resolve(transformed.data);
161
180
  return;
162
181
  }
163
182
  reject(transformed.error);
@@ -189,7 +208,6 @@ export class TRPCClient<TRouter extends AnyRouter> {
189
208
  context,
190
209
  });
191
210
  }
192
-
193
211
  public mutation<
194
212
  TMutations extends TRouter['_def']['mutations'],
195
213
  TPath extends string & keyof TMutations,
@@ -217,25 +235,26 @@ export class TRPCClient<TRouter extends AnyRouter> {
217
235
  path: TPath,
218
236
  input: TInput,
219
237
  opts: TRPCRequestOptions &
220
- Partial<Observer<TRPCResult<TOutput>, TRPCClientError<TRouter>>>,
221
- ): UnsubscribeFn {
238
+ Partial<Observer<TRPCResultMessage<TOutput>, TRPCClientError<TRouter>>>,
239
+ ): Unsubscribable {
222
240
  const observable$ = this.$request<TInput, TOutput>({
223
241
  type: 'subscription',
224
242
  path,
225
243
  input,
226
244
  context: opts.context,
227
245
  });
228
- const observer = observable$.subscribe({
246
+ const runtime = this.runtime;
247
+ return observable$.subscribe({
229
248
  next(result) {
230
- if ('error' in result.data) {
231
- const err = TRPCClientError.from(result.data, {
232
- meta: result.context,
233
- });
234
-
235
- opts.error?.(err);
249
+ const transformed = transformSubscriptionOperationResult(
250
+ result,
251
+ runtime,
252
+ );
253
+ if (transformed.ok) {
254
+ opts.next?.(transformed.data);
236
255
  return;
237
256
  }
238
- opts.next?.(result.data.result);
257
+ opts.error?.(transformed.error);
239
258
  },
240
259
  error(err) {
241
260
  opts.error?.(err);
@@ -244,8 +263,5 @@ export class TRPCClient<TRouter extends AnyRouter> {
244
263
  opts.complete?.();
245
264
  },
246
265
  });
247
- return () => {
248
- observer.unsubscribe();
249
- };
250
266
  }
251
267
  }
@@ -1,18 +1,32 @@
1
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
1
2
  import { CancelFn, PromiseAndCancel } from '../links/types';
2
3
 
3
4
  type BatchItem<TKey, TValue> = {
4
- cancelled: boolean;
5
+ aborted: boolean;
5
6
  key: TKey;
6
7
  resolve: (value: TValue) => void;
7
8
  reject: (error: Error) => void;
9
+ batch: Batch<TKey, TValue> | null;
8
10
  };
9
11
  type Batch<TKey, TValue> = {
10
12
  items: BatchItem<TKey, TValue>[];
11
13
  cancel: CancelFn;
12
14
  };
13
- type BatchLoadFn<TKey, TValue> = (keys: TKey[]) => {
14
- promise: Promise<TValue[]>;
15
- cancel: CancelFn;
15
+ type BatchLoader<TKey, TValue> = {
16
+ validate: (keys: TKey[]) => boolean;
17
+ fetch: (keys: TKey[]) => {
18
+ promise: Promise<TValue[]>;
19
+ cancel: CancelFn;
20
+ };
21
+ };
22
+
23
+ /**
24
+ * A function that should never be called unless we messed something up.
25
+ */
26
+ const throwFatalError = () => {
27
+ throw new Error(
28
+ 'Something went wrong. Please submit an issue at https://github.com/trpc/trpc/issues/new',
29
+ );
16
30
  };
17
31
 
18
32
  /**
@@ -20,67 +34,128 @@ type BatchLoadFn<TKey, TValue> = (keys: TKey[]) => {
20
34
  * Less configuration, no caching, and allows you to cancel requests
21
35
  * When cancelling a single fetch the whole batch will be cancelled only when _all_ items are cancelled
22
36
  */
23
- export function dataLoader<TKey, TValue>(fetchMany: BatchLoadFn<TKey, TValue>) {
24
- let batch: Batch<TKey, TValue> | null = null;
25
- let dispatchTimer: NodeJS.Timer | number | null = null;
37
+ export function dataLoader<TKey, TValue>(
38
+ batchLoader: BatchLoader<TKey, TValue>,
39
+ ) {
40
+ let pendingItems: BatchItem<TKey, TValue>[] | null = null;
41
+ let dispatchTimer: ReturnType<typeof setTimeout> | null = null;
26
42
 
27
- const destroyTimerAndBatch = () => {
43
+ const destroyTimerAndPendingItems = () => {
28
44
  clearTimeout(dispatchTimer as any);
29
45
  dispatchTimer = null;
30
- batch = null;
46
+ pendingItems = null;
31
47
  };
48
+
49
+ /**
50
+ * Iterate through the items and split them into groups based on the `batchLoader`'s validate function
51
+ */
52
+ function groupItems(items: BatchItem<TKey, TValue>[]) {
53
+ const groupedItems: BatchItem<TKey, TValue>[][] = [[]];
54
+ let index = 0;
55
+ while (true) {
56
+ const item = items[index];
57
+ if (!item) {
58
+ // we're done
59
+ break;
60
+ }
61
+ const lastGroup = groupedItems[groupedItems.length - 1]!;
62
+
63
+ if (item.aborted) {
64
+ // Item was aborted before it was dispatched
65
+ item.reject(new Error('Aborted'));
66
+ index++;
67
+ continue;
68
+ }
69
+
70
+ const isValid = batchLoader.validate(
71
+ lastGroup.concat(item).map((it) => it.key),
72
+ );
73
+
74
+ if (isValid) {
75
+ lastGroup.push(item);
76
+ index++;
77
+ continue;
78
+ }
79
+
80
+ if (lastGroup.length === 0) {
81
+ item.reject(new Error('Input is too big for a single dispatch'));
82
+ index++;
83
+ continue;
84
+ }
85
+ // Create new group, next iteration will try to add the item to that
86
+ groupedItems.push([]);
87
+ }
88
+ return groupedItems;
89
+ }
90
+
32
91
  function dispatch() {
33
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
34
- const batchCopy = batch!;
35
- destroyTimerAndBatch();
36
- const { promise, cancel } = fetchMany(batchCopy.items.map((v) => v.key));
37
- batchCopy.cancel = cancel;
38
-
39
- promise
40
- .then((result) => {
41
- for (let i = 0; i < result.length; i++) {
42
- const value = result[i];
43
- batchCopy.items[i].resolve(value);
44
- }
45
- })
46
- .catch((cause) => {
47
- for (const item of batchCopy.items) {
48
- item.reject(cause);
49
- }
50
- });
92
+ const groupedItems = groupItems(pendingItems!);
93
+ destroyTimerAndPendingItems();
94
+
95
+ // Create batches for each group of items
96
+ for (const items of groupedItems) {
97
+ if (!items.length) {
98
+ continue;
99
+ }
100
+ const batch: Batch<TKey, TValue> = {
101
+ items,
102
+ cancel: throwFatalError,
103
+ };
104
+ for (const item of items) {
105
+ item.batch = batch;
106
+ }
107
+ const { promise, cancel } = batchLoader.fetch(
108
+ batch.items.map((_item) => _item.key),
109
+ );
110
+ batch.cancel = cancel;
111
+
112
+ promise
113
+ .then((result) => {
114
+ for (let i = 0; i < result.length; i++) {
115
+ const value = result[i]!;
116
+ const item = batch.items[i]!;
117
+ item.resolve(value);
118
+ item.batch = null;
119
+ }
120
+ })
121
+ .catch((cause) => {
122
+ for (const item of batch.items) {
123
+ item.reject(cause);
124
+ item.batch = null;
125
+ }
126
+ });
127
+ }
51
128
  }
52
129
  function load(key: TKey): PromiseAndCancel<TValue> {
53
- const batchItem = {
54
- cancelled: false,
130
+ const item: BatchItem<TKey, TValue> = {
131
+ aborted: false,
55
132
  key,
133
+ batch: null,
134
+ resolve: throwFatalError,
135
+ reject: throwFatalError,
56
136
  };
57
137
 
58
- if (!batch) {
59
- batch = {
60
- items: [],
61
- cancel() {
62
- destroyTimerAndBatch();
63
- },
64
- };
65
- }
66
- const thisBatch = batch;
67
138
  const promise = new Promise<TValue>((resolve, reject) => {
68
- const item = batchItem as any as BatchItem<TKey, TValue>;
69
139
  item.reject = reject;
70
140
  item.resolve = resolve;
71
- thisBatch.items.push(item);
141
+
142
+ if (!pendingItems) {
143
+ pendingItems = [];
144
+ }
145
+ pendingItems.push(item);
72
146
  });
147
+
73
148
  if (!dispatchTimer) {
74
149
  dispatchTimer = setTimeout(dispatch);
75
150
  }
76
151
  const cancel = () => {
77
- batchItem.cancelled = true;
152
+ item.aborted = true;
78
153
 
79
- if (thisBatch.items.some((item) => !item.cancelled)) {
80
- // there are still things that can be resolved
81
- return;
154
+ if (item.batch?.items.every((item) => item.aborted)) {
155
+ // All items in the batch have been cancelled
156
+ item.batch.cancel();
157
+ item.batch = null;
82
158
  }
83
- thisBatch.cancel();
84
159
  };
85
160
 
86
161
  return { promise, cancel };
@@ -1,7 +1,7 @@
1
1
  import { waitFor } from '@testing-library/dom';
2
2
  import { AnyRouter } from '@trpc/server';
3
+ import { observable } from '@trpc/server/observable';
3
4
  import { OperationLink } from '..';
4
- import { observable } from '../rx/observable';
5
5
  import { dedupeLink } from './dedupeLink';
6
6
  import { createChain } from './internals/createChain';
7
7