@trpc/client 10.0.0-alpha.41 → 10.0.0-alpha.44

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 (58) hide show
  1. package/dist/TRPCClientError.d.ts +13 -10
  2. package/dist/TRPCClientError.d.ts.map +1 -1
  3. package/dist/createTRPCClient.d.ts +1 -1
  4. package/dist/createTRPCClient.d.ts.map +1 -1
  5. package/dist/createTRPCClientProxy.d.ts +20 -7
  6. package/dist/createTRPCClientProxy.d.ts.map +1 -1
  7. package/dist/index.js +38 -91
  8. package/dist/index.mjs +35 -88
  9. package/dist/internals/TRPCClient.d.ts +28 -6
  10. package/dist/internals/TRPCClient.d.ts.map +1 -1
  11. package/dist/links/httpBatchLink.d.ts.map +1 -1
  12. package/dist/links/httpBatchLink.js +18 -1
  13. package/dist/links/httpBatchLink.mjs +18 -1
  14. package/dist/links/httpLink.d.ts.map +1 -1
  15. package/dist/links/httpLink.js +21 -2
  16. package/dist/links/httpLink.mjs +21 -2
  17. package/dist/links/internals/httpUtils.d.ts +4 -3
  18. package/dist/links/internals/httpUtils.d.ts.map +1 -1
  19. package/dist/links/internals/transformResult.d.ts +28 -0
  20. package/dist/links/internals/transformResult.d.ts.map +1 -0
  21. package/dist/links/loggerLink.d.ts +3 -3
  22. package/dist/links/loggerLink.d.ts.map +1 -1
  23. package/dist/links/loggerLink.js +1 -1
  24. package/dist/links/loggerLink.mjs +1 -1
  25. package/dist/links/types.d.ts +6 -8
  26. package/dist/links/types.d.ts.map +1 -1
  27. package/dist/links/wsLink.d.ts +11 -4
  28. package/dist/links/wsLink.d.ts.map +1 -1
  29. package/dist/links/wsLink.js +400 -12
  30. package/dist/links/wsLink.mjs +391 -10
  31. package/dist/transformResult-06bec648.mjs +108 -0
  32. package/dist/transformResult-3ccc74ea.js +122 -0
  33. package/links/httpBatchLink/dist/trpc-client-links-httpBatchLink.cjs.dev.js +4 -4
  34. package/links/httpBatchLink/dist/trpc-client-links-httpBatchLink.cjs.prod.js +4 -4
  35. package/links/httpBatchLink/dist/trpc-client-links-httpBatchLink.esm.js +1 -1
  36. package/links/httpLink/dist/trpc-client-links-httpLink.cjs.dev.js +4 -4
  37. package/links/httpLink/dist/trpc-client-links-httpLink.cjs.prod.js +4 -4
  38. package/links/httpLink/dist/trpc-client-links-httpLink.esm.js +1 -1
  39. package/package.json +4 -4
  40. package/src/TRPCClientError.ts +29 -17
  41. package/src/createTRPCClient.ts +1 -0
  42. package/src/createTRPCClientProxy.ts +64 -10
  43. package/src/internals/TRPCClient.ts +58 -38
  44. package/src/links/dedupeLink.test.ts +8 -14
  45. package/src/links/httpBatchLink.ts +17 -7
  46. package/src/links/httpLink.ts +14 -2
  47. package/src/links/internals/createChain.test.ts +18 -33
  48. package/src/links/internals/httpUtils.ts +6 -5
  49. package/src/links/internals/transformResult.ts +40 -0
  50. package/src/links/loggerLink.ts +5 -5
  51. package/src/links/retryLink.ts +1 -1
  52. package/src/links/types.ts +8 -10
  53. package/src/links/wsLink.ts +41 -8
  54. package/dist/links/internals/transformOperationResult.d.ts +0 -30
  55. package/dist/links/internals/transformOperationResult.d.ts.map +0 -1
  56. package/dist/wsLink-11ee4922.mjs +0 -439
  57. package/dist/wsLink-807f4ad9.js +0 -455
  58. package/src/links/internals/transformOperationResult.ts +0 -53
@@ -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,12 +51,9 @@ 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
59
  const subscription = next(op).subscribe(observer);
@@ -71,13 +65,10 @@ describe('chain', () => {
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,4 +1,5 @@
1
1
  import { ProcedureType } from '@trpc/server';
2
+ import { TRPCResponse } from '@trpc/server/rpc';
2
3
  import { PromiseAndCancel, TRPCClientRuntime } from '../types';
3
4
 
4
5
  export interface HTTPLinkOptions {
@@ -21,8 +22,8 @@ const METHOD = {
21
22
  subscription: 'PATCH',
22
23
  } as const;
23
24
 
24
- export interface ResponseShape {
25
- json: unknown;
25
+ export interface HTTPResult {
26
+ json: TRPCResponse;
26
27
  meta: {
27
28
  response: Response;
28
29
  };
@@ -76,15 +77,15 @@ export function getBody(opts: GetBodyOptions) {
76
77
 
77
78
  export function httpRequest(
78
79
  opts: HTTPRequestOptions,
79
- ): PromiseAndCancel<ResponseShape> {
80
+ ): PromiseAndCancel<HTTPResult> {
80
81
  const { type, runtime } = opts;
81
82
  const ac = runtime.AbortController ? new runtime.AbortController() : null;
82
83
 
83
- const promise = new Promise<ResponseShape>((resolve, reject) => {
84
+ const promise = new Promise<HTTPResult>((resolve, reject) => {
84
85
  const url = getUrl(opts);
85
86
  const body = getBody(opts);
86
87
 
87
- const meta = {} as any as ResponseShape['meta'];
88
+ const meta = {} as any as HTTPResult['meta'];
88
89
  Promise.resolve(runtime.headers())
89
90
  .then((headers) =>
90
91
  runtime.fetch(url, {
@@ -0,0 +1,40 @@
1
+ import { AnyRouter, inferRouterError } from '@trpc/server';
2
+ import {
3
+ TRPCResponse,
4
+ TRPCResponseMessage,
5
+ TRPCResultMessage,
6
+ } from '@trpc/server/rpc';
7
+ import { TRPCClientRuntime } from '..';
8
+
9
+ // FIXME:
10
+ // - the generics here are probably unnecessary
11
+ // - the RPC-spec could probably be simplified to combine HTTP + WS
12
+ /** @internal */
13
+ export function transformResult<TRouter extends AnyRouter, TOutput>(
14
+ response:
15
+ | TRPCResponseMessage<TOutput, inferRouterError<TRouter>>
16
+ | TRPCResponse<TOutput, inferRouterError<TRouter>>,
17
+ runtime: TRPCClientRuntime,
18
+ ) {
19
+ if ('error' in response) {
20
+ const error = runtime.transformer.deserialize(
21
+ response.error,
22
+ ) as inferRouterError<TRouter>;
23
+ return {
24
+ ok: false,
25
+ error: {
26
+ ...response,
27
+ error,
28
+ },
29
+ } as const;
30
+ }
31
+
32
+ const result = {
33
+ ...response.result,
34
+ ...((!response.result.type || response.result.type === 'data') && {
35
+ type: 'data',
36
+ data: runtime.transformer.deserialize(response.result.data),
37
+ }),
38
+ } as TRPCResultMessage<TOutput>['result'];
39
+ return { ok: true, result } as const;
40
+ }
@@ -1,7 +1,7 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
2
  import { observable, tap } from '@trpc/server/observable';
3
3
  import { TRPCClientError } from '..';
4
- import { Operation, OperationResult, TRPCLink } from './types';
4
+ import { Operation, OperationResultEnvelope, TRPCLink } from './types';
5
5
 
6
6
  type ConsoleEsque = {
7
7
  log: (...args: any[]) => void;
@@ -14,7 +14,7 @@ type EnableFnOptions<TRouter extends AnyRouter> =
14
14
  })
15
15
  | {
16
16
  direction: 'down';
17
- result: OperationResult<TRouter, unknown> | TRPCClientError<TRouter>;
17
+ result: OperationResultEnvelope<unknown> | TRPCClientError<TRouter>;
18
18
  };
19
19
  type EnabledFn<TRouter extends AnyRouter> = (
20
20
  opts: EnableFnOptions<TRouter>,
@@ -33,7 +33,7 @@ type LogFnOptions<TRouter extends AnyRouter> = Operation &
33
33
  * Request result
34
34
  */
35
35
  direction: 'down';
36
- result: OperationResult<TRouter, unknown> | TRPCClientError<TRouter>;
36
+ result: OperationResultEnvelope<unknown> | TRPCClientError<TRouter>;
37
37
  elapsedMs: number;
38
38
  }
39
39
  );
@@ -92,7 +92,7 @@ const defaultLogger =
92
92
  const fn: 'error' | 'log' =
93
93
  props.direction === 'down' &&
94
94
  props.result &&
95
- (props.result instanceof Error || 'error' in props.result.data)
95
+ (props.result instanceof Error || 'error' in props.result.result)
96
96
  ? 'error'
97
97
  : 'log';
98
98
 
@@ -116,7 +116,7 @@ export function loggerLink<TRouter extends AnyRouter = AnyRouter>(
116
116
  });
117
117
  const requestStartTime = Date.now();
118
118
  function logResult(
119
- result: OperationResult<TRouter, unknown> | TRPCClientError<TRouter>,
119
+ result: OperationResultEnvelope<unknown> | TRPCClientError<TRouter>,
120
120
  ) {
121
121
  const elapsedMs = Date.now() - requestStartTime;
122
122
 
@@ -26,7 +26,7 @@ export function retryLink<TRouter extends AnyRouter = AnyRouter>(opts: {
26
26
  attempt();
27
27
  },
28
28
  next(result) {
29
- if ('result' in result.data) {
29
+ if ('result' in result.result) {
30
30
  isDone = true;
31
31
  observer.next(result);
32
32
  return;
@@ -1,6 +1,6 @@
1
- import { AnyRouter, DataTransformer, inferRouterError } from '@trpc/server';
1
+ import { AnyRouter, DataTransformer } from '@trpc/server';
2
2
  import { Observable, Observer } from '@trpc/server/observable';
3
- import { TRPCResponse, TRPCResponseMessage } from '@trpc/server/rpc';
3
+ import { TRPCResultMessage, TRPCSuccessResponse } from '@trpc/server/rpc';
4
4
  import { TRPCClientError } from '../TRPCClientError';
5
5
 
6
6
  export type CancelFn = () => void;
@@ -37,24 +37,22 @@ export interface TRPCClientRuntime {
37
37
  transformer: DataTransformer;
38
38
  }
39
39
 
40
- type OperationResultData<TRouter extends AnyRouter, TOutput> =
41
- | TRPCResponse<TOutput, inferRouterError<TRouter>>
42
- | TRPCResponseMessage<TOutput, inferRouterError<TRouter>>;
43
-
44
- export interface OperationResult<TRouter extends AnyRouter, TOutput> {
45
- data: OperationResultData<TRouter, TOutput>;
40
+ export interface OperationResultEnvelope<TOutput> {
41
+ result:
42
+ | TRPCSuccessResponse<TOutput>['result']
43
+ | TRPCResultMessage<TOutput>['result'];
46
44
  context?: OperationContext;
47
45
  }
48
46
 
49
47
  export type OperationResultObservable<
50
48
  TRouter extends AnyRouter,
51
49
  TOutput,
52
- > = Observable<OperationResult<TRouter, TOutput>, TRPCClientError<TRouter>>;
50
+ > = Observable<OperationResultEnvelope<TOutput>, TRPCClientError<TRouter>>;
53
51
 
54
52
  export type OperationResultObserver<
55
53
  TRouter extends AnyRouter,
56
54
  TOutput,
57
- > = Observer<OperationResult<TRouter, TOutput>, TRPCClientError<TRouter>>;
55
+ > = Observer<OperationResultEnvelope<TOutput>, TRPCClientError<TRouter>>;
58
56
 
59
57
  export type OperationLink<
60
58
  TRouter extends AnyRouter,
@@ -1,5 +1,5 @@
1
- import { AnyRouter, ProcedureType } from '@trpc/server';
2
- import { UnsubscribeFn, observable } from '@trpc/server/observable';
1
+ import { AnyRouter, ProcedureType, inferRouterError } from '@trpc/server';
2
+ import { Observer, UnsubscribeFn, observable } from '@trpc/server/observable';
3
3
  import {
4
4
  TRPCClientIncomingMessage,
5
5
  TRPCClientIncomingRequest,
@@ -9,18 +9,34 @@ import {
9
9
  } from '@trpc/server/rpc';
10
10
  import { TRPCClientError } from '../TRPCClientError';
11
11
  import { retryDelay } from '../internals/retryDelay';
12
- import { Operation, OperationResultObserver, TRPCLink } from './types';
12
+ import { transformResult } from './internals/transformResult';
13
+ import { Operation, TRPCLink } from './types';
14
+
15
+ type WSCallbackResult<TRouter extends AnyRouter, TOutput> = TRPCResponseMessage<
16
+ TOutput,
17
+ inferRouterError<TRouter>
18
+ >;
19
+
20
+ type WSCallbackObserver<TRouter extends AnyRouter, TOutput> = Observer<
21
+ WSCallbackResult<TRouter, TOutput>,
22
+ TRPCClientError<TRouter>
23
+ >;
13
24
 
14
25
  export interface WebSocketClientOptions {
15
26
  url: string;
16
27
  WebSocket?: typeof WebSocket;
17
28
  retryDelayMs?: typeof retryDelay;
29
+ onOpen?: () => void;
30
+ onClose?: () => void;
18
31
  }
32
+
19
33
  export function createWSClient(opts: WebSocketClientOptions) {
20
34
  const {
21
35
  url,
22
36
  WebSocket: WebSocketImpl = WebSocket,
23
37
  retryDelayMs: retryDelayFn = retryDelay,
38
+ onOpen,
39
+ onClose,
24
40
  } = opts;
25
41
  /* istanbul ignore next */
26
42
  if (!WebSocketImpl) {
@@ -35,7 +51,7 @@ export function createWSClient(opts: WebSocketClientOptions) {
35
51
  /**
36
52
  * pending outgoing requests that are awaiting callback
37
53
  */
38
- type TCallbacks = OperationResultObserver<AnyRouter, unknown>;
54
+ type TCallbacks = WSCallbackObserver<AnyRouter, unknown>;
39
55
  type TRequest = {
40
56
  /**
41
57
  * Reference to the WebSocket instance this request was made to
@@ -123,6 +139,7 @@ export function createWSClient(opts: WebSocketClientOptions) {
123
139
  }
124
140
  connectAttempt = 0;
125
141
  state = 'open';
142
+ onOpen?.();
126
143
  dispatch();
127
144
  });
128
145
  conn.addEventListener('error', () => {
@@ -132,6 +149,9 @@ export function createWSClient(opts: WebSocketClientOptions) {
132
149
  });
133
150
  const handleIncomingRequest = (req: TRPCClientIncomingRequest) => {
134
151
  if (req.method === 'reconnect' && conn === activeConnection) {
152
+ if (state === 'open') {
153
+ onClose?.();
154
+ }
135
155
  reconnect();
136
156
  // notify subscribers
137
157
  for (const pendingReq of Object.values(pendingRequests)) {
@@ -148,7 +168,7 @@ export function createWSClient(opts: WebSocketClientOptions) {
148
168
  return;
149
169
  }
150
170
 
151
- req.callbacks.next?.({ data });
171
+ req.callbacks.next?.(data);
152
172
  if (req.ws !== activeConnection && conn === activeConnection) {
153
173
  const oldWs = req.ws;
154
174
  // gracefully replace old connection with this
@@ -179,6 +199,10 @@ export function createWSClient(opts: WebSocketClientOptions) {
179
199
  });
180
200
 
181
201
  conn.addEventListener('close', () => {
202
+ if (state === 'open') {
203
+ onClose?.();
204
+ }
205
+
182
206
  if (activeConnection === conn) {
183
207
  // connection might have been replaced already
184
208
  tryReconnect();
@@ -244,6 +268,7 @@ export function createWSClient(opts: WebSocketClientOptions) {
244
268
  return {
245
269
  close: () => {
246
270
  state = 'closed';
271
+ onClose?.();
247
272
  closeIfNoPending(activeConnection);
248
273
  clearTimeout(connectTimer as any);
249
274
  connectTimer = null;
@@ -292,7 +317,7 @@ export function wsLink<TRouter extends AnyRouter>(
292
317
  {
293
318
  error(err) {
294
319
  isDone = true;
295
- observer.error(err);
320
+ observer.error(err as any);
296
321
  unsub();
297
322
  },
298
323
  complete() {
@@ -309,8 +334,16 @@ export function wsLink<TRouter extends AnyRouter>(
309
334
  observer.complete();
310
335
  }
311
336
  },
312
- next(result) {
313
- observer.next(result);
337
+ next(message) {
338
+ const transformed = transformResult(message, runtime);
339
+
340
+ if (!transformed.ok) {
341
+ observer.error(TRPCClientError.from(transformed.error));
342
+ return;
343
+ }
344
+ observer.next({
345
+ result: transformed.result,
346
+ });
314
347
 
315
348
  if (op.type !== 'subscription') {
316
349
  // if it isn't a subscription we don't care about next response
@@ -1,30 +0,0 @@
1
- import { AnyRouter } from '@trpc/server';
2
- import { TRPCResultMessage } from '@trpc/server/rpc';
3
- import { TRPCClientRuntime } from '..';
4
- import { TRPCClientError } from '../../TRPCClientError';
5
- import { OperationResult } from '../types';
6
- /** @internal */
7
- export declare function transformOperationResult<TRouter extends AnyRouter, TOutput>(result: OperationResult<TRouter, TOutput>, runtime: TRPCClientRuntime): {
8
- readonly ok: false;
9
- readonly error: TRPCClientError<TRouter>;
10
- readonly context: import("..").OperationContext | undefined;
11
- readonly data?: undefined;
12
- } | {
13
- readonly ok: true;
14
- readonly data: TOutput;
15
- readonly context: import("..").OperationContext | undefined;
16
- readonly error?: undefined;
17
- };
18
- /** @internal */
19
- export declare function transformSubscriptionOperationResult<TRouter extends AnyRouter, TOutput>(result: OperationResult<TRouter, TOutput>, runtime: TRPCClientRuntime): {
20
- readonly ok: false;
21
- readonly error: TRPCClientError<TRouter>;
22
- readonly context: import("..").OperationContext | undefined;
23
- readonly data?: undefined;
24
- } | {
25
- readonly ok: true;
26
- readonly data: TRPCResultMessage<TOutput>;
27
- readonly context: import("..").OperationContext | undefined;
28
- readonly error?: undefined;
29
- };
30
- //# sourceMappingURL=transformOperationResult.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"transformOperationResult.d.ts","sourceRoot":"","sources":["../../../src/links/internals/transformOperationResult.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,IAAI,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C,gBAAgB;AAChB,wBAAgB,wBAAwB,CAAC,OAAO,SAAS,SAAS,EAAE,OAAO,EACzE,MAAM,EAAE,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,EACzC,OAAO,EAAE,iBAAiB;;;;;;;;;;EAgB3B;AAED,gBAAgB;AAChB,wBAAgB,oCAAoC,CAClD,OAAO,SAAS,SAAS,EACzB,OAAO,EACP,MAAM,EAAE,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,iBAAiB;;;;;;;;;;EAqBtE"}