@trpc/client 10.0.0-alpha.11 → 10.0.0-alpha.12
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.
- package/dist/{createChain-b7cb1f5a.mjs → createChain-480b6341.mjs} +4 -4
- package/dist/{createChain-3b458753.js → createChain-e77be464.js} +4 -4
- package/dist/index.js +79 -10
- package/dist/index.mjs +72 -8
- package/dist/internals/TRPCClient.d.ts +4 -2
- package/dist/internals/TRPCClient.d.ts.map +1 -1
- package/dist/links/dedupeLink.d.ts.map +1 -1
- package/dist/links/httpBatchLink.js +2 -2
- package/dist/links/httpBatchLink.mjs +2 -2
- package/dist/links/httpLink.js +2 -2
- package/dist/links/httpLink.mjs +2 -2
- package/dist/links/loggerLink.d.ts.map +1 -1
- package/dist/links/loggerLink.js +4 -3
- package/dist/links/loggerLink.mjs +3 -2
- package/dist/links/retryLink.d.ts.map +1 -1
- package/dist/links/splitLink.js +3 -3
- package/dist/links/splitLink.mjs +3 -3
- package/dist/links/transformerLink.js +2 -2
- package/dist/links/transformerLink.mjs +2 -2
- package/dist/links/types.d.ts +4 -3
- package/dist/links/types.d.ts.map +1 -1
- package/dist/links/wsLink.d.ts +1 -2
- package/dist/links/wsLink.d.ts.map +1 -1
- package/dist/links/wsLink.js +2 -2
- package/dist/links/wsLink.mjs +2 -2
- package/dist/observable/index.d.ts +4 -0
- package/dist/observable/index.d.ts.map +1 -0
- package/dist/observable/index.js +40 -0
- package/dist/observable/index.mjs +33 -0
- package/dist/{rx.ts.js → observable/index.ts.js} +0 -0
- package/dist/observable/observable.d.ts +4 -0
- package/dist/observable/observable.d.ts.map +1 -0
- package/dist/observable/operators/index.d.ts +4 -0
- package/dist/observable/operators/index.d.ts.map +1 -0
- package/dist/observable/operators/map.d.ts +3 -0
- package/dist/observable/operators/map.d.ts.map +1 -0
- package/dist/observable/operators/share.d.ts +6 -0
- package/dist/observable/operators/share.d.ts.map +1 -0
- package/dist/observable/operators/tap.d.ts +3 -0
- package/dist/observable/operators/tap.d.ts.map +1 -0
- package/dist/observable/types.d.ts +29 -0
- package/dist/observable/types.d.ts.map +1 -0
- package/dist/observable/util/identity.d.ts +2 -0
- package/dist/observable/util/identity.d.ts.map +1 -0
- package/dist/observable/util/observableToPromise.d.ts +10 -0
- package/dist/observable/util/observableToPromise.d.ts.map +1 -0
- package/dist/observable/util/pipe.d.ts +4 -0
- package/dist/observable/util/pipe.d.ts.map +1 -0
- package/dist/observable-16fde241.mjs +102 -0
- package/dist/observable-9aaca086.js +104 -0
- package/dist/share-4afc084f.js +110 -0
- package/dist/share-9f12d26c.mjs +108 -0
- package/dist/tap-aacf31bf.js +32 -0
- package/dist/tap-f567ea97.mjs +30 -0
- package/package.json +12 -12
- package/src/internals/TRPCClient.ts +8 -4
- package/src/links/dedupeLink.test.ts +3 -3
- package/src/links/dedupeLink.ts +27 -26
- package/src/links/httpBatchLink.ts +2 -2
- package/src/links/httpLink.ts +2 -2
- package/src/links/internals/createChain.test.ts +7 -7
- package/src/links/internals/createChain.ts +4 -4
- package/src/links/loggerLink.ts +3 -2
- package/src/links/retryLink.ts +3 -2
- package/src/links/splitLink.test.ts +3 -3
- package/src/links/splitLink.ts +2 -2
- package/src/links/transformerLink.ts +2 -2
- package/src/links/types.ts +4 -3
- package/src/links/wsLink.ts +3 -4
- package/src/observable/index.ts +3 -0
- package/src/observable/observable.test.ts +103 -0
- package/src/observable/observable.ts +70 -0
- package/src/observable/operators/index.ts +3 -0
- package/src/observable/operators/map.test.ts +92 -0
- package/src/observable/operators/map.ts +25 -0
- package/src/observable/operators/share.test.ts +60 -0
- package/src/observable/operators/share.ts +67 -0
- package/src/observable/operators/tap.ts +26 -0
- package/src/observable/types.ts +69 -0
- package/src/observable/util/identity.ts +3 -0
- package/src/observable/util/observableToPromise.ts +49 -0
- package/src/observable/util/pipe.ts +22 -0
- package/dist/rx.d.ts +0 -12
- package/dist/rx.d.ts.map +0 -1
- package/dist/rx.js +0 -130
- package/dist/rx.mjs +0 -114
- package/src/rx.ts +0 -82
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
function tap(observer) {
|
|
2
|
+
return function (originalObserver) {
|
|
3
|
+
return {
|
|
4
|
+
subscribe: function subscribe(observer2) {
|
|
5
|
+
return originalObserver.subscribe({
|
|
6
|
+
next: function next(v) {
|
|
7
|
+
var _observer$next, _observer2$next;
|
|
8
|
+
|
|
9
|
+
(_observer$next = observer.next) === null || _observer$next === void 0 ? void 0 : _observer$next.call(observer, v);
|
|
10
|
+
(_observer2$next = observer2.next) === null || _observer2$next === void 0 ? void 0 : _observer2$next.call(observer2, v);
|
|
11
|
+
},
|
|
12
|
+
error: function error(v) {
|
|
13
|
+
var _observer$error, _observer2$error;
|
|
14
|
+
|
|
15
|
+
(_observer$error = observer.error) === null || _observer$error === void 0 ? void 0 : _observer$error.call(observer, v);
|
|
16
|
+
(_observer2$error = observer2.error) === null || _observer2$error === void 0 ? void 0 : _observer2$error.call(observer2, v);
|
|
17
|
+
},
|
|
18
|
+
complete: function complete() {
|
|
19
|
+
var _observer$complete, _observer2$complete;
|
|
20
|
+
|
|
21
|
+
(_observer$complete = observer.complete) === null || _observer$complete === void 0 ? void 0 : _observer$complete.call(observer);
|
|
22
|
+
(_observer2$complete = observer2.complete) === null || _observer2$complete === void 0 ? void 0 : _observer2$complete.call(observer2);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { tap as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trpc/client",
|
|
3
|
-
"version": "10.0.0-alpha.
|
|
3
|
+
"version": "10.0.0-alpha.12",
|
|
4
4
|
"description": "tRPC Client lib",
|
|
5
5
|
"author": "KATT",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,11 +19,6 @@
|
|
|
19
19
|
"require": "./dist/index.js",
|
|
20
20
|
"default": "./dist/index.js"
|
|
21
21
|
},
|
|
22
|
-
"./rx": {
|
|
23
|
-
"import": "./dist/rx.mjs",
|
|
24
|
-
"require": "./dist/rx.js",
|
|
25
|
-
"default": "./dist/rx.js"
|
|
26
|
-
},
|
|
27
22
|
"./links/httpBatchLink": {
|
|
28
23
|
"import": "./dist/links/httpBatchLink.mjs",
|
|
29
24
|
"require": "./dist/links/httpBatchLink.js",
|
|
@@ -53,29 +48,34 @@
|
|
|
53
48
|
"import": "./dist/links/wsLink.mjs",
|
|
54
49
|
"require": "./dist/links/wsLink.js",
|
|
55
50
|
"default": "./dist/links/wsLink.js"
|
|
51
|
+
},
|
|
52
|
+
"./observable": {
|
|
53
|
+
"import": "./dist/observable/index.mjs",
|
|
54
|
+
"require": "./dist/observable/index.js",
|
|
55
|
+
"default": "./dist/observable/index.js"
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
58
|
"files": [
|
|
59
59
|
"README.md",
|
|
60
60
|
"dist",
|
|
61
61
|
"links",
|
|
62
|
-
"src"
|
|
62
|
+
"src",
|
|
63
|
+
"rx"
|
|
63
64
|
],
|
|
64
65
|
"scripts": {
|
|
65
66
|
"build": "rollup -c"
|
|
66
67
|
},
|
|
67
68
|
"dependencies": {
|
|
68
|
-
"@babel/runtime": "^7.9.0"
|
|
69
|
-
"rxjs": "^7.5.4"
|
|
69
|
+
"@babel/runtime": "^7.9.0"
|
|
70
70
|
},
|
|
71
71
|
"peerDependencies": {
|
|
72
|
-
"@trpc/server": "10.0.0-alpha.
|
|
72
|
+
"@trpc/server": "10.0.0-alpha.12"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
|
-
"@trpc/server": "10.0.0-alpha.
|
|
75
|
+
"@trpc/server": "10.0.0-alpha.12"
|
|
76
76
|
},
|
|
77
77
|
"publishConfig": {
|
|
78
78
|
"access": "public"
|
|
79
79
|
},
|
|
80
|
-
"gitHead": "
|
|
80
|
+
"gitHead": "04b7957f4b462d4e4a83d68cccc50abd72c332e3"
|
|
81
81
|
}
|
|
@@ -18,8 +18,11 @@ import {
|
|
|
18
18
|
OperationLink,
|
|
19
19
|
TRPCLink,
|
|
20
20
|
} from '../links/types';
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
21
|
+
import { Unsubscribable } from '../observable';
|
|
22
|
+
import { inferObservableValue } from '../observable/observable';
|
|
23
|
+
import { share } from '../observable/operators';
|
|
24
|
+
import { Observer } from '../observable/types';
|
|
25
|
+
import { observableToPromise } from '../observable/util/observableToPromise';
|
|
23
26
|
import { TRPCClientError } from '../TRPCClientError';
|
|
24
27
|
import { getAbortController } from './fetchHelpers';
|
|
25
28
|
|
|
@@ -213,8 +216,9 @@ export class TRPCClient<TRouter extends AnyRouter> {
|
|
|
213
216
|
>(
|
|
214
217
|
path: TPath,
|
|
215
218
|
input: TInput,
|
|
216
|
-
opts: TRPCRequestOptions &
|
|
217
|
-
|
|
219
|
+
opts: TRPCRequestOptions &
|
|
220
|
+
Partial<Observer<TRPCResult<TOutput>, TRPCClientError<TRouter>>>,
|
|
221
|
+
): Unsubscribable {
|
|
218
222
|
const observable$ = this.$request<TInput, TOutput>({
|
|
219
223
|
type: 'subscription',
|
|
220
224
|
path,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { waitFor } from '@testing-library/dom';
|
|
2
2
|
import { AnyRouter } from '@trpc/server';
|
|
3
3
|
import { OperationLink } from '..';
|
|
4
|
-
import {
|
|
4
|
+
import { observable } from '../observable/observable';
|
|
5
5
|
import { dedupeLink } from './dedupeLink';
|
|
6
6
|
import { createChain } from './internals/createChain';
|
|
7
7
|
|
|
@@ -12,7 +12,7 @@ test('dedupeLink', async () => {
|
|
|
12
12
|
// "dedupe link"
|
|
13
13
|
dedupeLink()(null as any),
|
|
14
14
|
({ op }) => {
|
|
15
|
-
return
|
|
15
|
+
return observable((subscribe) => {
|
|
16
16
|
endingLinkTriggered();
|
|
17
17
|
const timer = setTimeout(() => {
|
|
18
18
|
timerTriggered();
|
|
@@ -75,7 +75,7 @@ test('dedupe - cancel one does not cancel the other', async () => {
|
|
|
75
75
|
// "dedupe link"
|
|
76
76
|
dedupeLink()(null as any),
|
|
77
77
|
({ op }) => {
|
|
78
|
-
return
|
|
78
|
+
return observable((subscribe) => {
|
|
79
79
|
endingLinkTriggered();
|
|
80
80
|
const timer = setTimeout(() => {
|
|
81
81
|
timerTriggered();
|
package/src/links/dedupeLink.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { AnyRouter } from '@trpc/server';
|
|
2
|
-
import {
|
|
3
|
-
import { share } from '../
|
|
4
|
-
import {
|
|
2
|
+
import { observable } from '../observable/observable';
|
|
3
|
+
import { share } from '../observable/operators';
|
|
4
|
+
import { Observable } from '../observable/types';
|
|
5
|
+
import { TRPCLink } from './types';
|
|
5
6
|
|
|
6
7
|
export function dedupeLink<
|
|
7
8
|
TRouter extends AnyRouter = AnyRouter,
|
|
@@ -9,7 +10,7 @@ export function dedupeLink<
|
|
|
9
10
|
// initialized config
|
|
10
11
|
return () => {
|
|
11
12
|
// initialized in app
|
|
12
|
-
const pending: Record<string, Observable<any>> = {};
|
|
13
|
+
const pending: Record<string, Observable<any, any>> = {};
|
|
13
14
|
return ({ op, next }) => {
|
|
14
15
|
// initialized for request
|
|
15
16
|
|
|
@@ -20,31 +21,31 @@ export function dedupeLink<
|
|
|
20
21
|
const key = JSON.stringify([op.path, op.input]);
|
|
21
22
|
if (pending[key]) {
|
|
22
23
|
// console.log('hooking into pending', { op });
|
|
23
|
-
return
|
|
24
|
+
return observable((observer) => pending[key].subscribe(observer));
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
const shared$ =
|
|
27
|
-
(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
next(v)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
error(e) {
|
|
36
|
-
observer.error(e);
|
|
37
|
-
},
|
|
38
|
-
complete() {
|
|
39
|
-
observer.complete();
|
|
40
|
-
},
|
|
41
|
-
});
|
|
42
|
-
return () => {
|
|
27
|
+
const shared$ = observable((observer) => {
|
|
28
|
+
function reset() {
|
|
29
|
+
delete pending[key];
|
|
30
|
+
}
|
|
31
|
+
const subscription = next(op).subscribe({
|
|
32
|
+
next(v) {
|
|
33
|
+
observer.next(v);
|
|
34
|
+
},
|
|
35
|
+
error(e) {
|
|
43
36
|
reset();
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
37
|
+
observer.error(e);
|
|
38
|
+
},
|
|
39
|
+
complete() {
|
|
40
|
+
reset();
|
|
41
|
+
observer.complete();
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
return () => {
|
|
45
|
+
reset();
|
|
46
|
+
subscription.unsubscribe();
|
|
47
|
+
};
|
|
48
|
+
}).pipe(share());
|
|
48
49
|
pending[key] = shared$;
|
|
49
50
|
return shared$;
|
|
50
51
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AnyRouter, ProcedureType } from '@trpc/server';
|
|
2
2
|
import { dataLoader } from '../internals/dataLoader';
|
|
3
|
-
import {
|
|
3
|
+
import { observable } from '../observable/observable';
|
|
4
4
|
import { TRPCLink } from './types';
|
|
5
5
|
import { HTTPLinkOptions, httpRequest, ResponseShape } from './httpUtils';
|
|
6
6
|
|
|
@@ -52,7 +52,7 @@ export function httpBatchLink<TRouter extends AnyRouter>(
|
|
|
52
52
|
|
|
53
53
|
const loaders = { query, subscription, mutation };
|
|
54
54
|
return ({ op }) => {
|
|
55
|
-
return
|
|
55
|
+
return observable((observer) => {
|
|
56
56
|
const loader = loaders[op.type];
|
|
57
57
|
const { promise, cancel } = loader.load(op);
|
|
58
58
|
|
package/src/links/httpLink.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AnyRouter } from '@trpc/server';
|
|
2
|
-
import {
|
|
2
|
+
import { observable } from '../observable/observable';
|
|
3
3
|
import { TRPCLink } from './types';
|
|
4
4
|
import { HTTPLinkOptions, httpRequest } from './httpUtils';
|
|
5
5
|
|
|
@@ -9,7 +9,7 @@ export function httpLink<TRouter extends AnyRouter>(
|
|
|
9
9
|
const { url } = opts;
|
|
10
10
|
return (runtime) =>
|
|
11
11
|
({ op }) =>
|
|
12
|
-
|
|
12
|
+
observable((observer) => {
|
|
13
13
|
const { path, input, type } = op;
|
|
14
14
|
const { promise, cancel } = httpRequest({
|
|
15
15
|
runtime,
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { AnyRouter } from '@trpc/server/src';
|
|
2
2
|
import { createChain } from './createChain';
|
|
3
|
-
import {
|
|
3
|
+
import { observable } from '../../observable/observable';
|
|
4
4
|
|
|
5
5
|
describe('chain', () => {
|
|
6
6
|
test('trivial', () => {
|
|
7
7
|
const result$ = createChain<AnyRouter, unknown, unknown>({
|
|
8
8
|
links: [
|
|
9
9
|
({ next, op }) => {
|
|
10
|
-
return
|
|
10
|
+
return observable((observer) => {
|
|
11
11
|
const subscription = next(op).subscribe(observer);
|
|
12
12
|
return () => {
|
|
13
13
|
subscription.unsubscribe();
|
|
@@ -15,7 +15,7 @@ describe('chain', () => {
|
|
|
15
15
|
});
|
|
16
16
|
},
|
|
17
17
|
({ op }) => {
|
|
18
|
-
return
|
|
18
|
+
return observable((observer) => {
|
|
19
19
|
observer.next({
|
|
20
20
|
context: {},
|
|
21
21
|
data: {
|
|
@@ -51,7 +51,7 @@ describe('chain', () => {
|
|
|
51
51
|
const result$ = createChain<AnyRouter, unknown, unknown>({
|
|
52
52
|
links: [
|
|
53
53
|
({ next, op }) => {
|
|
54
|
-
return
|
|
54
|
+
return observable((observer) => {
|
|
55
55
|
observer.next({
|
|
56
56
|
context: {},
|
|
57
57
|
data: {
|
|
@@ -62,14 +62,14 @@ describe('chain', () => {
|
|
|
62
62
|
},
|
|
63
63
|
},
|
|
64
64
|
});
|
|
65
|
-
const
|
|
65
|
+
const subscription = next(op).subscribe(observer);
|
|
66
66
|
return () => {
|
|
67
|
-
|
|
67
|
+
subscription.unsubscribe();
|
|
68
68
|
};
|
|
69
69
|
});
|
|
70
70
|
},
|
|
71
71
|
({ op }) => {
|
|
72
|
-
return
|
|
72
|
+
return observable((observer) => {
|
|
73
73
|
observer.next({
|
|
74
74
|
data: {
|
|
75
75
|
id: null,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AnyRouter } from '@trpc/server';
|
|
2
|
-
import {
|
|
2
|
+
import { observable } from '../../observable/observable';
|
|
3
3
|
import { Operation, OperationLink, OperationResultObservable } from '../types';
|
|
4
4
|
|
|
5
5
|
/** @internal */
|
|
@@ -11,10 +11,10 @@ export function createChain<
|
|
|
11
11
|
links: OperationLink<TRouter, TInput, TOutput>[];
|
|
12
12
|
op: Operation<TInput>;
|
|
13
13
|
}): OperationResultObservable<TRouter, TOutput> {
|
|
14
|
-
return
|
|
14
|
+
return observable((observer) => {
|
|
15
15
|
function execute(index = 0, op = opts.op) {
|
|
16
16
|
const next = opts.links[index];
|
|
17
|
-
const
|
|
17
|
+
const subscription = next({
|
|
18
18
|
op,
|
|
19
19
|
next(nextOp) {
|
|
20
20
|
const nextObserver = execute(index + 1, nextOp);
|
|
@@ -22,7 +22,7 @@ export function createChain<
|
|
|
22
22
|
return nextObserver;
|
|
23
23
|
},
|
|
24
24
|
});
|
|
25
|
-
return
|
|
25
|
+
return subscription;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const obs$ = execute();
|
package/src/links/loggerLink.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AnyRouter } from '@trpc/server';
|
|
2
2
|
import { TRPCClientError } from '..';
|
|
3
|
-
import {
|
|
3
|
+
import { observable } from '../observable/observable';
|
|
4
|
+
import { tap } from '../observable/operators';
|
|
4
5
|
import { Operation, OperationResult, TRPCLink } from './types';
|
|
5
6
|
|
|
6
7
|
type ConsoleEsque = {
|
|
@@ -107,7 +108,7 @@ export function loggerLink<TRouter extends AnyRouter = AnyRouter>(
|
|
|
107
108
|
|
|
108
109
|
return () => {
|
|
109
110
|
return ({ op, next }) => {
|
|
110
|
-
return
|
|
111
|
+
return observable((observer) => {
|
|
111
112
|
// ->
|
|
112
113
|
enabled({ ...op, direction: 'up' }) &&
|
|
113
114
|
logger({
|
package/src/links/retryLink.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AnyRouter } from '@trpc/server';
|
|
2
|
-
import {
|
|
2
|
+
import { observable } from '../observable/observable';
|
|
3
|
+
import { Unsubscribable } from '../observable/types';
|
|
3
4
|
import { TRPCLink } from './types';
|
|
4
5
|
|
|
5
6
|
export function retryLink<TRouter extends AnyRouter = AnyRouter>(opts: {
|
|
@@ -10,7 +11,7 @@ export function retryLink<TRouter extends AnyRouter = AnyRouter>(opts: {
|
|
|
10
11
|
// initialized in app
|
|
11
12
|
return ({ op, next }) => {
|
|
12
13
|
// initialized for request
|
|
13
|
-
return
|
|
14
|
+
return observable((observer) => {
|
|
14
15
|
let next$: Unsubscribable | null = null;
|
|
15
16
|
let attempts = 0;
|
|
16
17
|
let isDone = false;
|
|
@@ -3,17 +3,17 @@ import { AnyRouter } from '../../../server/src';
|
|
|
3
3
|
import { createChain } from '../links/internals/createChain';
|
|
4
4
|
import { splitLink } from '../links/splitLink';
|
|
5
5
|
import { OperationLink, TRPCLink } from '../links/types';
|
|
6
|
-
import {
|
|
6
|
+
import { observable } from '../observable';
|
|
7
7
|
|
|
8
8
|
test('splitLink', () => {
|
|
9
9
|
const wsLinkSpy = jest.fn();
|
|
10
10
|
const wsLink: TRPCLink<any> = () => () =>
|
|
11
|
-
|
|
11
|
+
observable(() => {
|
|
12
12
|
wsLinkSpy();
|
|
13
13
|
});
|
|
14
14
|
const httpLinkSpy = jest.fn();
|
|
15
15
|
const httpLink: TRPCLink<any> = () => () =>
|
|
16
|
-
|
|
16
|
+
observable(() => {
|
|
17
17
|
httpLinkSpy();
|
|
18
18
|
});
|
|
19
19
|
const links: OperationLink<AnyRouter, any, any>[] = [
|
package/src/links/splitLink.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AnyRouter } from '@trpc/server';
|
|
2
|
-
import {
|
|
2
|
+
import { observable } from '../observable/observable';
|
|
3
3
|
import { TRPCLink, Operation } from './types';
|
|
4
4
|
import { createChain } from './internals/createChain';
|
|
5
5
|
|
|
@@ -21,7 +21,7 @@ export function splitLink<TRouter extends AnyRouter = AnyRouter>(opts: {
|
|
|
21
21
|
const yes = asArray(opts.true).map((link) => link(rt));
|
|
22
22
|
const no = asArray(opts.false).map((link) => link(rt));
|
|
23
23
|
return (props) => {
|
|
24
|
-
return
|
|
24
|
+
return observable((observer) => {
|
|
25
25
|
const links = opts.condition(props.op) ? yes : no;
|
|
26
26
|
return createChain({ op: props.op, links }).subscribe(observer);
|
|
27
27
|
});
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
ClientDataTransformerOptions,
|
|
4
4
|
DataTransformer,
|
|
5
5
|
} from '@trpc/server';
|
|
6
|
-
import {
|
|
6
|
+
import { observable } from '../observable/observable';
|
|
7
7
|
import { OperationResult, TRPCLink } from './types';
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -54,7 +54,7 @@ export function transformerLink<TRouter extends AnyRouter = AnyRouter>(
|
|
|
54
54
|
return () => {
|
|
55
55
|
return (props) => {
|
|
56
56
|
const input = _transformer.serialize(props.op.input);
|
|
57
|
-
return
|
|
57
|
+
return observable((observer) => {
|
|
58
58
|
const subscription = props.next({ ...props.op, input }).subscribe({
|
|
59
59
|
next(value) {
|
|
60
60
|
const transformed = transformOperationResult(value, _transformer);
|
package/src/links/types.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AnyRouter, inferRouterError, Dict } from '@trpc/server';
|
|
2
2
|
import { TRPCResponse } from '@trpc/server/rpc';
|
|
3
|
-
import { Observable, Observer } from '
|
|
3
|
+
import { Observable, Observer } from '../observable/types';
|
|
4
|
+
import { TRPCClientError } from '../TRPCClientError';
|
|
4
5
|
|
|
5
6
|
export type CancelFn = () => void;
|
|
6
7
|
|
|
@@ -43,12 +44,12 @@ export interface OperationResult<TRouter extends AnyRouter, TOutput> {
|
|
|
43
44
|
export type OperationResultObservable<
|
|
44
45
|
TRouter extends AnyRouter,
|
|
45
46
|
TOutput,
|
|
46
|
-
> = Observable<OperationResult<TRouter, TOutput>>;
|
|
47
|
+
> = Observable<OperationResult<TRouter, TOutput>, TRPCClientError<TRouter>>;
|
|
47
48
|
|
|
48
49
|
export type OperationResultObserver<
|
|
49
50
|
TRouter extends AnyRouter,
|
|
50
51
|
TOutput,
|
|
51
|
-
> = Observer<OperationResult<TRouter, TOutput>>;
|
|
52
|
+
> = Observer<OperationResult<TRouter, TOutput>, TRPCClientError<TRouter>>;
|
|
52
53
|
|
|
53
54
|
export type OperationLink<
|
|
54
55
|
TRouter extends AnyRouter,
|
package/src/links/wsLink.ts
CHANGED
|
@@ -6,12 +6,11 @@ import {
|
|
|
6
6
|
TRPCResponse,
|
|
7
7
|
} from '@trpc/server/rpc';
|
|
8
8
|
import { retryDelay } from '../internals/retryDelay';
|
|
9
|
-
|
|
10
|
-
import {
|
|
9
|
+
import { UnsubscribeFn } from '../observable';
|
|
10
|
+
import { observable } from '../observable/observable';
|
|
11
11
|
import { TRPCClientError } from '../TRPCClientError';
|
|
12
12
|
import { Operation, OperationResultObserver, TRPCLink } from './types';
|
|
13
13
|
|
|
14
|
-
type UnsubscribeFn = () => void;
|
|
15
14
|
export interface WebSocketClientOptions {
|
|
16
15
|
url: string;
|
|
17
16
|
WebSocket?: WebSocket;
|
|
@@ -283,7 +282,7 @@ export function wsLink<TRouter extends AnyRouter>(
|
|
|
283
282
|
return () => {
|
|
284
283
|
const { client } = opts;
|
|
285
284
|
return ({ op }) => {
|
|
286
|
-
return
|
|
285
|
+
return observable((observer) => {
|
|
287
286
|
const { type, input, path, id, context } = op;
|
|
288
287
|
|
|
289
288
|
let isDone = false;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
2
|
+
import { observable } from './observable';
|
|
3
|
+
import { tap } from './operators';
|
|
4
|
+
import { share } from './operators/share';
|
|
5
|
+
|
|
6
|
+
test('vanilla observable - complete()', () => {
|
|
7
|
+
const obs = observable<number, Error>((observer) => {
|
|
8
|
+
observer.next(1);
|
|
9
|
+
observer.complete();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const next = jest.fn();
|
|
13
|
+
const error = jest.fn();
|
|
14
|
+
const complete = jest.fn();
|
|
15
|
+
obs.subscribe({
|
|
16
|
+
next,
|
|
17
|
+
error,
|
|
18
|
+
complete,
|
|
19
|
+
});
|
|
20
|
+
expect(next.mock.calls).toHaveLength(1);
|
|
21
|
+
expect(complete.mock.calls).toHaveLength(1);
|
|
22
|
+
expect(error.mock.calls).toHaveLength(0);
|
|
23
|
+
expect(next.mock.calls[0][0]).toBe(1);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('vanilla observable - unsubscribe()', () => {
|
|
27
|
+
const obs$ = observable<number, Error>((observer) => {
|
|
28
|
+
observer.next(1);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const next = jest.fn();
|
|
32
|
+
const error = jest.fn();
|
|
33
|
+
const complete = jest.fn();
|
|
34
|
+
const sub = obs$.subscribe({
|
|
35
|
+
next,
|
|
36
|
+
error,
|
|
37
|
+
complete,
|
|
38
|
+
});
|
|
39
|
+
sub.unsubscribe();
|
|
40
|
+
expect(next.mock.calls).toHaveLength(1);
|
|
41
|
+
expect(complete.mock.calls).toHaveLength(0);
|
|
42
|
+
expect(error.mock.calls).toHaveLength(0);
|
|
43
|
+
expect(next.mock.calls[0][0]).toBe(1);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('pipe - combine operators', () => {
|
|
47
|
+
const taps = {
|
|
48
|
+
next: jest.fn(),
|
|
49
|
+
complete: jest.fn(),
|
|
50
|
+
error: jest.fn(),
|
|
51
|
+
};
|
|
52
|
+
const obs = observable<number, Error>((observer) => {
|
|
53
|
+
observer.next(1);
|
|
54
|
+
}).pipe(
|
|
55
|
+
// operators:
|
|
56
|
+
share(),
|
|
57
|
+
tap(taps),
|
|
58
|
+
);
|
|
59
|
+
{
|
|
60
|
+
const next = jest.fn();
|
|
61
|
+
const error = jest.fn();
|
|
62
|
+
const complete = jest.fn();
|
|
63
|
+
obs.subscribe({
|
|
64
|
+
next,
|
|
65
|
+
error,
|
|
66
|
+
complete,
|
|
67
|
+
});
|
|
68
|
+
expect(next.mock.calls).toHaveLength(1);
|
|
69
|
+
expect(complete.mock.calls).toHaveLength(0);
|
|
70
|
+
expect(error.mock.calls).toHaveLength(0);
|
|
71
|
+
expect(next.mock.calls[0][0]).toBe(1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
{
|
|
75
|
+
const next = jest.fn();
|
|
76
|
+
const error = jest.fn();
|
|
77
|
+
const complete = jest.fn();
|
|
78
|
+
obs.subscribe({
|
|
79
|
+
next,
|
|
80
|
+
error,
|
|
81
|
+
complete,
|
|
82
|
+
});
|
|
83
|
+
expect(next.mock.calls).toHaveLength(0);
|
|
84
|
+
expect(complete.mock.calls).toHaveLength(0);
|
|
85
|
+
expect(error.mock.calls).toHaveLength(0);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
expect({
|
|
89
|
+
next: taps.next.mock.calls,
|
|
90
|
+
error: taps.error.mock.calls,
|
|
91
|
+
complete: taps.complete.mock.calls,
|
|
92
|
+
}).toMatchInlineSnapshot(`
|
|
93
|
+
Object {
|
|
94
|
+
"complete": Array [],
|
|
95
|
+
"error": Array [],
|
|
96
|
+
"next": Array [
|
|
97
|
+
Array [
|
|
98
|
+
1,
|
|
99
|
+
],
|
|
100
|
+
],
|
|
101
|
+
}
|
|
102
|
+
`);
|
|
103
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { pipeFromArray } from './util/pipe';
|
|
2
|
+
import { Observable, Observer, OperatorFunction, TeardownLogic } from './types';
|
|
3
|
+
|
|
4
|
+
export type inferObservableValue<TObservable extends Observable<any, any>> =
|
|
5
|
+
TObservable extends Observable<infer TValue, any> ? TValue : never;
|
|
6
|
+
|
|
7
|
+
export function observable<TValue, TError = unknown>(
|
|
8
|
+
subscribe: (observer: Observer<TValue, TError>) => TeardownLogic,
|
|
9
|
+
): Observable<TValue, TError> {
|
|
10
|
+
const self: Observable<TValue, TError> = {
|
|
11
|
+
subscribe(observer) {
|
|
12
|
+
let teardownRef: TeardownLogic | null = null;
|
|
13
|
+
let isDone = false;
|
|
14
|
+
let unsubscribed = false;
|
|
15
|
+
let teardownImmediately = false;
|
|
16
|
+
function unsubscribe() {
|
|
17
|
+
if (teardownRef === null) {
|
|
18
|
+
teardownImmediately = true;
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (unsubscribed) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
unsubscribed = true;
|
|
25
|
+
|
|
26
|
+
if (typeof teardownRef === 'function') {
|
|
27
|
+
teardownRef();
|
|
28
|
+
} else if (teardownRef) {
|
|
29
|
+
teardownRef.unsubscribe();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
teardownRef = subscribe({
|
|
33
|
+
next(value) {
|
|
34
|
+
if (isDone) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
observer.next?.(value);
|
|
38
|
+
},
|
|
39
|
+
error(err) {
|
|
40
|
+
if (isDone) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
isDone = true;
|
|
44
|
+
observer.error?.(err);
|
|
45
|
+
unsubscribe();
|
|
46
|
+
},
|
|
47
|
+
complete() {
|
|
48
|
+
if (isDone) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
isDone = true;
|
|
52
|
+
observer.complete?.();
|
|
53
|
+
unsubscribe();
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
if (teardownImmediately) {
|
|
57
|
+
unsubscribe();
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
unsubscribe,
|
|
61
|
+
};
|
|
62
|
+
},
|
|
63
|
+
pipe(
|
|
64
|
+
...operations: OperatorFunction<any, any, any, any>[]
|
|
65
|
+
): Observable<any, any> {
|
|
66
|
+
return pipeFromArray(operations)(self) as any;
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
return self;
|
|
70
|
+
}
|