@trpc/client 9.18.0 → 10.0.0-alpha.3

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 (208) hide show
  1. package/dist/TRPCClientError-17b117e1.mjs +81 -0
  2. package/dist/TRPCClientError-ec6bd2ca.js +94 -0
  3. package/dist/{declarations/src/TRPCClientError.d.ts → TRPCClientError.d.ts} +29 -33
  4. package/dist/TRPCClientError.d.ts.map +1 -0
  5. package/dist/createChain-389cc116.mjs +25 -0
  6. package/dist/createChain-864dbb30.js +27 -0
  7. package/dist/{declarations/src/createTRPCClient.d.ts → createTRPCClient.d.ts} +5 -6
  8. package/dist/createTRPCClient.d.ts.map +1 -0
  9. package/dist/{declarations/src/getFetch.d.ts → getFetch.d.ts} +1 -1
  10. package/dist/getFetch.d.ts.map +1 -0
  11. package/dist/httpUtils-1f9e4e3c.js +97 -0
  12. package/dist/httpUtils-c09d7b79.mjs +91 -0
  13. package/dist/{declarations/src/index.d.ts → index.d.ts} +4 -4
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +314 -0
  16. package/dist/index.mjs +299 -0
  17. package/dist/index.ts.js +1 -0
  18. package/dist/{declarations/src/internals → internals}/TRPCClient.d.ts +64 -61
  19. package/dist/internals/TRPCClient.d.ts.map +1 -0
  20. package/dist/{declarations/src/internals → internals}/dataLoader.d.ts +14 -16
  21. package/dist/internals/dataLoader.d.ts.map +1 -0
  22. package/dist/{declarations/src/internals → internals}/fetchHelpers.d.ts +2 -2
  23. package/dist/internals/fetchHelpers.d.ts.map +1 -0
  24. package/dist/{declarations/src/internals → internals}/retryDelay.d.ts +1 -1
  25. package/dist/internals/retryDelay.d.ts.map +1 -0
  26. package/dist/internals/transformRPCResponse.d.ts +15 -0
  27. package/dist/internals/transformRPCResponse.d.ts.map +1 -0
  28. package/dist/links/dedupeLink.d.ts +4 -0
  29. package/dist/links/dedupeLink.d.ts.map +1 -0
  30. package/dist/links/httpBatchLink.d.ts +5 -0
  31. package/dist/links/httpBatchLink.d.ts.map +1 -0
  32. package/dist/links/httpBatchLink.js +189 -0
  33. package/dist/links/httpBatchLink.mjs +185 -0
  34. package/dist/links/httpBatchLink.ts.js +1 -0
  35. package/dist/{declarations/src/links → links}/httpLink.d.ts +4 -3
  36. package/dist/links/httpLink.d.ts.map +1 -0
  37. package/dist/links/httpLink.js +44 -0
  38. package/dist/links/httpLink.mjs +40 -0
  39. package/dist/links/httpLink.ts.js +1 -0
  40. package/dist/links/httpUtils.d.ts +22 -0
  41. package/dist/links/httpUtils.d.ts.map +1 -0
  42. package/dist/links/internals/createChain.d.ts +8 -0
  43. package/dist/links/internals/createChain.d.ts.map +1 -0
  44. package/dist/links/internals/transformOperationResult.d.ts +16 -0
  45. package/dist/links/internals/transformOperationResult.d.ts.map +1 -0
  46. package/dist/{declarations/src/links → links}/loggerLink.d.ts +38 -37
  47. package/dist/links/loggerLink.d.ts.map +1 -0
  48. package/dist/links/loggerLink.js +108 -0
  49. package/dist/links/loggerLink.mjs +99 -0
  50. package/dist/links/loggerLink.ts.js +1 -0
  51. package/dist/links/retryLink.d.ts +6 -0
  52. package/dist/links/retryLink.d.ts.map +1 -0
  53. package/dist/links/splitLink.d.ts +14 -0
  54. package/dist/links/splitLink.d.ts.map +1 -0
  55. package/dist/links/splitLink.js +32 -0
  56. package/dist/links/splitLink.mjs +28 -0
  57. package/dist/links/splitLink.ts.js +1 -0
  58. package/dist/links/transformerLink.d.ts +4 -0
  59. package/dist/links/transformerLink.d.ts.map +1 -0
  60. package/dist/links/transformerLink.js +75 -0
  61. package/dist/links/transformerLink.mjs +67 -0
  62. package/dist/links/transformerLink.ts.js +1 -0
  63. package/dist/links/types.d.ts +40 -0
  64. package/dist/links/types.d.ts.map +1 -0
  65. package/dist/{declarations/src/links → links}/wsLink.d.ts +19 -26
  66. package/dist/links/wsLink.d.ts.map +1 -0
  67. package/dist/links/wsLink.js +384 -0
  68. package/dist/links/wsLink.mjs +370 -0
  69. package/dist/links/wsLink.ts.js +1 -0
  70. package/dist/observable-7e66cb56.mjs +102 -0
  71. package/dist/observable-85669100.js +104 -0
  72. package/dist/rx/index.d.ts +3 -0
  73. package/dist/rx/index.d.ts.map +1 -0
  74. package/dist/rx/index.js +9 -0
  75. package/dist/rx/index.mjs +1 -0
  76. package/dist/rx/index.ts.js +1 -0
  77. package/dist/rx/observable.d.ts +4 -0
  78. package/dist/rx/observable.d.ts.map +1 -0
  79. package/dist/rx/operators/index.d.ts +4 -0
  80. package/dist/rx/operators/index.d.ts.map +1 -0
  81. package/dist/rx/operators/index.js +38 -0
  82. package/dist/rx/operators/index.mjs +32 -0
  83. package/dist/rx/operators/index.ts.js +1 -0
  84. package/dist/rx/operators/map.d.ts +3 -0
  85. package/dist/rx/operators/map.d.ts.map +1 -0
  86. package/dist/rx/operators/share.d.ts +6 -0
  87. package/dist/rx/operators/share.d.ts.map +1 -0
  88. package/dist/rx/operators/tap.d.ts +3 -0
  89. package/dist/rx/operators/tap.d.ts.map +1 -0
  90. package/dist/rx/types.d.ts +29 -0
  91. package/dist/rx/types.d.ts.map +1 -0
  92. package/dist/rx/util/identity.d.ts +2 -0
  93. package/dist/rx/util/identity.d.ts.map +1 -0
  94. package/dist/rx/util/observableToPromise.d.ts +10 -0
  95. package/dist/rx/util/observableToPromise.d.ts.map +1 -0
  96. package/dist/rx/util/pipe.d.ts +4 -0
  97. package/dist/rx/util/pipe.d.ts.map +1 -0
  98. package/dist/share-4d79dc49.js +110 -0
  99. package/dist/share-671b63fa.mjs +108 -0
  100. package/dist/tap-538fa07f.mjs +30 -0
  101. package/dist/tap-799a2d33.js +32 -0
  102. package/links/httpBatchLink/index.d.ts +1 -0
  103. package/links/httpBatchLink/index.js +1 -0
  104. package/links/httpLink/index.d.ts +1 -0
  105. package/links/httpLink/index.js +1 -0
  106. package/links/loggerLink/index.d.ts +1 -0
  107. package/links/loggerLink/index.js +1 -0
  108. package/links/splitLink/index.d.ts +1 -0
  109. package/links/splitLink/index.js +1 -0
  110. package/links/transformerLink/index.d.ts +1 -0
  111. package/links/transformerLink/index.js +1 -0
  112. package/links/wsLink/index.d.ts +1 -0
  113. package/links/wsLink/index.js +1 -0
  114. package/package.json +58 -18
  115. package/rx/dist/trpc-client-rx.cjs.d.ts +1 -0
  116. package/rx/dist/trpc-client-rx.cjs.dev.js +9 -0
  117. package/rx/dist/trpc-client-rx.cjs.js +7 -0
  118. package/rx/dist/trpc-client-rx.cjs.prod.js +9 -0
  119. package/rx/dist/trpc-client-rx.esm.js +1 -0
  120. package/rx/index.d.ts +1 -0
  121. package/rx/index.js +1 -0
  122. package/rx/operators/dist/trpc-client-rx-operators.cjs.d.ts +1 -0
  123. package/rx/operators/dist/trpc-client-rx-operators.cjs.dev.js +39 -0
  124. package/rx/operators/dist/trpc-client-rx-operators.cjs.js +7 -0
  125. package/rx/operators/dist/trpc-client-rx-operators.cjs.prod.js +39 -0
  126. package/rx/operators/dist/trpc-client-rx-operators.esm.js +33 -0
  127. package/rx/operators/index.d.ts +1 -0
  128. package/rx/operators/index.js +1 -0
  129. package/src/TRPCClientError.ts +17 -21
  130. package/src/createTRPCClient.ts +4 -3
  131. package/src/index.ts +1 -1
  132. package/src/internals/TRPCClient.ts +80 -88
  133. package/src/internals/dataLoader.ts +2 -14
  134. package/src/internals/transformRPCResponse.ts +2 -2
  135. package/src/links/dedupeLink.test.ts +134 -0
  136. package/src/links/dedupeLink.ts +53 -0
  137. package/src/links/httpBatchLink.ts +36 -52
  138. package/src/links/httpLink.ts +26 -37
  139. package/src/{internals/httpRequest.ts → links/httpUtils.ts} +30 -21
  140. package/src/links/internals/createChain.test.ts +132 -0
  141. package/src/links/internals/createChain.ts +31 -0
  142. package/src/links/internals/transformOperationResult.ts +25 -0
  143. package/src/links/loggerLink.ts +40 -22
  144. package/src/links/retryLink.ts +45 -14
  145. package/src/links/splitLink.test.ts +56 -0
  146. package/src/links/splitLink.ts +23 -38
  147. package/src/links/transformerLink.ts +70 -0
  148. package/src/links/{core.ts → types.ts} +40 -46
  149. package/src/links/wsLink.ts +56 -77
  150. package/src/rx/index.ts +2 -0
  151. package/src/rx/observable.test.ts +83 -0
  152. package/src/rx/observable.ts +70 -0
  153. package/src/rx/operators/index.ts +3 -0
  154. package/src/rx/operators/map.test.ts +92 -0
  155. package/src/rx/operators/map.ts +25 -0
  156. package/src/rx/operators/share.test.ts +60 -0
  157. package/src/rx/operators/share.ts +67 -0
  158. package/src/rx/operators/tap.ts +26 -0
  159. package/src/rx/types.ts +69 -0
  160. package/src/rx/util/identity.ts +3 -0
  161. package/src/rx/util/observableToPromise.ts +49 -0
  162. package/src/rx/util/pipe.ts +22 -0
  163. package/dist/TRPCClientError-09b8a26b.esm.js +0 -77
  164. package/dist/TRPCClientError-bfee2bf5.cjs.dev.js +0 -79
  165. package/dist/TRPCClientError-e9bf96e9.cjs.prod.js +0 -79
  166. package/dist/declarations/src/TRPCClientError.d.ts.map +0 -1
  167. package/dist/declarations/src/createTRPCClient.d.ts.map +0 -1
  168. package/dist/declarations/src/getFetch.d.ts.map +0 -1
  169. package/dist/declarations/src/index.d.ts.map +0 -1
  170. package/dist/declarations/src/internals/TRPCAbortError.d.ts +0 -4
  171. package/dist/declarations/src/internals/TRPCAbortError.d.ts.map +0 -1
  172. package/dist/declarations/src/internals/TRPCClient.d.ts.map +0 -1
  173. package/dist/declarations/src/internals/dataLoader.d.ts.map +0 -1
  174. package/dist/declarations/src/internals/executeChain.d.ts +0 -8
  175. package/dist/declarations/src/internals/executeChain.d.ts.map +0 -1
  176. package/dist/declarations/src/internals/fetchHelpers.d.ts.map +0 -1
  177. package/dist/declarations/src/internals/httpRequest.d.ts +0 -14
  178. package/dist/declarations/src/internals/httpRequest.d.ts.map +0 -1
  179. package/dist/declarations/src/internals/observable.d.ts +0 -18
  180. package/dist/declarations/src/internals/observable.d.ts.map +0 -1
  181. package/dist/declarations/src/internals/retryDelay.d.ts.map +0 -1
  182. package/dist/declarations/src/internals/transformRPCResponse.d.ts +0 -7
  183. package/dist/declarations/src/internals/transformRPCResponse.d.ts.map +0 -1
  184. package/dist/declarations/src/links/core.d.ts +0 -45
  185. package/dist/declarations/src/links/core.d.ts.map +0 -1
  186. package/dist/declarations/src/links/httpBatchLink.d.ts +0 -7
  187. package/dist/declarations/src/links/httpBatchLink.d.ts.map +0 -1
  188. package/dist/declarations/src/links/httpLink.d.ts.map +0 -1
  189. package/dist/declarations/src/links/loggerLink.d.ts.map +0 -1
  190. package/dist/declarations/src/links/splitLink.d.ts +0 -24
  191. package/dist/declarations/src/links/splitLink.d.ts.map +0 -1
  192. package/dist/declarations/src/links/wsLink.d.ts.map +0 -1
  193. package/dist/transformRPCResponse-57e80136.cjs.dev.js +0 -133
  194. package/dist/transformRPCResponse-739c13d0.cjs.prod.js +0 -133
  195. package/dist/transformRPCResponse-f7f8b0e1.esm.js +0 -129
  196. package/dist/trpc-client.cjs.d.ts +0 -1
  197. package/dist/trpc-client.cjs.dev.js +0 -379
  198. package/dist/trpc-client.cjs.js +0 -7
  199. package/dist/trpc-client.cjs.prod.js +0 -379
  200. package/dist/trpc-client.esm.js +0 -374
  201. package/links/httpBatchLink/package.json +0 -4
  202. package/links/httpLink/package.json +0 -4
  203. package/links/loggerLink/package.json +0 -4
  204. package/links/splitLink/package.json +0 -4
  205. package/links/wsLink/package.json +0 -4
  206. package/src/internals/TRPCAbortError.ts +0 -7
  207. package/src/internals/executeChain.ts +0 -67
  208. package/src/internals/observable.ts +0 -89
@@ -1,25 +1,15 @@
1
1
  import { AnyRouter, ProcedureType } from '@trpc/server';
2
- import { TRPCResponse } from '@trpc/server/rpc';
3
2
  import { dataLoader } from '../internals/dataLoader';
4
- import { httpRequest } from '../internals/httpRequest';
5
- import { transformRPCResponse } from '../internals/transformRPCResponse';
6
- import { TRPCAbortError } from '../internals/TRPCAbortError';
7
- import { TRPCClientError } from '../TRPCClientError';
8
- import { HTTPLinkOptions, TRPCLink } from './core';
9
-
10
- export interface HttpBatchLinkOptions extends HTTPLinkOptions {
11
- maxBatchSize?: number;
12
- }
3
+ import { observable } from '../rx/observable';
4
+ import { TRPCLink } from './types';
5
+ import { HTTPLinkOptions, httpRequest, ResponseShape } from './httpUtils';
13
6
 
14
7
  export function httpBatchLink<TRouter extends AnyRouter>(
15
- opts: HttpBatchLinkOptions,
8
+ opts: HTTPLinkOptions,
16
9
  ): TRPCLink<TRouter> {
17
- const { url, maxBatchSize } = opts;
18
- // initialized config
10
+ const { url } = opts;
19
11
  return (runtime) => {
20
- // initialized in app
21
12
  type Key = { id: number; path: string; input: unknown };
22
-
23
13
  const fetcher = (type: ProcedureType) => (keyInputPairs: Key[]) => {
24
14
  const path = keyInputPairs.map((op) => op.path).join(',');
25
15
  const inputs = keyInputPairs.map((op) => op.input);
@@ -33,53 +23,47 @@ export function httpBatchLink<TRouter extends AnyRouter>(
33
23
  });
34
24
 
35
25
  return {
36
- promise: promise.then((res: unknown[] | unknown) => {
37
- if (!Array.isArray(res)) {
38
- return keyInputPairs.map(() => res);
39
- }
40
- return res;
26
+ promise: promise.then((res) => {
27
+ const resJSON = Array.isArray(res.json)
28
+ ? res.json
29
+ : keyInputPairs.map(() => res.json);
30
+
31
+ const result = resJSON.map((item) => ({
32
+ meta: res.meta,
33
+ json: item,
34
+ }));
35
+
36
+ return result;
41
37
  }),
42
38
  cancel,
43
39
  };
44
40
  };
45
-
46
- const query = dataLoader<Key, TRPCResponse>(fetcher('query'), {
47
- maxBatchSize,
48
- });
49
-
50
- const mutation = dataLoader<Key, TRPCResponse>(fetcher('mutation'), {
51
- maxBatchSize,
52
- });
53
-
54
- const subscription = dataLoader<Key, TRPCResponse>(
41
+ const query = dataLoader<Key, ResponseShape>(fetcher('query'));
42
+ const mutation = dataLoader<Key, ResponseShape>(fetcher('mutation'));
43
+ const subscription = dataLoader<Key, ResponseShape>(
55
44
  fetcher('subscription'),
56
- { maxBatchSize },
57
45
  );
58
46
 
59
47
  const loaders = { query, subscription, mutation };
48
+ return ({ op }) => {
49
+ return observable((observer) => {
50
+ const loader = loaders[op.type];
51
+ const { promise, cancel } = loader.load(op);
60
52
 
61
- return ({ op, prev, onDestroy }) => {
62
- const loader = loaders[op.type];
63
- const { promise, cancel } = loader.load(op);
64
- let isDone = false;
65
- const prevOnce: typeof prev = (result) => {
66
- if (isDone) {
67
- return;
68
- }
69
- isDone = true;
70
- prev(result);
71
- };
72
- onDestroy(() => {
73
- prevOnce(TRPCClientError.from(new TRPCAbortError(), { isDone: true }));
74
- cancel();
53
+ promise
54
+ .then((res) => {
55
+ observer.next({
56
+ context: res.meta,
57
+ data: res.json as any,
58
+ });
59
+ observer.complete();
60
+ })
61
+ .catch((err) => observer.error(err as any));
62
+
63
+ return () => {
64
+ cancel();
65
+ };
75
66
  });
76
- promise
77
- .then((envelope) => {
78
- prevOnce(transformRPCResponse({ envelope, runtime }));
79
- })
80
- .catch((cause) => {
81
- prevOnce(TRPCClientError.from<TRouter>(cause));
82
- });
83
67
  };
84
68
  };
85
69
  }
@@ -1,46 +1,35 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
- import { TRPCClientError } from '../TRPCClientError';
3
- import { transformRPCResponse } from '../internals/transformRPCResponse';
4
- import { httpRequest } from '../internals/httpRequest';
5
- import { HTTPLinkOptions, TRPCLink } from './core';
6
- import { TRPCAbortError } from '../internals/TRPCAbortError';
2
+ import { observable } from '../rx/observable';
3
+ import { TRPCLink } from './types';
4
+ import { HTTPLinkOptions, httpRequest } from './httpUtils';
7
5
 
8
6
  export function httpLink<TRouter extends AnyRouter>(
9
7
  opts: HTTPLinkOptions,
10
8
  ): TRPCLink<TRouter> {
11
9
  const { url } = opts;
10
+ return (runtime) =>
11
+ ({ op }) =>
12
+ observable((observer) => {
13
+ const { path, input, type } = op;
14
+ const { promise, cancel } = httpRequest({
15
+ runtime,
16
+ path,
17
+ input,
18
+ type,
19
+ url,
20
+ });
21
+ promise
22
+ .then((res) => {
23
+ observer.next({
24
+ context: res.meta,
25
+ data: res.json as any,
26
+ });
27
+ observer.complete();
28
+ })
29
+ .catch(observer.error);
12
30
 
13
- // initialized config
14
- return (runtime) => {
15
- // initialized in app
16
- return ({ op, prev, onDestroy }) => {
17
- const { path, input, type } = op;
18
- const { promise, cancel } = httpRequest({
19
- runtime,
20
- type,
21
- input,
22
- url,
23
- path,
24
- });
25
- let isDone = false;
26
- const prevOnce: typeof prev = (result) => {
27
- if (isDone) {
28
- return;
29
- }
30
- isDone = true;
31
- prev(result);
32
- };
33
- onDestroy(() => {
34
- prevOnce(TRPCClientError.from(new TRPCAbortError(), { isDone: true }));
35
- cancel();
31
+ return () => {
32
+ cancel();
33
+ };
36
34
  });
37
- promise
38
- .then((envelope) => {
39
- prevOnce(transformRPCResponse({ envelope, runtime }));
40
- })
41
- .catch((cause) => {
42
- prevOnce(TRPCClientError.from(cause));
43
- });
44
- };
45
- };
46
35
  }
@@ -1,6 +1,8 @@
1
1
  import { ProcedureType } from '@trpc/server';
2
- import { TRPCResponse } from '@trpc/server/rpc';
3
- import { LinkRuntimeOptions, PromiseAndCancel } from '../links/core';
2
+ import { LinkRuntime, PromiseAndCancel } from './types';
3
+ export interface HTTPLinkOptions {
4
+ url: string;
5
+ }
4
6
 
5
7
  // https://github.com/trpc/trpc/pull/669
6
8
  function arrayToDict(array: unknown[]) {
@@ -11,28 +13,30 @@ function arrayToDict(array: unknown[]) {
11
13
  }
12
14
  return dict;
13
15
  }
16
+ const METHOD = {
17
+ query: 'GET',
18
+ mutation: 'POST',
19
+ subscription: 'PATCH',
20
+ } as const;
14
21
 
15
- export function httpRequest<TResponseShape = TRPCResponse>(
22
+ export interface ResponseShape {
23
+ json: unknown;
24
+ meta: {
25
+ response: Response;
26
+ };
27
+ }
28
+ export function httpRequest(
16
29
  props: {
17
- runtime: LinkRuntimeOptions;
30
+ runtime: LinkRuntime;
18
31
  type: ProcedureType;
19
32
  path: string;
20
33
  url: string;
21
34
  } & ({ inputs: unknown[] } | { input: unknown }),
22
- ): PromiseAndCancel<TResponseShape> {
35
+ ): PromiseAndCancel<ResponseShape> {
23
36
  const { type, runtime: rt, path } = props;
24
37
  const ac = rt.AbortController ? new rt.AbortController() : null;
25
- const method = {
26
- query: 'GET',
27
- mutation: 'POST',
28
- subscription: 'PATCH',
29
- };
30
- const input =
31
- 'input' in props
32
- ? rt.transformer.serialize(props.input)
33
- : arrayToDict(
34
- props.inputs.map((_input) => rt.transformer.serialize(_input)),
35
- );
38
+
39
+ const input = 'input' in props ? props.input : arrayToDict(props.inputs);
36
40
 
37
41
  function getUrl() {
38
42
  let url = props.url + '/' + path;
@@ -55,13 +59,14 @@ export function httpRequest<TResponseShape = TRPCResponse>(
55
59
  return input !== undefined ? JSON.stringify(input) : undefined;
56
60
  }
57
61
 
58
- const promise = new Promise<TResponseShape>((resolve, reject) => {
62
+ const promise = new Promise<ResponseShape>((resolve, reject) => {
59
63
  const url = getUrl();
60
64
 
65
+ const meta = {} as any as ResponseShape['meta'];
61
66
  Promise.resolve(rt.headers())
62
67
  .then((headers) =>
63
68
  rt.fetch(url, {
64
- method: method[type],
69
+ method: METHOD[type],
65
70
  signal: ac?.signal,
66
71
  body: getBody(),
67
72
  headers: {
@@ -70,11 +75,15 @@ export function httpRequest<TResponseShape = TRPCResponse>(
70
75
  },
71
76
  }),
72
77
  )
73
- .then((res) => {
74
- return res.json();
78
+ .then((_res) => {
79
+ meta.response = _res;
80
+ return _res.json();
75
81
  })
76
82
  .then((json) => {
77
- resolve(json);
83
+ resolve({
84
+ json,
85
+ meta,
86
+ });
78
87
  })
79
88
  .catch(reject);
80
89
  });
@@ -0,0 +1,132 @@
1
+ import { AnyRouter } from '@trpc/server/src';
2
+ import { createChain } from './createChain';
3
+ import { observable } from '../../rx/observable';
4
+
5
+ describe('chain', () => {
6
+ test('trivial', () => {
7
+ const result$ = createChain<AnyRouter, unknown, unknown>({
8
+ links: [
9
+ ({ next, op }) => {
10
+ return observable((observer) => {
11
+ const next$ = next(op).subscribe(observer);
12
+ return () => {
13
+ next$.unsubscribe();
14
+ };
15
+ });
16
+ },
17
+ ({ op }) => {
18
+ return observable((observer) => {
19
+ observer.next({
20
+ context: {},
21
+ data: {
22
+ id: null,
23
+ result: {
24
+ type: 'data',
25
+ data: {
26
+ input: op.input,
27
+ },
28
+ },
29
+ },
30
+ });
31
+ observer.complete();
32
+ });
33
+ },
34
+ ],
35
+ op: {
36
+ type: 'query',
37
+ id: 1,
38
+ input: 'world',
39
+ path: 'hello',
40
+ context: {},
41
+ },
42
+ });
43
+
44
+ const next = jest.fn();
45
+
46
+ result$.subscribe({ next });
47
+ // console.log(next.mock.calls);
48
+ expect(next).toHaveBeenCalledTimes(1);
49
+ });
50
+ test('multiple responses', () => {
51
+ const result$ = createChain<AnyRouter, unknown, unknown>({
52
+ links: [
53
+ ({ next, op }) => {
54
+ return observable((observer) => {
55
+ observer.next({
56
+ context: {},
57
+ data: {
58
+ id: null,
59
+ result: {
60
+ type: 'data',
61
+ data: 'from cache',
62
+ },
63
+ },
64
+ });
65
+ const next$ = next(op).subscribe(observer);
66
+ return () => {
67
+ next$.unsubscribe();
68
+ };
69
+ });
70
+ },
71
+ ({ op }) => {
72
+ return observable((observer) => {
73
+ observer.next({
74
+ data: {
75
+ id: null,
76
+ result: {
77
+ type: 'data',
78
+ data: {
79
+ input: op.input,
80
+ },
81
+ },
82
+ },
83
+ });
84
+ observer.complete();
85
+ });
86
+ },
87
+ ],
88
+ op: {
89
+ type: 'query',
90
+ id: 1,
91
+ input: 'world',
92
+ path: 'hello',
93
+ context: {},
94
+ },
95
+ });
96
+
97
+ const next = jest.fn();
98
+
99
+ result$.subscribe({ next });
100
+
101
+ expect(next).toHaveBeenCalledTimes(2);
102
+ expect(next.mock.calls[0]).toMatchInlineSnapshot(`
103
+ Array [
104
+ Object {
105
+ "context": Object {},
106
+ "data": Object {
107
+ "id": null,
108
+ "result": Object {
109
+ "data": "from cache",
110
+ "type": "data",
111
+ },
112
+ },
113
+ },
114
+ ]
115
+ `);
116
+ expect(next.mock.calls[1]).toMatchInlineSnapshot(`
117
+ Array [
118
+ Object {
119
+ "data": Object {
120
+ "id": null,
121
+ "result": Object {
122
+ "data": Object {
123
+ "input": "world",
124
+ },
125
+ "type": "data",
126
+ },
127
+ },
128
+ },
129
+ ]
130
+ `);
131
+ });
132
+ });
@@ -0,0 +1,31 @@
1
+ import { AnyRouter } from '@trpc/server';
2
+ import { observable } from '../../rx/observable';
3
+ import { Operation, OperationLink, OperationResultObservable } from '../types';
4
+
5
+ /** @internal */
6
+ export function createChain<
7
+ TRouter extends AnyRouter,
8
+ TInput = unknown,
9
+ TOutput = unknown,
10
+ >(opts: {
11
+ links: OperationLink<TRouter, TInput, TOutput>[];
12
+ op: Operation<TInput>;
13
+ }): OperationResultObservable<TRouter, TOutput> {
14
+ return observable((observer) => {
15
+ function execute(index = 0, op = opts.op) {
16
+ const next = opts.links[index];
17
+ const next$ = next({
18
+ op,
19
+ next(nextOp) {
20
+ const nextObserver = execute(index + 1, nextOp);
21
+
22
+ return nextObserver;
23
+ },
24
+ });
25
+ return next$;
26
+ }
27
+
28
+ const obs$ = execute();
29
+ return obs$.subscribe(observer);
30
+ });
31
+ }
@@ -0,0 +1,25 @@
1
+ import { AnyRouter } from '@trpc/server';
2
+ import { TRPCClientError } from '../../TRPCClientError';
3
+ import { OperationResult } from '../types';
4
+
5
+ /** @internal */
6
+ export function transformOperationResult<TRouter extends AnyRouter, TOutput>(
7
+ result: OperationResult<TRouter, TOutput>,
8
+ ) {
9
+ const { context } = result;
10
+
11
+ if ('error' in result.data) {
12
+ const error = TRPCClientError.from<TRouter>(result.data);
13
+ return {
14
+ ok: false,
15
+ error,
16
+ context,
17
+ } as const;
18
+ }
19
+ const data = (result.data.result as any).data as TOutput;
20
+ return {
21
+ ok: true,
22
+ data,
23
+ context,
24
+ } as const;
25
+ }
@@ -1,5 +1,8 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
- import { Operation, OperationResponse, TRPCLink } from './core';
2
+ import { TRPCClientError } from '..';
3
+ import { observable } from '../rx/observable';
4
+ import { tap } from '../rx/operators';
5
+ import { Operation, OperationResult, TRPCLink } from './types';
3
6
 
4
7
  type ConsoleEsque = {
5
8
  log: (...args: any[]) => void;
@@ -12,7 +15,7 @@ type EnableFnOptions<TRouter extends AnyRouter> =
12
15
  })
13
16
  | {
14
17
  direction: 'down';
15
- result: OperationResponse<TRouter>;
18
+ result: OperationResult<TRouter, unknown> | TRPCClientError<TRouter>;
16
19
  };
17
20
  type EnabledFn<TRouter extends AnyRouter> = (
18
21
  opts: EnableFnOptions<TRouter>,
@@ -31,7 +34,7 @@ type LogFnOptions<TRouter extends AnyRouter> = Operation &
31
34
  * Request result
32
35
  */
33
36
  direction: 'down';
34
- result: OperationResponse<TRouter>;
37
+ result: OperationResult<TRouter, unknown> | TRPCClientError<TRouter>;
35
38
  elapsedMs: number;
36
39
  }
37
40
  );
@@ -78,7 +81,7 @@ const defaultLogger =
78
81
  `${css}; font-weight: normal;`,
79
82
  ];
80
83
  if (props.direction === 'up') {
81
- args.push({ input, context });
84
+ args.push({ input, context: context });
82
85
  } else {
83
86
  args.push({
84
87
  input,
@@ -90,7 +93,7 @@ const defaultLogger =
90
93
  const fn: 'error' | 'log' =
91
94
  props.direction === 'down' &&
92
95
  props.result &&
93
- props.result instanceof Error
96
+ (props.result instanceof Error || 'error' in props.result.data)
94
97
  ? 'error'
95
98
  : 'log';
96
99
 
@@ -102,27 +105,42 @@ export function loggerLink<TRouter extends AnyRouter = AnyRouter>(
102
105
  const { enabled = () => true } = opts;
103
106
 
104
107
  const { logger = defaultLogger(opts.console) } = opts;
105
- return () => {
106
- return ({ op, next, prev }) => {
107
- // ->
108
- enabled({ ...op, direction: 'up' }) &&
109
- logger({
110
- ...op,
111
- direction: 'up',
112
- });
113
- const requestStartTime = Date.now();
114
- next(op, (result) => {
115
- const elapsedMs = Date.now() - requestStartTime;
116
108
 
117
- enabled({ ...op, direction: 'down', result }) &&
109
+ return () => {
110
+ return ({ op, next }) => {
111
+ return observable((observer) => {
112
+ // ->
113
+ enabled({ ...op, direction: 'up' }) &&
118
114
  logger({
119
115
  ...op,
120
- direction: 'down',
121
- elapsedMs,
122
- result,
116
+ direction: 'up',
123
117
  });
124
- // <-
125
- prev(result);
118
+ const requestStartTime = Date.now();
119
+ function logResult(
120
+ result: OperationResult<TRouter, unknown> | TRPCClientError<TRouter>,
121
+ ) {
122
+ const elapsedMs = Date.now() - requestStartTime;
123
+
124
+ enabled({ ...op, direction: 'down', result }) &&
125
+ logger({
126
+ ...op,
127
+ direction: 'down',
128
+ elapsedMs,
129
+ result,
130
+ });
131
+ }
132
+ return next(op)
133
+ .pipe(
134
+ tap({
135
+ next(result) {
136
+ logResult(result);
137
+ },
138
+ error(result) {
139
+ logResult(result);
140
+ },
141
+ }),
142
+ )
143
+ .subscribe(observer);
126
144
  });
127
145
  };
128
146
  };
@@ -1,5 +1,7 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
- import { TRPCLink } from './core';
2
+ import { observable } from '../rx/observable';
3
+ import { Unsubscribable } from '../rx/types';
4
+ import { TRPCLink } from './types';
3
5
 
4
6
  export function retryLink<TRouter extends AnyRouter = AnyRouter>(opts: {
5
7
  attempts: number;
@@ -7,20 +9,49 @@ export function retryLink<TRouter extends AnyRouter = AnyRouter>(opts: {
7
9
  // initialized config
8
10
  return () => {
9
11
  // initialized in app
10
- return ({ op, next, prev }) => {
12
+ return ({ op, next }) => {
11
13
  // initialized for request
12
- let attempts = 0;
13
- const fn = () => {
14
- attempts++;
15
- next(op, (result) => {
16
- if (result instanceof Error) {
17
- attempts < opts.attempts ? fn() : prev(result);
18
- } else {
19
- prev(result);
20
- }
21
- });
22
- };
23
- fn();
14
+ return observable((observer) => {
15
+ let next$: Unsubscribable | null = null;
16
+ let attempts = 0;
17
+ let isDone = false;
18
+ function attempt() {
19
+ attempts++;
20
+ next$?.unsubscribe();
21
+ next$ = next(op).subscribe({
22
+ error(error) {
23
+ if (attempts >= opts.attempts) {
24
+ observer.error(error);
25
+ return;
26
+ }
27
+ attempt();
28
+ },
29
+ next(result) {
30
+ if ('result' in result.data) {
31
+ isDone = true;
32
+ observer.next(result);
33
+ return;
34
+ }
35
+ if (attempts >= opts.attempts) {
36
+ isDone = true;
37
+ observer.next(result);
38
+ return;
39
+ }
40
+ attempt();
41
+ },
42
+ complete() {
43
+ if (isDone) {
44
+ observer.complete();
45
+ }
46
+ },
47
+ });
48
+ }
49
+ attempt();
50
+ return () => {
51
+ isDone = true;
52
+ next$?.unsubscribe();
53
+ };
54
+ });
24
55
  };
25
56
  };
26
57
  }