@trpc/client 11.0.0-alpha-tmp-subscription-connection-state.488 → 11.0.0-alpha-tmp-12-06-react.665
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/TRPCClientError.d.ts +1 -1
- package/dist/TRPCClientError.d.ts.map +1 -1
- package/dist/TRPCClientError.js +19 -1
- package/dist/TRPCClientError.mjs +19 -1
- package/dist/bundle-analysis.json +124 -98
- package/dist/createTRPCClient.d.ts +3 -2
- package/dist/createTRPCClient.d.ts.map +1 -1
- package/dist/createTRPCClient.js +1 -1
- package/dist/createTRPCClient.mjs +1 -1
- package/dist/index.js +6 -6
- package/dist/index.mjs +2 -2
- package/dist/internals/TRPCUntypedClient.d.ts +5 -4
- package/dist/internals/TRPCUntypedClient.d.ts.map +1 -1
- package/dist/internals/TRPCUntypedClient.js +42 -12
- package/dist/internals/TRPCUntypedClient.mjs +42 -12
- package/dist/internals/inputWithTrackedEventId.d.ts +2 -0
- package/dist/internals/inputWithTrackedEventId.d.ts.map +1 -0
- package/dist/internals/inputWithTrackedEventId.js +16 -0
- package/dist/internals/inputWithTrackedEventId.mjs +14 -0
- package/dist/internals/signals.d.ts +15 -0
- package/dist/internals/signals.d.ts.map +1 -0
- package/dist/internals/signals.js +47 -0
- package/dist/internals/signals.mjs +44 -0
- package/dist/internals/transformer.d.ts +2 -2
- package/dist/internals/types.d.ts +1 -1
- package/dist/internals/types.d.ts.map +1 -1
- package/dist/links/HTTPBatchLinkOptions.d.ts +1 -1
- package/dist/links/httpBatchLink.d.ts.map +1 -1
- package/dist/links/httpBatchLink.js +4 -3
- package/dist/links/httpBatchLink.mjs +5 -4
- package/dist/links/httpBatchStreamLink.d.ts.map +1 -1
- package/dist/links/httpBatchStreamLink.js +6 -4
- package/dist/links/httpBatchStreamLink.mjs +7 -5
- package/dist/links/httpLink.d.ts +2 -2
- package/dist/links/httpLink.js +3 -3
- package/dist/links/httpLink.mjs +3 -3
- package/dist/links/httpSubscriptionLink.d.ts +11 -6
- package/dist/links/httpSubscriptionLink.d.ts.map +1 -1
- package/dist/links/httpSubscriptionLink.js +130 -94
- package/dist/links/httpSubscriptionLink.mjs +132 -96
- package/dist/links/internals/contentTypes.d.ts +2 -2
- package/dist/links/internals/contentTypes.d.ts.map +1 -1
- package/dist/links/internals/httpUtils.d.ts +1 -8
- package/dist/links/internals/httpUtils.d.ts.map +1 -1
- package/dist/links/internals/httpUtils.js +1 -30
- package/dist/links/internals/httpUtils.mjs +2 -30
- package/dist/links/internals/subscriptions.d.ts +20 -0
- package/dist/links/internals/subscriptions.d.ts.map +1 -0
- package/dist/links/internals/urlWithConnectionParams.d.ts +2 -1
- package/dist/links/internals/urlWithConnectionParams.d.ts.map +1 -1
- package/dist/links/internals/urlWithConnectionParams.js +3 -2
- package/dist/links/internals/urlWithConnectionParams.mjs +3 -2
- package/dist/links/loggerLink.d.ts +5 -5
- package/dist/links/loggerLink.d.ts.map +1 -1
- package/dist/links/loggerLink.js +25 -21
- package/dist/links/loggerLink.mjs +25 -21
- package/dist/links/retryLink.d.ts +29 -0
- package/dist/links/retryLink.d.ts.map +1 -0
- package/dist/links/retryLink.js +65 -0
- package/dist/links/retryLink.mjs +63 -0
- package/dist/links/types.d.ts +4 -23
- package/dist/links/types.d.ts.map +1 -1
- package/dist/links/wsLink.d.ts +54 -6
- package/dist/links/wsLink.d.ts.map +1 -1
- package/dist/links/wsLink.js +244 -175
- package/dist/links/wsLink.mjs +245 -176
- package/dist/links.d.ts +1 -0
- package/dist/links.d.ts.map +1 -1
- package/dist/unstable-internals.d.ts +1 -0
- package/dist/unstable-internals.d.ts.map +1 -1
- package/package.json +14 -11
- package/src/TRPCClientError.ts +1 -1
- package/src/createTRPCClient.ts +28 -23
- package/src/internals/TRPCUntypedClient.ts +26 -15
- package/src/internals/inputWithTrackedEventId.ts +15 -0
- package/src/internals/signals.ts +54 -0
- package/src/internals/transformer.ts +2 -2
- package/src/internals/types.ts +1 -1
- package/src/links/HTTPBatchLinkOptions.ts +1 -1
- package/src/links/httpBatchLink.ts +3 -3
- package/src/links/httpBatchStreamLink.ts +7 -4
- package/src/links/httpLink.ts +2 -2
- package/src/links/httpSubscriptionLink.ts +172 -115
- package/src/links/internals/httpUtils.ts +1 -41
- package/src/links/internals/subscriptions.ts +26 -0
- package/src/links/internals/urlWithConnectionParams.ts +8 -2
- package/src/links/loggerLink.ts +21 -9
- package/src/links/retryLink.ts +101 -0
- package/src/links/types.ts +8 -46
- package/src/links/wsLink.ts +308 -181
- package/src/links.ts +1 -1
- package/src/unstable-internals.ts +1 -0
- package/dist/links/internals/retryLink.d.ts +0 -9
- package/dist/links/internals/retryLink.d.ts.map +0 -1
- package/dist/links/types.js +0 -7
- package/dist/links/types.mjs +0 -5
- package/src/links/internals/retryLink.ts +0 -53
package/dist/links/wsLink.mjs
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { observable } from '@trpc/server/observable';
|
|
1
|
+
import { behaviorSubject, observable } from '@trpc/server/observable';
|
|
2
2
|
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';
|
|
7
6
|
|
|
8
7
|
const run = (fn)=>fn();
|
|
9
8
|
const exponentialBackoff = (attemptIndex)=>attemptIndex === 0 ? 0 : Math.min(1000 * 2 ** attemptIndex, 30000);
|
|
@@ -11,8 +10,13 @@ const lazyDefaults = {
|
|
|
11
10
|
enabled: false,
|
|
12
11
|
closeMs: 0
|
|
13
12
|
};
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
/**
|
|
14
|
+
* @see https://trpc.io/docs/v11/client/links/wsLink
|
|
15
|
+
* @deprecated
|
|
16
|
+
* 🙋♂️ **Contributors needed** to continue supporting WebSockets!
|
|
17
|
+
* See https://github.com/trpc/trpc/issues/6109
|
|
18
|
+
*/ function createWSClient(opts) {
|
|
19
|
+
const { WebSocket: WebSocketImpl = WebSocket, retryDelayMs: retryDelayFn = exponentialBackoff } = opts;
|
|
16
20
|
const lazyOpts = {
|
|
17
21
|
...lazyDefaults,
|
|
18
22
|
...opts.lazy
|
|
@@ -28,12 +32,22 @@ function createWSClient(opts) {
|
|
|
28
32
|
let connectTimer = undefined;
|
|
29
33
|
let connectionIndex = 0;
|
|
30
34
|
let lazyDisconnectTimer = undefined;
|
|
31
|
-
let activeConnection = lazyOpts.enabled ? null : createConnection(
|
|
35
|
+
let activeConnection = lazyOpts.enabled ? null : createConnection();
|
|
36
|
+
const initState = activeConnection ? {
|
|
37
|
+
type: 'state',
|
|
38
|
+
state: 'connecting',
|
|
39
|
+
error: null
|
|
40
|
+
} : {
|
|
41
|
+
type: 'state',
|
|
42
|
+
state: 'idle',
|
|
43
|
+
error: null
|
|
44
|
+
};
|
|
45
|
+
const connectionState = behaviorSubject(initState);
|
|
32
46
|
/**
|
|
33
47
|
* tries to send the list of messages
|
|
34
48
|
*/ function dispatch() {
|
|
35
49
|
if (!activeConnection) {
|
|
36
|
-
|
|
50
|
+
reconnect(null);
|
|
37
51
|
return;
|
|
38
52
|
}
|
|
39
53
|
// using a timeout to batch messages
|
|
@@ -58,11 +72,10 @@ function createWSClient(opts) {
|
|
|
58
72
|
startLazyDisconnectTimer();
|
|
59
73
|
});
|
|
60
74
|
}
|
|
61
|
-
function tryReconnect(
|
|
75
|
+
function tryReconnect(cause) {
|
|
62
76
|
if (!!connectTimer) {
|
|
63
77
|
return;
|
|
64
78
|
}
|
|
65
|
-
conn.state = 'connecting';
|
|
66
79
|
const timeout = retryDelayFn(connectAttempt++);
|
|
67
80
|
reconnectInMs(timeout, cause);
|
|
68
81
|
}
|
|
@@ -75,18 +88,30 @@ function createWSClient(opts) {
|
|
|
75
88
|
}
|
|
76
89
|
function reconnect(cause) {
|
|
77
90
|
if (lazyOpts.enabled && !hasPendingRequests()) {
|
|
78
|
-
// Skip reconnecting if there
|
|
91
|
+
// Skip reconnecting if there aren't pending requests and we're in lazy mode
|
|
79
92
|
return;
|
|
80
93
|
}
|
|
81
94
|
const oldConnection = activeConnection;
|
|
82
|
-
activeConnection = createConnection(
|
|
83
|
-
|
|
95
|
+
activeConnection = createConnection();
|
|
96
|
+
if (oldConnection) {
|
|
97
|
+
closeIfNoPending(oldConnection);
|
|
98
|
+
}
|
|
99
|
+
const currentState = connectionState.get();
|
|
100
|
+
if (currentState.state !== 'connecting') {
|
|
101
|
+
connectionState.next({
|
|
102
|
+
type: 'state',
|
|
103
|
+
state: 'connecting',
|
|
104
|
+
error: cause ? TRPCClientError.from(cause) : null
|
|
105
|
+
});
|
|
106
|
+
}
|
|
84
107
|
}
|
|
85
108
|
function reconnectInMs(ms, cause) {
|
|
86
109
|
if (connectTimer) {
|
|
87
110
|
return;
|
|
88
111
|
}
|
|
89
|
-
connectTimer = setTimeout(
|
|
112
|
+
connectTimer = setTimeout(()=>{
|
|
113
|
+
reconnect(cause);
|
|
114
|
+
}, ms);
|
|
90
115
|
}
|
|
91
116
|
function closeIfNoPending(conn) {
|
|
92
117
|
// disconnect as soon as there are are no pending requests
|
|
@@ -98,7 +123,11 @@ function createWSClient(opts) {
|
|
|
98
123
|
if (outgoing.some((r)=>r.id === req.op.id)) {
|
|
99
124
|
return;
|
|
100
125
|
}
|
|
101
|
-
request(
|
|
126
|
+
request({
|
|
127
|
+
op: req.op,
|
|
128
|
+
callbacks: req.callbacks,
|
|
129
|
+
lastEventId: req.lastEventId
|
|
130
|
+
});
|
|
102
131
|
}
|
|
103
132
|
const startLazyDisconnectTimer = ()=>{
|
|
104
133
|
if (!lazyOpts.enabled) {
|
|
@@ -109,37 +138,69 @@ function createWSClient(opts) {
|
|
|
109
138
|
if (!activeConnection) {
|
|
110
139
|
return;
|
|
111
140
|
}
|
|
112
|
-
if (!hasPendingRequests(
|
|
141
|
+
if (!hasPendingRequests()) {
|
|
113
142
|
activeConnection.ws?.close();
|
|
114
143
|
activeConnection = null;
|
|
144
|
+
connectionState.next({
|
|
145
|
+
type: 'state',
|
|
146
|
+
state: 'idle',
|
|
147
|
+
error: null
|
|
148
|
+
});
|
|
115
149
|
}
|
|
116
150
|
}, lazyOpts.closeMs);
|
|
117
151
|
};
|
|
118
|
-
function createConnection(
|
|
152
|
+
function createConnection() {
|
|
153
|
+
let pingTimeout = undefined;
|
|
154
|
+
let pongTimeout = undefined;
|
|
119
155
|
const self = {
|
|
120
156
|
id: ++connectionIndex,
|
|
121
157
|
state: 'connecting'
|
|
122
158
|
};
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
159
|
+
clearTimeout(lazyDisconnectTimer);
|
|
160
|
+
function destroy() {
|
|
161
|
+
const noop = ()=>{
|
|
162
|
+
// no-op
|
|
163
|
+
};
|
|
164
|
+
const { ws } = self;
|
|
165
|
+
if (ws) {
|
|
166
|
+
ws.onclose = noop;
|
|
167
|
+
ws.onerror = noop;
|
|
168
|
+
ws.onmessage = noop;
|
|
169
|
+
ws.onopen = noop;
|
|
170
|
+
ws.close();
|
|
132
171
|
}
|
|
172
|
+
self.state = 'closed';
|
|
133
173
|
}
|
|
134
|
-
|
|
135
|
-
|
|
174
|
+
const onCloseOrError = (cause)=>{
|
|
175
|
+
clearTimeout(pingTimeout);
|
|
176
|
+
clearTimeout(pongTimeout);
|
|
136
177
|
self.state = 'closed';
|
|
137
|
-
if (
|
|
138
|
-
|
|
178
|
+
if (activeConnection === self) {
|
|
179
|
+
// connection might have been replaced already
|
|
180
|
+
tryReconnect(cause);
|
|
181
|
+
}
|
|
182
|
+
for (const [key, req] of Object.entries(pendingRequests)){
|
|
183
|
+
if (req.connection !== self) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
// The connection was closed either unexpectedly or because of a reconnect
|
|
187
|
+
if (req.type === 'subscription') {
|
|
188
|
+
// Subscriptions will resume after we've reconnected
|
|
189
|
+
resumeSubscriptionOnReconnect(req);
|
|
190
|
+
} else {
|
|
191
|
+
// Queries and mutations will error if interrupted
|
|
192
|
+
delete pendingRequests[key];
|
|
193
|
+
req.callbacks.error?.(TRPCClientError.from(cause ?? new TRPCWebSocketClosedError()));
|
|
194
|
+
}
|
|
139
195
|
}
|
|
140
196
|
};
|
|
141
|
-
|
|
142
|
-
|
|
197
|
+
const onError = (evt)=>{
|
|
198
|
+
onCloseOrError(new TRPCWebSocketClosedError({
|
|
199
|
+
cause: evt
|
|
200
|
+
}));
|
|
201
|
+
opts.onError?.(evt);
|
|
202
|
+
};
|
|
203
|
+
function connect(url) {
|
|
143
204
|
if (opts.connectionParams) {
|
|
144
205
|
// append `?connectionParams=1` when connection params are used
|
|
145
206
|
const prefix = url.includes('?') ? '&' : '?';
|
|
@@ -149,51 +210,78 @@ function createWSClient(opts) {
|
|
|
149
210
|
self.ws = ws;
|
|
150
211
|
clearTimeout(connectTimer);
|
|
151
212
|
connectTimer = undefined;
|
|
152
|
-
ws.
|
|
153
|
-
|
|
154
|
-
|
|
213
|
+
ws.onopen = ()=>{
|
|
214
|
+
async function sendConnectionParams() {
|
|
215
|
+
if (!opts.connectionParams) {
|
|
155
216
|
return;
|
|
156
217
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
218
|
+
const connectMsg = {
|
|
219
|
+
method: 'connectionParams',
|
|
220
|
+
data: await resultOf(opts.connectionParams)
|
|
221
|
+
};
|
|
222
|
+
ws.send(JSON.stringify(connectMsg));
|
|
223
|
+
}
|
|
224
|
+
function handleKeepAlive() {
|
|
225
|
+
if (!opts.keepAlive?.enabled) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const { pongTimeoutMs = 1000, intervalMs = 5000 } = opts.keepAlive;
|
|
229
|
+
const schedulePing = ()=>{
|
|
230
|
+
const schedulePongTimeout = ()=>{
|
|
231
|
+
pongTimeout = setTimeout(()=>{
|
|
232
|
+
const wasOpen = self.state === 'open';
|
|
233
|
+
destroy();
|
|
234
|
+
if (wasOpen) {
|
|
235
|
+
opts.onClose?.();
|
|
236
|
+
}
|
|
237
|
+
}, pongTimeoutMs);
|
|
161
238
|
};
|
|
162
|
-
|
|
239
|
+
pingTimeout = setTimeout(()=>{
|
|
240
|
+
ws.send('PING');
|
|
241
|
+
schedulePongTimeout();
|
|
242
|
+
}, intervalMs);
|
|
243
|
+
};
|
|
244
|
+
ws.addEventListener('message', ()=>{
|
|
245
|
+
clearTimeout(pingTimeout);
|
|
246
|
+
clearTimeout(pongTimeout);
|
|
247
|
+
schedulePing();
|
|
248
|
+
});
|
|
249
|
+
schedulePing();
|
|
250
|
+
}
|
|
251
|
+
run(async ()=>{
|
|
252
|
+
/* istanbul ignore next -- @preserve */ if (activeConnection?.ws !== ws) {
|
|
253
|
+
return;
|
|
163
254
|
}
|
|
255
|
+
handleKeepAlive();
|
|
256
|
+
await sendConnectionParams();
|
|
164
257
|
connectAttempt = 0;
|
|
165
258
|
self.state = 'open';
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
onOpen?.();
|
|
259
|
+
// Update connection state
|
|
260
|
+
connectionState.next({
|
|
261
|
+
type: 'state',
|
|
262
|
+
state: 'pending',
|
|
263
|
+
error: null
|
|
264
|
+
});
|
|
265
|
+
opts.onOpen?.();
|
|
177
266
|
dispatch();
|
|
178
267
|
}).catch((cause)=>{
|
|
179
268
|
ws.close(// "Status codes in the range 3000-3999 are reserved for use by libraries, frameworks, and applications"
|
|
180
|
-
3000
|
|
181
|
-
|
|
269
|
+
3000);
|
|
270
|
+
onCloseOrError(new TRPCWebSocketClosedError({
|
|
271
|
+
message: 'Initialization error',
|
|
272
|
+
cause
|
|
273
|
+
}));
|
|
182
274
|
});
|
|
183
|
-
}
|
|
184
|
-
ws.
|
|
185
|
-
if (globalThis.ErrorEvent && event instanceof ErrorEvent) {
|
|
186
|
-
onError(event.error);
|
|
187
|
-
} else {
|
|
188
|
-
onError(new Error('Unknown WebSocket error'));
|
|
189
|
-
}
|
|
190
|
-
});
|
|
275
|
+
};
|
|
276
|
+
ws.onerror = onError;
|
|
191
277
|
const handleIncomingRequest = (req)=>{
|
|
192
278
|
if (self !== activeConnection) {
|
|
193
279
|
return;
|
|
194
280
|
}
|
|
195
281
|
if (req.method === 'reconnect') {
|
|
196
|
-
reconnect(new
|
|
282
|
+
reconnect(new TRPCWebSocketClosedError({
|
|
283
|
+
message: 'Server requested reconnect'
|
|
284
|
+
}));
|
|
197
285
|
// notify subscribers
|
|
198
286
|
for (const pendingReq of Object.values(pendingRequests)){
|
|
199
287
|
if (pendingReq.type === 'subscription') {
|
|
@@ -210,16 +298,29 @@ function createWSClient(opts) {
|
|
|
210
298
|
}
|
|
211
299
|
req.callbacks.next?.(data);
|
|
212
300
|
if (self === activeConnection && req.connection !== activeConnection) {
|
|
213
|
-
// gracefully replace old connection with
|
|
214
|
-
const oldConn = req.connection;
|
|
301
|
+
// gracefully replace old connection with a new connection
|
|
215
302
|
req.connection = self;
|
|
216
|
-
|
|
303
|
+
}
|
|
304
|
+
if (req.connection !== self) {
|
|
305
|
+
// the connection has been replaced
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
if ('result' in data && data.result.type === 'data' && typeof data.result.id === 'string') {
|
|
309
|
+
req.lastEventId = data.result.id;
|
|
217
310
|
}
|
|
218
311
|
if ('result' in data && data.result.type === 'stopped' && activeConnection === self) {
|
|
219
312
|
req.callbacks.complete();
|
|
220
313
|
}
|
|
221
314
|
};
|
|
222
|
-
ws.
|
|
315
|
+
ws.onmessage = (event)=>{
|
|
316
|
+
const { data } = event;
|
|
317
|
+
if (data === 'PONG') {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
if (data === 'PING') {
|
|
321
|
+
ws.send('PONG');
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
223
324
|
startLazyDisconnectTimer();
|
|
224
325
|
const msg = JSON.parse(data);
|
|
225
326
|
if ('method' in msg) {
|
|
@@ -231,57 +332,41 @@ function createWSClient(opts) {
|
|
|
231
332
|
// when receiving a message, we close old connection that has no pending requests
|
|
232
333
|
closeIfNoPending(self);
|
|
233
334
|
}
|
|
234
|
-
}
|
|
235
|
-
ws.
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
// connection might have been replaced already
|
|
244
|
-
tryReconnect(self, new Error(reason));
|
|
245
|
-
}
|
|
246
|
-
for (const [key, req] of Object.entries(pendingRequests)){
|
|
247
|
-
if (req.connection !== self) {
|
|
248
|
-
continue;
|
|
249
|
-
}
|
|
250
|
-
if (self.state === 'closed') {
|
|
251
|
-
// If the connection was closed, we just call `complete()` on the request
|
|
252
|
-
delete pendingRequests[key];
|
|
253
|
-
req.callbacks.complete?.();
|
|
254
|
-
continue;
|
|
255
|
-
}
|
|
256
|
-
// The connection was closed either unexpectedly or because of a reconnect
|
|
257
|
-
if (req.type === 'subscription') {
|
|
258
|
-
// Subscriptions will resume after we've reconnected
|
|
259
|
-
resumeSubscriptionOnReconnect(req);
|
|
260
|
-
} else {
|
|
261
|
-
// Queries and mutations will error if interrupted
|
|
262
|
-
delete pendingRequests[key];
|
|
263
|
-
req.callbacks.error?.(TRPCClientError.from(new TRPCWebSocketClosedError('WebSocket closed prematurely')));
|
|
264
|
-
}
|
|
335
|
+
};
|
|
336
|
+
ws.onclose = (event)=>{
|
|
337
|
+
const wasOpen = self.state === 'open';
|
|
338
|
+
destroy();
|
|
339
|
+
onCloseOrError(new TRPCWebSocketClosedError({
|
|
340
|
+
cause: event
|
|
341
|
+
}));
|
|
342
|
+
if (wasOpen) {
|
|
343
|
+
opts.onClose?.(event);
|
|
265
344
|
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
Promise.resolve(resultOf(opts.url)).then(connect).catch(()=>{
|
|
348
|
+
onCloseOrError(new Error('Failed to resolve url'));
|
|
349
|
+
});
|
|
268
350
|
return self;
|
|
269
351
|
}
|
|
270
|
-
function request(
|
|
271
|
-
const {
|
|
352
|
+
function request(opts) {
|
|
353
|
+
const { op, callbacks, lastEventId } = opts;
|
|
354
|
+
const { type, input, path, id } = op;
|
|
272
355
|
const envelope = {
|
|
273
356
|
id,
|
|
274
357
|
method: type,
|
|
275
358
|
params: {
|
|
276
359
|
input,
|
|
277
|
-
path
|
|
360
|
+
path,
|
|
361
|
+
lastEventId
|
|
278
362
|
}
|
|
279
363
|
};
|
|
280
364
|
pendingRequests[id] = {
|
|
281
365
|
connection: null,
|
|
282
366
|
type,
|
|
283
367
|
callbacks,
|
|
284
|
-
op
|
|
368
|
+
op,
|
|
369
|
+
lastEventId
|
|
285
370
|
};
|
|
286
371
|
// enqueue message
|
|
287
372
|
outgoing.push(envelope);
|
|
@@ -309,10 +394,14 @@ function createWSClient(opts) {
|
|
|
309
394
|
req.callbacks.complete();
|
|
310
395
|
} else if (!req.connection) {
|
|
311
396
|
// close pending requests that aren't attached to a connection yet
|
|
312
|
-
req.callbacks.error(TRPCClientError.from(new
|
|
397
|
+
req.callbacks.error(TRPCClientError.from(new TRPCWebSocketClosedError({
|
|
398
|
+
message: 'Closed before connection was established'
|
|
399
|
+
})));
|
|
313
400
|
}
|
|
314
401
|
}
|
|
315
|
-
|
|
402
|
+
if (activeConnection) {
|
|
403
|
+
closeIfNoPending(activeConnection);
|
|
404
|
+
}
|
|
316
405
|
clearTimeout(connectTimer);
|
|
317
406
|
connectTimer = undefined;
|
|
318
407
|
activeConnection = null;
|
|
@@ -323,100 +412,80 @@ function createWSClient(opts) {
|
|
|
323
412
|
},
|
|
324
413
|
/**
|
|
325
414
|
* Reconnect to the WebSocket server
|
|
326
|
-
*/ reconnect
|
|
415
|
+
*/ reconnect,
|
|
416
|
+
connectionState: connectionState
|
|
327
417
|
};
|
|
328
418
|
}
|
|
329
419
|
class TRPCWebSocketClosedError extends Error {
|
|
330
|
-
constructor(
|
|
331
|
-
super(message
|
|
420
|
+
constructor(opts){
|
|
421
|
+
super(opts?.message ?? 'WebSocket closed', // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
422
|
+
// @ts-ignore https://github.com/tc39/proposal-error-cause
|
|
423
|
+
{
|
|
424
|
+
cause: opts?.cause
|
|
425
|
+
});
|
|
332
426
|
this.name = 'TRPCWebSocketClosedError';
|
|
333
427
|
Object.setPrototypeOf(this, TRPCWebSocketClosedError.prototype);
|
|
334
428
|
}
|
|
335
429
|
}
|
|
336
430
|
/**
|
|
337
|
-
* @
|
|
431
|
+
* @see https://trpc.io/docs/v11/client/links/wsLink
|
|
432
|
+
* @deprecated
|
|
433
|
+
* 🙋♂️ **Contributors needed** to continue supporting WebSockets!
|
|
434
|
+
* See https://github.com/trpc/trpc/issues/6109
|
|
338
435
|
*/ function wsLink(opts) {
|
|
339
436
|
const transformer = getTransformer(opts.transformer);
|
|
340
437
|
return ()=>{
|
|
341
|
-
const { client
|
|
342
|
-
return ({ op
|
|
438
|
+
const { client } = opts;
|
|
439
|
+
return ({ op })=>{
|
|
343
440
|
return observable((observer)=>{
|
|
344
|
-
const { type
|
|
441
|
+
const { type, path, id, context } = op;
|
|
345
442
|
const input = transformer.input.serialize(op.input);
|
|
346
|
-
const
|
|
347
|
-
|
|
348
|
-
path,
|
|
349
|
-
input,
|
|
350
|
-
id,
|
|
351
|
-
context,
|
|
352
|
-
signal: null
|
|
353
|
-
}, {
|
|
354
|
-
error (err) {
|
|
355
|
-
observer.next({
|
|
356
|
-
result: {
|
|
357
|
-
type: 'state',
|
|
358
|
-
state: 'error',
|
|
359
|
-
data: err
|
|
360
|
-
},
|
|
361
|
-
context: context
|
|
362
|
-
});
|
|
363
|
-
observer.error(err);
|
|
364
|
-
unsub();
|
|
365
|
-
},
|
|
366
|
-
complete () {
|
|
367
|
-
observer.complete();
|
|
443
|
+
const connState = type === 'subscription' ? client.connectionState.subscribe({
|
|
444
|
+
next (result) {
|
|
368
445
|
observer.next({
|
|
369
|
-
result
|
|
370
|
-
|
|
371
|
-
state: 'idle'
|
|
372
|
-
},
|
|
373
|
-
context: context
|
|
446
|
+
result,
|
|
447
|
+
context
|
|
374
448
|
});
|
|
449
|
+
}
|
|
450
|
+
}) : null;
|
|
451
|
+
const unsubscribeRequest = client.request({
|
|
452
|
+
op: {
|
|
453
|
+
type,
|
|
454
|
+
path,
|
|
455
|
+
input,
|
|
456
|
+
id,
|
|
457
|
+
context,
|
|
458
|
+
signal: null
|
|
375
459
|
},
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
460
|
+
callbacks: {
|
|
461
|
+
error (err) {
|
|
462
|
+
observer.error(err);
|
|
463
|
+
unsubscribeRequest();
|
|
464
|
+
},
|
|
465
|
+
complete () {
|
|
466
|
+
observer.complete();
|
|
467
|
+
},
|
|
468
|
+
next (event) {
|
|
469
|
+
const transformed = transformResult(event, transformer.output);
|
|
470
|
+
if (!transformed.ok) {
|
|
471
|
+
observer.error(TRPCClientError.from(transformed.error));
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
389
474
|
observer.next({
|
|
390
|
-
result:
|
|
391
|
-
type: 'state',
|
|
392
|
-
state: 'error',
|
|
393
|
-
data: error
|
|
394
|
-
},
|
|
395
|
-
context: context
|
|
475
|
+
result: transformed.result
|
|
396
476
|
});
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
context: context
|
|
403
|
-
});
|
|
404
|
-
if (op.type !== 'subscription') {
|
|
405
|
-
// if it isn't a subscription we don't care about next response
|
|
406
|
-
unsub();
|
|
407
|
-
observer.complete();
|
|
477
|
+
if (op.type !== 'subscription') {
|
|
478
|
+
// if it isn't a subscription we don't care about next response
|
|
479
|
+
unsubscribeRequest();
|
|
480
|
+
observer.complete();
|
|
481
|
+
}
|
|
408
482
|
}
|
|
409
|
-
}
|
|
483
|
+
},
|
|
484
|
+
lastEventId: undefined
|
|
410
485
|
});
|
|
411
486
|
return ()=>{
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
result: {
|
|
415
|
-
type: 'state',
|
|
416
|
-
state: 'idle'
|
|
417
|
-
},
|
|
418
|
-
context: context
|
|
419
|
-
});
|
|
487
|
+
unsubscribeRequest();
|
|
488
|
+
connState?.unsubscribe();
|
|
420
489
|
};
|
|
421
490
|
});
|
|
422
491
|
};
|
package/dist/links.d.ts
CHANGED
package/dist/links.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../src/links.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAE9B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,8BAA8B,CAAC"}
|
|
1
|
+
{"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../src/links.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAE9B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,mBAAmB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unstable-internals.d.ts","sourceRoot":"","sources":["../src/unstable-internals.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC"}
|
|
1
|
+
{"version":3,"file":"unstable-internals.d.ts","sourceRoot":"","sources":["../src/unstable-internals.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,iCAAiC,CAAC"}
|
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-12-06-react.665+f3677f632",
|
|
4
4
|
"description": "The tRPC client library",
|
|
5
5
|
"author": "KATT",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"build": "rollup --config rollup.config.ts --configPlugin rollup-plugin-swc3",
|
|
26
26
|
"dev": "pnpm build --watch",
|
|
27
27
|
"codegen-entrypoints": "tsx entrypoints.script.ts",
|
|
28
|
-
"lint": "eslint --cache
|
|
28
|
+
"lint": "eslint --cache src",
|
|
29
29
|
"ts-watch": "tsc --watch"
|
|
30
30
|
},
|
|
31
31
|
"exports": {
|
|
@@ -73,22 +73,25 @@
|
|
|
73
73
|
"package.json",
|
|
74
74
|
"links",
|
|
75
75
|
"unstable-internals",
|
|
76
|
-
"!**/*.test.*"
|
|
76
|
+
"!**/*.test.*",
|
|
77
|
+
"!**/__tests__"
|
|
77
78
|
],
|
|
78
79
|
"peerDependencies": {
|
|
79
|
-
"@trpc/server": "11.0.0-alpha-tmp-
|
|
80
|
+
"@trpc/server": "11.0.0-alpha-tmp-12-06-react.665+f3677f632",
|
|
81
|
+
"typescript": ">=5.6.2"
|
|
80
82
|
},
|
|
81
83
|
"devDependencies": {
|
|
82
|
-
"@trpc/server": "11.0.0-alpha-tmp-
|
|
84
|
+
"@trpc/server": "11.0.0-alpha-tmp-12-06-react.665+f3677f632",
|
|
83
85
|
"@types/isomorphic-fetch": "^0.0.39",
|
|
84
|
-
"@types/node": "^
|
|
85
|
-
"eslint": "^
|
|
86
|
+
"@types/node": "^22.9.0",
|
|
87
|
+
"eslint": "^9.13.0",
|
|
86
88
|
"isomorphic-fetch": "^3.0.0",
|
|
87
89
|
"node-fetch": "^3.3.0",
|
|
88
|
-
"rollup": "^4.
|
|
89
|
-
"tslib": "^2.
|
|
90
|
+
"rollup": "^4.24.4",
|
|
91
|
+
"tslib": "^2.8.1",
|
|
90
92
|
"tsx": "^4.0.0",
|
|
91
|
-
"
|
|
93
|
+
"typescript": "^5.7.0",
|
|
94
|
+
"undici": "^7.0.0"
|
|
92
95
|
},
|
|
93
96
|
"publishConfig": {
|
|
94
97
|
"access": "public"
|
|
@@ -96,5 +99,5 @@
|
|
|
96
99
|
"funding": [
|
|
97
100
|
"https://trpc.io/sponsor"
|
|
98
101
|
],
|
|
99
|
-
"gitHead": "
|
|
102
|
+
"gitHead": "f3677f6326d62400c29d1c358db9f3a68a0dd27d"
|
|
100
103
|
}
|