@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
@@ -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,47 +1,80 @@
1
1
  import { AnyRouter, ProcedureType } from '@trpc/server';
2
+ import { observable } from '@trpc/server/observable';
2
3
  import { dataLoader } from '../internals/dataLoader';
3
- import { observable } from '../rx/observable';
4
+ import {
5
+ HTTPLinkOptions,
6
+ ResponseShape,
7
+ getUrl,
8
+ httpRequest,
9
+ } from './internals/httpUtils';
4
10
  import { TRPCLink } from './types';
5
- import { HTTPLinkOptions, httpRequest, ResponseShape } from './httpUtils';
11
+
12
+ export interface HttpBatchLinkOptions extends HTTPLinkOptions {
13
+ maxURLLength?: number;
14
+ }
6
15
 
7
16
  export function httpBatchLink<TRouter extends AnyRouter>(
8
- opts: HTTPLinkOptions,
17
+ opts: HttpBatchLinkOptions,
9
18
  ): TRPCLink<TRouter> {
10
- const { url } = opts;
19
+ // initialized config
11
20
  return (runtime) => {
12
- type Key = { id: number; path: string; input: unknown };
13
- const fetcher = (type: ProcedureType) => (keyInputPairs: Key[]) => {
14
- const path = keyInputPairs.map((op) => op.path).join(',');
15
- const inputs = keyInputPairs.map((op) => op.input);
21
+ type BatchOperation = { id: number; path: string; input: unknown };
16
22
 
17
- const { promise, cancel } = httpRequest({
18
- url,
19
- inputs,
20
- path,
21
- runtime,
22
- type,
23
- });
23
+ const maxURLLength = opts.maxURLLength || Infinity;
24
+
25
+ const batchLoader = (type: ProcedureType) => {
26
+ const validate = (batchOps: BatchOperation[]) => {
27
+ if (maxURLLength === Infinity) {
28
+ // escape hatch for quick calcs
29
+ return true;
30
+ }
31
+ const path = batchOps.map((op) => op.path).join(',');
32
+ const inputs = batchOps.map((op) => op.input);
33
+
34
+ const url = getUrl({ url: opts.url, runtime, type, path, inputs });
35
+ return url.length <= maxURLLength;
36
+ };
37
+
38
+ const fetch = (batchOps: BatchOperation[]) => {
39
+ const path = batchOps.map((op) => op.path).join(',');
40
+ const inputs = batchOps.map((op) => op.input);
24
41
 
25
- return {
26
- promise: promise.then((res) => {
27
- const resJSON = Array.isArray(res.json)
28
- ? res.json
29
- : keyInputPairs.map(() => res.json);
42
+ const { promise, cancel } = httpRequest({
43
+ url: opts.url,
44
+ runtime,
45
+ type,
46
+ path,
47
+ inputs,
48
+ });
30
49
 
31
- const result = resJSON.map((item) => ({
32
- meta: res.meta,
33
- json: item,
34
- }));
50
+ return {
51
+ promise: promise.then((res) => {
52
+ const resJSON = Array.isArray(res.json)
53
+ ? res.json
54
+ : batchOps.map(() => res.json);
35
55
 
36
- return result;
37
- }),
38
- cancel,
56
+ const result = resJSON.map((item) => ({
57
+ meta: res.meta,
58
+ json: item,
59
+ }));
60
+
61
+ return result;
62
+ }),
63
+ cancel,
64
+ };
39
65
  };
66
+
67
+ return { validate, fetch };
40
68
  };
41
- const query = dataLoader<Key, ResponseShape>(fetcher('query'));
42
- const mutation = dataLoader<Key, ResponseShape>(fetcher('mutation'));
43
- const subscription = dataLoader<Key, ResponseShape>(
44
- fetcher('subscription'),
69
+
70
+ const query = dataLoader<BatchOperation, ResponseShape>(
71
+ batchLoader('query'),
72
+ );
73
+ const mutation = dataLoader<BatchOperation, ResponseShape>(
74
+ batchLoader('mutation'),
75
+ );
76
+ const subscription = dataLoader<BatchOperation, ResponseShape>(
77
+ batchLoader('subscription'),
45
78
  );
46
79
 
47
80
  const loaders = { query, subscription, mutation };
@@ -1,7 +1,7 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
- import { observable } from '../rx/observable';
2
+ import { observable } from '@trpc/server/observable';
3
+ import { HTTPLinkOptions, httpRequest } from './internals/httpUtils';
3
4
  import { TRPCLink } from './types';
4
- import { HTTPLinkOptions, httpRequest } from './httpUtils';
5
5
 
6
6
  export function httpLink<TRouter extends AnyRouter>(
7
7
  opts: HTTPLinkOptions,
@@ -12,11 +12,11 @@ export function httpLink<TRouter extends AnyRouter>(
12
12
  observable((observer) => {
13
13
  const { path, input, type } = op;
14
14
  const { promise, cancel } = httpRequest({
15
+ url,
15
16
  runtime,
17
+ type,
16
18
  path,
17
19
  input,
18
- type,
19
- url,
20
20
  });
21
21
  promise
22
22
  .then((res) => {
@@ -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
  },
@@ -62,9 +62,9 @@ describe('chain', () => {
62
62
  },
63
63
  },
64
64
  });
65
- const next$ = next(op).subscribe(observer);
65
+ const subscription = next(op).subscribe(observer);
66
66
  return () => {
67
- next$.unsubscribe();
67
+ subscription.unsubscribe();
68
68
  };
69
69
  });
70
70
  },
@@ -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();
@@ -0,0 +1,116 @@
1
+ import { ProcedureType } from '@trpc/server';
2
+ import { PromiseAndCancel, TRPCClientRuntime } from '../types';
3
+
4
+ export interface HTTPLinkOptions {
5
+ url: string;
6
+ }
7
+
8
+ // https://github.com/trpc/trpc/pull/669
9
+ function arrayToDict(array: unknown[]) {
10
+ const dict: Record<number, unknown> = {};
11
+ for (let index = 0; index < array.length; index++) {
12
+ const element = array[index];
13
+ dict[index] = element;
14
+ }
15
+ return dict;
16
+ }
17
+
18
+ const METHOD = {
19
+ query: 'GET',
20
+ mutation: 'POST',
21
+ subscription: 'PATCH',
22
+ } as const;
23
+
24
+ export interface ResponseShape {
25
+ json: unknown;
26
+ meta: {
27
+ response: Response;
28
+ };
29
+ }
30
+
31
+ type GetInputOptions = {
32
+ runtime: TRPCClientRuntime;
33
+ } & ({ inputs: unknown[] } | { input: unknown });
34
+
35
+ function getInput(opts: GetInputOptions) {
36
+ return 'input' in opts
37
+ ? opts.runtime.transformer.serialize(opts.input)
38
+ : arrayToDict(
39
+ opts.inputs.map((_input) => opts.runtime.transformer.serialize(_input)),
40
+ );
41
+ }
42
+
43
+ export type HTTPRequestOptions = HTTPLinkOptions &
44
+ GetInputOptions & {
45
+ type: ProcedureType;
46
+ path: string;
47
+ };
48
+
49
+ export function getUrl(opts: HTTPRequestOptions) {
50
+ let url = opts.url + '/' + opts.path;
51
+ const queryParts: string[] = [];
52
+ if ('inputs' in opts) {
53
+ queryParts.push('batch=1');
54
+ }
55
+ if (opts.type === 'query') {
56
+ const input = getInput(opts);
57
+ if (input !== undefined) {
58
+ queryParts.push(`input=${encodeURIComponent(JSON.stringify(input))}`);
59
+ }
60
+ }
61
+ if (queryParts.length) {
62
+ url += '?' + queryParts.join('&');
63
+ }
64
+ return url;
65
+ }
66
+
67
+ type GetBodyOptions = { type: ProcedureType } & GetInputOptions;
68
+
69
+ export function getBody(opts: GetBodyOptions) {
70
+ if (opts.type === 'query') {
71
+ return undefined;
72
+ }
73
+ const input = getInput(opts);
74
+ return input !== undefined ? JSON.stringify(input) : undefined;
75
+ }
76
+
77
+ export function httpRequest(
78
+ opts: HTTPRequestOptions,
79
+ ): PromiseAndCancel<ResponseShape> {
80
+ const { type, runtime } = opts;
81
+ const ac = runtime.AbortController ? new runtime.AbortController() : null;
82
+
83
+ const promise = new Promise<ResponseShape>((resolve, reject) => {
84
+ const url = getUrl(opts);
85
+ const body = getBody(opts);
86
+
87
+ const meta = {} as any as ResponseShape['meta'];
88
+ Promise.resolve(runtime.headers())
89
+ .then((headers) =>
90
+ runtime.fetch(url, {
91
+ method: METHOD[type],
92
+ signal: ac?.signal,
93
+ body: body,
94
+ headers: {
95
+ 'content-type': 'application/json',
96
+ ...headers,
97
+ },
98
+ }),
99
+ )
100
+ .then((_res) => {
101
+ meta.response = _res;
102
+ return _res.json();
103
+ })
104
+ .then((json) => {
105
+ resolve({
106
+ json,
107
+ meta,
108
+ });
109
+ })
110
+ .catch(reject);
111
+ });
112
+ const cancel = () => {
113
+ ac?.abort();
114
+ };
115
+ return { promise, cancel };
116
+ }
@@ -1,25 +1,53 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
+ import { TRPCResultMessage } from '@trpc/server/rpc';
3
+ import { TRPCClientRuntime } from '..';
2
4
  import { TRPCClientError } from '../../TRPCClientError';
3
5
  import { OperationResult } from '../types';
4
6
 
5
7
  /** @internal */
6
8
  export function transformOperationResult<TRouter extends AnyRouter, TOutput>(
7
9
  result: OperationResult<TRouter, TOutput>,
10
+ runtime: TRPCClientRuntime,
8
11
  ) {
9
12
  const { context } = result;
10
13
 
11
14
  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;
15
+ const error = TRPCClientError.from<TRouter>({
16
+ ...result.data,
17
+ error: runtime.transformer.deserialize(result.data.error),
18
+ });
19
+ return { ok: false, error, context } as const;
18
20
  }
19
- const data = (result.data.result as any).data as TOutput;
20
- return {
21
- ok: true,
22
- data,
23
- context,
24
- } as const;
21
+
22
+ const data = runtime.transformer.deserialize(
23
+ (result.data.result as any).data,
24
+ ) as TOutput;
25
+ return { ok: true, data, context } as const;
26
+ }
27
+
28
+ /** @internal */
29
+ export function transformSubscriptionOperationResult<
30
+ TRouter extends AnyRouter,
31
+ TOutput,
32
+ >(result: OperationResult<TRouter, TOutput>, runtime: TRPCClientRuntime) {
33
+ const { context } = result;
34
+
35
+ if ('error' in result.data) {
36
+ const error = TRPCClientError.from<TRouter>(
37
+ {
38
+ ...result.data,
39
+ error: runtime.transformer.deserialize(result.data.error),
40
+ },
41
+ { meta: context },
42
+ );
43
+ return { ok: false, error, context } as const;
44
+ }
45
+
46
+ const data = {
47
+ ...result.data.result,
48
+ ...((result.data.result as any).type === 'data' && {
49
+ data: runtime.transformer.deserialize((result.data.result as any).data),
50
+ }),
51
+ } as TRPCResultMessage<TOutput>;
52
+ return { ok: true, data, context } as const;
25
53
  }
@@ -1,7 +1,6 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
+ import { observable, tap } from '@trpc/server/observable';
2
3
  import { TRPCClientError } from '..';
3
- import { observable } from '../rx/observable';
4
- import { tap } from '../rx/operators';
5
4
  import { Operation, OperationResult, TRPCLink } from './types';
6
5
 
7
6
  type ConsoleEsque = {
@@ -1,6 +1,5 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
- import { observable } from '../rx/observable';
3
- import { Unsubscribable } from '../rx/types';
2
+ import { Unsubscribable, observable } from '@trpc/server/observable';
4
3
  import { TRPCLink } from './types';
5
4
 
6
5
  export function retryLink<TRouter extends AnyRouter = AnyRouter>(opts: {
@@ -1,9 +1,9 @@
1
1
  /* eslint-disable @typescript-eslint/no-empty-function */
2
+ import { observable } from '@trpc/server/observable';
3
+ import { splitLink } from '../';
4
+ import { OperationLink, TRPCLink } from '../';
2
5
  import { AnyRouter } from '../../../server/src';
3
6
  import { createChain } from '../links/internals/createChain';
4
- import { splitLink } from '../links/splitLink';
5
- import { OperationLink, TRPCLink } from '../links/types';
6
- import { observable } from '../rx';
7
7
 
8
8
  test('splitLink', () => {
9
9
  const wsLinkSpy = jest.fn();
@@ -1,7 +1,7 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
- import { observable } from '../rx/observable';
3
- import { TRPCLink, Operation } from './types';
2
+ import { observable } from '@trpc/server/observable';
4
3
  import { createChain } from './internals/createChain';
4
+ import { Operation, TRPCLink } from './types';
5
5
 
6
6
  function asArray<T>(value: T | T[]) {
7
7
  return Array.isArray(value) ? value : [value];
@@ -17,9 +17,9 @@ export function splitLink<TRouter extends AnyRouter = AnyRouter>(opts: {
17
17
  */
18
18
  false: TRPCLink<TRouter> | TRPCLink<TRouter>[];
19
19
  }): TRPCLink<TRouter> {
20
- return (rt) => {
21
- const yes = asArray(opts.true).map((link) => link(rt));
22
- const no = asArray(opts.false).map((link) => link(rt));
20
+ return (runtime) => {
21
+ const yes = asArray(opts.true).map((link) => link(runtime));
22
+ const no = asArray(opts.false).map((link) => link(runtime));
23
23
  return (props) => {
24
24
  return observable((observer) => {
25
25
  const links = opts.condition(props.op) ? yes : no;
@@ -1,6 +1,6 @@
1
- import { AnyRouter, inferRouterError, Dict } from '@trpc/server';
2
- import { TRPCResponse } from '@trpc/server/rpc';
3
- import { Observable, Observer } from '../rx/types';
1
+ import { AnyRouter, DataTransformer, inferRouterError } from '@trpc/server';
2
+ import { Observable, Observer } from '@trpc/server/observable';
3
+ import { TRPCResponse, TRPCResponseMessage } from '@trpc/server/rpc';
4
4
  import { TRPCClientError } from '../TRPCClientError';
5
5
 
6
6
  export type CancelFn = () => void;
@@ -16,10 +16,10 @@ export type Operation<TInput = unknown> = {
16
16
  type: 'query' | 'mutation' | 'subscription';
17
17
  input: TInput;
18
18
  path: string;
19
- context?: OperationContext;
19
+ context: OperationContext;
20
20
  };
21
21
 
22
- export type HTTPHeaders = Dict<string | string[]>;
22
+ export type HTTPHeaders = Record<string, string | string[]>;
23
23
 
24
24
  /**
25
25
  * The default `fetch` implementation has an overloaded signature. By convention this library
@@ -30,14 +30,19 @@ export type TRPCFetch = (
30
30
  options?: RequestInit,
31
31
  ) => Promise<Response>;
32
32
 
33
- export interface LinkRuntime {
34
- headers: () => HTTPHeaders | Promise<HTTPHeaders>;
33
+ export interface TRPCClientRuntime {
35
34
  fetch: TRPCFetch;
36
35
  AbortController?: typeof AbortController;
36
+ headers: () => HTTPHeaders | Promise<HTTPHeaders>;
37
+ transformer: DataTransformer;
37
38
  }
38
39
 
40
+ type OperationResultData<TRouter extends AnyRouter, TOutput> =
41
+ | TRPCResponse<TOutput, inferRouterError<TRouter>>
42
+ | TRPCResponseMessage<TOutput, inferRouterError<TRouter>>;
43
+
39
44
  export interface OperationResult<TRouter extends AnyRouter, TOutput> {
40
- data: TRPCResponse<TOutput, inferRouterError<TRouter>>;
45
+ data: OperationResultData<TRouter, TOutput>;
41
46
  context?: OperationContext;
42
47
  }
43
48
 
@@ -61,5 +66,5 @@ export type OperationLink<
61
66
  }) => OperationResultObservable<TRouter, TOutput>;
62
67
 
63
68
  export type TRPCLink<TRouter extends AnyRouter> = (
64
- opts: LinkRuntime,
69
+ opts: TRPCClientRuntime,
65
70
  ) => OperationLink<TRouter>;
@@ -1,19 +1,19 @@
1
1
  import { AnyRouter, ProcedureType } from '@trpc/server';
2
+ import { UnsubscribeFn, observable } from '@trpc/server/observable';
2
3
  import {
3
4
  TRPCClientIncomingMessage,
4
5
  TRPCClientIncomingRequest,
5
- TRPCRequest,
6
- TRPCResponse,
6
+ TRPCClientOutgoingMessage,
7
+ TRPCRequestMessage,
8
+ TRPCResponseMessage,
7
9
  } from '@trpc/server/rpc';
8
- import { retryDelay } from '../internals/retryDelay';
9
- import { UnsubscribeFn } from '../rx';
10
- import { observable } from '../rx/observable';
11
10
  import { TRPCClientError } from '../TRPCClientError';
11
+ import { retryDelay } from '../internals/retryDelay';
12
12
  import { Operation, OperationResultObserver, TRPCLink } from './types';
13
13
 
14
14
  export interface WebSocketClientOptions {
15
15
  url: string;
16
- WebSocket?: WebSocket;
16
+ WebSocket?: typeof WebSocket;
17
17
  retryDelayMs?: typeof retryDelay;
18
18
  }
19
19
  export function createWSClient(opts: WebSocketClientOptions) {
@@ -31,7 +31,7 @@ export function createWSClient(opts: WebSocketClientOptions) {
31
31
  /**
32
32
  * outgoing messages buffer whilst not open
33
33
  */
34
- let outgoing: TRPCRequest[] = [];
34
+ let outgoing: TRPCClientOutgoingMessage[] = [];
35
35
  /**
36
36
  * pending outgoing requests that are awaiting callback
37
37
  */
@@ -112,7 +112,7 @@ export function createWSClient(opts: WebSocketClientOptions) {
112
112
  }
113
113
 
114
114
  function createWS() {
115
- const conn = new WebSocket(url);
115
+ const conn = new WebSocketImpl(url);
116
116
  clearTimeout(connectTimer as any);
117
117
  connectTimer = null;
118
118
 
@@ -141,7 +141,7 @@ export function createWSClient(opts: WebSocketClientOptions) {
141
141
  }
142
142
  }
143
143
  };
144
- const handleIncomingResponse = (data: TRPCResponse) => {
144
+ const handleIncomingResponse = (data: TRPCResponseMessage) => {
145
145
  const req = data.id !== null && pendingRequests[data.id];
146
146
  if (!req) {
147
147
  // do something?
@@ -184,8 +184,7 @@ export function createWSClient(opts: WebSocketClientOptions) {
184
184
  tryReconnect();
185
185
  }
186
186
 
187
- for (const key in pendingRequests) {
188
- const req = pendingRequests[key];
187
+ for (const [key, req] of Object.entries(pendingRequests)) {
189
188
  if (req.ws !== conn) {
190
189
  continue;
191
190
  }
@@ -208,9 +207,8 @@ export function createWSClient(opts: WebSocketClientOptions) {
208
207
 
209
208
  function request(op: Operation, callbacks: TCallbacks): UnsubscribeFn {
210
209
  const { type, input, path, id } = op;
211
- const envelope: TRPCRequest = {
210
+ const envelope: TRPCRequestMessage = {
212
211
  id,
213
- jsonrpc: '2.0',
214
212
  method: type,
215
213
  params: {
216
214
  input,
@@ -238,7 +236,6 @@ export function createWSClient(opts: WebSocketClientOptions) {
238
236
  outgoing.push({
239
237
  id,
240
238
  method: 'subscription.stop',
241
- params: undefined,
242
239
  });
243
240
  dispatch();
244
241
  }
@@ -248,6 +245,8 @@ export function createWSClient(opts: WebSocketClientOptions) {
248
245
  close: () => {
249
246
  state = 'closed';
250
247
  closeIfNoPending(activeConnection);
248
+ clearTimeout(connectTimer as any);
249
+ connectTimer = null;
251
250
  },
252
251
  request,
253
252
  getConnection() {
@@ -279,11 +278,13 @@ class TRPCSubscriptionEndedError extends Error {
279
278
  export function wsLink<TRouter extends AnyRouter>(
280
279
  opts: WebSocketLinkOptions,
281
280
  ): TRPCLink<TRouter> {
282
- return () => {
281
+ return (runtime) => {
283
282
  const { client } = opts;
284
283
  return ({ op }) => {
285
284
  return observable((observer) => {
286
- const { type, input, path, id, context } = op;
285
+ const { type, path, id, context } = op;
286
+
287
+ const input = runtime.transformer.serialize(op.input);
287
288
 
288
289
  let isDone = false;
289
290
  const unsub = client.request(