@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.
Files changed (154) 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-3b458753.js +27 -0
  6. package/dist/createChain-b7cb1f5a.mjs +25 -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 +243 -0
  16. package/dist/index.mjs +233 -0
  17. package/dist/index.ts.js +1 -0
  18. package/dist/{declarations/src/internals → internals}/TRPCClient.d.ts +62 -61
  19. package/dist/internals/TRPCClient.d.ts.map +1 -0
  20. package/dist/{declarations/src/internals → internals}/dataLoader.d.ts +16 -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/links/dedupeLink.d.ts +4 -0
  27. package/dist/links/dedupeLink.d.ts.map +1 -0
  28. package/dist/{declarations/src/links → links}/httpBatchLink.d.ts +7 -6
  29. package/dist/links/httpBatchLink.d.ts.map +1 -0
  30. package/dist/links/httpBatchLink.js +195 -0
  31. package/dist/links/httpBatchLink.mjs +191 -0
  32. package/dist/links/httpBatchLink.ts.js +1 -0
  33. package/dist/{declarations/src/links → links}/httpLink.d.ts +4 -3
  34. package/dist/links/httpLink.d.ts.map +1 -0
  35. package/dist/links/httpLink.js +44 -0
  36. package/dist/links/httpLink.mjs +40 -0
  37. package/dist/links/httpLink.ts.js +1 -0
  38. package/dist/links/httpUtils.d.ts +22 -0
  39. package/dist/links/httpUtils.d.ts.map +1 -0
  40. package/dist/links/internals/createChain.d.ts +8 -0
  41. package/dist/links/internals/createChain.d.ts.map +1 -0
  42. package/dist/links/internals/transformOperationResult.d.ts +16 -0
  43. package/dist/links/internals/transformOperationResult.d.ts.map +1 -0
  44. package/dist/{declarations/src/links → links}/loggerLink.d.ts +38 -37
  45. package/dist/links/loggerLink.d.ts.map +1 -0
  46. package/dist/links/loggerLink.js +107 -0
  47. package/dist/links/loggerLink.mjs +98 -0
  48. package/dist/links/loggerLink.ts.js +1 -0
  49. package/dist/links/retryLink.d.ts +6 -0
  50. package/dist/links/retryLink.d.ts.map +1 -0
  51. package/dist/links/splitLink.d.ts +14 -0
  52. package/dist/links/splitLink.d.ts.map +1 -0
  53. package/dist/links/splitLink.js +32 -0
  54. package/dist/links/splitLink.mjs +28 -0
  55. package/dist/links/splitLink.ts.js +1 -0
  56. package/dist/links/transformerLink.d.ts +4 -0
  57. package/dist/links/transformerLink.d.ts.map +1 -0
  58. package/dist/links/transformerLink.js +79 -0
  59. package/dist/links/transformerLink.mjs +71 -0
  60. package/dist/links/transformerLink.ts.js +1 -0
  61. package/dist/links/types.d.ts +39 -0
  62. package/dist/links/types.d.ts.map +1 -0
  63. package/dist/links/wsLink.d.ts +21 -0
  64. package/dist/links/wsLink.d.ts.map +1 -0
  65. package/dist/links/wsLink.js +385 -0
  66. package/dist/links/wsLink.mjs +370 -0
  67. package/dist/links/wsLink.ts.js +1 -0
  68. package/dist/rx.d.ts +11 -0
  69. package/dist/rx.d.ts.map +1 -0
  70. package/dist/rx.js +88 -0
  71. package/dist/rx.mjs +73 -0
  72. package/dist/rx.ts.js +1 -0
  73. package/links/httpBatchLink/index.d.ts +1 -0
  74. package/links/httpBatchLink/index.js +1 -0
  75. package/links/httpLink/index.d.ts +1 -0
  76. package/links/httpLink/index.js +1 -0
  77. package/links/loggerLink/index.d.ts +1 -0
  78. package/links/loggerLink/index.js +1 -0
  79. package/links/splitLink/index.d.ts +1 -0
  80. package/links/splitLink/index.js +1 -0
  81. package/links/transformerLink/index.d.ts +1 -0
  82. package/links/transformerLink/index.js +1 -0
  83. package/links/wsLink/index.d.ts +1 -0
  84. package/links/wsLink/index.js +1 -0
  85. package/package.json +53 -18
  86. package/src/TRPCClientError.ts +17 -21
  87. package/src/createTRPCClient.ts +4 -3
  88. package/src/index.ts +1 -1
  89. package/src/internals/TRPCClient.ts +78 -92
  90. package/src/internals/dataLoader.ts +1 -1
  91. package/src/links/dedupeLink.test.ts +134 -0
  92. package/src/links/dedupeLink.ts +54 -0
  93. package/src/links/httpBatchLink.ts +36 -46
  94. package/src/links/httpLink.ts +26 -37
  95. package/src/{internals/httpRequest.ts → links/httpUtils.ts} +30 -21
  96. package/src/links/internals/createChain.test.ts +132 -0
  97. package/src/links/internals/createChain.ts +31 -0
  98. package/src/links/internals/transformOperationResult.ts +25 -0
  99. package/src/links/loggerLink.ts +39 -22
  100. package/src/links/retryLink.ts +44 -14
  101. package/src/links/splitLink.test.ts +56 -0
  102. package/src/links/splitLink.ts +23 -38
  103. package/src/links/transformerLink.ts +74 -0
  104. package/src/links/types.ts +64 -0
  105. package/src/links/wsLink.ts +57 -77
  106. package/src/rx.ts +50 -0
  107. package/dist/TRPCClientError-09b8a26b.esm.js +0 -77
  108. package/dist/TRPCClientError-bfee2bf5.cjs.dev.js +0 -79
  109. package/dist/TRPCClientError-e9bf96e9.cjs.prod.js +0 -79
  110. package/dist/declarations/src/TRPCClientError.d.ts.map +0 -1
  111. package/dist/declarations/src/createTRPCClient.d.ts.map +0 -1
  112. package/dist/declarations/src/getFetch.d.ts.map +0 -1
  113. package/dist/declarations/src/index.d.ts.map +0 -1
  114. package/dist/declarations/src/internals/TRPCAbortError.d.ts +0 -4
  115. package/dist/declarations/src/internals/TRPCAbortError.d.ts.map +0 -1
  116. package/dist/declarations/src/internals/TRPCClient.d.ts.map +0 -1
  117. package/dist/declarations/src/internals/dataLoader.d.ts.map +0 -1
  118. package/dist/declarations/src/internals/executeChain.d.ts +0 -9
  119. package/dist/declarations/src/internals/executeChain.d.ts.map +0 -1
  120. package/dist/declarations/src/internals/fetchHelpers.d.ts.map +0 -1
  121. package/dist/declarations/src/internals/httpRequest.d.ts +0 -14
  122. package/dist/declarations/src/internals/httpRequest.d.ts.map +0 -1
  123. package/dist/declarations/src/internals/observable.d.ts +0 -18
  124. package/dist/declarations/src/internals/observable.d.ts.map +0 -1
  125. package/dist/declarations/src/internals/retryDelay.d.ts.map +0 -1
  126. package/dist/declarations/src/internals/transformRPCResponse.d.ts +0 -15
  127. package/dist/declarations/src/internals/transformRPCResponse.d.ts.map +0 -1
  128. package/dist/declarations/src/links/core.d.ts +0 -45
  129. package/dist/declarations/src/links/core.d.ts.map +0 -1
  130. package/dist/declarations/src/links/httpBatchLink.d.ts.map +0 -1
  131. package/dist/declarations/src/links/httpLink.d.ts.map +0 -1
  132. package/dist/declarations/src/links/loggerLink.d.ts.map +0 -1
  133. package/dist/declarations/src/links/splitLink.d.ts +0 -24
  134. package/dist/declarations/src/links/splitLink.d.ts.map +0 -1
  135. package/dist/declarations/src/links/wsLink.d.ts +0 -30
  136. package/dist/declarations/src/links/wsLink.d.ts.map +0 -1
  137. package/dist/transformRPCResponse-57e80136.cjs.dev.js +0 -133
  138. package/dist/transformRPCResponse-739c13d0.cjs.prod.js +0 -133
  139. package/dist/transformRPCResponse-f7f8b0e1.esm.js +0 -129
  140. package/dist/trpc-client.cjs.d.ts +0 -1
  141. package/dist/trpc-client.cjs.dev.js +0 -379
  142. package/dist/trpc-client.cjs.js +0 -7
  143. package/dist/trpc-client.cjs.prod.js +0 -379
  144. package/dist/trpc-client.esm.js +0 -374
  145. package/links/httpBatchLink/package.json +0 -4
  146. package/links/httpLink/package.json +0 -4
  147. package/links/loggerLink/package.json +0 -4
  148. package/links/splitLink/package.json +0 -4
  149. package/links/wsLink/package.json +0 -4
  150. package/src/internals/TRPCAbortError.ts +0 -7
  151. package/src/internals/executeChain.ts +0 -67
  152. package/src/internals/observable.ts +0 -89
  153. package/src/internals/transformRPCResponse.ts +0 -25
  154. package/src/links/core.ts +0 -71
@@ -1,23 +1,18 @@
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';
3
+ import { Observable } from 'rxjs';
4
+ import { TRPCLink } from './types';
5
+ import { HTTPLinkOptions, httpRequest, ResponseShape } from './httpUtils';
9
6
 
10
7
  export interface HttpBatchLinkOptions extends HTTPLinkOptions {
11
8
  maxBatchSize?: number;
12
9
  }
13
-
14
10
  export function httpBatchLink<TRouter extends AnyRouter>(
15
11
  opts: HttpBatchLinkOptions,
16
12
  ): TRPCLink<TRouter> {
17
- const { url, maxBatchSize } = opts;
13
+ const { url } = opts;
18
14
  // initialized config
19
15
  return (runtime) => {
20
- // initialized in app
21
16
  type Key = { id: number; path: string; input: unknown };
22
17
 
23
18
  const fetcher = (type: ProcedureType) => (keyInputPairs: Key[]) => {
@@ -33,53 +28,48 @@ export function httpBatchLink<TRouter extends AnyRouter>(
33
28
  });
34
29
 
35
30
  return {
36
- promise: promise.then((res: unknown[] | unknown) => {
37
- if (!Array.isArray(res)) {
38
- return keyInputPairs.map(() => res);
39
- }
40
- return res;
31
+ promise: promise.then((res) => {
32
+ const resJSON = Array.isArray(res.json)
33
+ ? res.json
34
+ : keyInputPairs.map(() => res.json);
35
+
36
+ const result = resJSON.map((item) => ({
37
+ meta: res.meta,
38
+ json: item,
39
+ }));
40
+
41
+ return result;
41
42
  }),
42
43
  cancel,
43
44
  };
44
45
  };
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>(
46
+ const query = dataLoader<Key, ResponseShape>(fetcher('query'), opts);
47
+ const mutation = dataLoader<Key, ResponseShape>(fetcher('mutation'), opts);
48
+ const subscription = dataLoader<Key, ResponseShape>(
55
49
  fetcher('subscription'),
56
- { maxBatchSize },
50
+ opts,
57
51
  );
58
52
 
59
53
  const loaders = { query, subscription, mutation };
54
+ return ({ op }) => {
55
+ return new Observable((observer) => {
56
+ const loader = loaders[op.type];
57
+ const { promise, cancel } = loader.load(op);
60
58
 
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();
59
+ promise
60
+ .then((res) => {
61
+ observer.next({
62
+ context: res.meta,
63
+ data: res.json as any,
64
+ });
65
+ observer.complete();
66
+ })
67
+ .catch((err) => observer.error(err as any));
68
+
69
+ return () => {
70
+ cancel();
71
+ };
75
72
  });
76
- promise
77
- .then((envelope) => {
78
- prevOnce(transformRPCResponse({ envelope, runtime }));
79
- })
80
- .catch((cause) => {
81
- prevOnce(TRPCClientError.from<TRouter>(cause));
82
- });
83
73
  };
84
74
  };
85
75
  }
@@ -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 'rxjs';
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
+ new 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 'rxjs';
4
+
5
+ describe('chain', () => {
6
+ test('trivial', () => {
7
+ const result$ = createChain<AnyRouter, unknown, unknown>({
8
+ links: [
9
+ ({ next, op }) => {
10
+ return new Observable((observer) => {
11
+ const subscription = next(op).subscribe(observer);
12
+ return () => {
13
+ subscription.unsubscribe();
14
+ };
15
+ });
16
+ },
17
+ ({ op }) => {
18
+ return new 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 new 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 new 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 'rxjs';
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 new 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,7 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
- import { Operation, OperationResponse, TRPCLink } from './core';
2
+ import { TRPCClientError } from '..';
3
+ import { Observable, tap } from 'rxjs';
4
+ import { Operation, OperationResult, TRPCLink } from './types';
3
5
 
4
6
  type ConsoleEsque = {
5
7
  log: (...args: any[]) => void;
@@ -12,7 +14,7 @@ type EnableFnOptions<TRouter extends AnyRouter> =
12
14
  })
13
15
  | {
14
16
  direction: 'down';
15
- result: OperationResponse<TRouter>;
17
+ result: OperationResult<TRouter, unknown> | TRPCClientError<TRouter>;
16
18
  };
17
19
  type EnabledFn<TRouter extends AnyRouter> = (
18
20
  opts: EnableFnOptions<TRouter>,
@@ -31,7 +33,7 @@ type LogFnOptions<TRouter extends AnyRouter> = Operation &
31
33
  * Request result
32
34
  */
33
35
  direction: 'down';
34
- result: OperationResponse<TRouter>;
36
+ result: OperationResult<TRouter, unknown> | TRPCClientError<TRouter>;
35
37
  elapsedMs: number;
36
38
  }
37
39
  );
@@ -78,7 +80,7 @@ const defaultLogger =
78
80
  `${css}; font-weight: normal;`,
79
81
  ];
80
82
  if (props.direction === 'up') {
81
- args.push({ input, context });
83
+ args.push({ input, context: context });
82
84
  } else {
83
85
  args.push({
84
86
  input,
@@ -90,7 +92,7 @@ const defaultLogger =
90
92
  const fn: 'error' | 'log' =
91
93
  props.direction === 'down' &&
92
94
  props.result &&
93
- props.result instanceof Error
95
+ (props.result instanceof Error || 'error' in props.result.data)
94
96
  ? 'error'
95
97
  : 'log';
96
98
 
@@ -102,27 +104,42 @@ export function loggerLink<TRouter extends AnyRouter = AnyRouter>(
102
104
  const { enabled = () => true } = opts;
103
105
 
104
106
  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
107
 
117
- enabled({ ...op, direction: 'down', result }) &&
108
+ return () => {
109
+ return ({ op, next }) => {
110
+ return new Observable((observer) => {
111
+ // ->
112
+ enabled({ ...op, direction: 'up' }) &&
118
113
  logger({
119
114
  ...op,
120
- direction: 'down',
121
- elapsedMs,
122
- result,
115
+ direction: 'up',
123
116
  });
124
- // <-
125
- prev(result);
117
+ const requestStartTime = Date.now();
118
+ function logResult(
119
+ result: OperationResult<TRouter, unknown> | TRPCClientError<TRouter>,
120
+ ) {
121
+ const elapsedMs = Date.now() - requestStartTime;
122
+
123
+ enabled({ ...op, direction: 'down', result }) &&
124
+ logger({
125
+ ...op,
126
+ direction: 'down',
127
+ elapsedMs,
128
+ result,
129
+ });
130
+ }
131
+ return next(op)
132
+ .pipe(
133
+ tap({
134
+ next(result) {
135
+ logResult(result);
136
+ },
137
+ error(result) {
138
+ logResult(result);
139
+ },
140
+ }),
141
+ )
142
+ .subscribe(observer);
126
143
  });
127
144
  };
128
145
  };
@@ -1,5 +1,6 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
- import { TRPCLink } from './core';
2
+ import { Observable, Unsubscribable } from 'rxjs';
3
+ import { TRPCLink } from './types';
3
4
 
4
5
  export function retryLink<TRouter extends AnyRouter = AnyRouter>(opts: {
5
6
  attempts: number;
@@ -7,20 +8,49 @@ export function retryLink<TRouter extends AnyRouter = AnyRouter>(opts: {
7
8
  // initialized config
8
9
  return () => {
9
10
  // initialized in app
10
- return ({ op, next, prev }) => {
11
+ return ({ op, next }) => {
11
12
  // 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();
13
+ return new Observable((observer) => {
14
+ let next$: Unsubscribable | null = null;
15
+ let attempts = 0;
16
+ let isDone = false;
17
+ function attempt() {
18
+ attempts++;
19
+ next$?.unsubscribe();
20
+ next$ = next(op).subscribe({
21
+ error(error) {
22
+ if (attempts >= opts.attempts) {
23
+ observer.error(error);
24
+ return;
25
+ }
26
+ attempt();
27
+ },
28
+ next(result) {
29
+ if ('result' in result.data) {
30
+ isDone = true;
31
+ observer.next(result);
32
+ return;
33
+ }
34
+ if (attempts >= opts.attempts) {
35
+ isDone = true;
36
+ observer.next(result);
37
+ return;
38
+ }
39
+ attempt();
40
+ },
41
+ complete() {
42
+ if (isDone) {
43
+ observer.complete();
44
+ }
45
+ },
46
+ });
47
+ }
48
+ attempt();
49
+ return () => {
50
+ isDone = true;
51
+ next$?.unsubscribe();
52
+ };
53
+ });
24
54
  };
25
55
  };
26
56
  }