@trpc/client 11.0.0-alpha-tmp-issues-5851-take-two.496 → 11.0.0-alpha-tmp-subscription-connection-state.485
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/bundle-analysis.json +80 -63
- package/dist/index.js +6 -4
- package/dist/index.mjs +2 -1
- package/dist/internals/TRPCUntypedClient.d.ts +2 -1
- package/dist/internals/TRPCUntypedClient.d.ts.map +1 -1
- package/dist/internals/TRPCUntypedClient.js +2 -0
- package/dist/internals/TRPCUntypedClient.mjs +2 -0
- package/dist/links/httpSubscriptionLink.d.ts +3 -2
- package/dist/links/httpSubscriptionLink.d.ts.map +1 -1
- package/dist/links/httpSubscriptionLink.js +53 -3
- package/dist/links/httpSubscriptionLink.mjs +53 -3
- package/dist/links/internals/httpUtils.d.ts.map +1 -1
- package/dist/links/internals/httpUtils.js +28 -1
- package/dist/links/internals/httpUtils.mjs +28 -1
- package/dist/links/internals/urlWithConnectionParams.d.ts +1 -2
- package/dist/links/internals/urlWithConnectionParams.d.ts.map +1 -1
- package/dist/links/types.d.ts +23 -3
- package/dist/links/types.d.ts.map +1 -1
- package/dist/links/types.js +7 -0
- package/dist/links/types.mjs +5 -0
- package/dist/links/wsLink.d.ts +5 -3
- package/dist/links/wsLink.d.ts.map +1 -1
- package/dist/links/wsLink.js +86 -17
- package/dist/links/wsLink.mjs +86 -17
- package/package.json +4 -4
- package/src/internals/TRPCUntypedClient.ts +4 -0
- package/src/links/httpSubscriptionLink.ts +70 -5
- package/src/links/internals/httpUtils.ts +35 -1
- package/src/links/internals/urlWithConnectionParams.ts +1 -1
- package/src/links/types.ts +48 -2
- package/src/links/wsLink.ts +108 -21
|
@@ -6,7 +6,7 @@ export declare const resultOf: <T>(value: T | (() => T)) => T;
|
|
|
6
6
|
/**
|
|
7
7
|
* A value that can be wrapped in callback
|
|
8
8
|
*/
|
|
9
|
-
type CallbackOrValue<T> = T | (() => T | Promise<T>);
|
|
9
|
+
export type CallbackOrValue<T> = T | (() => T | Promise<T>);
|
|
10
10
|
export interface UrlOptionsWithConnectionParams {
|
|
11
11
|
/**
|
|
12
12
|
* The URL to connect to (can be a function that returns a URL)
|
|
@@ -19,5 +19,4 @@ export interface UrlOptionsWithConnectionParams {
|
|
|
19
19
|
*/
|
|
20
20
|
connectionParams?: CallbackOrValue<TRPCRequestInfo['connectionParams']>;
|
|
21
21
|
}
|
|
22
|
-
export {};
|
|
23
22
|
//# sourceMappingURL=urlWithConnectionParams.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"urlWithConnectionParams.d.ts","sourceRoot":"","sources":["../../../src/links/internals/urlWithConnectionParams.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD;;GAEG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,KAAG,CAElD,CAAC;AAEF;;GAEG;AACH,
|
|
1
|
+
{"version":3,"file":"urlWithConnectionParams.d.ts","sourceRoot":"","sources":["../../../src/links/internals/urlWithConnectionParams.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD;;GAEG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,KAAG,CAElD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAE5D,MAAM,WAAW,8BAA8B;IAC7C;;OAEG;IACH,GAAG,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;IAE7B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,eAAe,CAAC,eAAe,CAAC,kBAAkB,CAAC,CAAC,CAAC;CACzE"}
|
package/dist/links/types.d.ts
CHANGED
|
@@ -33,17 +33,37 @@ export type HTTPHeaders = HeadersInitEsque | Record<string, string[] | string |
|
|
|
33
33
|
export type TRPCFetch = (url: string, options?: RequestInit) => Promise<ResponseEsque>;
|
|
34
34
|
export interface TRPCClientRuntime {
|
|
35
35
|
}
|
|
36
|
+
export type ConnectionState = 'idle' | 'connecting' | 'pending' | 'error';
|
|
37
|
+
export interface ConnectionStateMessageBase {
|
|
38
|
+
type: 'state';
|
|
39
|
+
}
|
|
40
|
+
export interface IdleStateMessage extends ConnectionStateMessageBase {
|
|
41
|
+
state: 'idle';
|
|
42
|
+
}
|
|
43
|
+
export interface ConnectingStateMessage<TError> extends ConnectionStateMessageBase {
|
|
44
|
+
state: 'connecting';
|
|
45
|
+
data: TError | null;
|
|
46
|
+
}
|
|
47
|
+
export interface PendingStateMessage extends ConnectionStateMessageBase {
|
|
48
|
+
state: 'pending';
|
|
49
|
+
}
|
|
50
|
+
export interface ErrorStateMessage<TError> extends ConnectionStateMessageBase {
|
|
51
|
+
state: 'error';
|
|
52
|
+
data: TError;
|
|
53
|
+
}
|
|
54
|
+
export type TRPCConnectionStateMessage<TError> = IdleStateMessage | ConnectingStateMessage<TError> | PendingStateMessage | ErrorStateMessage<TError>;
|
|
55
|
+
export declare const isConnectionStateMessage: <TError>(msg: unknown) => msg is TRPCConnectionStateMessage<TError>;
|
|
36
56
|
/**
|
|
37
57
|
* @internal
|
|
38
58
|
*/
|
|
39
|
-
export interface OperationResultEnvelope<TOutput> {
|
|
40
|
-
result: TRPCResultMessage<TOutput>['result'] | TRPCSuccessResponse<TOutput>['result'];
|
|
59
|
+
export interface OperationResultEnvelope<TOutput, TError = unknown> {
|
|
60
|
+
result: TRPCConnectionStateMessage<TError> | TRPCResultMessage<TOutput>['result'] | TRPCSuccessResponse<TOutput>['result'];
|
|
41
61
|
context?: OperationContext;
|
|
42
62
|
}
|
|
43
63
|
/**
|
|
44
64
|
* @internal
|
|
45
65
|
*/
|
|
46
|
-
export type OperationResultObservable<TInferrable extends InferrableClientTypes, TOutput> = Observable<OperationResultEnvelope<TOutput
|
|
66
|
+
export type OperationResultObservable<TInferrable extends InferrableClientTypes, TOutput> = Observable<OperationResultEnvelope<TOutput, TRPCClientError<TInferrable>>, TRPCClientError<TInferrable>>;
|
|
47
67
|
/**
|
|
48
68
|
* @internal
|
|
49
69
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/links/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,KAAK,EACV,qBAAqB,EACrB,KAAK,EACL,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,0CAA0C,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,EACL,qBAAqB,EACrB,UAAU,EACV,WAAW,GACZ,MAAM,0BAA0B,CAAC;AAElC;;GAEG;AACH,MAAM,WAAW,gBAAiB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAAG;AAEpE;;GAEG;AACH,MAAM,MAAM,SAAS,CAAC,MAAM,GAAG,OAAO,IAAI;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,UAAU,GAAG,OAAO,GAAG,cAAc,CAAC;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,gBAAgB,CAAC;IAC1B,MAAM,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;CAC5B,CAAC;AAEF,UAAU,gBAAgB;IACxB,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,gBAAgB,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACzD;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,GACnB,gBAAgB,GAChB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;AAElD;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,CACtB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,WAAW,KAClB,OAAO,CAAC,aAAa,CAAC,CAAC;AAE5B,MAAM,WAAW,iBAAiB;CAEjC;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB,CAAC,OAAO;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/links/types.ts"],"names":[],"mappings":"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"}
|
package/dist/links/wsLink.d.ts
CHANGED
|
@@ -3,8 +3,10 @@ import type { AnyRouter, inferClientTypes, inferRouterError, TRPCResponseMessage
|
|
|
3
3
|
import { TRPCClientError } from '../TRPCClientError';
|
|
4
4
|
import type { TransformerOptions } from '../unstable-internals';
|
|
5
5
|
import { type UrlOptionsWithConnectionParams } from './internals/urlWithConnectionParams';
|
|
6
|
-
import type
|
|
7
|
-
type WSCallbackResult<TRouter extends AnyRouter, TOutput> = TRPCResponseMessage<TOutput, inferRouterError<TRouter
|
|
6
|
+
import { type Operation, type TRPCConnectionStateMessage, type TRPCLink } from './types';
|
|
7
|
+
type WSCallbackResult<TRouter extends AnyRouter, TOutput> = TRPCResponseMessage<TOutput, inferRouterError<TRouter>> | {
|
|
8
|
+
result: TRPCConnectionStateMessage<inferRouterError<TRouter>>;
|
|
9
|
+
};
|
|
8
10
|
type WSCallbackObserver<TRouter extends AnyRouter, TOutput> = Observer<WSCallbackResult<TRouter, TOutput>, TRPCClientError<TRouter>>;
|
|
9
11
|
declare const exponentialBackoff: (attemptIndex: number) => number;
|
|
10
12
|
export interface WebSocketClientOptions extends UrlOptionsWithConnectionParams {
|
|
@@ -61,7 +63,7 @@ export declare function createWSClient(opts: WebSocketClientOptions): {
|
|
|
61
63
|
/**
|
|
62
64
|
* Reconnect to the WebSocket server
|
|
63
65
|
*/
|
|
64
|
-
reconnect: () => void;
|
|
66
|
+
reconnect: (cause: Error | null) => void;
|
|
65
67
|
};
|
|
66
68
|
export type TRPCWebSocketClient = ReturnType<typeof createWSClient>;
|
|
67
69
|
export type WebSocketLinkOptions<TRouter extends AnyRouter> = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wsLink.d.ts","sourceRoot":"","sources":["../../src/links/wsLink.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGvE,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAChB,gBAAgB,EAMhB,mBAAmB,EACpB,MAAM,0CAA0C,CAAC;AAElD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,OAAO,EAEL,KAAK,8BAA8B,EACpC,MAAM,qCAAqC,CAAC;AAC7C,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"wsLink.d.ts","sourceRoot":"","sources":["../../src/links/wsLink.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGvE,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAChB,gBAAgB,EAMhB,mBAAmB,EACpB,MAAM,0CAA0C,CAAC;AAElD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,OAAO,EAEL,KAAK,8BAA8B,EACpC,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,0BAA0B,EAC/B,KAAK,QAAQ,EACd,MAAM,SAAS,CAAC;AAIjB,KAAK,gBAAgB,CAAC,OAAO,SAAS,SAAS,EAAE,OAAO,IACpD,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC,GACvD;IAAE,MAAM,EAAE,0BAA0B,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAA;CAAE,CAAC;AAEtE,KAAK,kBAAkB,CAAC,OAAO,SAAS,SAAS,EAAE,OAAO,IAAI,QAAQ,CACpE,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,EAClC,eAAe,CAAC,OAAO,CAAC,CACzB,CAAC;AAEF,QAAA,MAAM,kBAAkB,iBAAkB,MAAM,WACoB,CAAC;AAErE,MAAM,WAAW,sBAAuB,SAAQ,8BAA8B;IAC5E;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,SAAS,CAAC;IAC7B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,kBAAkB,CAAC;IACzC;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC9C;;OAEG;IACH,IAAI,CAAC,EAAE;QACL;;;WAGG;QACH,OAAO,EAAE,OAAO,CAAC;QACjB;;;WAGG;QACH,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAOD,wBAAgB,cAAc,CAAC,IAAI,EAAE,sBAAsB;;kBAoVpC,SAAS,wDAA0B,aAAa;;YArS/D,MAAM;;eAGC,MAAM;YACT,SAAS;;eAGN,QAAQ;YACX,SAAS;;eAGN,YAAY;aACd,SAAS;;IAwVlB;;OAEG;uBAtSqB,KAAK,GAAG,IAAI;EAySvC;AACD,MAAM,MAAM,mBAAmB,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAEpE,MAAM,MAAM,oBAAoB,CAAC,OAAO,SAAS,SAAS,IAAI;IAC5D,MAAM,EAAE,mBAAmB,CAAC;CAC7B,GAAG,kBAAkB,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;AASlD;;GAEG;AACH,wBAAgB,MAAM,CAAC,OAAO,SAAS,SAAS,EAC9C,IAAI,EAAE,oBAAoB,CAAC,OAAO,CAAC,GAClC,QAAQ,CAAC,OAAO,CAAC,CAoGnB"}
|
package/dist/links/wsLink.js
CHANGED
|
@@ -5,6 +5,7 @@ var unstableCoreDoNotImport = require('@trpc/server/unstable-core-do-not-import'
|
|
|
5
5
|
var TRPCClientError = require('../TRPCClientError.js');
|
|
6
6
|
var transformer = require('../internals/transformer.js');
|
|
7
7
|
var urlWithConnectionParams = require('./internals/urlWithConnectionParams.js');
|
|
8
|
+
var types = require('./types.js');
|
|
8
9
|
|
|
9
10
|
const run = (fn)=>fn();
|
|
10
11
|
const exponentialBackoff = (attemptIndex)=>attemptIndex === 0 ? 0 : Math.min(1000 * 2 ** attemptIndex, 30000);
|
|
@@ -29,12 +30,12 @@ function createWSClient(opts) {
|
|
|
29
30
|
let connectTimer = undefined;
|
|
30
31
|
let connectionIndex = 0;
|
|
31
32
|
let lazyDisconnectTimer = undefined;
|
|
32
|
-
let activeConnection = lazyOpts.enabled ? null : createConnection();
|
|
33
|
+
let activeConnection = lazyOpts.enabled ? null : createConnection(null);
|
|
33
34
|
/**
|
|
34
35
|
* tries to send the list of messages
|
|
35
36
|
*/ function dispatch() {
|
|
36
37
|
if (!activeConnection) {
|
|
37
|
-
activeConnection = createConnection();
|
|
38
|
+
activeConnection = createConnection(null);
|
|
38
39
|
return;
|
|
39
40
|
}
|
|
40
41
|
// using a timeout to batch messages
|
|
@@ -59,13 +60,13 @@ function createWSClient(opts) {
|
|
|
59
60
|
startLazyDisconnectTimer();
|
|
60
61
|
});
|
|
61
62
|
}
|
|
62
|
-
function tryReconnect(conn) {
|
|
63
|
+
function tryReconnect(conn, cause) {
|
|
63
64
|
if (!!connectTimer) {
|
|
64
65
|
return;
|
|
65
66
|
}
|
|
66
67
|
conn.state = 'connecting';
|
|
67
68
|
const timeout = retryDelayFn(connectAttempt++);
|
|
68
|
-
reconnectInMs(timeout);
|
|
69
|
+
reconnectInMs(timeout, cause);
|
|
69
70
|
}
|
|
70
71
|
function hasPendingRequests(conn) {
|
|
71
72
|
const requests = Object.values(pendingRequests);
|
|
@@ -74,20 +75,20 @@ function createWSClient(opts) {
|
|
|
74
75
|
}
|
|
75
76
|
return requests.some((req)=>req.connection === conn);
|
|
76
77
|
}
|
|
77
|
-
function reconnect() {
|
|
78
|
+
function reconnect(cause) {
|
|
78
79
|
if (lazyOpts.enabled && !hasPendingRequests()) {
|
|
79
80
|
// Skip reconnecting if there are pending requests and we're in lazy mode
|
|
80
81
|
return;
|
|
81
82
|
}
|
|
82
83
|
const oldConnection = activeConnection;
|
|
83
|
-
activeConnection = createConnection();
|
|
84
|
+
activeConnection = createConnection(cause);
|
|
84
85
|
oldConnection && closeIfNoPending(oldConnection);
|
|
85
86
|
}
|
|
86
|
-
function reconnectInMs(ms) {
|
|
87
|
+
function reconnectInMs(ms, cause) {
|
|
87
88
|
if (connectTimer) {
|
|
88
89
|
return;
|
|
89
90
|
}
|
|
90
|
-
connectTimer = setTimeout(reconnect, ms);
|
|
91
|
+
connectTimer = setTimeout(reconnect, ms, cause);
|
|
91
92
|
}
|
|
92
93
|
function closeIfNoPending(conn) {
|
|
93
94
|
// disconnect as soon as there are are no pending requests
|
|
@@ -116,16 +117,27 @@ function createWSClient(opts) {
|
|
|
116
117
|
}
|
|
117
118
|
}, lazyOpts.closeMs);
|
|
118
119
|
};
|
|
119
|
-
function createConnection() {
|
|
120
|
+
function createConnection(cause) {
|
|
120
121
|
const self = {
|
|
121
122
|
id: ++connectionIndex,
|
|
122
123
|
state: 'connecting'
|
|
123
124
|
};
|
|
125
|
+
for (const req of Object.values(pendingRequests)){
|
|
126
|
+
if (req.type === 'subscription') {
|
|
127
|
+
req.callbacks.next?.({
|
|
128
|
+
result: {
|
|
129
|
+
type: 'state',
|
|
130
|
+
state: 'connecting',
|
|
131
|
+
data: cause ?? null
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
124
136
|
clearTimeout(lazyDisconnectTimer);
|
|
125
|
-
const onError = ()=>{
|
|
137
|
+
const onError = (cause)=>{
|
|
126
138
|
self.state = 'closed';
|
|
127
139
|
if (self === activeConnection) {
|
|
128
|
-
tryReconnect(self);
|
|
140
|
+
tryReconnect(self, cause);
|
|
129
141
|
}
|
|
130
142
|
};
|
|
131
143
|
run(async ()=>{
|
|
@@ -153,21 +165,37 @@ function createWSClient(opts) {
|
|
|
153
165
|
}
|
|
154
166
|
connectAttempt = 0;
|
|
155
167
|
self.state = 'open';
|
|
168
|
+
for (const req of Object.values(pendingRequests)){
|
|
169
|
+
if (req.type === 'subscription') {
|
|
170
|
+
req.callbacks.next?.({
|
|
171
|
+
result: {
|
|
172
|
+
type: 'state',
|
|
173
|
+
state: 'pending'
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
156
178
|
onOpen?.();
|
|
157
179
|
dispatch();
|
|
158
180
|
}).catch((cause)=>{
|
|
159
181
|
ws.close(// "Status codes in the range 3000-3999 are reserved for use by libraries, frameworks, and applications"
|
|
160
182
|
3000, cause);
|
|
161
|
-
onError();
|
|
183
|
+
onError(cause);
|
|
162
184
|
});
|
|
163
185
|
});
|
|
164
|
-
ws.addEventListener('error',
|
|
186
|
+
ws.addEventListener('error', (event)=>{
|
|
187
|
+
if (event instanceof ErrorEvent) {
|
|
188
|
+
onError(event.error);
|
|
189
|
+
} else {
|
|
190
|
+
onError(new Error('Unknown WebSocket error'));
|
|
191
|
+
}
|
|
192
|
+
});
|
|
165
193
|
const handleIncomingRequest = (req)=>{
|
|
166
194
|
if (self !== activeConnection) {
|
|
167
195
|
return;
|
|
168
196
|
}
|
|
169
197
|
if (req.method === 'reconnect') {
|
|
170
|
-
reconnect();
|
|
198
|
+
reconnect(new Error('Server requested reconnect'));
|
|
171
199
|
// notify subscribers
|
|
172
200
|
for (const pendingReq of Object.values(pendingRequests)){
|
|
173
201
|
if (pendingReq.type === 'subscription') {
|
|
@@ -206,7 +234,7 @@ function createWSClient(opts) {
|
|
|
206
234
|
closeIfNoPending(self);
|
|
207
235
|
}
|
|
208
236
|
});
|
|
209
|
-
ws.addEventListener('close', ({ code })=>{
|
|
237
|
+
ws.addEventListener('close', ({ code , reason })=>{
|
|
210
238
|
if (self.state === 'open') {
|
|
211
239
|
onClose?.({
|
|
212
240
|
code
|
|
@@ -215,7 +243,7 @@ function createWSClient(opts) {
|
|
|
215
243
|
self.state = 'closed';
|
|
216
244
|
if (activeConnection === self) {
|
|
217
245
|
// connection might have been replaced already
|
|
218
|
-
tryReconnect(self);
|
|
246
|
+
tryReconnect(self, new Error(reason));
|
|
219
247
|
}
|
|
220
248
|
for (const [key, req] of Object.entries(pendingRequests)){
|
|
221
249
|
if (req.connection !== self) {
|
|
@@ -327,19 +355,53 @@ class TRPCWebSocketClosedError extends Error {
|
|
|
327
355
|
}, {
|
|
328
356
|
error (err) {
|
|
329
357
|
observer.error(err);
|
|
358
|
+
observer.next({
|
|
359
|
+
result: {
|
|
360
|
+
type: 'state',
|
|
361
|
+
state: 'error',
|
|
362
|
+
data: err
|
|
363
|
+
},
|
|
364
|
+
context: context
|
|
365
|
+
});
|
|
330
366
|
unsub();
|
|
331
367
|
},
|
|
332
368
|
complete () {
|
|
333
369
|
observer.complete();
|
|
370
|
+
observer.next({
|
|
371
|
+
result: {
|
|
372
|
+
type: 'state',
|
|
373
|
+
state: 'idle'
|
|
374
|
+
},
|
|
375
|
+
context: context
|
|
376
|
+
});
|
|
334
377
|
},
|
|
335
378
|
next (message) {
|
|
379
|
+
if ('result' in message && types.isConnectionStateMessage(message.result)) {
|
|
380
|
+
message.result;
|
|
381
|
+
observer.next({
|
|
382
|
+
result: message.result,
|
|
383
|
+
context: context
|
|
384
|
+
});
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
if (!('id' in message)) return;
|
|
336
388
|
const transformed = unstableCoreDoNotImport.transformResult(message, transformer$1.output);
|
|
337
389
|
if (!transformed.ok) {
|
|
390
|
+
const error = TRPCClientError.TRPCClientError.from(transformed.error);
|
|
391
|
+
observer.next({
|
|
392
|
+
result: {
|
|
393
|
+
type: 'state',
|
|
394
|
+
state: 'error',
|
|
395
|
+
data: error
|
|
396
|
+
},
|
|
397
|
+
context: context
|
|
398
|
+
});
|
|
338
399
|
observer.error(TRPCClientError.TRPCClientError.from(transformed.error));
|
|
339
400
|
return;
|
|
340
401
|
}
|
|
341
402
|
observer.next({
|
|
342
|
-
result: transformed.result
|
|
403
|
+
result: transformed.result,
|
|
404
|
+
context: context
|
|
343
405
|
});
|
|
344
406
|
if (op.type !== 'subscription') {
|
|
345
407
|
// if it isn't a subscription we don't care about next response
|
|
@@ -350,6 +412,13 @@ class TRPCWebSocketClosedError extends Error {
|
|
|
350
412
|
});
|
|
351
413
|
return ()=>{
|
|
352
414
|
unsub();
|
|
415
|
+
observer.next({
|
|
416
|
+
result: {
|
|
417
|
+
type: 'state',
|
|
418
|
+
state: 'idle'
|
|
419
|
+
},
|
|
420
|
+
context: context
|
|
421
|
+
});
|
|
353
422
|
};
|
|
354
423
|
});
|
|
355
424
|
};
|
package/dist/links/wsLink.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { transformResult } from '@trpc/server/unstable-core-do-not-import';
|
|
|
3
3
|
import { TRPCClientError } from '../TRPCClientError.mjs';
|
|
4
4
|
import { getTransformer } from '../internals/transformer.mjs';
|
|
5
5
|
import { resultOf } from './internals/urlWithConnectionParams.mjs';
|
|
6
|
+
import { isConnectionStateMessage } from './types.mjs';
|
|
6
7
|
|
|
7
8
|
const run = (fn)=>fn();
|
|
8
9
|
const exponentialBackoff = (attemptIndex)=>attemptIndex === 0 ? 0 : Math.min(1000 * 2 ** attemptIndex, 30000);
|
|
@@ -27,12 +28,12 @@ function createWSClient(opts) {
|
|
|
27
28
|
let connectTimer = undefined;
|
|
28
29
|
let connectionIndex = 0;
|
|
29
30
|
let lazyDisconnectTimer = undefined;
|
|
30
|
-
let activeConnection = lazyOpts.enabled ? null : createConnection();
|
|
31
|
+
let activeConnection = lazyOpts.enabled ? null : createConnection(null);
|
|
31
32
|
/**
|
|
32
33
|
* tries to send the list of messages
|
|
33
34
|
*/ function dispatch() {
|
|
34
35
|
if (!activeConnection) {
|
|
35
|
-
activeConnection = createConnection();
|
|
36
|
+
activeConnection = createConnection(null);
|
|
36
37
|
return;
|
|
37
38
|
}
|
|
38
39
|
// using a timeout to batch messages
|
|
@@ -57,13 +58,13 @@ function createWSClient(opts) {
|
|
|
57
58
|
startLazyDisconnectTimer();
|
|
58
59
|
});
|
|
59
60
|
}
|
|
60
|
-
function tryReconnect(conn) {
|
|
61
|
+
function tryReconnect(conn, cause) {
|
|
61
62
|
if (!!connectTimer) {
|
|
62
63
|
return;
|
|
63
64
|
}
|
|
64
65
|
conn.state = 'connecting';
|
|
65
66
|
const timeout = retryDelayFn(connectAttempt++);
|
|
66
|
-
reconnectInMs(timeout);
|
|
67
|
+
reconnectInMs(timeout, cause);
|
|
67
68
|
}
|
|
68
69
|
function hasPendingRequests(conn) {
|
|
69
70
|
const requests = Object.values(pendingRequests);
|
|
@@ -72,20 +73,20 @@ function createWSClient(opts) {
|
|
|
72
73
|
}
|
|
73
74
|
return requests.some((req)=>req.connection === conn);
|
|
74
75
|
}
|
|
75
|
-
function reconnect() {
|
|
76
|
+
function reconnect(cause) {
|
|
76
77
|
if (lazyOpts.enabled && !hasPendingRequests()) {
|
|
77
78
|
// Skip reconnecting if there are pending requests and we're in lazy mode
|
|
78
79
|
return;
|
|
79
80
|
}
|
|
80
81
|
const oldConnection = activeConnection;
|
|
81
|
-
activeConnection = createConnection();
|
|
82
|
+
activeConnection = createConnection(cause);
|
|
82
83
|
oldConnection && closeIfNoPending(oldConnection);
|
|
83
84
|
}
|
|
84
|
-
function reconnectInMs(ms) {
|
|
85
|
+
function reconnectInMs(ms, cause) {
|
|
85
86
|
if (connectTimer) {
|
|
86
87
|
return;
|
|
87
88
|
}
|
|
88
|
-
connectTimer = setTimeout(reconnect, ms);
|
|
89
|
+
connectTimer = setTimeout(reconnect, ms, cause);
|
|
89
90
|
}
|
|
90
91
|
function closeIfNoPending(conn) {
|
|
91
92
|
// disconnect as soon as there are are no pending requests
|
|
@@ -114,16 +115,27 @@ function createWSClient(opts) {
|
|
|
114
115
|
}
|
|
115
116
|
}, lazyOpts.closeMs);
|
|
116
117
|
};
|
|
117
|
-
function createConnection() {
|
|
118
|
+
function createConnection(cause) {
|
|
118
119
|
const self = {
|
|
119
120
|
id: ++connectionIndex,
|
|
120
121
|
state: 'connecting'
|
|
121
122
|
};
|
|
123
|
+
for (const req of Object.values(pendingRequests)){
|
|
124
|
+
if (req.type === 'subscription') {
|
|
125
|
+
req.callbacks.next?.({
|
|
126
|
+
result: {
|
|
127
|
+
type: 'state',
|
|
128
|
+
state: 'connecting',
|
|
129
|
+
data: cause ?? null
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
122
134
|
clearTimeout(lazyDisconnectTimer);
|
|
123
|
-
const onError = ()=>{
|
|
135
|
+
const onError = (cause)=>{
|
|
124
136
|
self.state = 'closed';
|
|
125
137
|
if (self === activeConnection) {
|
|
126
|
-
tryReconnect(self);
|
|
138
|
+
tryReconnect(self, cause);
|
|
127
139
|
}
|
|
128
140
|
};
|
|
129
141
|
run(async ()=>{
|
|
@@ -151,21 +163,37 @@ function createWSClient(opts) {
|
|
|
151
163
|
}
|
|
152
164
|
connectAttempt = 0;
|
|
153
165
|
self.state = 'open';
|
|
166
|
+
for (const req of Object.values(pendingRequests)){
|
|
167
|
+
if (req.type === 'subscription') {
|
|
168
|
+
req.callbacks.next?.({
|
|
169
|
+
result: {
|
|
170
|
+
type: 'state',
|
|
171
|
+
state: 'pending'
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
154
176
|
onOpen?.();
|
|
155
177
|
dispatch();
|
|
156
178
|
}).catch((cause)=>{
|
|
157
179
|
ws.close(// "Status codes in the range 3000-3999 are reserved for use by libraries, frameworks, and applications"
|
|
158
180
|
3000, cause);
|
|
159
|
-
onError();
|
|
181
|
+
onError(cause);
|
|
160
182
|
});
|
|
161
183
|
});
|
|
162
|
-
ws.addEventListener('error',
|
|
184
|
+
ws.addEventListener('error', (event)=>{
|
|
185
|
+
if (event instanceof ErrorEvent) {
|
|
186
|
+
onError(event.error);
|
|
187
|
+
} else {
|
|
188
|
+
onError(new Error('Unknown WebSocket error'));
|
|
189
|
+
}
|
|
190
|
+
});
|
|
163
191
|
const handleIncomingRequest = (req)=>{
|
|
164
192
|
if (self !== activeConnection) {
|
|
165
193
|
return;
|
|
166
194
|
}
|
|
167
195
|
if (req.method === 'reconnect') {
|
|
168
|
-
reconnect();
|
|
196
|
+
reconnect(new Error('Server requested reconnect'));
|
|
169
197
|
// notify subscribers
|
|
170
198
|
for (const pendingReq of Object.values(pendingRequests)){
|
|
171
199
|
if (pendingReq.type === 'subscription') {
|
|
@@ -204,7 +232,7 @@ function createWSClient(opts) {
|
|
|
204
232
|
closeIfNoPending(self);
|
|
205
233
|
}
|
|
206
234
|
});
|
|
207
|
-
ws.addEventListener('close', ({ code })=>{
|
|
235
|
+
ws.addEventListener('close', ({ code , reason })=>{
|
|
208
236
|
if (self.state === 'open') {
|
|
209
237
|
onClose?.({
|
|
210
238
|
code
|
|
@@ -213,7 +241,7 @@ function createWSClient(opts) {
|
|
|
213
241
|
self.state = 'closed';
|
|
214
242
|
if (activeConnection === self) {
|
|
215
243
|
// connection might have been replaced already
|
|
216
|
-
tryReconnect(self);
|
|
244
|
+
tryReconnect(self, new Error(reason));
|
|
217
245
|
}
|
|
218
246
|
for (const [key, req] of Object.entries(pendingRequests)){
|
|
219
247
|
if (req.connection !== self) {
|
|
@@ -325,19 +353,53 @@ class TRPCWebSocketClosedError extends Error {
|
|
|
325
353
|
}, {
|
|
326
354
|
error (err) {
|
|
327
355
|
observer.error(err);
|
|
356
|
+
observer.next({
|
|
357
|
+
result: {
|
|
358
|
+
type: 'state',
|
|
359
|
+
state: 'error',
|
|
360
|
+
data: err
|
|
361
|
+
},
|
|
362
|
+
context: context
|
|
363
|
+
});
|
|
328
364
|
unsub();
|
|
329
365
|
},
|
|
330
366
|
complete () {
|
|
331
367
|
observer.complete();
|
|
368
|
+
observer.next({
|
|
369
|
+
result: {
|
|
370
|
+
type: 'state',
|
|
371
|
+
state: 'idle'
|
|
372
|
+
},
|
|
373
|
+
context: context
|
|
374
|
+
});
|
|
332
375
|
},
|
|
333
376
|
next (message) {
|
|
377
|
+
if ('result' in message && isConnectionStateMessage(message.result)) {
|
|
378
|
+
message.result;
|
|
379
|
+
observer.next({
|
|
380
|
+
result: message.result,
|
|
381
|
+
context: context
|
|
382
|
+
});
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
if (!('id' in message)) return;
|
|
334
386
|
const transformed = transformResult(message, transformer.output);
|
|
335
387
|
if (!transformed.ok) {
|
|
388
|
+
const error = TRPCClientError.from(transformed.error);
|
|
389
|
+
observer.next({
|
|
390
|
+
result: {
|
|
391
|
+
type: 'state',
|
|
392
|
+
state: 'error',
|
|
393
|
+
data: error
|
|
394
|
+
},
|
|
395
|
+
context: context
|
|
396
|
+
});
|
|
336
397
|
observer.error(TRPCClientError.from(transformed.error));
|
|
337
398
|
return;
|
|
338
399
|
}
|
|
339
400
|
observer.next({
|
|
340
|
-
result: transformed.result
|
|
401
|
+
result: transformed.result,
|
|
402
|
+
context: context
|
|
341
403
|
});
|
|
342
404
|
if (op.type !== 'subscription') {
|
|
343
405
|
// if it isn't a subscription we don't care about next response
|
|
@@ -348,6 +410,13 @@ class TRPCWebSocketClosedError extends Error {
|
|
|
348
410
|
});
|
|
349
411
|
return ()=>{
|
|
350
412
|
unsub();
|
|
413
|
+
observer.next({
|
|
414
|
+
result: {
|
|
415
|
+
type: 'state',
|
|
416
|
+
state: 'idle'
|
|
417
|
+
},
|
|
418
|
+
context: context
|
|
419
|
+
});
|
|
351
420
|
};
|
|
352
421
|
});
|
|
353
422
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trpc/client",
|
|
3
|
-
"version": "11.0.0-alpha-tmp-
|
|
3
|
+
"version": "11.0.0-alpha-tmp-subscription-connection-state.485+386eae02c",
|
|
4
4
|
"description": "The tRPC client library",
|
|
5
5
|
"author": "KATT",
|
|
6
6
|
"license": "MIT",
|
|
@@ -76,10 +76,10 @@
|
|
|
76
76
|
"!**/*.test.*"
|
|
77
77
|
],
|
|
78
78
|
"peerDependencies": {
|
|
79
|
-
"@trpc/server": "11.0.0-alpha-tmp-
|
|
79
|
+
"@trpc/server": "11.0.0-alpha-tmp-subscription-connection-state.485+386eae02c"
|
|
80
80
|
},
|
|
81
81
|
"devDependencies": {
|
|
82
|
-
"@trpc/server": "11.0.0-alpha-tmp-
|
|
82
|
+
"@trpc/server": "11.0.0-alpha-tmp-subscription-connection-state.485+386eae02c",
|
|
83
83
|
"@types/isomorphic-fetch": "^0.0.39",
|
|
84
84
|
"@types/node": "^20.10.0",
|
|
85
85
|
"eslint": "^8.56.0",
|
|
@@ -96,5 +96,5 @@
|
|
|
96
96
|
"funding": [
|
|
97
97
|
"https://trpc.io/sponsor"
|
|
98
98
|
],
|
|
99
|
-
"gitHead": "
|
|
99
|
+
"gitHead": "386eae02c675ba0fe0feda78188b6975e56d0e49"
|
|
100
100
|
}
|
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
OperationContext,
|
|
15
15
|
OperationLink,
|
|
16
16
|
TRPCClientRuntime,
|
|
17
|
+
TRPCConnectionStateMessage,
|
|
17
18
|
TRPCLink,
|
|
18
19
|
} from '../links/types';
|
|
19
20
|
import { TRPCClientError } from '../TRPCClientError';
|
|
@@ -33,6 +34,7 @@ export interface TRPCSubscriptionObserver<TValue, TError> {
|
|
|
33
34
|
onError: (err: TError) => void;
|
|
34
35
|
onStopped: () => void;
|
|
35
36
|
onComplete: () => void;
|
|
37
|
+
onStateChange: (state: TRPCConnectionStateMessage<TError>) => void;
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
/** @internal */
|
|
@@ -143,6 +145,8 @@ export class TRPCUntypedClient<TRouter extends AnyRouter> {
|
|
|
143
145
|
});
|
|
144
146
|
} else if (envelope.result.type === 'stopped') {
|
|
145
147
|
opts.onStopped?.();
|
|
148
|
+
} else if (envelope.result.type === 'state') {
|
|
149
|
+
opts.onStateChange?.(envelope.result);
|
|
146
150
|
} else {
|
|
147
151
|
opts.onData?.(envelope.result.data);
|
|
148
152
|
}
|