@milaboratories/pl-client 2.16.12 → 2.16.14
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/__external/.pnpm/{@rollup_plugin-typescript@12.1.4_rollup@4.52.4_tslib@2.8.1_typescript@5.6.3 → @rollup_plugin-typescript@12.3.0_rollup@4.52.4_tslib@2.8.1_typescript@5.6.3}/__external/tslib/tslib.es6.cjs.map +1 -1
- package/dist/__external/.pnpm/{@rollup_plugin-typescript@12.1.4_rollup@4.52.4_tslib@2.8.1_typescript@5.6.3 → @rollup_plugin-typescript@12.3.0_rollup@4.52.4_tslib@2.8.1_typescript@5.6.3}/__external/tslib/tslib.es6.js.map +1 -1
- package/dist/core/client.cjs +31 -16
- package/dist/core/client.cjs.map +1 -1
- package/dist/core/client.d.ts +3 -2
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/client.js +31 -16
- package/dist/core/client.js.map +1 -1
- package/dist/core/default_client.cjs +1 -1
- package/dist/core/default_client.cjs.map +1 -1
- package/dist/core/default_client.js +1 -1
- package/dist/core/default_client.js.map +1 -1
- package/dist/core/driver.cjs +1 -1
- package/dist/core/driver.cjs.map +1 -1
- package/dist/core/driver.js +1 -1
- package/dist/core/driver.js.map +1 -1
- package/dist/core/errors.cjs +15 -4
- package/dist/core/errors.cjs.map +1 -1
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +15 -4
- package/dist/core/errors.js.map +1 -1
- package/dist/core/ll_client.cjs +61 -21
- package/dist/core/ll_client.cjs.map +1 -1
- package/dist/core/ll_client.d.ts +12 -3
- package/dist/core/ll_client.d.ts.map +1 -1
- package/dist/core/ll_client.js +62 -22
- package/dist/core/ll_client.js.map +1 -1
- package/dist/core/transaction.cjs +1 -1
- package/dist/core/transaction.js +1 -1
- package/dist/core/unauth_client.cjs +6 -2
- package/dist/core/unauth_client.cjs.map +1 -1
- package/dist/core/unauth_client.d.ts +2 -1
- package/dist/core/unauth_client.d.ts.map +1 -1
- package/dist/core/unauth_client.js +6 -2
- package/dist/core/unauth_client.js.map +1 -1
- package/dist/core/websocket_stream.cjs +147 -129
- package/dist/core/websocket_stream.cjs.map +1 -1
- package/dist/core/websocket_stream.d.ts +29 -22
- package/dist/core/websocket_stream.d.ts.map +1 -1
- package/dist/core/websocket_stream.js +148 -130
- package/dist/core/websocket_stream.js.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.cjs +136 -0
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.cjs.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.d.ts +75 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.d.ts.map +1 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.js +135 -1
- package/dist/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.js.map +1 -1
- package/dist/proto-rest/index.cjs +16 -2
- package/dist/proto-rest/index.cjs.map +1 -1
- package/dist/proto-rest/index.d.ts.map +1 -1
- package/dist/proto-rest/index.js +16 -2
- package/dist/proto-rest/index.js.map +1 -1
- package/dist/test/test_config.cjs +13 -3
- package/dist/test/test_config.cjs.map +1 -1
- package/dist/test/test_config.d.ts +4 -0
- package/dist/test/test_config.d.ts.map +1 -1
- package/dist/test/test_config.js +12 -4
- package/dist/test/test_config.js.map +1 -1
- package/package.json +6 -6
- package/src/core/client.ts +40 -21
- package/src/core/default_client.ts +1 -1
- package/src/core/driver.ts +1 -1
- package/src/core/errors.ts +14 -4
- package/src/core/ll_client.test.ts +9 -3
- package/src/core/ll_client.ts +81 -26
- package/src/core/unauth_client.test.ts +4 -4
- package/src/core/unauth_client.ts +7 -2
- package/src/core/websocket_stream.test.ts +19 -8
- package/src/core/websocket_stream.ts +173 -164
- package/src/proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.ts +179 -1
- package/src/proto-rest/index.ts +17 -2
- package/src/test/test_config.ts +13 -4
- /package/dist/__external/.pnpm/{@rollup_plugin-typescript@12.1.4_rollup@4.52.4_tslib@2.8.1_typescript@5.6.3 → @rollup_plugin-typescript@12.3.0_rollup@4.52.4_tslib@2.8.1_typescript@5.6.3}/__external/tslib/tslib.es6.cjs +0 -0
- /package/dist/__external/.pnpm/{@rollup_plugin-typescript@12.1.4_rollup@4.52.4_tslib@2.8.1_typescript@5.6.3 → @rollup_plugin-typescript@12.3.0_rollup@4.52.4_tslib@2.8.1_typescript@5.6.3}/__external/tslib/tslib.es6.js +0 -0
|
@@ -1,181 +1,182 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var undici = require('undici');
|
|
4
|
-
var api = require('../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api.cjs');
|
|
5
4
|
var Denque = require('denque');
|
|
6
5
|
var retry_strategy = require('../helpers/retry_strategy.cjs');
|
|
6
|
+
var errors = require('./errors.cjs');
|
|
7
7
|
|
|
8
|
+
var ConnectionState;
|
|
9
|
+
(function (ConnectionState) {
|
|
10
|
+
ConnectionState[ConnectionState["NEW"] = 0] = "NEW";
|
|
11
|
+
ConnectionState[ConnectionState["CONNECTING"] = 1] = "CONNECTING";
|
|
12
|
+
ConnectionState[ConnectionState["CONNECTED"] = 2] = "CONNECTED";
|
|
13
|
+
ConnectionState[ConnectionState["CLOSING"] = 3] = "CLOSING";
|
|
14
|
+
ConnectionState[ConnectionState["CLOSED"] = 4] = "CLOSED";
|
|
15
|
+
})(ConnectionState || (ConnectionState = {}));
|
|
8
16
|
/**
|
|
9
17
|
* WebSocket-based bidirectional stream implementation for LLTransaction.
|
|
10
18
|
* Implements BiDiStream interface which is compatible with DuplexStreamingCall.
|
|
11
19
|
*/
|
|
12
20
|
class WebSocketBiDiStream {
|
|
21
|
+
url;
|
|
22
|
+
serializeClientMessage;
|
|
23
|
+
parseServerMessage;
|
|
24
|
+
options;
|
|
13
25
|
// Connection
|
|
14
26
|
ws = null;
|
|
15
|
-
connectionState =
|
|
16
|
-
url;
|
|
17
|
-
jwtToken;
|
|
18
|
-
abortSignal;
|
|
27
|
+
connectionState = ConnectionState.NEW;
|
|
19
28
|
reconnection;
|
|
20
29
|
// Send management
|
|
21
30
|
sendQueue = new Denque();
|
|
22
31
|
sendCompleted = false;
|
|
32
|
+
onComplete;
|
|
23
33
|
// Response management
|
|
24
34
|
responseQueue = new Denque();
|
|
25
35
|
responseResolvers = [];
|
|
26
36
|
// Error tracking
|
|
27
|
-
|
|
37
|
+
lastError;
|
|
28
38
|
// === Public API ===
|
|
29
39
|
requests = {
|
|
30
40
|
send: async (message) => {
|
|
31
|
-
this.
|
|
32
|
-
return this.enqueueSend(message);
|
|
41
|
+
return await this.enqueueSend(message);
|
|
33
42
|
},
|
|
34
43
|
complete: async () => {
|
|
35
44
|
if (this.sendCompleted)
|
|
36
45
|
return;
|
|
46
|
+
await this.drainSendQueue(); // ensure we sent all already queued messages before closing the stream
|
|
47
|
+
try {
|
|
48
|
+
await this.onComplete(this); // custom onComplete may send additional messages
|
|
49
|
+
}
|
|
50
|
+
catch (_) {
|
|
51
|
+
// When 'complete' gets called concurrently with connection break or over a broken
|
|
52
|
+
// transaction stream (server decided it should drop transaction), server would close
|
|
53
|
+
// connection anyway on its end. We can safely ignore error here and just continue working.
|
|
54
|
+
}
|
|
37
55
|
this.sendCompleted = true;
|
|
38
|
-
await this.drainSendQueue();
|
|
39
|
-
this.closeConnection();
|
|
40
56
|
},
|
|
41
57
|
};
|
|
42
58
|
responses = {
|
|
43
59
|
[Symbol.asyncIterator]: () => this.createResponseIterator(),
|
|
44
60
|
};
|
|
45
|
-
|
|
61
|
+
close() {
|
|
62
|
+
this.reconnection.cancel();
|
|
63
|
+
if (this.connectionState < ConnectionState.CONNECTED) {
|
|
64
|
+
// Never reached CONNECTED state. ws.close() will never trigger 'close' event.
|
|
65
|
+
this.ws?.close();
|
|
66
|
+
this.onClose();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (!this.progressConnectionState(ConnectionState.CLOSING))
|
|
70
|
+
return;
|
|
71
|
+
this.ws.close();
|
|
72
|
+
}
|
|
73
|
+
constructor(url, serializeClientMessage, parseServerMessage, options = {}) {
|
|
46
74
|
this.url = url;
|
|
47
|
-
this.
|
|
48
|
-
this.
|
|
75
|
+
this.serializeClientMessage = serializeClientMessage;
|
|
76
|
+
this.parseServerMessage = parseServerMessage;
|
|
77
|
+
this.options = options;
|
|
78
|
+
this.onComplete = this.options.onComplete ?? ((stream) => stream.close());
|
|
79
|
+
const retryConfig = this.options.retryConfig ?? {};
|
|
49
80
|
this.reconnection = new retry_strategy.RetryStrategy(retryConfig, {
|
|
50
81
|
onRetry: () => { void this.connect(); },
|
|
51
82
|
onMaxAttemptsReached: (error) => this.handleError(error),
|
|
52
83
|
});
|
|
53
|
-
if (abortSignal
|
|
54
|
-
this.
|
|
84
|
+
if (this.options.abortSignal?.aborted) {
|
|
85
|
+
this.progressConnectionState(ConnectionState.CLOSED);
|
|
55
86
|
return;
|
|
56
87
|
}
|
|
57
|
-
this.
|
|
58
|
-
|
|
88
|
+
this.options.abortSignal?.addEventListener('abort', () => this.close());
|
|
89
|
+
this.connect();
|
|
59
90
|
}
|
|
60
91
|
// === Connection Lifecycle ===
|
|
61
92
|
connect() {
|
|
62
|
-
if (this.
|
|
93
|
+
if (this.options.abortSignal?.aborted)
|
|
94
|
+
return;
|
|
95
|
+
// Prevent reconnecting after first successful connection.
|
|
96
|
+
if (!this.progressConnectionState(ConnectionState.CONNECTING))
|
|
63
97
|
return;
|
|
64
|
-
this.connectionState = 'connecting';
|
|
65
|
-
this.connectionError = null;
|
|
66
98
|
try {
|
|
67
99
|
this.ws = this.createWebSocket();
|
|
68
|
-
this.
|
|
100
|
+
this.ws.addEventListener('open', () => this.onOpen());
|
|
101
|
+
this.ws.addEventListener('message', (event) => this.onMessage(event.data));
|
|
102
|
+
this.ws.addEventListener('error', (error) => this.onError(error));
|
|
103
|
+
this.ws.addEventListener('close', () => this.onClose());
|
|
69
104
|
}
|
|
70
105
|
catch (error) {
|
|
71
|
-
this.
|
|
72
|
-
this.connectionState = 'disconnected';
|
|
106
|
+
this.lastError = this.toError(error);
|
|
73
107
|
this.reconnection.schedule();
|
|
74
108
|
}
|
|
75
109
|
}
|
|
76
110
|
createWebSocket() {
|
|
77
|
-
const options =
|
|
78
|
-
|
|
79
|
-
:
|
|
111
|
+
const options = {};
|
|
112
|
+
if (this.options.jwtToken)
|
|
113
|
+
options.headers = { authorization: `Bearer ${this.options.jwtToken}` };
|
|
114
|
+
if (this.options.dispatcher)
|
|
115
|
+
options.dispatcher = this.options.dispatcher;
|
|
80
116
|
const ws = new undici.WebSocket(this.url, options);
|
|
81
|
-
|
|
82
|
-
ws.binaryType = 'arraybuffer';
|
|
83
|
-
}
|
|
117
|
+
ws.binaryType = 'arraybuffer';
|
|
84
118
|
return ws;
|
|
85
119
|
}
|
|
86
|
-
attachWebSocketHandlers() {
|
|
87
|
-
if (!this.ws)
|
|
88
|
-
return;
|
|
89
|
-
this.ws.addEventListener('open', () => this.onOpen());
|
|
90
|
-
this.ws.addEventListener('message', (event) => this.onMessage(event.data));
|
|
91
|
-
this.ws.addEventListener('error', (error) => this.onError(error));
|
|
92
|
-
this.ws.addEventListener('close', () => this.onClose());
|
|
93
|
-
}
|
|
94
|
-
attachAbortSignalHandler() {
|
|
95
|
-
this.abortSignal.addEventListener('abort', () => this.close());
|
|
96
|
-
}
|
|
97
120
|
onOpen() {
|
|
98
|
-
this.
|
|
99
|
-
this.
|
|
100
|
-
void this.processSendQueue();
|
|
121
|
+
this.progressConnectionState(ConnectionState.CONNECTED);
|
|
122
|
+
this.processSendQueue();
|
|
101
123
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
124
|
+
onMessage(data) {
|
|
125
|
+
if (!(data instanceof ArrayBuffer)) {
|
|
126
|
+
this.handleError(new Error(`Unexpected WS message format: ${typeof data}`));
|
|
105
127
|
return;
|
|
106
|
-
if (this.sendCompleted) {
|
|
107
|
-
this.finalizeStream();
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
this.connectionState = 'disconnected';
|
|
111
|
-
this.reconnection.schedule();
|
|
112
128
|
}
|
|
113
|
-
}
|
|
114
|
-
onError(error) {
|
|
115
|
-
this.handleError(this.toError(error));
|
|
116
|
-
}
|
|
117
|
-
onMessage(data) {
|
|
118
129
|
try {
|
|
119
|
-
const message = this.
|
|
130
|
+
const message = this.parseServerMessage(new Uint8Array(data));
|
|
120
131
|
this.deliverResponse(message);
|
|
121
132
|
}
|
|
122
133
|
catch (error) {
|
|
123
134
|
this.handleError(this.toError(error));
|
|
124
135
|
}
|
|
125
136
|
}
|
|
126
|
-
|
|
127
|
-
if (this.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
close() {
|
|
132
|
-
if (this.isClosed())
|
|
133
|
-
return;
|
|
134
|
-
this.connectionState = 'closed';
|
|
135
|
-
this.reconnection.cancel();
|
|
136
|
-
this.closeWebSocket();
|
|
137
|
-
this.rejectAllPendingOperations();
|
|
138
|
-
}
|
|
139
|
-
closeWebSocket() {
|
|
140
|
-
if (!this.ws)
|
|
137
|
+
onError(error) {
|
|
138
|
+
if (this.connectionState < ConnectionState.CONNECTED) {
|
|
139
|
+
// Try to connect several times until we succeed or run out of attempts.
|
|
140
|
+
this.lastError = this.toError(error);
|
|
141
|
+
this.reconnection.schedule();
|
|
141
142
|
return;
|
|
142
|
-
try {
|
|
143
|
-
this.ws.close();
|
|
144
|
-
}
|
|
145
|
-
catch {
|
|
146
|
-
// Suppress close errors
|
|
147
143
|
}
|
|
148
|
-
this.
|
|
149
|
-
}
|
|
150
|
-
finalizeStream() {
|
|
151
|
-
this.connectionState = 'closed';
|
|
152
|
-
this.resolveAllPendingResponses();
|
|
144
|
+
this.handleError(this.toError(error));
|
|
153
145
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
146
|
+
onClose() {
|
|
147
|
+
this.progressConnectionState(ConnectionState.CLOSED);
|
|
148
|
+
// If abort signal was triggered, use that as the error source
|
|
149
|
+
if (this.options.abortSignal?.aborted && !this.lastError) {
|
|
150
|
+
const reason = this.options.abortSignal.reason;
|
|
151
|
+
if (reason instanceof Error) {
|
|
152
|
+
this.lastError = reason;
|
|
153
|
+
}
|
|
154
|
+
else if (reason !== undefined) {
|
|
155
|
+
this.lastError = new Error(String(reason), { cause: reason });
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
this.lastError = this.createStreamClosedError();
|
|
159
|
+
}
|
|
158
160
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
161
|
+
if (!this.lastError) {
|
|
162
|
+
this.rejectAllSendOperations(this.createStreamClosedError());
|
|
163
|
+
this.resolveAllPendingResponses(); // unblock active async iterator
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
this.rejectAllPendingOperations(this.lastError);
|
|
163
167
|
}
|
|
164
|
-
throw new Error(`Unsupported message format: ${typeof data}`);
|
|
165
168
|
}
|
|
166
169
|
// === Send Queue Management ===
|
|
167
|
-
|
|
170
|
+
enqueueSend(message) {
|
|
168
171
|
if (this.sendCompleted) {
|
|
169
172
|
throw new Error('Cannot send: stream already completed');
|
|
170
173
|
}
|
|
171
|
-
if (this.abortSignal
|
|
174
|
+
if (this.options.abortSignal?.aborted) {
|
|
172
175
|
throw new Error('Cannot send: stream aborted');
|
|
173
176
|
}
|
|
174
|
-
}
|
|
175
|
-
enqueueSend(message) {
|
|
176
177
|
return new Promise((resolve, reject) => {
|
|
177
178
|
this.sendQueue.push({ message, resolve, reject });
|
|
178
|
-
|
|
179
|
+
this.processSendQueue();
|
|
179
180
|
});
|
|
180
181
|
}
|
|
181
182
|
processSendQueue() {
|
|
@@ -187,7 +188,7 @@ class WebSocketBiDiStream {
|
|
|
187
188
|
}
|
|
188
189
|
}
|
|
189
190
|
canSendMessages() {
|
|
190
|
-
return this.connectionState ===
|
|
191
|
+
return this.connectionState === ConnectionState.CONNECTED;
|
|
191
192
|
}
|
|
192
193
|
sendQueuedMessage(queued) {
|
|
193
194
|
try {
|
|
@@ -199,7 +200,7 @@ class WebSocketBiDiStream {
|
|
|
199
200
|
if (ws.readyState !== undici.WebSocket.OPEN) {
|
|
200
201
|
throw new Error(`WebSocket is not open (readyState: ${ws.readyState})`);
|
|
201
202
|
}
|
|
202
|
-
const binary =
|
|
203
|
+
const binary = this.serializeClientMessage(queued.message);
|
|
203
204
|
ws.send(binary);
|
|
204
205
|
queued.resolve();
|
|
205
206
|
}
|
|
@@ -208,25 +209,25 @@ class WebSocketBiDiStream {
|
|
|
208
209
|
}
|
|
209
210
|
}
|
|
210
211
|
async drainSendQueue() {
|
|
211
|
-
const POLL_INTERVAL_MS =
|
|
212
|
+
const POLL_INTERVAL_MS = 5;
|
|
212
213
|
while (this.sendQueue.length > 0) {
|
|
213
214
|
await this.waitForCondition(() => this.sendQueue.length === 0, POLL_INTERVAL_MS);
|
|
214
215
|
}
|
|
215
216
|
}
|
|
216
217
|
waitForCondition(condition, intervalMs) {
|
|
217
218
|
return new Promise((resolve, reject) => {
|
|
218
|
-
if (this.abortSignal
|
|
219
|
-
return reject(this.toError(this.abortSignal.reason) ?? new Error('Stream aborted'));
|
|
219
|
+
if (this.options.abortSignal?.aborted) {
|
|
220
|
+
return reject(this.toError(this.options.abortSignal.reason) ?? new Error('Stream aborted'));
|
|
220
221
|
}
|
|
221
222
|
let timeoutId;
|
|
222
223
|
const onAbort = () => {
|
|
223
224
|
clearTimeout(timeoutId);
|
|
224
|
-
reject(this.toError(this.abortSignal
|
|
225
|
+
reject(this.toError(this.options.abortSignal?.reason) ?? new Error('Stream aborted'));
|
|
225
226
|
};
|
|
226
|
-
this.abortSignal
|
|
227
|
+
this.options.abortSignal?.addEventListener('abort', onAbort, { once: true });
|
|
227
228
|
const check = () => {
|
|
228
229
|
if (condition() || this.isStreamEnded()) {
|
|
229
|
-
this.abortSignal
|
|
230
|
+
this.options.abortSignal?.removeEventListener('abort', onAbort);
|
|
230
231
|
resolve();
|
|
231
232
|
}
|
|
232
233
|
else {
|
|
@@ -264,8 +265,8 @@ class WebSocketBiDiStream {
|
|
|
264
265
|
}
|
|
265
266
|
// Stream ended
|
|
266
267
|
if (this.isStreamEnded()) {
|
|
267
|
-
if (this.
|
|
268
|
-
reject(this.
|
|
268
|
+
if (this.lastError) {
|
|
269
|
+
reject(this.lastError);
|
|
269
270
|
}
|
|
270
271
|
else {
|
|
271
272
|
resolve({ value: undefined, done: true });
|
|
@@ -276,20 +277,20 @@ class WebSocketBiDiStream {
|
|
|
276
277
|
this.responseResolvers.push({ resolve, reject });
|
|
277
278
|
});
|
|
278
279
|
}
|
|
280
|
+
resolveAllPendingResponses() {
|
|
281
|
+
while (this.responseResolvers.length > 0) {
|
|
282
|
+
const resolver = this.responseResolvers.shift();
|
|
283
|
+
resolver.resolve({ value: undefined, done: true });
|
|
284
|
+
}
|
|
285
|
+
}
|
|
279
286
|
// === Error Handling ===
|
|
280
287
|
handleError(error) {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
this.connectionState = 'closed';
|
|
284
|
-
this.connectionError = error;
|
|
285
|
-
this.reconnection.cancel();
|
|
286
|
-
this.closeWebSocket();
|
|
287
|
-
this.rejectAllPendingOperations(error);
|
|
288
|
+
this.lastError = error;
|
|
289
|
+
this.close();
|
|
288
290
|
}
|
|
289
291
|
rejectAllPendingOperations(error) {
|
|
290
|
-
|
|
291
|
-
this.
|
|
292
|
-
this.rejectAllResponseResolvers(err);
|
|
292
|
+
this.rejectAllSendOperations(error);
|
|
293
|
+
this.rejectAllResponseResolvers(error);
|
|
293
294
|
}
|
|
294
295
|
rejectAllSendOperations(error) {
|
|
295
296
|
while (this.sendQueue.length > 0) {
|
|
@@ -304,8 +305,8 @@ class WebSocketBiDiStream {
|
|
|
304
305
|
}
|
|
305
306
|
}
|
|
306
307
|
createStreamClosedError() {
|
|
307
|
-
if (this.abortSignal
|
|
308
|
-
const reason = this.abortSignal.reason;
|
|
308
|
+
if (this.options.abortSignal?.aborted) {
|
|
309
|
+
const reason = this.options.abortSignal.reason;
|
|
309
310
|
if (reason instanceof Error) {
|
|
310
311
|
return reason;
|
|
311
312
|
}
|
|
@@ -313,19 +314,36 @@ class WebSocketBiDiStream {
|
|
|
313
314
|
}
|
|
314
315
|
return new Error('Stream closed');
|
|
315
316
|
}
|
|
316
|
-
// ===
|
|
317
|
-
isConnectingOrConnected() {
|
|
318
|
-
return this.connectionState === 'connecting'
|
|
319
|
-
|| this.connectionState === 'connected';
|
|
320
|
-
}
|
|
321
|
-
isClosed() {
|
|
322
|
-
return this.connectionState === 'closed';
|
|
323
|
-
}
|
|
317
|
+
// === Helpers ===
|
|
324
318
|
isStreamEnded() {
|
|
325
|
-
return this.
|
|
319
|
+
return this.connectionState === ConnectionState.CLOSED || this.options.abortSignal?.aborted || false;
|
|
326
320
|
}
|
|
327
321
|
toError(error) {
|
|
328
|
-
|
|
322
|
+
if (error instanceof Error)
|
|
323
|
+
return error;
|
|
324
|
+
if (error instanceof undici.ErrorEvent) {
|
|
325
|
+
const err = error.error;
|
|
326
|
+
// undici WebSocket throws TypeError with empty message on socket close
|
|
327
|
+
// (e.g., when connection is lost or server disconnects)
|
|
328
|
+
if (err instanceof TypeError && !err.message) {
|
|
329
|
+
return new errors.DisconnectedError('WebSocket connection closed unexpectedly');
|
|
330
|
+
}
|
|
331
|
+
return err instanceof Error ? err : new Error('WebSocket error', { cause: error });
|
|
332
|
+
}
|
|
333
|
+
return new Error(String(error));
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Connection state progresses linearly from NEW to CLOSED and never goes back.
|
|
337
|
+
* This internal contract dramatically simplifies the internal stream state management.
|
|
338
|
+
*
|
|
339
|
+
* If you ever feel the need to make this contract less strict, think twice.
|
|
340
|
+
*/
|
|
341
|
+
progressConnectionState(newState) {
|
|
342
|
+
if (newState < this.connectionState) {
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
this.connectionState = newState;
|
|
346
|
+
return true;
|
|
329
347
|
}
|
|
330
348
|
}
|
|
331
349
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket_stream.cjs","sources":["../../src/core/websocket_stream.ts"],"sourcesContent":["import { WebSocket } from 'undici';\nimport {\n TxAPI_ClientMessage as ClientMessageType,\n TxAPI_ServerMessage as ServerMessageType,\n} from '../proto-grpc/github.com/milaboratory/pl/plapi/plapiproto/api';\nimport type { BiDiStream } from './abstract_stream';\nimport Denque from 'denque';\nimport type { RetryConfig } from '../helpers/retry_strategy';\nimport { RetryStrategy } from '../helpers/retry_strategy';\n\ntype ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'closing' | 'closed';\n\ninterface QueuedMessage {\n message: ClientMessageType;\n resolve: () => void;\n reject: (error: Error) => void;\n}\n\ninterface ResponseResolver {\n resolve: (value: IteratorResult<ServerMessageType>) => void;\n reject: (error: Error) => void;\n}\n\n/**\n * WebSocket-based bidirectional stream implementation for LLTransaction.\n * Implements BiDiStream interface which is compatible with DuplexStreamingCall.\n */\nexport class WebSocketBiDiStream implements BiDiStream<ClientMessageType, ServerMessageType> {\n // Connection\n private ws: WebSocket | null = null;\n private connectionState: ConnectionState = 'disconnected';\n private readonly url: string;\n private readonly jwtToken?: string;\n private readonly abortSignal: AbortSignal;\n private readonly reconnection: RetryStrategy;\n\n // Send management\n private readonly sendQueue = new Denque<QueuedMessage>();\n private sendCompleted = false;\n\n // Response management\n private readonly responseQueue = new Denque<ServerMessageType>();\n private responseResolvers: ResponseResolver[] = [];\n\n // Error tracking\n private connectionError: Error | null = null;\n\n // === Public API ===\n\n public readonly requests = {\n send: async (message: ClientMessageType): Promise<void> => {\n this.validateSendState();\n return this.enqueueSend(message);\n },\n\n complete: async (): Promise<void> => {\n if (this.sendCompleted) return;\n\n this.sendCompleted = true;\n await this.drainSendQueue();\n this.closeConnection();\n },\n };\n\n public readonly responses: AsyncIterable<ServerMessageType> = {\n [Symbol.asyncIterator]: () => this.createResponseIterator(),\n };\n\n constructor(\n url: string,\n abortSignal: AbortSignal,\n jwtToken?: string,\n retryConfig: Partial<RetryConfig> = {},\n ) {\n this.url = url;\n this.jwtToken = jwtToken;\n this.abortSignal = abortSignal;\n\n this.reconnection = new RetryStrategy(retryConfig, {\n onRetry: () => { void this.connect(); },\n onMaxAttemptsReached: (error) => this.handleError(error),\n });\n\n if (abortSignal.aborted) {\n this.connectionState = 'closed';\n return;\n }\n\n this.attachAbortSignalHandler();\n void this.connect();\n }\n\n // === Connection Lifecycle ===\n\n private connect(): void {\n if (this.isConnectingOrConnected() || this.abortSignal.aborted) return;\n\n this.connectionState = 'connecting';\n this.connectionError = null;\n\n try {\n this.ws = this.createWebSocket();\n this.attachWebSocketHandlers();\n } catch (error) {\n this.connectionError = this.toError(error);\n this.connectionState = 'disconnected';\n this.reconnection.schedule();\n }\n }\n\n private createWebSocket(): WebSocket {\n const options = this.jwtToken\n ? { headers: { authorization: `Bearer ${this.jwtToken}` } }\n : undefined;\n\n const ws = new (WebSocket as any)(this.url, options);\n if (ws) {\n ws.binaryType = 'arraybuffer';\n }\n return ws;\n }\n\n private attachWebSocketHandlers(): void {\n if (!this.ws) return;\n\n this.ws.addEventListener('open', () => this.onOpen());\n this.ws.addEventListener('message', (event) => this.onMessage(event.data));\n this.ws.addEventListener('error', (error) => this.onError(error));\n this.ws.addEventListener('close', () => this.onClose());\n }\n\n private attachAbortSignalHandler(): void {\n this.abortSignal.addEventListener('abort', () => this.close());\n }\n\n private onOpen(): void {\n this.connectionState = 'connected';\n this.reconnection.reset();\n void this.processSendQueue();\n }\n\n private onClose(): void {\n this.ws = null;\n\n if (this.isClosed() || this.abortSignal.aborted) return;\n\n if (this.sendCompleted) {\n this.finalizeStream();\n } else {\n this.connectionState = 'disconnected';\n this.reconnection.schedule();\n }\n }\n\n private onError(error: unknown): void {\n this.handleError(this.toError(error));\n }\n\n private onMessage(data: unknown): void {\n try {\n const message = this.parseMessage(data);\n this.deliverResponse(message);\n } catch (error) {\n this.handleError(this.toError(error));\n }\n }\n\n private closeConnection(): void {\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.ws.close();\n }\n }\n\n private close(): void {\n if (this.isClosed()) return;\n\n this.connectionState = 'closed';\n this.reconnection.cancel();\n this.closeWebSocket();\n this.rejectAllPendingOperations();\n }\n\n private closeWebSocket(): void {\n if (!this.ws) return;\n\n try {\n this.ws.close();\n } catch {\n // Suppress close errors\n }\n\n this.ws = null;\n }\n\n private finalizeStream(): void {\n this.connectionState = 'closed';\n this.resolveAllPendingResponses();\n }\n\n private resolveAllPendingResponses(): void {\n while (this.responseResolvers.length > 0) {\n const resolver = this.responseResolvers.shift()!;\n resolver.resolve({ value: undefined as any, done: true });\n }\n }\n\n private parseMessage(data: unknown): ServerMessageType {\n if (data instanceof ArrayBuffer) {\n return ServerMessageType.fromBinary(new Uint8Array(data));\n }\n\n throw new Error(`Unsupported message format: ${typeof data}`);\n }\n\n // === Send Queue Management ===\n\n private validateSendState(): void {\n if (this.sendCompleted) {\n throw new Error('Cannot send: stream already completed');\n }\n\n if (this.abortSignal.aborted) {\n throw new Error('Cannot send: stream aborted');\n }\n }\n\n private enqueueSend(message: ClientMessageType): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n this.sendQueue.push({ message, resolve, reject });\n void this.processSendQueue();\n });\n }\n\n private processSendQueue(): void {\n if (!this.canSendMessages()) return;\n\n while (this.sendQueue.length > 0) {\n const queued = this.sendQueue.shift()!;\n this.sendQueuedMessage(queued);\n }\n }\n\n private canSendMessages(): boolean {\n return this.connectionState === 'connected' && this.ws !== null;\n }\n\n private sendQueuedMessage(queued: QueuedMessage): void {\n try {\n const ws = this.ws;\n if (!ws) {\n throw new Error('WebSocket is not connected');\n }\n\n // Check if WebSocket is in a valid state for sending\n if (ws.readyState !== WebSocket.OPEN) {\n throw new Error(`WebSocket is not open (readyState: ${ws.readyState})`);\n }\n\n const binary = ClientMessageType.toBinary(queued.message);\n ws.send(binary);\n queued.resolve();\n } catch (error) {\n queued.reject(this.toError(error));\n }\n }\n\n private async drainSendQueue(): Promise<void> {\n const POLL_INTERVAL_MS = 10;\n\n while (this.sendQueue.length > 0) {\n await this.waitForCondition(\n () => this.sendQueue.length === 0,\n POLL_INTERVAL_MS,\n );\n }\n }\n\n private waitForCondition(\n condition: () => boolean,\n intervalMs: number,\n ): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (this.abortSignal.aborted) {\n return reject(this.toError(this.abortSignal.reason) ?? new Error('Stream aborted'));\n }\n\n let timeoutId: ReturnType<typeof setTimeout>;\n const onAbort = () => {\n clearTimeout(timeoutId);\n reject(this.toError(this.abortSignal.reason) ?? new Error('Stream aborted'));\n };\n\n this.abortSignal.addEventListener('abort', onAbort, { once: true });\n\n const check = () => {\n if (condition() || this.isStreamEnded()) {\n this.abortSignal.removeEventListener('abort', onAbort);\n resolve();\n } else {\n timeoutId = setTimeout(check, intervalMs);\n }\n };\n\n check();\n });\n }\n\n // === Response Delivery ===\n\n private deliverResponse(message: ServerMessageType): void {\n if (this.responseResolvers.length > 0) {\n const resolver = this.responseResolvers.shift()!;\n resolver.resolve({ value: message, done: false });\n } else {\n this.responseQueue.push(message);\n }\n }\n\n private async *createResponseIterator(): AsyncIterator<ServerMessageType> {\n while (true) {\n const result = await this.nextResponse();\n\n if (result.done) break;\n\n yield result.value;\n }\n }\n\n private nextResponse(): Promise<IteratorResult<ServerMessageType>> {\n return new Promise<IteratorResult<ServerMessageType>>((resolve, reject) => {\n // Fast path: message already available\n if (this.responseQueue.length > 0) {\n const message = this.responseQueue.shift()!;\n resolve({ value: message, done: false });\n return;\n }\n\n // Stream ended\n if (this.isStreamEnded()) {\n if (this.connectionError) {\n reject(this.connectionError);\n } else {\n resolve({ value: undefined as any, done: true });\n }\n return;\n }\n\n // Wait for next message\n this.responseResolvers.push({ resolve, reject });\n });\n }\n\n // === Error Handling ===\n private handleError(error: Error): void {\n if (this.isClosed()) return;\n\n this.connectionState = 'closed';\n this.connectionError = error;\n this.reconnection.cancel();\n this.closeWebSocket();\n this.rejectAllPendingOperations(error);\n }\n\n private rejectAllPendingOperations(error?: Error): void {\n const err = error ?? this.createStreamClosedError();\n this.rejectAllSendOperations(err);\n this.rejectAllResponseResolvers(err);\n }\n\n private rejectAllSendOperations(error: Error): void {\n while (this.sendQueue.length > 0) {\n const queued = this.sendQueue.shift()!;\n queued.reject(error);\n }\n }\n\n private rejectAllResponseResolvers(error: Error): void {\n while (this.responseResolvers.length > 0) {\n const resolver = this.responseResolvers.shift()!;\n resolver.reject(error);\n }\n }\n\n private createStreamClosedError(): Error {\n if (this.abortSignal.aborted) {\n const reason = this.abortSignal.reason;\n if (reason instanceof Error) {\n return reason;\n }\n return new Error('Stream aborted', { cause: reason });\n }\n return new Error('Stream closed');\n }\n // === State Checks ===\n\n private isConnectingOrConnected(): boolean {\n return this.connectionState === 'connecting'\n || this.connectionState === 'connected';\n }\n\n private isClosed(): boolean {\n return this.connectionState === 'closed';\n }\n\n private isStreamEnded(): boolean {\n return this.isClosed() || this.abortSignal.aborted;\n }\n\n private toError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n }\n}\n"],"names":["RetryStrategy","WebSocket","ServerMessageType","ClientMessageType"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"websocket_stream.cjs","sources":["../../src/core/websocket_stream.ts"],"sourcesContent":["import { WebSocket, type WebSocketInit, type Dispatcher, ErrorEvent } from 'undici';\nimport type { BiDiStream } from './abstract_stream';\nimport Denque from 'denque';\nimport type { RetryConfig } from '../helpers/retry_strategy';\nimport { RetryStrategy } from '../helpers/retry_strategy';\nimport { DisconnectedError } from './errors';\n\ninterface QueuedMessage<InType extends object> {\n message: InType;\n resolve: () => void;\n reject: (error: Error) => void;\n}\n\ninterface ResponseResolver<OutType extends object> {\n resolve: (value: IteratorResult<OutType>) => void;\n reject: (error: Error) => void;\n}\n\nenum ConnectionState {\n NEW = 0,\n CONNECTING = 1,\n CONNECTED = 2,\n CLOSING = 3,\n CLOSED = 4,\n}\n\nexport type WSStreamOptions<ClientMsg extends object, ServerMsg extends object> = {\n abortSignal?: AbortSignal;\n\n dispatcher?: Dispatcher;\n jwtToken?: string;\n retryConfig?: Partial<RetryConfig>;\n\n onComplete?: (stream: WebSocketBiDiStream<ClientMsg, ServerMsg>) => void | Promise<void>;\n};\n\n/**\n * WebSocket-based bidirectional stream implementation for LLTransaction.\n * Implements BiDiStream interface which is compatible with DuplexStreamingCall.\n */\nexport class WebSocketBiDiStream<ClientMsg extends object, ServerMsg extends object> implements BiDiStream<ClientMsg, ServerMsg> {\n // Connection\n private ws: WebSocket | null = null;\n private connectionState: ConnectionState = ConnectionState.NEW;\n private readonly reconnection: RetryStrategy;\n\n // Send management\n private readonly sendQueue = new Denque<QueuedMessage<ClientMsg>>();\n private sendCompleted = false;\n private readonly onComplete: (stream: WebSocketBiDiStream<ClientMsg, ServerMsg>) => void | Promise<void>;\n\n // Response management\n private readonly responseQueue = new Denque<ServerMsg>();\n private responseResolvers: ResponseResolver<ServerMsg>[] = [];\n\n // Error tracking\n private lastError?: Error;\n\n // === Public API ===\n\n public readonly requests = {\n send: async (message: ClientMsg): Promise<void> => {\n return await this.enqueueSend(message);\n },\n\n complete: async (): Promise<void> => {\n if (this.sendCompleted) return;\n\n await this.drainSendQueue(); // ensure we sent all already queued messages before closing the stream\n try {\n await this.onComplete(this); // custom onComplete may send additional messages\n } catch (_: unknown) {\n // When 'complete' gets called concurrently with connection break or over a broken\n // transaction stream (server decided it should drop transaction), server would close\n // connection anyway on its end. We can safely ignore error here and just continue working.\n }\n this.sendCompleted = true;\n },\n };\n\n public readonly responses: AsyncIterable<ServerMsg> = {\n [Symbol.asyncIterator]: () => this.createResponseIterator(),\n };\n\n public close(): void {\n this.reconnection.cancel();\n\n if (this.connectionState < ConnectionState.CONNECTED) {\n // Never reached CONNECTED state. ws.close() will never trigger 'close' event.\n this.ws?.close();\n this.onClose();\n return;\n }\n\n if (!this.progressConnectionState(ConnectionState.CLOSING)) return;\n this.ws!.close();\n }\n\n constructor(\n private readonly url: string,\n private readonly serializeClientMessage: (message: ClientMsg) => Uint8Array,\n private readonly parseServerMessage: (data: Uint8Array) => ServerMsg,\n private readonly options: WSStreamOptions<ClientMsg, ServerMsg> = {},\n ) {\n this.onComplete = this.options.onComplete ?? ((stream) => stream.close());\n\n const retryConfig = this.options.retryConfig ?? {};\n this.reconnection = new RetryStrategy(retryConfig, {\n onRetry: () => { void this.connect(); },\n onMaxAttemptsReached: (error) => this.handleError(error),\n });\n\n if (this.options.abortSignal?.aborted) {\n this.progressConnectionState(ConnectionState.CLOSED);\n return;\n }\n\n this.options.abortSignal?.addEventListener('abort', () => this.close());\n this.connect();\n }\n\n // === Connection Lifecycle ===\n\n private connect(): void {\n if (this.options.abortSignal?.aborted) return;\n\n // Prevent reconnecting after first successful connection.\n if (!this.progressConnectionState(ConnectionState.CONNECTING)) return;\n\n try {\n this.ws = this.createWebSocket();\n\n this.ws.addEventListener('open', () => this.onOpen());\n this.ws.addEventListener('message', (event) => this.onMessage(event.data));\n this.ws.addEventListener('error', (error) => this.onError(error));\n this.ws.addEventListener('close', () => this.onClose());\n } catch (error) {\n this.lastError = this.toError(error);\n this.reconnection.schedule();\n }\n }\n\n private createWebSocket(): WebSocket {\n const options: WebSocketInit = {};\n\n if (this.options.jwtToken) options.headers = { authorization: `Bearer ${this.options.jwtToken}` };\n if (this.options.dispatcher) options.dispatcher = this.options.dispatcher;\n\n const ws = new WebSocket(this.url, options);\n ws.binaryType = 'arraybuffer';\n return ws;\n }\n\n private onOpen(): void {\n this.progressConnectionState(ConnectionState.CONNECTED);\n this.processSendQueue();\n }\n\n private onMessage(data: unknown): void {\n if (!(data instanceof ArrayBuffer)) {\n this.handleError(new Error(`Unexpected WS message format: ${typeof data}`));\n return;\n }\n\n try {\n const message = this.parseServerMessage(new Uint8Array(data));\n this.deliverResponse(message);\n } catch (error) {\n this.handleError(this.toError(error));\n }\n }\n\n private onError(error: unknown): void {\n if (this.connectionState < ConnectionState.CONNECTED) {\n // Try to connect several times until we succeed or run out of attempts.\n this.lastError = this.toError(error);\n this.reconnection.schedule();\n return;\n }\n\n this.handleError(this.toError(error));\n }\n\n private onClose(): void {\n this.progressConnectionState(ConnectionState.CLOSED);\n\n // If abort signal was triggered, use that as the error source\n if (this.options.abortSignal?.aborted && !this.lastError) {\n const reason = this.options.abortSignal.reason;\n if (reason instanceof Error) {\n this.lastError = reason;\n } else if (reason !== undefined) {\n this.lastError = new Error(String(reason), { cause: reason });\n } else {\n this.lastError = this.createStreamClosedError();\n }\n }\n\n if (!this.lastError) {\n this.rejectAllSendOperations(this.createStreamClosedError());\n this.resolveAllPendingResponses(); // unblock active async iterator\n } else {\n this.rejectAllPendingOperations(this.lastError);\n }\n }\n\n // === Send Queue Management ===\n\n private enqueueSend(message: ClientMsg): Promise<void> {\n if (this.sendCompleted) {\n throw new Error('Cannot send: stream already completed');\n }\n\n if (this.options.abortSignal?.aborted) {\n throw new Error('Cannot send: stream aborted');\n }\n\n return new Promise<void>((resolve, reject) => {\n this.sendQueue.push({ message, resolve, reject });\n this.processSendQueue();\n });\n }\n\n private processSendQueue(): void {\n if (!this.canSendMessages()) return;\n\n while (this.sendQueue.length > 0) {\n const queued = this.sendQueue.shift()!;\n this.sendQueuedMessage(queued);\n }\n }\n\n private canSendMessages(): boolean {\n return this.connectionState === ConnectionState.CONNECTED;\n }\n\n private sendQueuedMessage(queued: QueuedMessage<ClientMsg>): void {\n try {\n const ws = this.ws;\n if (!ws) {\n throw new Error('WebSocket is not connected');\n }\n\n // Check if WebSocket is in a valid state for sending\n if (ws.readyState !== WebSocket.OPEN) {\n throw new Error(`WebSocket is not open (readyState: ${ws.readyState})`);\n }\n\n const binary = this.serializeClientMessage(queued.message);\n ws.send(binary);\n queued.resolve();\n } catch (error) {\n queued.reject(this.toError(error));\n }\n }\n\n private async drainSendQueue(): Promise<void> {\n const POLL_INTERVAL_MS = 5;\n\n while (this.sendQueue.length > 0) {\n await this.waitForCondition(\n () => this.sendQueue.length === 0,\n POLL_INTERVAL_MS,\n );\n }\n }\n\n private waitForCondition(\n condition: () => boolean,\n intervalMs: number,\n ): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (this.options.abortSignal?.aborted) {\n return reject(this.toError(this.options.abortSignal.reason) ?? new Error('Stream aborted'));\n }\n\n let timeoutId: ReturnType<typeof setTimeout>;\n const onAbort = () => {\n clearTimeout(timeoutId);\n reject(this.toError(this.options.abortSignal?.reason) ?? new Error('Stream aborted'));\n };\n\n this.options.abortSignal?.addEventListener('abort', onAbort, { once: true });\n\n const check = () => {\n if (condition() || this.isStreamEnded()) {\n this.options.abortSignal?.removeEventListener('abort', onAbort);\n resolve();\n } else {\n timeoutId = setTimeout(check, intervalMs);\n }\n };\n\n check();\n });\n }\n\n // === Response Delivery ===\n\n private deliverResponse(message: ServerMsg): void {\n if (this.responseResolvers.length > 0) {\n const resolver = this.responseResolvers.shift()!;\n resolver.resolve({ value: message, done: false });\n } else {\n this.responseQueue.push(message);\n }\n }\n\n private async *createResponseIterator(): AsyncIterator<ServerMsg> {\n while (true) {\n const result = await this.nextResponse();\n\n if (result.done) break;\n\n yield result.value;\n }\n }\n\n private nextResponse(): Promise<IteratorResult<ServerMsg>> {\n return new Promise<IteratorResult<ServerMsg>>((resolve, reject) => {\n // Fast path: message already available\n if (this.responseQueue.length > 0) {\n const message = this.responseQueue.shift()!;\n resolve({ value: message, done: false });\n return;\n }\n\n // Stream ended\n if (this.isStreamEnded()) {\n if (this.lastError) {\n reject(this.lastError);\n } else {\n resolve({ value: undefined as any, done: true });\n }\n return;\n }\n\n // Wait for next message\n this.responseResolvers.push({ resolve, reject });\n });\n }\n\n private resolveAllPendingResponses(): void {\n while (this.responseResolvers.length > 0) {\n const resolver = this.responseResolvers.shift()!;\n resolver.resolve({ value: undefined as any, done: true });\n }\n }\n\n // === Error Handling ===\n\n private handleError(error: Error): void {\n this.lastError = error;\n this.close();\n }\n\n private rejectAllPendingOperations(error: Error): void {\n this.rejectAllSendOperations(error);\n this.rejectAllResponseResolvers(error);\n }\n\n private rejectAllSendOperations(error: Error): void {\n while (this.sendQueue.length > 0) {\n const queued = this.sendQueue.shift()!;\n queued.reject(error);\n }\n }\n\n private rejectAllResponseResolvers(error: Error): void {\n while (this.responseResolvers.length > 0) {\n const resolver = this.responseResolvers.shift()!;\n resolver.reject(error);\n }\n }\n\n private createStreamClosedError(): Error {\n if (this.options.abortSignal?.aborted) {\n const reason = this.options.abortSignal.reason;\n if (reason instanceof Error) {\n return reason;\n }\n return new Error('Stream aborted', { cause: reason });\n }\n\n return new Error('Stream closed');\n }\n\n // === Helpers ===\n\n private isStreamEnded(): boolean {\n return this.connectionState === ConnectionState.CLOSED || this.options.abortSignal?.aborted || false;\n }\n\n private toError(error: unknown): Error {\n if (error instanceof Error) return error;\n if (error instanceof ErrorEvent) {\n const err = error.error;\n // undici WebSocket throws TypeError with empty message on socket close\n // (e.g., when connection is lost or server disconnects)\n if (err instanceof TypeError && !err.message) {\n return new DisconnectedError('WebSocket connection closed unexpectedly');\n }\n return err instanceof Error ? err : new Error('WebSocket error', { cause: error });\n }\n return new Error(String(error));\n }\n\n /**\n * Connection state progresses linearly from NEW to CLOSED and never goes back.\n * This internal contract dramatically simplifies the internal stream state management.\n *\n * If you ever feel the need to make this contract less strict, think twice.\n */\n private progressConnectionState(newState: ConnectionState): boolean {\n if (newState < this.connectionState) {\n return false;\n }\n this.connectionState = newState;\n return true;\n }\n}\n"],"names":["RetryStrategy","WebSocket","ErrorEvent","DisconnectedError"],"mappings":"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"}
|
|
@@ -1,43 +1,44 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type Dispatcher } from 'undici';
|
|
2
2
|
import type { BiDiStream } from './abstract_stream';
|
|
3
3
|
import type { RetryConfig } from '../helpers/retry_strategy';
|
|
4
|
+
export type WSStreamOptions<ClientMsg extends object, ServerMsg extends object> = {
|
|
5
|
+
abortSignal?: AbortSignal;
|
|
6
|
+
dispatcher?: Dispatcher;
|
|
7
|
+
jwtToken?: string;
|
|
8
|
+
retryConfig?: Partial<RetryConfig>;
|
|
9
|
+
onComplete?: (stream: WebSocketBiDiStream<ClientMsg, ServerMsg>) => void | Promise<void>;
|
|
10
|
+
};
|
|
4
11
|
/**
|
|
5
12
|
* WebSocket-based bidirectional stream implementation for LLTransaction.
|
|
6
13
|
* Implements BiDiStream interface which is compatible with DuplexStreamingCall.
|
|
7
14
|
*/
|
|
8
|
-
export declare class WebSocketBiDiStream implements BiDiStream<
|
|
15
|
+
export declare class WebSocketBiDiStream<ClientMsg extends object, ServerMsg extends object> implements BiDiStream<ClientMsg, ServerMsg> {
|
|
16
|
+
private readonly url;
|
|
17
|
+
private readonly serializeClientMessage;
|
|
18
|
+
private readonly parseServerMessage;
|
|
19
|
+
private readonly options;
|
|
9
20
|
private ws;
|
|
10
21
|
private connectionState;
|
|
11
|
-
private readonly url;
|
|
12
|
-
private readonly jwtToken?;
|
|
13
|
-
private readonly abortSignal;
|
|
14
22
|
private readonly reconnection;
|
|
15
23
|
private readonly sendQueue;
|
|
16
24
|
private sendCompleted;
|
|
25
|
+
private readonly onComplete;
|
|
17
26
|
private readonly responseQueue;
|
|
18
27
|
private responseResolvers;
|
|
19
|
-
private
|
|
28
|
+
private lastError?;
|
|
20
29
|
readonly requests: {
|
|
21
|
-
send: (message:
|
|
30
|
+
send: (message: ClientMsg) => Promise<void>;
|
|
22
31
|
complete: () => Promise<void>;
|
|
23
32
|
};
|
|
24
|
-
readonly responses: AsyncIterable<
|
|
25
|
-
|
|
33
|
+
readonly responses: AsyncIterable<ServerMsg>;
|
|
34
|
+
close(): void;
|
|
35
|
+
constructor(url: string, serializeClientMessage: (message: ClientMsg) => Uint8Array, parseServerMessage: (data: Uint8Array) => ServerMsg, options?: WSStreamOptions<ClientMsg, ServerMsg>);
|
|
26
36
|
private connect;
|
|
27
37
|
private createWebSocket;
|
|
28
|
-
private attachWebSocketHandlers;
|
|
29
|
-
private attachAbortSignalHandler;
|
|
30
38
|
private onOpen;
|
|
31
|
-
private onClose;
|
|
32
|
-
private onError;
|
|
33
39
|
private onMessage;
|
|
34
|
-
private
|
|
35
|
-
private
|
|
36
|
-
private closeWebSocket;
|
|
37
|
-
private finalizeStream;
|
|
38
|
-
private resolveAllPendingResponses;
|
|
39
|
-
private parseMessage;
|
|
40
|
-
private validateSendState;
|
|
40
|
+
private onError;
|
|
41
|
+
private onClose;
|
|
41
42
|
private enqueueSend;
|
|
42
43
|
private processSendQueue;
|
|
43
44
|
private canSendMessages;
|
|
@@ -47,14 +48,20 @@ export declare class WebSocketBiDiStream implements BiDiStream<ClientMessageType
|
|
|
47
48
|
private deliverResponse;
|
|
48
49
|
private createResponseIterator;
|
|
49
50
|
private nextResponse;
|
|
51
|
+
private resolveAllPendingResponses;
|
|
50
52
|
private handleError;
|
|
51
53
|
private rejectAllPendingOperations;
|
|
52
54
|
private rejectAllSendOperations;
|
|
53
55
|
private rejectAllResponseResolvers;
|
|
54
56
|
private createStreamClosedError;
|
|
55
|
-
private isConnectingOrConnected;
|
|
56
|
-
private isClosed;
|
|
57
57
|
private isStreamEnded;
|
|
58
58
|
private toError;
|
|
59
|
+
/**
|
|
60
|
+
* Connection state progresses linearly from NEW to CLOSED and never goes back.
|
|
61
|
+
* This internal contract dramatically simplifies the internal stream state management.
|
|
62
|
+
*
|
|
63
|
+
* If you ever feel the need to make this contract less strict, think twice.
|
|
64
|
+
*/
|
|
65
|
+
private progressConnectionState;
|
|
59
66
|
}
|
|
60
67
|
//# sourceMappingURL=websocket_stream.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket_stream.d.ts","sourceRoot":"","sources":["../../src/core/websocket_stream.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"websocket_stream.d.ts","sourceRoot":"","sources":["../../src/core/websocket_stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,KAAK,UAAU,EAAc,MAAM,QAAQ,CAAC;AACpF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAuB7D,MAAM,MAAM,eAAe,CAAC,SAAS,SAAS,MAAM,EAAE,SAAS,SAAS,MAAM,IAAI;IAChF,WAAW,CAAC,EAAE,WAAW,CAAC;IAE1B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAEnC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1F,CAAC;AAEF;;;GAGG;AACH,qBAAa,mBAAmB,CAAC,SAAS,SAAS,MAAM,EAAE,SAAS,SAAS,MAAM,CAAE,YAAW,UAAU,CAAC,SAAS,EAAE,SAAS,CAAC;IA2D5H,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,sBAAsB;IACvC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO;IA5D1B,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,eAAe,CAAwC;IAC/D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAG7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0C;IACpE,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA8E;IAGzG,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA2B;IACzD,OAAO,CAAC,iBAAiB,CAAqC;IAG9D,OAAO,CAAC,SAAS,CAAC,CAAQ;IAI1B,SAAgB,QAAQ;wBACA,SAAS,KAAG,OAAO,CAAC,IAAI,CAAC;wBAI3B,OAAO,CAAC,IAAI,CAAC;MAajC;IAEF,SAAgB,SAAS,EAAE,aAAa,CAAC,SAAS,CAAC,CAEjD;IAEK,KAAK,IAAI,IAAI;gBAeD,GAAG,EAAE,MAAM,EACX,sBAAsB,EAAE,CAAC,OAAO,EAAE,SAAS,KAAK,UAAU,EAC1D,kBAAkB,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,SAAS,EACnD,OAAO,GAAE,eAAe,CAAC,SAAS,EAAE,SAAS,CAAM;IAqBtE,OAAO,CAAC,OAAO;IAmBf,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,MAAM;IAKd,OAAO,CAAC,SAAS;IAcjB,OAAO,CAAC,OAAO;IAWf,OAAO,CAAC,OAAO;IAyBf,OAAO,CAAC,WAAW;IAenB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,iBAAiB;YAoBX,cAAc;IAW5B,OAAO,CAAC,gBAAgB;IAgCxB,OAAO,CAAC,eAAe;YASR,sBAAsB;IAUrC,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,0BAA0B;IASlC,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,0BAA0B;IAKlC,OAAO,CAAC,uBAAuB;IAO/B,OAAO,CAAC,0BAA0B;IAOlC,OAAO,CAAC,uBAAuB;IAc/B,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,OAAO;IAcf;;;;;OAKG;IACH,OAAO,CAAC,uBAAuB;CAOhC"}
|