@trpc/client 10.0.0-alpha.8 → 10.0.0-proxy-alpha.53

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 (180) hide show
  1. package/README.md +58 -1
  2. package/dist/TRPCClientError.d.ts +16 -20
  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 +37 -0
  7. package/dist/createTRPCClientProxy.d.ts.map +1 -0
  8. package/dist/httpUtils-44781613.mjs +76 -0
  9. package/dist/httpUtils-801112a6.js +79 -0
  10. package/dist/index.d.ts +2 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +260 -280
  13. package/dist/index.mjs +253 -271
  14. package/dist/internals/TRPCClient.d.ts +39 -21
  15. package/dist/internals/TRPCClient.d.ts.map +1 -1
  16. package/dist/internals/dataLoader.d.ts +7 -6
  17. package/dist/internals/dataLoader.d.ts.map +1 -1
  18. package/dist/internals/fetchHelpers.d.ts +1 -1
  19. package/dist/internals/fetchHelpers.d.ts.map +1 -1
  20. package/dist/internals/retryDelay.d.ts.map +1 -1
  21. package/dist/links/dedupeLink.d.ts.map +1 -1
  22. package/dist/links/httpBatchLink.d.ts +2 -2
  23. package/dist/links/httpBatchLink.d.ts.map +1 -1
  24. package/dist/links/httpBatchLink.js +189 -172
  25. package/dist/links/httpBatchLink.mjs +189 -172
  26. package/dist/links/httpLink.d.ts +1 -1
  27. package/dist/links/httpLink.d.ts.map +1 -1
  28. package/dist/links/httpLink.js +31 -35
  29. package/dist/links/httpLink.mjs +31 -35
  30. package/dist/links/index.d.ts +9 -0
  31. package/dist/links/index.d.ts.map +1 -0
  32. package/dist/links/internals/createChain.d.ts.map +1 -1
  33. package/dist/links/internals/httpUtils.d.ts +31 -0
  34. package/dist/links/internals/httpUtils.d.ts.map +1 -0
  35. package/dist/links/internals/transformResult.d.ts +28 -0
  36. package/dist/links/internals/transformResult.d.ts.map +1 -0
  37. package/dist/links/loggerLink.d.ts +3 -3
  38. package/dist/links/loggerLink.d.ts.map +1 -1
  39. package/dist/links/loggerLink.js +90 -96
  40. package/dist/links/loggerLink.mjs +90 -91
  41. package/dist/links/retryLink.d.ts.map +1 -1
  42. package/dist/links/splitLink.d.ts +1 -1
  43. package/dist/links/splitLink.d.ts.map +1 -1
  44. package/dist/links/splitLink.js +3 -25
  45. package/dist/links/splitLink.mjs +2 -28
  46. package/dist/links/types.d.ts +13 -12
  47. package/dist/links/types.d.ts.map +1 -1
  48. package/dist/links/wsLink.d.ts +12 -5
  49. package/dist/links/wsLink.d.ts.map +1 -1
  50. package/dist/links/wsLink.js +250 -358
  51. package/dist/links/wsLink.mjs +250 -348
  52. package/dist/splitLink-695ae288.js +48 -0
  53. package/dist/splitLink-ad44a55d.mjs +45 -0
  54. package/dist/transformResult-106791d7.mjs +62 -0
  55. package/dist/transformResult-e15ccdf6.js +65 -0
  56. package/links/httpBatchLink/dist/trpc-client-links-httpBatchLink.cjs.dev.js +15 -13
  57. package/links/httpBatchLink/dist/trpc-client-links-httpBatchLink.cjs.prod.js +15 -13
  58. package/links/httpBatchLink/dist/trpc-client-links-httpBatchLink.esm.js +12 -10
  59. package/links/httpLink/dist/trpc-client-links-httpLink.cjs.dev.js +4 -4
  60. package/links/httpLink/dist/trpc-client-links-httpLink.cjs.prod.js +4 -4
  61. package/links/httpLink/dist/trpc-client-links-httpLink.esm.js +1 -1
  62. package/links/wsLink/dist/trpc-client-links-wsLink.cjs.dev.js +3 -1
  63. package/links/wsLink/dist/trpc-client-links-wsLink.cjs.prod.js +3 -1
  64. package/links/wsLink/dist/trpc-client-links-wsLink.esm.js +3 -1
  65. package/package.json +23 -34
  66. package/src/TRPCClientError.ts +38 -28
  67. package/src/createTRPCClient.ts +8 -3
  68. package/src/createTRPCClientProxy.ts +113 -0
  69. package/src/index.ts +2 -1
  70. package/src/internals/TRPCClient.ts +118 -77
  71. package/src/internals/dataLoader.ts +116 -53
  72. package/src/internals/fetchHelpers.ts +2 -2
  73. package/src/links/dedupeLink.test.ts +9 -15
  74. package/src/links/dedupeLink.ts +6 -7
  75. package/src/links/httpBatchLink.ts +73 -36
  76. package/src/links/httpLink.ts +18 -6
  77. package/src/links/index.ts +8 -0
  78. package/src/links/internals/createChain.test.ts +23 -38
  79. package/src/links/internals/createChain.ts +8 -3
  80. package/src/links/internals/httpUtils.ts +117 -0
  81. package/src/links/internals/transformResult.ts +40 -0
  82. package/src/links/loggerLink.ts +6 -7
  83. package/src/links/retryLink.ts +2 -3
  84. package/src/links/splitLink.test.ts +3 -3
  85. package/src/links/splitLink.ts +5 -5
  86. package/src/links/types.ts +15 -12
  87. package/src/links/wsLink.ts +57 -23
  88. package/dist/TRPCClientError-17b117e1.mjs +0 -81
  89. package/dist/TRPCClientError-ec6bd2ca.js +0 -94
  90. package/dist/createChain-389cc116.mjs +0 -25
  91. package/dist/createChain-864dbb30.js +0 -27
  92. package/dist/httpUtils-1f9e4e3c.js +0 -97
  93. package/dist/httpUtils-c09d7b79.mjs +0 -91
  94. package/dist/index.ts.js +0 -1
  95. package/dist/internals/transformRPCResponse.d.ts +0 -15
  96. package/dist/internals/transformRPCResponse.d.ts.map +0 -1
  97. package/dist/links/httpBatchLink.ts.js +0 -1
  98. package/dist/links/httpLink.ts.js +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/internals/transformOperationResult.d.ts +0 -16
  102. package/dist/links/internals/transformOperationResult.d.ts.map +0 -1
  103. package/dist/links/loggerLink.ts.js +0 -1
  104. package/dist/links/splitLink.ts.js +0 -1
  105. package/dist/links/transformerLink.d.ts +0 -4
  106. package/dist/links/transformerLink.d.ts.map +0 -1
  107. package/dist/links/transformerLink.js +0 -75
  108. package/dist/links/transformerLink.mjs +0 -67
  109. package/dist/links/transformerLink.ts.js +0 -1
  110. package/dist/links/wsLink.ts.js +0 -1
  111. package/dist/observable-7e66cb56.mjs +0 -102
  112. package/dist/observable-85669100.js +0 -104
  113. package/dist/rx/index.d.ts +0 -3
  114. package/dist/rx/index.d.ts.map +0 -1
  115. package/dist/rx/index.js +0 -9
  116. package/dist/rx/index.mjs +0 -1
  117. package/dist/rx/index.ts.js +0 -1
  118. package/dist/rx/observable.d.ts +0 -4
  119. package/dist/rx/observable.d.ts.map +0 -1
  120. package/dist/rx/operators/index.d.ts +0 -4
  121. package/dist/rx/operators/index.d.ts.map +0 -1
  122. package/dist/rx/operators/index.js +0 -38
  123. package/dist/rx/operators/index.mjs +0 -32
  124. package/dist/rx/operators/index.ts.js +0 -1
  125. package/dist/rx/operators/map.d.ts +0 -3
  126. package/dist/rx/operators/map.d.ts.map +0 -1
  127. package/dist/rx/operators/share.d.ts +0 -6
  128. package/dist/rx/operators/share.d.ts.map +0 -1
  129. package/dist/rx/operators/tap.d.ts +0 -3
  130. package/dist/rx/operators/tap.d.ts.map +0 -1
  131. package/dist/rx/types.d.ts +0 -29
  132. package/dist/rx/types.d.ts.map +0 -1
  133. package/dist/rx/util/identity.d.ts +0 -2
  134. package/dist/rx/util/identity.d.ts.map +0 -1
  135. package/dist/rx/util/observableToPromise.d.ts +0 -10
  136. package/dist/rx/util/observableToPromise.d.ts.map +0 -1
  137. package/dist/rx/util/pipe.d.ts +0 -4
  138. package/dist/rx/util/pipe.d.ts.map +0 -1
  139. package/dist/share-4d79dc49.js +0 -110
  140. package/dist/share-671b63fa.mjs +0 -108
  141. package/dist/tap-538fa07f.mjs +0 -30
  142. package/dist/tap-799a2d33.js +0 -32
  143. package/links/transformerLink/dist/trpc-client-links-transformerLink.cjs.d.ts +0 -1
  144. package/links/transformerLink/dist/trpc-client-links-transformerLink.cjs.dev.js +0 -67
  145. package/links/transformerLink/dist/trpc-client-links-transformerLink.cjs.js +0 -7
  146. package/links/transformerLink/dist/trpc-client-links-transformerLink.cjs.prod.js +0 -67
  147. package/links/transformerLink/dist/trpc-client-links-transformerLink.esm.js +0 -63
  148. package/links/transformerLink/index.d.ts +0 -1
  149. package/links/transformerLink/index.js +0 -1
  150. package/rx/dist/trpc-client-rx.cjs.d.ts +0 -1
  151. package/rx/dist/trpc-client-rx.cjs.dev.js +0 -9
  152. package/rx/dist/trpc-client-rx.cjs.js +0 -7
  153. package/rx/dist/trpc-client-rx.cjs.prod.js +0 -9
  154. package/rx/dist/trpc-client-rx.esm.js +0 -1
  155. package/rx/index.d.ts +0 -1
  156. package/rx/index.js +0 -1
  157. package/rx/operators/dist/trpc-client-rx-operators.cjs.d.ts +0 -1
  158. package/rx/operators/dist/trpc-client-rx-operators.cjs.dev.js +0 -39
  159. package/rx/operators/dist/trpc-client-rx-operators.cjs.js +0 -7
  160. package/rx/operators/dist/trpc-client-rx-operators.cjs.prod.js +0 -39
  161. package/rx/operators/dist/trpc-client-rx-operators.esm.js +0 -33
  162. package/rx/operators/index.d.ts +0 -1
  163. package/rx/operators/index.js +0 -1
  164. package/src/internals/transformRPCResponse.ts +0 -25
  165. package/src/links/httpUtils.ts +0 -94
  166. package/src/links/internals/transformOperationResult.ts +0 -25
  167. package/src/links/transformerLink.ts +0 -70
  168. package/src/rx/index.ts +0 -2
  169. package/src/rx/observable.test.ts +0 -83
  170. package/src/rx/observable.ts +0 -70
  171. package/src/rx/operators/index.ts +0 -3
  172. package/src/rx/operators/map.test.ts +0 -92
  173. package/src/rx/operators/map.ts +0 -25
  174. package/src/rx/operators/share.test.ts +0 -60
  175. package/src/rx/operators/share.ts +0 -67
  176. package/src/rx/operators/tap.ts +0 -26
  177. package/src/rx/types.ts +0 -69
  178. package/src/rx/util/identity.ts +0 -3
  179. package/src/rx/util/observableToPromise.ts +0 -49
  180. package/src/rx/util/pipe.ts +0 -22
@@ -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
  /**
@@ -21,78 +35,127 @@ type BatchLoadFn<TKey, TValue> = (keys: TKey[]) => {
21
35
  * When cancelling a single fetch the whole batch will be cancelled only when _all_ items are cancelled
22
36
  */
23
37
  export function dataLoader<TKey, TValue>(
24
- fetchMany: BatchLoadFn<TKey, TValue>,
25
- opts?: { maxBatchSize?: number },
38
+ batchLoader: BatchLoader<TKey, TValue>,
26
39
  ) {
27
- let batch: Batch<TKey, TValue> | null = null;
28
- let dispatchTimer: NodeJS.Timer | number | null = null;
40
+ let pendingItems: BatchItem<TKey, TValue>[] | null = null;
41
+ let dispatchTimer: ReturnType<typeof setTimeout> | null = null;
29
42
 
30
- const destroyTimerAndBatch = () => {
43
+ const destroyTimerAndPendingItems = () => {
31
44
  clearTimeout(dispatchTimer as any);
32
45
  dispatchTimer = null;
33
- batch = null;
46
+ pendingItems = null;
34
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
+
35
91
  function dispatch() {
36
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
37
- const batchCopy = batch!;
38
- destroyTimerAndBatch();
39
- const { promise, cancel } = fetchMany(batchCopy.items.map((v) => v.key));
40
- batchCopy.cancel = cancel;
41
-
42
- promise
43
- .then((result) => {
44
- for (let i = 0; i < result.length; i++) {
45
- const value = result[i];
46
- batchCopy.items[i].resolve(value);
47
- }
48
- })
49
- .catch((cause) => {
50
- for (const item of batchCopy.items) {
51
- item.reject(cause);
52
- }
53
- });
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
+ }
54
128
  }
55
129
  function load(key: TKey): PromiseAndCancel<TValue> {
56
- const batchItem = {
57
- cancelled: false,
130
+ const item: BatchItem<TKey, TValue> = {
131
+ aborted: false,
58
132
  key,
133
+ batch: null,
134
+ resolve: throwFatalError,
135
+ reject: throwFatalError,
59
136
  };
60
137
 
61
- if (!batch) {
62
- batch = {
63
- items: [],
64
- cancel() {
65
- destroyTimerAndBatch();
66
- },
67
- };
68
- }
69
- const thisBatch = batch;
70
138
  const promise = new Promise<TValue>((resolve, reject) => {
71
- const item = batchItem as any as BatchItem<TKey, TValue>;
72
139
  item.reject = reject;
73
140
  item.resolve = resolve;
74
- thisBatch.items.push(item);
75
-
76
- if (
77
- typeof opts?.maxBatchSize !== 'undefined' &&
78
- thisBatch.items.length >= opts.maxBatchSize
79
- ) {
80
- dispatch();
81
- return;
141
+
142
+ if (!pendingItems) {
143
+ pendingItems = [];
82
144
  }
145
+ pendingItems.push(item);
83
146
  });
84
147
 
85
148
  if (!dispatchTimer) {
86
149
  dispatchTimer = setTimeout(dispatch);
87
150
  }
88
151
  const cancel = () => {
89
- batchItem.cancelled = true;
152
+ item.aborted = true;
90
153
 
91
- if (thisBatch.items.some((item) => !item.cancelled)) {
92
- // there are still things that can be resolved
93
- 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;
94
158
  }
95
- thisBatch.cancel();
96
159
  };
97
160
 
98
161
  return { promise, cancel };
@@ -6,7 +6,7 @@ export function getWindow() {
6
6
  }
7
7
  export function getAbortController(
8
8
  ac?: typeof AbortController,
9
- ): typeof AbortController | null {
9
+ ): typeof AbortController | undefined {
10
10
  const win = getWindow();
11
- return ac || win.AbortController || null;
11
+ return ac ?? win.AbortController ?? undefined;
12
12
  }
@@ -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
 
@@ -17,13 +17,10 @@ test('dedupeLink', async () => {
17
17
  const timer = setTimeout(() => {
18
18
  timerTriggered();
19
19
  subscribe.next({
20
- data: {
21
- id: null,
22
- result: {
23
- type: 'data',
24
- data: {
25
- input: op.input,
26
- },
20
+ result: {
21
+ type: 'data',
22
+ data: {
23
+ input: op.input,
27
24
  },
28
25
  },
29
26
  });
@@ -80,13 +77,10 @@ test('dedupe - cancel one does not cancel the other', async () => {
80
77
  const timer = setTimeout(() => {
81
78
  timerTriggered();
82
79
  subscribe.next({
83
- data: {
84
- id: null,
85
- result: {
86
- type: 'data',
87
- data: {
88
- input: op.input,
89
- },
80
+ result: {
81
+ type: 'data',
82
+ data: {
83
+ input: op.input,
90
84
  },
91
85
  },
92
86
  });
@@ -1,7 +1,5 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
- import { observable } from '../rx/observable';
3
- import { share } from '../rx/operators';
4
- import { Observable } from '../rx/types';
2
+ import { Observable, observable, share } from '@trpc/server/observable';
5
3
  import { TRPCLink } from './types';
6
4
 
7
5
  export function dedupeLink<
@@ -19,16 +17,17 @@ export function dedupeLink<
19
17
  return next(op);
20
18
  }
21
19
  const key = JSON.stringify([op.path, op.input]);
22
- if (pending[key]) {
20
+ const obs$ = pending[key];
21
+ if (obs$) {
23
22
  // console.log('hooking into pending', { op });
24
- return observable((observer) => pending[key].subscribe(observer));
23
+ return observable((observer) => obs$.subscribe(observer));
25
24
  }
26
25
 
27
26
  const shared$ = observable((observer) => {
28
27
  function reset() {
29
28
  delete pending[key];
30
29
  }
31
- const next$ = next(op).subscribe({
30
+ const subscription = next(op).subscribe({
32
31
  next(v) {
33
32
  observer.next(v);
34
33
  },
@@ -43,7 +42,7 @@ export function dedupeLink<
43
42
  });
44
43
  return () => {
45
44
  reset();
46
- next$.unsubscribe();
45
+ subscription.unsubscribe();
47
46
  };
48
47
  }).pipe(share());
49
48
  pending[key] = shared$;
@@ -1,53 +1,80 @@
1
1
  import { AnyRouter, ProcedureType } from '@trpc/server';
2
+ import { observable } from '@trpc/server/observable';
3
+ import { TRPCClientError } from '../TRPCClientError';
2
4
  import { dataLoader } from '../internals/dataLoader';
3
- import { observable } from '../rx/observable';
5
+ import {
6
+ HTTPLinkOptions,
7
+ HTTPResult,
8
+ getUrl,
9
+ httpRequest,
10
+ } from './internals/httpUtils';
11
+ import { transformResult } from './internals/transformResult';
4
12
  import { TRPCLink } from './types';
5
- import { HTTPLinkOptions, httpRequest, ResponseShape } from './httpUtils';
6
13
 
7
14
  export interface HttpBatchLinkOptions extends HTTPLinkOptions {
8
- maxBatchSize?: number;
15
+ maxURLLength?: number;
9
16
  }
17
+
10
18
  export function httpBatchLink<TRouter extends AnyRouter>(
11
19
  opts: HttpBatchLinkOptions,
12
20
  ): TRPCLink<TRouter> {
13
- const { url } = opts;
14
21
  // initialized config
15
22
  return (runtime) => {
16
- type Key = { id: number; path: string; input: unknown };
17
-
18
- const fetcher = (type: ProcedureType) => (keyInputPairs: Key[]) => {
19
- const path = keyInputPairs.map((op) => op.path).join(',');
20
- const inputs = keyInputPairs.map((op) => op.input);
21
-
22
- const { promise, cancel } = httpRequest({
23
- url,
24
- inputs,
25
- path,
26
- runtime,
27
- type,
28
- });
23
+ type BatchOperation = { id: number; path: string; input: unknown };
29
24
 
30
- return {
31
- promise: promise.then((res) => {
32
- const resJSON = Array.isArray(res.json)
33
- ? res.json
34
- : keyInputPairs.map(() => res.json);
25
+ const maxURLLength = opts.maxURLLength || Infinity;
35
26
 
36
- const result = resJSON.map((item) => ({
37
- meta: res.meta,
38
- json: item,
39
- }));
27
+ const batchLoader = (type: ProcedureType) => {
28
+ const validate = (batchOps: BatchOperation[]) => {
29
+ if (maxURLLength === Infinity) {
30
+ // escape hatch for quick calcs
31
+ return true;
32
+ }
33
+ const path = batchOps.map((op) => op.path).join(',');
34
+ const inputs = batchOps.map((op) => op.input);
40
35
 
41
- return result;
42
- }),
43
- cancel,
36
+ const url = getUrl({ url: opts.url, runtime, type, path, inputs });
37
+ return url.length <= maxURLLength;
44
38
  };
39
+
40
+ const fetch = (batchOps: BatchOperation[]) => {
41
+ const path = batchOps.map((op) => op.path).join(',');
42
+ const inputs = batchOps.map((op) => op.input);
43
+
44
+ const { promise, cancel } = httpRequest({
45
+ url: opts.url,
46
+ runtime,
47
+ type,
48
+ path,
49
+ inputs,
50
+ });
51
+
52
+ return {
53
+ promise: promise.then((res) => {
54
+ const resJSON = Array.isArray(res.json)
55
+ ? res.json
56
+ : batchOps.map(() => res.json);
57
+
58
+ const result = resJSON.map((item) => ({
59
+ meta: res.meta,
60
+ json: item,
61
+ }));
62
+
63
+ return result;
64
+ }),
65
+ cancel,
66
+ };
67
+ };
68
+
69
+ return { validate, fetch };
45
70
  };
46
- const query = dataLoader<Key, ResponseShape>(fetcher('query'), opts);
47
- const mutation = dataLoader<Key, ResponseShape>(fetcher('mutation'), opts);
48
- const subscription = dataLoader<Key, ResponseShape>(
49
- fetcher('subscription'),
50
- opts,
71
+
72
+ const query = dataLoader<BatchOperation, HTTPResult>(batchLoader('query'));
73
+ const mutation = dataLoader<BatchOperation, HTTPResult>(
74
+ batchLoader('mutation'),
75
+ );
76
+ const subscription = dataLoader<BatchOperation, HTTPResult>(
77
+ batchLoader('subscription'),
51
78
  );
52
79
 
53
80
  const loaders = { query, subscription, mutation };
@@ -58,13 +85,23 @@ export function httpBatchLink<TRouter extends AnyRouter>(
58
85
 
59
86
  promise
60
87
  .then((res) => {
88
+ const transformed = transformResult(res.json, runtime);
89
+
90
+ if (!transformed.ok) {
91
+ observer.error(
92
+ TRPCClientError.from(transformed.error, {
93
+ meta: res.meta,
94
+ }),
95
+ );
96
+ return;
97
+ }
61
98
  observer.next({
62
99
  context: res.meta,
63
- data: res.json as any,
100
+ result: transformed.result,
64
101
  });
65
102
  observer.complete();
66
103
  })
67
- .catch((err) => observer.error(err as any));
104
+ .catch((err) => observer.error(TRPCClientError.from(err)));
68
105
 
69
106
  return () => {
70
107
  cancel();
@@ -1,7 +1,9 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
- import { observable } from '../rx/observable';
2
+ import { observable } from '@trpc/server/observable';
3
+ import { TRPCClientError } from '../TRPCClientError';
4
+ import { HTTPLinkOptions, httpRequest } from './internals/httpUtils';
5
+ import { transformResult } from './internals/transformResult';
3
6
  import { TRPCLink } from './types';
4
- import { HTTPLinkOptions, httpRequest } from './httpUtils';
5
7
 
6
8
  export function httpLink<TRouter extends AnyRouter>(
7
9
  opts: HTTPLinkOptions,
@@ -12,21 +14,31 @@ export function httpLink<TRouter extends AnyRouter>(
12
14
  observable((observer) => {
13
15
  const { path, input, type } = op;
14
16
  const { promise, cancel } = httpRequest({
17
+ url,
15
18
  runtime,
19
+ type,
16
20
  path,
17
21
  input,
18
- type,
19
- url,
20
22
  });
21
23
  promise
22
24
  .then((res) => {
25
+ const transformed = transformResult(res.json, runtime);
26
+
27
+ if (!transformed.ok) {
28
+ observer.error(
29
+ TRPCClientError.from(transformed.error, {
30
+ meta: res.meta,
31
+ }),
32
+ );
33
+ return;
34
+ }
23
35
  observer.next({
24
36
  context: res.meta,
25
- data: res.json as any,
37
+ result: transformed.result,
26
38
  });
27
39
  observer.complete();
28
40
  })
29
- .catch(observer.error);
41
+ .catch((cause) => observer.error(TRPCClientError.from(cause)));
30
42
 
31
43
  return () => {
32
44
  cancel();
@@ -0,0 +1,8 @@
1
+ export * from './dedupeLink';
2
+ export * from './httpBatchLink';
3
+ export * from './httpLink';
4
+ export * from './loggerLink';
5
+ export * from './retryLink';
6
+ export * from './splitLink';
7
+ export * from './wsLink';
8
+ export * from './types';
@@ -1,6 +1,6 @@
1
+ import { observable } from '@trpc/server/observable';
1
2
  import { AnyRouter } from '@trpc/server/src';
2
3
  import { createChain } from './createChain';
3
- import { observable } from '../../rx/observable';
4
4
 
5
5
  describe('chain', () => {
6
6
  test('trivial', () => {
@@ -8,9 +8,9 @@ describe('chain', () => {
8
8
  links: [
9
9
  ({ next, op }) => {
10
10
  return observable((observer) => {
11
- const next$ = next(op).subscribe(observer);
11
+ const subscription = next(op).subscribe(observer);
12
12
  return () => {
13
- next$.unsubscribe();
13
+ subscription.unsubscribe();
14
14
  };
15
15
  });
16
16
  },
@@ -18,13 +18,10 @@ describe('chain', () => {
18
18
  return observable((observer) => {
19
19
  observer.next({
20
20
  context: {},
21
- data: {
22
- id: null,
23
- result: {
24
- type: 'data',
25
- data: {
26
- input: op.input,
27
- },
21
+ result: {
22
+ type: 'data',
23
+ data: {
24
+ input: op.input,
28
25
  },
29
26
  },
30
27
  });
@@ -54,30 +51,24 @@ describe('chain', () => {
54
51
  return observable((observer) => {
55
52
  observer.next({
56
53
  context: {},
57
- data: {
58
- id: null,
59
- result: {
60
- type: 'data',
61
- data: 'from cache',
62
- },
54
+ result: {
55
+ type: 'data',
56
+ data: 'from cache',
63
57
  },
64
58
  });
65
- const next$ = next(op).subscribe(observer);
59
+ const subscription = next(op).subscribe(observer);
66
60
  return () => {
67
- next$.unsubscribe();
61
+ subscription.unsubscribe();
68
62
  };
69
63
  });
70
64
  },
71
65
  ({ op }) => {
72
66
  return observable((observer) => {
73
67
  observer.next({
74
- data: {
75
- id: null,
76
- result: {
77
- type: 'data',
78
- data: {
79
- input: op.input,
80
- },
68
+ result: {
69
+ type: 'data',
70
+ data: {
71
+ input: op.input,
81
72
  },
82
73
  },
83
74
  });
@@ -103,12 +94,9 @@ describe('chain', () => {
103
94
  Array [
104
95
  Object {
105
96
  "context": Object {},
106
- "data": Object {
107
- "id": null,
108
- "result": Object {
109
- "data": "from cache",
110
- "type": "data",
111
- },
97
+ "result": Object {
98
+ "data": "from cache",
99
+ "type": "data",
112
100
  },
113
101
  },
114
102
  ]
@@ -116,14 +104,11 @@ describe('chain', () => {
116
104
  expect(next.mock.calls[1]).toMatchInlineSnapshot(`
117
105
  Array [
118
106
  Object {
119
- "data": Object {
120
- "id": null,
121
- "result": Object {
122
- "data": Object {
123
- "input": "world",
124
- },
125
- "type": "data",
107
+ "result": Object {
108
+ "data": Object {
109
+ "input": "world",
126
110
  },
111
+ "type": "data",
127
112
  },
128
113
  },
129
114
  ]
@@ -1,5 +1,5 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
- import { observable } from '../../rx/observable';
2
+ import { observable } from '@trpc/server/observable';
3
3
  import { Operation, OperationLink, OperationResultObservable } from '../types';
4
4
 
5
5
  /** @internal */
@@ -14,7 +14,12 @@ export function createChain<
14
14
  return observable((observer) => {
15
15
  function execute(index = 0, op = opts.op) {
16
16
  const next = opts.links[index];
17
- const next$ = next({
17
+ if (!next) {
18
+ throw new Error(
19
+ 'No more links to execute - did you forget to add an ending link?',
20
+ );
21
+ }
22
+ const subscription = next({
18
23
  op,
19
24
  next(nextOp) {
20
25
  const nextObserver = execute(index + 1, nextOp);
@@ -22,7 +27,7 @@ export function createChain<
22
27
  return nextObserver;
23
28
  },
24
29
  });
25
- return next$;
30
+ return subscription;
26
31
  }
27
32
 
28
33
  const obs$ = execute();