@replit/river 0.24.3 → 0.25.1
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/{chunk-XKHLA5MP.js → chunk-5CNNIOAO.js} +4 -4
- package/dist/{chunk-FKBXIWWN.js → chunk-D5O3ERJU.js} +3 -3
- package/dist/{chunk-EHXKU4TW.js → chunk-MBMEJIPU.js} +2 -2
- package/dist/{chunk-W3CY6PNC.js → chunk-PCBPPTXH.js} +28 -23
- package/dist/chunk-PCBPPTXH.js.map +1 -0
- package/dist/{chunk-LSHUPI6U.js → chunk-SGSRNAWJ.js} +41 -18
- package/dist/{chunk-LSHUPI6U.js.map → chunk-SGSRNAWJ.js.map} +1 -1
- package/dist/{chunk-DZNP3EI5.js → chunk-SZ5NBBX7.js} +2 -2
- package/dist/{chunk-DZNP3EI5.js.map → chunk-SZ5NBBX7.js.map} +1 -1
- package/dist/{chunk-KVLCQ24J.js → chunk-YM5Y4NAT.js} +34 -13
- package/dist/chunk-YM5Y4NAT.js.map +1 -0
- package/dist/{client-2ba72e89.d.ts → client-1321630c.d.ts} +1 -1
- package/dist/{connection-55cba970.d.ts → connection-bd907ca6.d.ts} +1 -1
- package/dist/{handshake-0b88e8fc.d.ts → handshake-3772d7ca.d.ts} +4 -2
- package/dist/router/index.cjs +40 -17
- package/dist/router/index.cjs.map +1 -1
- package/dist/router/index.d.cts +7 -7
- package/dist/router/index.d.ts +7 -7
- package/dist/router/index.js +2 -2
- package/dist/{server-732e7014.d.ts → server-f0fd2b98.d.ts} +1 -1
- package/dist/{services-adfd0bc3.d.ts → services-8d14ae16.d.ts} +2 -2
- package/dist/transport/impls/ws/client.cjs +33 -12
- package/dist/transport/impls/ws/client.cjs.map +1 -1
- package/dist/transport/impls/ws/client.d.cts +3 -3
- package/dist/transport/impls/ws/client.d.ts +3 -3
- package/dist/transport/impls/ws/client.js +7 -7
- package/dist/transport/impls/ws/server.cjs +57 -31
- package/dist/transport/impls/ws/server.cjs.map +1 -1
- package/dist/transport/impls/ws/server.d.cts +3 -3
- package/dist/transport/impls/ws/server.d.ts +3 -3
- package/dist/transport/impls/ws/server.js +5 -5
- package/dist/transport/index.cjs +57 -31
- package/dist/transport/index.cjs.map +1 -1
- package/dist/transport/index.d.cts +3 -3
- package/dist/transport/index.d.ts +3 -3
- package/dist/transport/index.js +7 -7
- package/dist/util/testHelpers.cjs +33 -27
- package/dist/util/testHelpers.cjs.map +1 -1
- package/dist/util/testHelpers.d.cts +4 -7
- package/dist/util/testHelpers.d.ts +4 -7
- package/dist/util/testHelpers.js +3 -14
- package/dist/util/testHelpers.js.map +1 -1
- package/package.json +13 -14
- package/dist/chunk-KVLCQ24J.js.map +0 -1
- package/dist/chunk-TDFWZIXR.js +0 -106
- package/dist/chunk-TDFWZIXR.js.map +0 -1
- package/dist/chunk-W3CY6PNC.js.map +0 -1
- package/dist/connection-c6db05d9.d.ts +0 -31
- package/dist/transport/impls/uds/client.cjs +0 -1684
- package/dist/transport/impls/uds/client.cjs.map +0 -1
- package/dist/transport/impls/uds/client.d.cts +0 -18
- package/dist/transport/impls/uds/client.d.ts +0 -18
- package/dist/transport/impls/uds/client.js +0 -38
- package/dist/transport/impls/uds/client.js.map +0 -1
- package/dist/transport/impls/uds/server.cjs +0 -1650
- package/dist/transport/impls/uds/server.cjs.map +0 -1
- package/dist/transport/impls/uds/server.d.cts +0 -19
- package/dist/transport/impls/uds/server.d.ts +0 -19
- package/dist/transport/impls/uds/server.js +0 -33
- package/dist/transport/impls/uds/server.js.map +0 -1
- /package/dist/{chunk-XKHLA5MP.js.map → chunk-5CNNIOAO.js.map} +0 -0
- /package/dist/{chunk-FKBXIWWN.js.map → chunk-D5O3ERJU.js.map} +0 -0
- /package/dist/{chunk-EHXKU4TW.js.map → chunk-MBMEJIPU.js.map} +0 -0
|
@@ -1,1650 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// transport/impls/uds/server.ts
|
|
21
|
-
var server_exports = {};
|
|
22
|
-
__export(server_exports, {
|
|
23
|
-
UnixDomainSocketServerTransport: () => UnixDomainSocketServerTransport
|
|
24
|
-
});
|
|
25
|
-
module.exports = __toCommonJS(server_exports);
|
|
26
|
-
|
|
27
|
-
// transport/transforms/messageFraming.ts
|
|
28
|
-
var import_node_stream = require("stream");
|
|
29
|
-
var Uint32LengthPrefixFraming = class extends import_node_stream.Transform {
|
|
30
|
-
receivedBuffer;
|
|
31
|
-
maxBufferSizeBytes;
|
|
32
|
-
constructor({ maxBufferSizeBytes, ...options }) {
|
|
33
|
-
super(options);
|
|
34
|
-
this.maxBufferSizeBytes = maxBufferSizeBytes;
|
|
35
|
-
this.receivedBuffer = Buffer.alloc(0);
|
|
36
|
-
}
|
|
37
|
-
_transform(chunk, _encoding, cb) {
|
|
38
|
-
if (this.receivedBuffer.byteLength + chunk.byteLength > this.maxBufferSizeBytes) {
|
|
39
|
-
const err = new Error(
|
|
40
|
-
`buffer overflow: ${this.receivedBuffer.byteLength}B > ${this.maxBufferSizeBytes}B`
|
|
41
|
-
);
|
|
42
|
-
this.emit("error", err);
|
|
43
|
-
cb(err);
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
this.receivedBuffer = Buffer.concat([this.receivedBuffer, chunk]);
|
|
47
|
-
while (this.receivedBuffer.length > 4) {
|
|
48
|
-
const claimedMessageLength = this.receivedBuffer.readUInt32BE(0) + 4;
|
|
49
|
-
if (this.receivedBuffer.length >= claimedMessageLength) {
|
|
50
|
-
const message = this.receivedBuffer.subarray(4, claimedMessageLength);
|
|
51
|
-
this.push(message);
|
|
52
|
-
this.receivedBuffer = this.receivedBuffer.subarray(claimedMessageLength);
|
|
53
|
-
} else {
|
|
54
|
-
break;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
cb();
|
|
58
|
-
}
|
|
59
|
-
_flush(cb) {
|
|
60
|
-
this.receivedBuffer = Buffer.alloc(0);
|
|
61
|
-
cb();
|
|
62
|
-
}
|
|
63
|
-
_destroy(error, callback) {
|
|
64
|
-
this.receivedBuffer = Buffer.alloc(0);
|
|
65
|
-
super._destroy(error, callback);
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
function createLengthEncodedStream(options) {
|
|
69
|
-
return new Uint32LengthPrefixFraming({
|
|
70
|
-
maxBufferSizeBytes: options?.maxBufferSizeBytes ?? 16 * 1024 * 1024
|
|
71
|
-
// 16MB
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
var MessageFramer = {
|
|
75
|
-
createFramedStream: createLengthEncodedStream,
|
|
76
|
-
write: (buf) => {
|
|
77
|
-
const lengthPrefix = Buffer.alloc(4);
|
|
78
|
-
lengthPrefix.writeUInt32BE(buf.length, 0);
|
|
79
|
-
return Buffer.concat([lengthPrefix, buf]);
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
// transport/id.ts
|
|
84
|
-
var import_nanoid = require("nanoid");
|
|
85
|
-
var alphabet = (0, import_nanoid.customAlphabet)(
|
|
86
|
-
"1234567890abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ"
|
|
87
|
-
);
|
|
88
|
-
var generateId = () => alphabet(12);
|
|
89
|
-
|
|
90
|
-
// transport/connection.ts
|
|
91
|
-
var Connection = class {
|
|
92
|
-
id;
|
|
93
|
-
telemetry;
|
|
94
|
-
constructor() {
|
|
95
|
-
this.id = `conn-${generateId()}`;
|
|
96
|
-
}
|
|
97
|
-
get loggingMetadata() {
|
|
98
|
-
const metadata = { connId: this.id };
|
|
99
|
-
const spanContext = this.telemetry?.span.spanContext();
|
|
100
|
-
if (this.telemetry?.span.isRecording() && spanContext) {
|
|
101
|
-
metadata.telemetry = {
|
|
102
|
-
traceId: spanContext.traceId,
|
|
103
|
-
spanId: spanContext.spanId
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
return metadata;
|
|
107
|
-
}
|
|
108
|
-
// can't use event emitter because we need this to work in both node + browser
|
|
109
|
-
_dataListeners = /* @__PURE__ */ new Set();
|
|
110
|
-
_closeListeners = /* @__PURE__ */ new Set();
|
|
111
|
-
_errorListeners = /* @__PURE__ */ new Set();
|
|
112
|
-
get dataListeners() {
|
|
113
|
-
return [...this._dataListeners];
|
|
114
|
-
}
|
|
115
|
-
get closeListeners() {
|
|
116
|
-
return [...this._closeListeners];
|
|
117
|
-
}
|
|
118
|
-
get errorListeners() {
|
|
119
|
-
return [...this._errorListeners];
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Handle adding a callback for when a message is received.
|
|
123
|
-
* @param msg The message that was received.
|
|
124
|
-
*/
|
|
125
|
-
addDataListener(cb) {
|
|
126
|
-
this._dataListeners.add(cb);
|
|
127
|
-
}
|
|
128
|
-
removeDataListener(cb) {
|
|
129
|
-
this._dataListeners.delete(cb);
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Handle adding a callback for when the connection is closed.
|
|
133
|
-
* This should also be called if an error happens and after notifying all the error listeners.
|
|
134
|
-
* @param cb The callback to call when the connection is closed.
|
|
135
|
-
*/
|
|
136
|
-
addCloseListener(cb) {
|
|
137
|
-
this._closeListeners.add(cb);
|
|
138
|
-
}
|
|
139
|
-
removeCloseListener(cb) {
|
|
140
|
-
this._closeListeners.delete(cb);
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Handle adding a callback for when an error is received.
|
|
144
|
-
* This should only be used for this.logging errors, all cleanup
|
|
145
|
-
* should be delegated to addCloseListener.
|
|
146
|
-
*
|
|
147
|
-
* The implementer should take care such that the implemented
|
|
148
|
-
* connection will call both the close and error callbacks
|
|
149
|
-
* on an error.
|
|
150
|
-
*
|
|
151
|
-
* @param cb The callback to call when an error is received.
|
|
152
|
-
*/
|
|
153
|
-
addErrorListener(cb) {
|
|
154
|
-
this._errorListeners.add(cb);
|
|
155
|
-
}
|
|
156
|
-
removeErrorListener(cb) {
|
|
157
|
-
this._errorListeners.delete(cb);
|
|
158
|
-
}
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
// transport/impls/uds/connection.ts
|
|
162
|
-
var UdsConnection = class extends Connection {
|
|
163
|
-
sock;
|
|
164
|
-
input;
|
|
165
|
-
framer;
|
|
166
|
-
constructor(sock) {
|
|
167
|
-
super();
|
|
168
|
-
this.framer = MessageFramer.createFramedStream();
|
|
169
|
-
this.sock = sock;
|
|
170
|
-
this.input = sock.pipe(this.framer);
|
|
171
|
-
this.sock.on("close", () => {
|
|
172
|
-
for (const cb of this.closeListeners) {
|
|
173
|
-
cb();
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
this.sock.on("error", (err) => {
|
|
177
|
-
if (err instanceof Error && "code" in err && err.code === "EPIPE") {
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
for (const cb of this.errorListeners) {
|
|
181
|
-
cb(err);
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
this.input.on("data", (msg) => {
|
|
185
|
-
for (const cb of this.dataListeners) {
|
|
186
|
-
cb(msg);
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
send(payload) {
|
|
191
|
-
if (this.framer.destroyed || !this.sock.writable || this.sock.closed) {
|
|
192
|
-
return false;
|
|
193
|
-
}
|
|
194
|
-
this.sock.write(MessageFramer.write(payload));
|
|
195
|
-
return true;
|
|
196
|
-
}
|
|
197
|
-
close() {
|
|
198
|
-
this.sock.destroy();
|
|
199
|
-
this.framer.destroy();
|
|
200
|
-
}
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
// transport/server.ts
|
|
204
|
-
var import_api3 = require("@opentelemetry/api");
|
|
205
|
-
|
|
206
|
-
// transport/message.ts
|
|
207
|
-
var import_typebox = require("@sinclair/typebox");
|
|
208
|
-
var TransportMessageSchema = (t) => import_typebox.Type.Object({
|
|
209
|
-
id: import_typebox.Type.String(),
|
|
210
|
-
from: import_typebox.Type.String(),
|
|
211
|
-
to: import_typebox.Type.String(),
|
|
212
|
-
seq: import_typebox.Type.Integer(),
|
|
213
|
-
ack: import_typebox.Type.Integer(),
|
|
214
|
-
serviceName: import_typebox.Type.Optional(import_typebox.Type.String()),
|
|
215
|
-
procedureName: import_typebox.Type.Optional(import_typebox.Type.String()),
|
|
216
|
-
streamId: import_typebox.Type.String(),
|
|
217
|
-
controlFlags: import_typebox.Type.Integer(),
|
|
218
|
-
tracing: import_typebox.Type.Optional(
|
|
219
|
-
import_typebox.Type.Object({
|
|
220
|
-
traceparent: import_typebox.Type.String(),
|
|
221
|
-
tracestate: import_typebox.Type.String()
|
|
222
|
-
})
|
|
223
|
-
),
|
|
224
|
-
payload: t
|
|
225
|
-
});
|
|
226
|
-
var ControlMessageAckSchema = import_typebox.Type.Object({
|
|
227
|
-
type: import_typebox.Type.Literal("ACK")
|
|
228
|
-
});
|
|
229
|
-
var ControlMessageCloseSchema = import_typebox.Type.Object({
|
|
230
|
-
type: import_typebox.Type.Literal("CLOSE")
|
|
231
|
-
});
|
|
232
|
-
var PROTOCOL_VERSION = "v1.1";
|
|
233
|
-
var ControlMessageHandshakeRequestSchema = import_typebox.Type.Object({
|
|
234
|
-
type: import_typebox.Type.Literal("HANDSHAKE_REQ"),
|
|
235
|
-
protocolVersion: import_typebox.Type.String(),
|
|
236
|
-
sessionId: import_typebox.Type.String(),
|
|
237
|
-
/**
|
|
238
|
-
* Specifies what the server's expected session state (from the pov of the client). This can be
|
|
239
|
-
* used by the server to know whether this is a new or a reestablished connection, and whether it
|
|
240
|
-
* is compatible with what it already has.
|
|
241
|
-
*/
|
|
242
|
-
expectedSessionState: import_typebox.Type.Object({
|
|
243
|
-
// what the client expects the server to send next
|
|
244
|
-
nextExpectedSeq: import_typebox.Type.Integer(),
|
|
245
|
-
// TODO: remove optional once we know all servers
|
|
246
|
-
// are nextSentSeq here
|
|
247
|
-
// what the server expects the client to send next
|
|
248
|
-
nextSentSeq: import_typebox.Type.Optional(import_typebox.Type.Integer())
|
|
249
|
-
}),
|
|
250
|
-
metadata: import_typebox.Type.Optional(import_typebox.Type.Unknown())
|
|
251
|
-
});
|
|
252
|
-
var HandshakeErrorRetriableResponseCodes = import_typebox.Type.Union([
|
|
253
|
-
import_typebox.Type.Literal("SESSION_STATE_MISMATCH")
|
|
254
|
-
]);
|
|
255
|
-
var HandshakeErrorFatalResponseCodes = import_typebox.Type.Union([
|
|
256
|
-
import_typebox.Type.Literal("MALFORMED_HANDSHAKE_META"),
|
|
257
|
-
import_typebox.Type.Literal("MALFORMED_HANDSHAKE"),
|
|
258
|
-
import_typebox.Type.Literal("PROTOCOL_VERSION_MISMATCH"),
|
|
259
|
-
import_typebox.Type.Literal("REJECTED_BY_CUSTOM_HANDLER")
|
|
260
|
-
]);
|
|
261
|
-
var HandshakeErrorResponseCodes = import_typebox.Type.Union([
|
|
262
|
-
HandshakeErrorRetriableResponseCodes,
|
|
263
|
-
HandshakeErrorFatalResponseCodes
|
|
264
|
-
]);
|
|
265
|
-
var ControlMessageHandshakeResponseSchema = import_typebox.Type.Object({
|
|
266
|
-
type: import_typebox.Type.Literal("HANDSHAKE_RESP"),
|
|
267
|
-
status: import_typebox.Type.Union([
|
|
268
|
-
import_typebox.Type.Object({
|
|
269
|
-
ok: import_typebox.Type.Literal(true),
|
|
270
|
-
sessionId: import_typebox.Type.String()
|
|
271
|
-
}),
|
|
272
|
-
import_typebox.Type.Object({
|
|
273
|
-
ok: import_typebox.Type.Literal(false),
|
|
274
|
-
reason: import_typebox.Type.String(),
|
|
275
|
-
// TODO: remove optional once we know all servers
|
|
276
|
-
// are sending code here
|
|
277
|
-
code: import_typebox.Type.Optional(HandshakeErrorResponseCodes)
|
|
278
|
-
})
|
|
279
|
-
])
|
|
280
|
-
});
|
|
281
|
-
var ControlMessagePayloadSchema = import_typebox.Type.Union([
|
|
282
|
-
ControlMessageCloseSchema,
|
|
283
|
-
ControlMessageAckSchema,
|
|
284
|
-
ControlMessageHandshakeRequestSchema,
|
|
285
|
-
ControlMessageHandshakeResponseSchema
|
|
286
|
-
]);
|
|
287
|
-
var OpaqueTransportMessageSchema = TransportMessageSchema(
|
|
288
|
-
import_typebox.Type.Unknown()
|
|
289
|
-
);
|
|
290
|
-
function handshakeResponseMessage({
|
|
291
|
-
from,
|
|
292
|
-
to,
|
|
293
|
-
status
|
|
294
|
-
}) {
|
|
295
|
-
return {
|
|
296
|
-
id: generateId(),
|
|
297
|
-
from,
|
|
298
|
-
to,
|
|
299
|
-
seq: 0,
|
|
300
|
-
ack: 0,
|
|
301
|
-
streamId: generateId(),
|
|
302
|
-
controlFlags: 0,
|
|
303
|
-
payload: {
|
|
304
|
-
type: "HANDSHAKE_RESP",
|
|
305
|
-
status
|
|
306
|
-
}
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
function isAck(controlFlag) {
|
|
310
|
-
return (controlFlag & 1 /* AckBit */) === 1 /* AckBit */;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// codec/json.ts
|
|
314
|
-
var encoder = new TextEncoder();
|
|
315
|
-
var decoder = new TextDecoder();
|
|
316
|
-
function uint8ArrayToBase64(uint8Array) {
|
|
317
|
-
let binary = "";
|
|
318
|
-
uint8Array.forEach((byte) => {
|
|
319
|
-
binary += String.fromCharCode(byte);
|
|
320
|
-
});
|
|
321
|
-
return btoa(binary);
|
|
322
|
-
}
|
|
323
|
-
function base64ToUint8Array(base64) {
|
|
324
|
-
const binaryString = atob(base64);
|
|
325
|
-
const uint8Array = new Uint8Array(binaryString.length);
|
|
326
|
-
for (let i = 0; i < binaryString.length; i++) {
|
|
327
|
-
uint8Array[i] = binaryString.charCodeAt(i);
|
|
328
|
-
}
|
|
329
|
-
return uint8Array;
|
|
330
|
-
}
|
|
331
|
-
var NaiveJsonCodec = {
|
|
332
|
-
toBuffer: (obj) => {
|
|
333
|
-
return encoder.encode(
|
|
334
|
-
JSON.stringify(obj, function replacer(key) {
|
|
335
|
-
const val = this[key];
|
|
336
|
-
if (val instanceof Uint8Array) {
|
|
337
|
-
return { $t: uint8ArrayToBase64(val) };
|
|
338
|
-
} else {
|
|
339
|
-
return val;
|
|
340
|
-
}
|
|
341
|
-
})
|
|
342
|
-
);
|
|
343
|
-
},
|
|
344
|
-
fromBuffer: (buff) => {
|
|
345
|
-
try {
|
|
346
|
-
const parsed = JSON.parse(
|
|
347
|
-
decoder.decode(buff),
|
|
348
|
-
function reviver(_key, val) {
|
|
349
|
-
if (val?.$t) {
|
|
350
|
-
return base64ToUint8Array(val.$t);
|
|
351
|
-
} else {
|
|
352
|
-
return val;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
);
|
|
356
|
-
if (typeof parsed === "object")
|
|
357
|
-
return parsed;
|
|
358
|
-
return null;
|
|
359
|
-
} catch {
|
|
360
|
-
return null;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
};
|
|
364
|
-
|
|
365
|
-
// transport/options.ts
|
|
366
|
-
var defaultTransportOptions = {
|
|
367
|
-
heartbeatIntervalMs: 1e3,
|
|
368
|
-
heartbeatsUntilDead: 2,
|
|
369
|
-
sessionDisconnectGraceMs: 5e3,
|
|
370
|
-
connectionTimeoutMs: 2e3,
|
|
371
|
-
handshakeTimeoutMs: 1e3,
|
|
372
|
-
codec: NaiveJsonCodec
|
|
373
|
-
};
|
|
374
|
-
var defaultConnectionRetryOptions = {
|
|
375
|
-
baseIntervalMs: 250,
|
|
376
|
-
maxJitterMs: 200,
|
|
377
|
-
maxBackoffMs: 32e3,
|
|
378
|
-
attemptBudgetCapacity: 5,
|
|
379
|
-
budgetRestoreIntervalMs: 200
|
|
380
|
-
};
|
|
381
|
-
var defaultClientTransportOptions = {
|
|
382
|
-
...defaultTransportOptions,
|
|
383
|
-
...defaultConnectionRetryOptions
|
|
384
|
-
};
|
|
385
|
-
var defaultServerTransportOptions = {
|
|
386
|
-
...defaultTransportOptions
|
|
387
|
-
};
|
|
388
|
-
|
|
389
|
-
// logging/log.ts
|
|
390
|
-
var LoggingLevels = {
|
|
391
|
-
debug: -1,
|
|
392
|
-
info: 0,
|
|
393
|
-
warn: 1,
|
|
394
|
-
error: 2
|
|
395
|
-
};
|
|
396
|
-
var cleanedLogFn = (log) => {
|
|
397
|
-
return (msg, metadata) => {
|
|
398
|
-
if (!metadata?.transportMessage) {
|
|
399
|
-
log(msg, metadata);
|
|
400
|
-
return;
|
|
401
|
-
}
|
|
402
|
-
const { payload, ...rest } = metadata.transportMessage;
|
|
403
|
-
metadata.transportMessage = rest;
|
|
404
|
-
log(msg, metadata);
|
|
405
|
-
};
|
|
406
|
-
};
|
|
407
|
-
var BaseLogger = class {
|
|
408
|
-
minLevel;
|
|
409
|
-
output;
|
|
410
|
-
constructor(output, minLevel = "info") {
|
|
411
|
-
this.minLevel = minLevel;
|
|
412
|
-
this.output = output;
|
|
413
|
-
}
|
|
414
|
-
debug(msg, metadata) {
|
|
415
|
-
if (LoggingLevels[this.minLevel] <= LoggingLevels.debug) {
|
|
416
|
-
this.output(msg, metadata ?? {}, "debug");
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
info(msg, metadata) {
|
|
420
|
-
if (LoggingLevels[this.minLevel] <= LoggingLevels.info) {
|
|
421
|
-
this.output(msg, metadata ?? {}, "info");
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
warn(msg, metadata) {
|
|
425
|
-
if (LoggingLevels[this.minLevel] <= LoggingLevels.warn) {
|
|
426
|
-
this.output(msg, metadata ?? {}, "warn");
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
error(msg, metadata) {
|
|
430
|
-
if (LoggingLevels[this.minLevel] <= LoggingLevels.error) {
|
|
431
|
-
this.output(msg, metadata ?? {}, "error");
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
};
|
|
435
|
-
var createLogProxy = (log) => ({
|
|
436
|
-
debug: cleanedLogFn(log.debug.bind(log)),
|
|
437
|
-
info: cleanedLogFn(log.info.bind(log)),
|
|
438
|
-
warn: cleanedLogFn(log.warn.bind(log)),
|
|
439
|
-
error: cleanedLogFn(log.error.bind(log))
|
|
440
|
-
});
|
|
441
|
-
|
|
442
|
-
// transport/events.ts
|
|
443
|
-
var ProtocolError = {
|
|
444
|
-
RetriesExceeded: "conn_retry_exceeded",
|
|
445
|
-
HandshakeFailed: "handshake_failed",
|
|
446
|
-
MessageOrderingViolated: "message_ordering_violated"
|
|
447
|
-
};
|
|
448
|
-
var EventDispatcher = class {
|
|
449
|
-
eventListeners = {};
|
|
450
|
-
removeAllListeners() {
|
|
451
|
-
this.eventListeners = {};
|
|
452
|
-
}
|
|
453
|
-
numberOfListeners(eventType) {
|
|
454
|
-
return this.eventListeners[eventType]?.size ?? 0;
|
|
455
|
-
}
|
|
456
|
-
addEventListener(eventType, handler) {
|
|
457
|
-
if (!this.eventListeners[eventType]) {
|
|
458
|
-
this.eventListeners[eventType] = /* @__PURE__ */ new Set();
|
|
459
|
-
}
|
|
460
|
-
this.eventListeners[eventType]?.add(handler);
|
|
461
|
-
}
|
|
462
|
-
removeEventListener(eventType, handler) {
|
|
463
|
-
const handlers = this.eventListeners[eventType];
|
|
464
|
-
if (handlers) {
|
|
465
|
-
this.eventListeners[eventType]?.delete(handler);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
dispatchEvent(eventType, event) {
|
|
469
|
-
const handlers = this.eventListeners[eventType];
|
|
470
|
-
if (handlers) {
|
|
471
|
-
const copy = [...handlers];
|
|
472
|
-
for (const handler of copy) {
|
|
473
|
-
handler(event);
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
};
|
|
478
|
-
|
|
479
|
-
// transport/sessionStateMachine/common.ts
|
|
480
|
-
var import_value = require("@sinclair/typebox/value");
|
|
481
|
-
var ERR_CONSUMED = `session state has been consumed and is no longer valid`;
|
|
482
|
-
var StateMachineState = class {
|
|
483
|
-
/*
|
|
484
|
-
* Whether this state has been consumed
|
|
485
|
-
* and we've moved on to another state
|
|
486
|
-
*/
|
|
487
|
-
_isConsumed;
|
|
488
|
-
close() {
|
|
489
|
-
this._handleClose();
|
|
490
|
-
}
|
|
491
|
-
constructor() {
|
|
492
|
-
this._isConsumed = false;
|
|
493
|
-
return new Proxy(this, {
|
|
494
|
-
get(target, prop) {
|
|
495
|
-
if (prop === "_isConsumed" || prop === "id" || prop === "state") {
|
|
496
|
-
return Reflect.get(target, prop);
|
|
497
|
-
}
|
|
498
|
-
if (prop === "_handleStateExit") {
|
|
499
|
-
return () => {
|
|
500
|
-
target._isConsumed = true;
|
|
501
|
-
target._handleStateExit();
|
|
502
|
-
};
|
|
503
|
-
}
|
|
504
|
-
if (prop === "_handleClose") {
|
|
505
|
-
return () => {
|
|
506
|
-
target._handleStateExit();
|
|
507
|
-
target._handleClose();
|
|
508
|
-
};
|
|
509
|
-
}
|
|
510
|
-
if (target._isConsumed) {
|
|
511
|
-
throw new Error(
|
|
512
|
-
`${ERR_CONSUMED}: getting ${prop.toString()} on consumed state`
|
|
513
|
-
);
|
|
514
|
-
}
|
|
515
|
-
return Reflect.get(target, prop);
|
|
516
|
-
},
|
|
517
|
-
set(target, prop, value) {
|
|
518
|
-
if (target._isConsumed) {
|
|
519
|
-
throw new Error(
|
|
520
|
-
`${ERR_CONSUMED}: setting ${prop.toString()} on consumed state`
|
|
521
|
-
);
|
|
522
|
-
}
|
|
523
|
-
return Reflect.set(target, prop, value);
|
|
524
|
-
}
|
|
525
|
-
});
|
|
526
|
-
}
|
|
527
|
-
};
|
|
528
|
-
var CommonSession = class extends StateMachineState {
|
|
529
|
-
from;
|
|
530
|
-
options;
|
|
531
|
-
log;
|
|
532
|
-
constructor(from, options, log) {
|
|
533
|
-
super();
|
|
534
|
-
this.from = from;
|
|
535
|
-
this.options = options;
|
|
536
|
-
this.log = log;
|
|
537
|
-
}
|
|
538
|
-
parseMsg(msg) {
|
|
539
|
-
const parsedMsg = this.options.codec.fromBuffer(msg);
|
|
540
|
-
if (parsedMsg === null) {
|
|
541
|
-
const decodedBuffer = new TextDecoder().decode(Buffer.from(msg));
|
|
542
|
-
this.log?.error(
|
|
543
|
-
`received malformed msg: ${decodedBuffer}`,
|
|
544
|
-
this.loggingMetadata
|
|
545
|
-
);
|
|
546
|
-
return null;
|
|
547
|
-
}
|
|
548
|
-
if (!import_value.Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
|
|
549
|
-
this.log?.error(`received invalid msg: ${JSON.stringify(parsedMsg)}`, {
|
|
550
|
-
...this.loggingMetadata,
|
|
551
|
-
validationErrors: [
|
|
552
|
-
...import_value.Value.Errors(OpaqueTransportMessageSchema, parsedMsg)
|
|
553
|
-
]
|
|
554
|
-
});
|
|
555
|
-
return null;
|
|
556
|
-
}
|
|
557
|
-
return parsedMsg;
|
|
558
|
-
}
|
|
559
|
-
};
|
|
560
|
-
var IdentifiedSession = class extends CommonSession {
|
|
561
|
-
id;
|
|
562
|
-
telemetry;
|
|
563
|
-
to;
|
|
564
|
-
/**
|
|
565
|
-
* Index of the message we will send next (excluding handshake)
|
|
566
|
-
*/
|
|
567
|
-
seq;
|
|
568
|
-
/**
|
|
569
|
-
* Number of unique messages we've received this session (excluding handshake)
|
|
570
|
-
*/
|
|
571
|
-
ack;
|
|
572
|
-
sendBuffer;
|
|
573
|
-
constructor(id, from, to, seq, ack, sendBuffer, telemetry, options, log) {
|
|
574
|
-
super(from, options, log);
|
|
575
|
-
this.id = id;
|
|
576
|
-
this.to = to;
|
|
577
|
-
this.seq = seq;
|
|
578
|
-
this.ack = ack;
|
|
579
|
-
this.sendBuffer = sendBuffer;
|
|
580
|
-
this.telemetry = telemetry;
|
|
581
|
-
this.log = log;
|
|
582
|
-
}
|
|
583
|
-
get loggingMetadata() {
|
|
584
|
-
const spanContext = this.telemetry.span.spanContext();
|
|
585
|
-
return {
|
|
586
|
-
clientId: this.from,
|
|
587
|
-
connectedTo: this.to,
|
|
588
|
-
sessionId: this.id,
|
|
589
|
-
telemetry: {
|
|
590
|
-
traceId: spanContext.traceId,
|
|
591
|
-
spanId: spanContext.spanId
|
|
592
|
-
}
|
|
593
|
-
};
|
|
594
|
-
}
|
|
595
|
-
constructMsg(partialMsg) {
|
|
596
|
-
const msg = {
|
|
597
|
-
...partialMsg,
|
|
598
|
-
id: generateId(),
|
|
599
|
-
to: this.to,
|
|
600
|
-
from: this.from,
|
|
601
|
-
seq: this.seq,
|
|
602
|
-
ack: this.ack
|
|
603
|
-
};
|
|
604
|
-
this.seq++;
|
|
605
|
-
return msg;
|
|
606
|
-
}
|
|
607
|
-
nextSeq() {
|
|
608
|
-
return this.sendBuffer.length > 0 ? this.sendBuffer[0].seq : this.seq;
|
|
609
|
-
}
|
|
610
|
-
send(msg) {
|
|
611
|
-
const constructedMsg = this.constructMsg(msg);
|
|
612
|
-
this.sendBuffer.push(constructedMsg);
|
|
613
|
-
return constructedMsg.id;
|
|
614
|
-
}
|
|
615
|
-
_handleStateExit() {
|
|
616
|
-
}
|
|
617
|
-
_handleClose() {
|
|
618
|
-
this.sendBuffer.length = 0;
|
|
619
|
-
this.telemetry.span.end();
|
|
620
|
-
}
|
|
621
|
-
};
|
|
622
|
-
|
|
623
|
-
// transport/sessionStateMachine/SessionConnecting.ts
|
|
624
|
-
var SessionConnecting = class extends IdentifiedSession {
|
|
625
|
-
state = "Connecting" /* Connecting */;
|
|
626
|
-
connPromise;
|
|
627
|
-
listeners;
|
|
628
|
-
connectionTimeout;
|
|
629
|
-
constructor(connPromise, listeners, ...args) {
|
|
630
|
-
super(...args);
|
|
631
|
-
this.connPromise = connPromise;
|
|
632
|
-
this.listeners = listeners;
|
|
633
|
-
this.connectionTimeout = setTimeout(() => {
|
|
634
|
-
listeners.onConnectionTimeout();
|
|
635
|
-
}, this.options.connectionTimeoutMs);
|
|
636
|
-
connPromise.then(
|
|
637
|
-
(conn) => {
|
|
638
|
-
if (this._isConsumed)
|
|
639
|
-
return;
|
|
640
|
-
listeners.onConnectionEstablished(conn);
|
|
641
|
-
},
|
|
642
|
-
(err) => {
|
|
643
|
-
if (this._isConsumed)
|
|
644
|
-
return;
|
|
645
|
-
listeners.onConnectionFailed(err);
|
|
646
|
-
}
|
|
647
|
-
);
|
|
648
|
-
}
|
|
649
|
-
// close a pending connection if it resolves, ignore errors if the promise
|
|
650
|
-
// ends up rejected anyways
|
|
651
|
-
bestEffortClose() {
|
|
652
|
-
void this.connPromise.then((conn) => conn.close()).catch(() => {
|
|
653
|
-
});
|
|
654
|
-
}
|
|
655
|
-
_handleStateExit() {
|
|
656
|
-
super._handleStateExit();
|
|
657
|
-
clearTimeout(this.connectionTimeout);
|
|
658
|
-
this.connectionTimeout = void 0;
|
|
659
|
-
}
|
|
660
|
-
_handleClose() {
|
|
661
|
-
this.bestEffortClose();
|
|
662
|
-
super._handleClose();
|
|
663
|
-
}
|
|
664
|
-
};
|
|
665
|
-
|
|
666
|
-
// transport/sessionStateMachine/SessionNoConnection.ts
|
|
667
|
-
var SessionNoConnection = class extends IdentifiedSession {
|
|
668
|
-
state = "NoConnection" /* NoConnection */;
|
|
669
|
-
listeners;
|
|
670
|
-
gracePeriodTimeout;
|
|
671
|
-
constructor(listeners, ...args) {
|
|
672
|
-
super(...args);
|
|
673
|
-
this.listeners = listeners;
|
|
674
|
-
this.gracePeriodTimeout = setTimeout(() => {
|
|
675
|
-
this.listeners.onSessionGracePeriodElapsed();
|
|
676
|
-
}, this.options.sessionDisconnectGraceMs);
|
|
677
|
-
}
|
|
678
|
-
_handleClose() {
|
|
679
|
-
super._handleClose();
|
|
680
|
-
}
|
|
681
|
-
_handleStateExit() {
|
|
682
|
-
super._handleStateExit();
|
|
683
|
-
if (this.gracePeriodTimeout) {
|
|
684
|
-
clearTimeout(this.gracePeriodTimeout);
|
|
685
|
-
this.gracePeriodTimeout = void 0;
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
};
|
|
689
|
-
|
|
690
|
-
// tracing/index.ts
|
|
691
|
-
var import_api = require("@opentelemetry/api");
|
|
692
|
-
|
|
693
|
-
// package.json
|
|
694
|
-
var version = "0.24.3";
|
|
695
|
-
|
|
696
|
-
// tracing/index.ts
|
|
697
|
-
function createSessionTelemetryInfo(sessionId, to, from, propagationCtx) {
|
|
698
|
-
const parentCtx = propagationCtx ? import_api.propagation.extract(import_api.context.active(), propagationCtx) : import_api.context.active();
|
|
699
|
-
const span = tracer.startSpan(
|
|
700
|
-
`session ${sessionId}`,
|
|
701
|
-
{
|
|
702
|
-
attributes: {
|
|
703
|
-
component: "river",
|
|
704
|
-
"river.session.id": sessionId,
|
|
705
|
-
"river.session.to": to,
|
|
706
|
-
"river.session.from": from
|
|
707
|
-
}
|
|
708
|
-
},
|
|
709
|
-
parentCtx
|
|
710
|
-
);
|
|
711
|
-
const ctx = import_api.trace.setSpan(parentCtx, span);
|
|
712
|
-
return { span, ctx };
|
|
713
|
-
}
|
|
714
|
-
var tracer = import_api.trace.getTracer("river", version);
|
|
715
|
-
|
|
716
|
-
// transport/sessionStateMachine/SessionWaitingForHandshake.ts
|
|
717
|
-
var SessionWaitingForHandshake = class extends CommonSession {
|
|
718
|
-
state = "WaitingForHandshake" /* WaitingForHandshake */;
|
|
719
|
-
conn;
|
|
720
|
-
listeners;
|
|
721
|
-
handshakeTimeout;
|
|
722
|
-
constructor(conn, listeners, ...args) {
|
|
723
|
-
super(...args);
|
|
724
|
-
this.conn = conn;
|
|
725
|
-
this.listeners = listeners;
|
|
726
|
-
this.handshakeTimeout = setTimeout(() => {
|
|
727
|
-
listeners.onHandshakeTimeout();
|
|
728
|
-
}, this.options.handshakeTimeoutMs);
|
|
729
|
-
this.conn.addDataListener(this.onHandshakeData);
|
|
730
|
-
this.conn.addErrorListener(listeners.onConnectionErrored);
|
|
731
|
-
this.conn.addCloseListener(listeners.onConnectionClosed);
|
|
732
|
-
}
|
|
733
|
-
onHandshakeData = (msg) => {
|
|
734
|
-
const parsedMsg = this.parseMsg(msg);
|
|
735
|
-
if (parsedMsg === null) {
|
|
736
|
-
this.listeners.onInvalidHandshake("could not parse message");
|
|
737
|
-
return;
|
|
738
|
-
}
|
|
739
|
-
this.listeners.onHandshake(parsedMsg);
|
|
740
|
-
};
|
|
741
|
-
get loggingMetadata() {
|
|
742
|
-
return {
|
|
743
|
-
clientId: this.from,
|
|
744
|
-
connId: this.conn.id
|
|
745
|
-
};
|
|
746
|
-
}
|
|
747
|
-
sendHandshake(msg) {
|
|
748
|
-
return this.conn.send(this.options.codec.toBuffer(msg));
|
|
749
|
-
}
|
|
750
|
-
_handleStateExit() {
|
|
751
|
-
this.conn.removeDataListener(this.onHandshakeData);
|
|
752
|
-
this.conn.removeErrorListener(this.listeners.onConnectionErrored);
|
|
753
|
-
this.conn.removeCloseListener(this.listeners.onConnectionClosed);
|
|
754
|
-
clearTimeout(this.handshakeTimeout);
|
|
755
|
-
this.handshakeTimeout = void 0;
|
|
756
|
-
}
|
|
757
|
-
_handleClose() {
|
|
758
|
-
this.conn.close();
|
|
759
|
-
}
|
|
760
|
-
};
|
|
761
|
-
|
|
762
|
-
// transport/sessionStateMachine/SessionHandshaking.ts
|
|
763
|
-
var SessionHandshaking = class extends IdentifiedSession {
|
|
764
|
-
state = "Handshaking" /* Handshaking */;
|
|
765
|
-
conn;
|
|
766
|
-
listeners;
|
|
767
|
-
handshakeTimeout;
|
|
768
|
-
constructor(conn, listeners, ...args) {
|
|
769
|
-
super(...args);
|
|
770
|
-
this.conn = conn;
|
|
771
|
-
this.listeners = listeners;
|
|
772
|
-
this.handshakeTimeout = setTimeout(() => {
|
|
773
|
-
listeners.onHandshakeTimeout();
|
|
774
|
-
}, this.options.handshakeTimeoutMs);
|
|
775
|
-
this.conn.addDataListener(this.onHandshakeData);
|
|
776
|
-
this.conn.addErrorListener(listeners.onConnectionErrored);
|
|
777
|
-
this.conn.addCloseListener(listeners.onConnectionClosed);
|
|
778
|
-
}
|
|
779
|
-
onHandshakeData = (msg) => {
|
|
780
|
-
const parsedMsg = this.parseMsg(msg);
|
|
781
|
-
if (parsedMsg === null) {
|
|
782
|
-
this.listeners.onInvalidHandshake("could not parse message");
|
|
783
|
-
return;
|
|
784
|
-
}
|
|
785
|
-
this.listeners.onHandshake(parsedMsg);
|
|
786
|
-
};
|
|
787
|
-
sendHandshake(msg) {
|
|
788
|
-
return this.conn.send(this.options.codec.toBuffer(msg));
|
|
789
|
-
}
|
|
790
|
-
_handleStateExit() {
|
|
791
|
-
super._handleStateExit();
|
|
792
|
-
this.conn.removeDataListener(this.onHandshakeData);
|
|
793
|
-
this.conn.removeErrorListener(this.listeners.onConnectionErrored);
|
|
794
|
-
this.conn.removeCloseListener(this.listeners.onConnectionClosed);
|
|
795
|
-
clearTimeout(this.handshakeTimeout);
|
|
796
|
-
}
|
|
797
|
-
_handleClose() {
|
|
798
|
-
super._handleClose();
|
|
799
|
-
this.conn.close();
|
|
800
|
-
}
|
|
801
|
-
};
|
|
802
|
-
|
|
803
|
-
// transport/sessionStateMachine/SessionConnected.ts
|
|
804
|
-
var import_api2 = require("@opentelemetry/api");
|
|
805
|
-
var SessionConnected = class extends IdentifiedSession {
|
|
806
|
-
state = "Connected" /* Connected */;
|
|
807
|
-
conn;
|
|
808
|
-
listeners;
|
|
809
|
-
heartbeatHandle;
|
|
810
|
-
heartbeatMisses = 0;
|
|
811
|
-
get isActivelyHeartbeating() {
|
|
812
|
-
return this.heartbeatHandle !== void 0;
|
|
813
|
-
}
|
|
814
|
-
updateBookkeeping(ack, seq) {
|
|
815
|
-
this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq >= ack);
|
|
816
|
-
this.ack = seq + 1;
|
|
817
|
-
this.heartbeatMisses = 0;
|
|
818
|
-
}
|
|
819
|
-
send(msg) {
|
|
820
|
-
const constructedMsg = this.constructMsg(msg);
|
|
821
|
-
this.sendBuffer.push(constructedMsg);
|
|
822
|
-
this.conn.send(this.options.codec.toBuffer(constructedMsg));
|
|
823
|
-
return constructedMsg.id;
|
|
824
|
-
}
|
|
825
|
-
constructor(conn, listeners, ...args) {
|
|
826
|
-
super(...args);
|
|
827
|
-
this.conn = conn;
|
|
828
|
-
this.listeners = listeners;
|
|
829
|
-
this.conn.addDataListener(this.onMessageData);
|
|
830
|
-
this.conn.addCloseListener(listeners.onConnectionClosed);
|
|
831
|
-
this.conn.addErrorListener(listeners.onConnectionErrored);
|
|
832
|
-
if (this.sendBuffer.length > 0) {
|
|
833
|
-
this.log?.debug(
|
|
834
|
-
`sending ${this.sendBuffer.length} buffered messages`,
|
|
835
|
-
this.loggingMetadata
|
|
836
|
-
);
|
|
837
|
-
}
|
|
838
|
-
for (const msg of this.sendBuffer) {
|
|
839
|
-
conn.send(this.options.codec.toBuffer(msg));
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
startActiveHeartbeat() {
|
|
843
|
-
this.heartbeatHandle = setInterval(() => {
|
|
844
|
-
const misses = this.heartbeatMisses;
|
|
845
|
-
const missDuration = misses * this.options.heartbeatIntervalMs;
|
|
846
|
-
if (misses >= this.options.heartbeatsUntilDead) {
|
|
847
|
-
this.log?.info(
|
|
848
|
-
`closing connection to ${this.to} due to inactivity (missed ${misses} heartbeats which is ${missDuration}ms)`,
|
|
849
|
-
this.loggingMetadata
|
|
850
|
-
);
|
|
851
|
-
this.telemetry.span.addEvent("closing connection due to inactivity");
|
|
852
|
-
this.conn.close();
|
|
853
|
-
clearInterval(this.heartbeatHandle);
|
|
854
|
-
this.heartbeatHandle = void 0;
|
|
855
|
-
return;
|
|
856
|
-
}
|
|
857
|
-
this.sendHeartbeat();
|
|
858
|
-
this.heartbeatMisses++;
|
|
859
|
-
}, this.options.heartbeatIntervalMs);
|
|
860
|
-
}
|
|
861
|
-
sendHeartbeat() {
|
|
862
|
-
this.send({
|
|
863
|
-
streamId: "heartbeat",
|
|
864
|
-
controlFlags: 1 /* AckBit */,
|
|
865
|
-
payload: {
|
|
866
|
-
type: "ACK"
|
|
867
|
-
}
|
|
868
|
-
});
|
|
869
|
-
}
|
|
870
|
-
onMessageData = (msg) => {
|
|
871
|
-
const parsedMsg = this.parseMsg(msg);
|
|
872
|
-
if (parsedMsg === null)
|
|
873
|
-
return;
|
|
874
|
-
if (parsedMsg.seq !== this.ack) {
|
|
875
|
-
if (parsedMsg.seq < this.ack) {
|
|
876
|
-
this.log?.debug(
|
|
877
|
-
`received duplicate msg (got seq: ${parsedMsg.seq}, wanted seq: ${this.ack}), discarding`,
|
|
878
|
-
{
|
|
879
|
-
...this.loggingMetadata,
|
|
880
|
-
transportMessage: parsedMsg
|
|
881
|
-
}
|
|
882
|
-
);
|
|
883
|
-
} else {
|
|
884
|
-
const reason = `received out-of-order msg (got seq: ${parsedMsg.seq}, wanted seq: ${this.ack})`;
|
|
885
|
-
this.log?.error(reason, {
|
|
886
|
-
...this.loggingMetadata,
|
|
887
|
-
transportMessage: parsedMsg,
|
|
888
|
-
tags: ["invariant-violation"]
|
|
889
|
-
});
|
|
890
|
-
this.telemetry.span.setStatus({
|
|
891
|
-
code: import_api2.SpanStatusCode.ERROR,
|
|
892
|
-
message: reason
|
|
893
|
-
});
|
|
894
|
-
this.listeners.onInvalidMessage(reason);
|
|
895
|
-
}
|
|
896
|
-
return;
|
|
897
|
-
}
|
|
898
|
-
this.log?.debug(`received msg`, {
|
|
899
|
-
...this.loggingMetadata,
|
|
900
|
-
transportMessage: parsedMsg
|
|
901
|
-
});
|
|
902
|
-
this.updateBookkeeping(parsedMsg.ack, parsedMsg.seq);
|
|
903
|
-
if (!isAck(parsedMsg.controlFlags)) {
|
|
904
|
-
this.listeners.onMessage(parsedMsg);
|
|
905
|
-
return;
|
|
906
|
-
}
|
|
907
|
-
this.log?.debug(`discarding msg (ack bit set)`, {
|
|
908
|
-
...this.loggingMetadata,
|
|
909
|
-
transportMessage: parsedMsg
|
|
910
|
-
});
|
|
911
|
-
if (!this.isActivelyHeartbeating) {
|
|
912
|
-
this.sendHeartbeat();
|
|
913
|
-
}
|
|
914
|
-
};
|
|
915
|
-
_handleStateExit() {
|
|
916
|
-
super._handleStateExit();
|
|
917
|
-
this.conn.removeDataListener(this.onMessageData);
|
|
918
|
-
this.conn.removeCloseListener(this.listeners.onConnectionClosed);
|
|
919
|
-
this.conn.removeErrorListener(this.listeners.onConnectionErrored);
|
|
920
|
-
clearInterval(this.heartbeatHandle);
|
|
921
|
-
this.heartbeatHandle = void 0;
|
|
922
|
-
}
|
|
923
|
-
_handleClose() {
|
|
924
|
-
super._handleClose();
|
|
925
|
-
this.conn.close();
|
|
926
|
-
}
|
|
927
|
-
};
|
|
928
|
-
|
|
929
|
-
// transport/sessionStateMachine/transitions.ts
|
|
930
|
-
function inheritSharedSession(session) {
|
|
931
|
-
return [
|
|
932
|
-
session.id,
|
|
933
|
-
session.from,
|
|
934
|
-
session.to,
|
|
935
|
-
session.seq,
|
|
936
|
-
session.ack,
|
|
937
|
-
session.sendBuffer,
|
|
938
|
-
session.telemetry,
|
|
939
|
-
session.options,
|
|
940
|
-
session.log
|
|
941
|
-
];
|
|
942
|
-
}
|
|
943
|
-
var SessionStateGraph = {
|
|
944
|
-
entrypoints: {
|
|
945
|
-
NoConnection(to, from, listeners, options, log) {
|
|
946
|
-
const id = `session-${generateId()}`;
|
|
947
|
-
const telemetry = createSessionTelemetryInfo(id, to, from);
|
|
948
|
-
const sendBuffer = [];
|
|
949
|
-
const session = new SessionNoConnection(
|
|
950
|
-
listeners,
|
|
951
|
-
id,
|
|
952
|
-
from,
|
|
953
|
-
to,
|
|
954
|
-
0,
|
|
955
|
-
0,
|
|
956
|
-
sendBuffer,
|
|
957
|
-
telemetry,
|
|
958
|
-
options,
|
|
959
|
-
log
|
|
960
|
-
);
|
|
961
|
-
session.log?.info(`session ${session.id} created in NoConnection state`, {
|
|
962
|
-
...session.loggingMetadata,
|
|
963
|
-
tags: ["state-transition"]
|
|
964
|
-
});
|
|
965
|
-
return session;
|
|
966
|
-
},
|
|
967
|
-
WaitingForHandshake(from, conn, listeners, options, log) {
|
|
968
|
-
const session = new SessionWaitingForHandshake(
|
|
969
|
-
conn,
|
|
970
|
-
listeners,
|
|
971
|
-
from,
|
|
972
|
-
options,
|
|
973
|
-
log
|
|
974
|
-
);
|
|
975
|
-
session.log?.info(`session created in WaitingForHandshake state`, {
|
|
976
|
-
...session.loggingMetadata,
|
|
977
|
-
tags: ["state-transition"]
|
|
978
|
-
});
|
|
979
|
-
return session;
|
|
980
|
-
}
|
|
981
|
-
},
|
|
982
|
-
// All of the transitions 'move'/'consume' the old session and return a new one.
|
|
983
|
-
// After a session is transitioned, any usage of the old session will throw.
|
|
984
|
-
transition: {
|
|
985
|
-
// happy path transitions
|
|
986
|
-
NoConnectionToConnecting(oldSession, connPromise, listeners) {
|
|
987
|
-
const carriedState = inheritSharedSession(oldSession);
|
|
988
|
-
oldSession._handleStateExit();
|
|
989
|
-
const session = new SessionConnecting(
|
|
990
|
-
connPromise,
|
|
991
|
-
listeners,
|
|
992
|
-
...carriedState
|
|
993
|
-
);
|
|
994
|
-
session.log?.info(
|
|
995
|
-
`session ${session.id} transition from NoConnection to Connecting`,
|
|
996
|
-
{
|
|
997
|
-
...session.loggingMetadata,
|
|
998
|
-
tags: ["state-transition"]
|
|
999
|
-
}
|
|
1000
|
-
);
|
|
1001
|
-
return session;
|
|
1002
|
-
},
|
|
1003
|
-
ConnectingToHandshaking(oldSession, conn, listeners) {
|
|
1004
|
-
const carriedState = inheritSharedSession(oldSession);
|
|
1005
|
-
oldSession._handleStateExit();
|
|
1006
|
-
const session = new SessionHandshaking(conn, listeners, ...carriedState);
|
|
1007
|
-
session.log?.info(
|
|
1008
|
-
`session ${session.id} transition from Connecting to Handshaking`,
|
|
1009
|
-
{
|
|
1010
|
-
...session.loggingMetadata,
|
|
1011
|
-
tags: ["state-transition"]
|
|
1012
|
-
}
|
|
1013
|
-
);
|
|
1014
|
-
return session;
|
|
1015
|
-
},
|
|
1016
|
-
HandshakingToConnected(oldSession, listeners) {
|
|
1017
|
-
const carriedState = inheritSharedSession(oldSession);
|
|
1018
|
-
const conn = oldSession.conn;
|
|
1019
|
-
oldSession._handleStateExit();
|
|
1020
|
-
const session = new SessionConnected(conn, listeners, ...carriedState);
|
|
1021
|
-
session.log?.info(
|
|
1022
|
-
`session ${session.id} transition from Handshaking to Connected`,
|
|
1023
|
-
{
|
|
1024
|
-
...session.loggingMetadata,
|
|
1025
|
-
tags: ["state-transition"]
|
|
1026
|
-
}
|
|
1027
|
-
);
|
|
1028
|
-
return session;
|
|
1029
|
-
},
|
|
1030
|
-
WaitingForHandshakeToConnected(pendingSession, oldSession, sessionId, to, propagationCtx, listeners) {
|
|
1031
|
-
const conn = pendingSession.conn;
|
|
1032
|
-
const { from, options } = pendingSession;
|
|
1033
|
-
const carriedState = oldSession ? (
|
|
1034
|
-
// old session exists, inherit state
|
|
1035
|
-
inheritSharedSession(oldSession)
|
|
1036
|
-
) : (
|
|
1037
|
-
// old session does not exist, create new state
|
|
1038
|
-
[
|
|
1039
|
-
sessionId,
|
|
1040
|
-
from,
|
|
1041
|
-
to,
|
|
1042
|
-
0,
|
|
1043
|
-
0,
|
|
1044
|
-
[],
|
|
1045
|
-
createSessionTelemetryInfo(sessionId, to, from, propagationCtx),
|
|
1046
|
-
options,
|
|
1047
|
-
pendingSession.log
|
|
1048
|
-
]
|
|
1049
|
-
);
|
|
1050
|
-
pendingSession._handleStateExit();
|
|
1051
|
-
oldSession?._handleStateExit();
|
|
1052
|
-
const session = new SessionConnected(conn, listeners, ...carriedState);
|
|
1053
|
-
session.log?.info(
|
|
1054
|
-
`session ${session.id} transition from WaitingForHandshake to Connected`,
|
|
1055
|
-
{
|
|
1056
|
-
...session.loggingMetadata,
|
|
1057
|
-
tags: ["state-transition"]
|
|
1058
|
-
}
|
|
1059
|
-
);
|
|
1060
|
-
return session;
|
|
1061
|
-
},
|
|
1062
|
-
// disconnect paths
|
|
1063
|
-
ConnectingToNoConnection(oldSession, listeners) {
|
|
1064
|
-
const carriedState = inheritSharedSession(oldSession);
|
|
1065
|
-
oldSession.bestEffortClose();
|
|
1066
|
-
oldSession._handleStateExit();
|
|
1067
|
-
const session = new SessionNoConnection(listeners, ...carriedState);
|
|
1068
|
-
session.log?.info(
|
|
1069
|
-
`session ${session.id} transition from Connecting to NoConnection`,
|
|
1070
|
-
{
|
|
1071
|
-
...session.loggingMetadata,
|
|
1072
|
-
tags: ["state-transition"]
|
|
1073
|
-
}
|
|
1074
|
-
);
|
|
1075
|
-
return session;
|
|
1076
|
-
},
|
|
1077
|
-
HandshakingToNoConnection(oldSession, listeners) {
|
|
1078
|
-
const carriedState = inheritSharedSession(oldSession);
|
|
1079
|
-
oldSession.conn.close();
|
|
1080
|
-
oldSession._handleStateExit();
|
|
1081
|
-
const session = new SessionNoConnection(listeners, ...carriedState);
|
|
1082
|
-
session.log?.info(
|
|
1083
|
-
`session ${session.id} transition from Handshaking to NoConnection`,
|
|
1084
|
-
{
|
|
1085
|
-
...session.loggingMetadata,
|
|
1086
|
-
tags: ["state-transition"]
|
|
1087
|
-
}
|
|
1088
|
-
);
|
|
1089
|
-
return session;
|
|
1090
|
-
},
|
|
1091
|
-
ConnectedToNoConnection(oldSession, listeners) {
|
|
1092
|
-
const carriedState = inheritSharedSession(oldSession);
|
|
1093
|
-
oldSession.conn.close();
|
|
1094
|
-
oldSession._handleStateExit();
|
|
1095
|
-
const session = new SessionNoConnection(listeners, ...carriedState);
|
|
1096
|
-
session.log?.info(
|
|
1097
|
-
`session ${session.id} transition from Connected to NoConnection`,
|
|
1098
|
-
{
|
|
1099
|
-
...session.loggingMetadata,
|
|
1100
|
-
tags: ["state-transition"]
|
|
1101
|
-
}
|
|
1102
|
-
);
|
|
1103
|
-
return session;
|
|
1104
|
-
}
|
|
1105
|
-
}
|
|
1106
|
-
};
|
|
1107
|
-
|
|
1108
|
-
// transport/transport.ts
|
|
1109
|
-
var Transport = class {
|
|
1110
|
-
/**
|
|
1111
|
-
* The status of the transport.
|
|
1112
|
-
*/
|
|
1113
|
-
status;
|
|
1114
|
-
/**
|
|
1115
|
-
* The client ID of this transport.
|
|
1116
|
-
*/
|
|
1117
|
-
clientId;
|
|
1118
|
-
/**
|
|
1119
|
-
* The event dispatcher for handling events of type EventTypes.
|
|
1120
|
-
*/
|
|
1121
|
-
eventDispatcher;
|
|
1122
|
-
/**
|
|
1123
|
-
* The options for this transport.
|
|
1124
|
-
*/
|
|
1125
|
-
options;
|
|
1126
|
-
log;
|
|
1127
|
-
sessions;
|
|
1128
|
-
/**
|
|
1129
|
-
* Creates a new Transport instance.
|
|
1130
|
-
* @param codec The codec used to encode and decode messages.
|
|
1131
|
-
* @param clientId The client ID of this transport.
|
|
1132
|
-
*/
|
|
1133
|
-
constructor(clientId, providedOptions) {
|
|
1134
|
-
this.options = { ...defaultTransportOptions, ...providedOptions };
|
|
1135
|
-
this.eventDispatcher = new EventDispatcher();
|
|
1136
|
-
this.clientId = clientId;
|
|
1137
|
-
this.status = "open";
|
|
1138
|
-
this.sessions = /* @__PURE__ */ new Map();
|
|
1139
|
-
}
|
|
1140
|
-
bindLogger(fn, level) {
|
|
1141
|
-
if (typeof fn === "function") {
|
|
1142
|
-
this.log = createLogProxy(new BaseLogger(fn, level));
|
|
1143
|
-
return;
|
|
1144
|
-
}
|
|
1145
|
-
this.log = createLogProxy(fn);
|
|
1146
|
-
}
|
|
1147
|
-
/**
|
|
1148
|
-
* Called when a message is received by this transport.
|
|
1149
|
-
* You generally shouldn't need to override this in downstream transport implementations.
|
|
1150
|
-
* @param msg The received message.
|
|
1151
|
-
*/
|
|
1152
|
-
handleMsg(msg) {
|
|
1153
|
-
if (this.getStatus() !== "open")
|
|
1154
|
-
return;
|
|
1155
|
-
this.eventDispatcher.dispatchEvent("message", msg);
|
|
1156
|
-
}
|
|
1157
|
-
/**
|
|
1158
|
-
* Adds a listener to this transport.
|
|
1159
|
-
* @param the type of event to listen for
|
|
1160
|
-
* @param handler The message handler to add.
|
|
1161
|
-
*/
|
|
1162
|
-
addEventListener(type, handler) {
|
|
1163
|
-
this.eventDispatcher.addEventListener(type, handler);
|
|
1164
|
-
}
|
|
1165
|
-
/**
|
|
1166
|
-
* Removes a listener from this transport.
|
|
1167
|
-
* @param the type of event to un-listen on
|
|
1168
|
-
* @param handler The message handler to remove.
|
|
1169
|
-
*/
|
|
1170
|
-
removeEventListener(type, handler) {
|
|
1171
|
-
this.eventDispatcher.removeEventListener(type, handler);
|
|
1172
|
-
}
|
|
1173
|
-
protocolError(type, message) {
|
|
1174
|
-
this.eventDispatcher.dispatchEvent("protocolError", { type, message });
|
|
1175
|
-
}
|
|
1176
|
-
/**
|
|
1177
|
-
* Default close implementation for transports. You should override this in the downstream
|
|
1178
|
-
* implementation if you need to do any additional cleanup and call super.close() at the end.
|
|
1179
|
-
* Closes the transport. Any messages sent while the transport is closed will be silently discarded.
|
|
1180
|
-
*/
|
|
1181
|
-
close() {
|
|
1182
|
-
this.status = "closed";
|
|
1183
|
-
for (const session of this.sessions.values()) {
|
|
1184
|
-
this.deleteSession(session);
|
|
1185
|
-
}
|
|
1186
|
-
this.eventDispatcher.dispatchEvent("transportStatus", {
|
|
1187
|
-
status: this.status
|
|
1188
|
-
});
|
|
1189
|
-
this.eventDispatcher.removeAllListeners();
|
|
1190
|
-
this.log?.info(`manually closed transport`, { clientId: this.clientId });
|
|
1191
|
-
}
|
|
1192
|
-
getStatus() {
|
|
1193
|
-
return this.status;
|
|
1194
|
-
}
|
|
1195
|
-
updateSession(session) {
|
|
1196
|
-
const activeSession = this.sessions.get(session.to);
|
|
1197
|
-
if (activeSession && activeSession.id !== session.id) {
|
|
1198
|
-
const msg = `attempt to transition active session for ${session.to} but active session (${activeSession.id}) is different from handle (${session.id})`;
|
|
1199
|
-
throw new Error(msg);
|
|
1200
|
-
}
|
|
1201
|
-
this.sessions.set(session.to, session);
|
|
1202
|
-
if (!activeSession) {
|
|
1203
|
-
this.eventDispatcher.dispatchEvent("sessionStatus", {
|
|
1204
|
-
status: "connect",
|
|
1205
|
-
session
|
|
1206
|
-
});
|
|
1207
|
-
}
|
|
1208
|
-
this.eventDispatcher.dispatchEvent("sessionTransition", {
|
|
1209
|
-
state: session.state,
|
|
1210
|
-
session
|
|
1211
|
-
});
|
|
1212
|
-
return session;
|
|
1213
|
-
}
|
|
1214
|
-
// state transitions
|
|
1215
|
-
deleteSession(session) {
|
|
1216
|
-
session.log?.info(`closing session ${session.id}`, session.loggingMetadata);
|
|
1217
|
-
this.eventDispatcher.dispatchEvent("sessionStatus", {
|
|
1218
|
-
status: "disconnect",
|
|
1219
|
-
session
|
|
1220
|
-
});
|
|
1221
|
-
session.close();
|
|
1222
|
-
this.sessions.delete(session.to);
|
|
1223
|
-
}
|
|
1224
|
-
// common listeners
|
|
1225
|
-
onSessionGracePeriodElapsed(session) {
|
|
1226
|
-
this.log?.warn(
|
|
1227
|
-
`session to ${session.to} grace period elapsed, closing`,
|
|
1228
|
-
session.loggingMetadata
|
|
1229
|
-
);
|
|
1230
|
-
this.deleteSession(session);
|
|
1231
|
-
}
|
|
1232
|
-
onConnectingFailed(session) {
|
|
1233
|
-
const noConnectionSession = SessionStateGraph.transition.ConnectingToNoConnection(session, {
|
|
1234
|
-
onSessionGracePeriodElapsed: () => {
|
|
1235
|
-
this.onSessionGracePeriodElapsed(noConnectionSession);
|
|
1236
|
-
}
|
|
1237
|
-
});
|
|
1238
|
-
return this.updateSession(noConnectionSession);
|
|
1239
|
-
}
|
|
1240
|
-
onConnClosed(session) {
|
|
1241
|
-
let noConnectionSession;
|
|
1242
|
-
if (session.state === "Handshaking" /* Handshaking */) {
|
|
1243
|
-
noConnectionSession = SessionStateGraph.transition.HandshakingToNoConnection(session, {
|
|
1244
|
-
onSessionGracePeriodElapsed: () => {
|
|
1245
|
-
this.onSessionGracePeriodElapsed(noConnectionSession);
|
|
1246
|
-
}
|
|
1247
|
-
});
|
|
1248
|
-
} else {
|
|
1249
|
-
noConnectionSession = SessionStateGraph.transition.ConnectedToNoConnection(session, {
|
|
1250
|
-
onSessionGracePeriodElapsed: () => {
|
|
1251
|
-
this.onSessionGracePeriodElapsed(noConnectionSession);
|
|
1252
|
-
}
|
|
1253
|
-
});
|
|
1254
|
-
}
|
|
1255
|
-
return this.updateSession(noConnectionSession);
|
|
1256
|
-
}
|
|
1257
|
-
};
|
|
1258
|
-
|
|
1259
|
-
// util/stringify.ts
|
|
1260
|
-
function coerceErrorString(err) {
|
|
1261
|
-
if (err instanceof Error) {
|
|
1262
|
-
return err.message || "unknown reason";
|
|
1263
|
-
}
|
|
1264
|
-
return `[coerced to error] ${String(err)}`;
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
// transport/server.ts
|
|
1268
|
-
var import_value2 = require("@sinclair/typebox/value");
|
|
1269
|
-
var ServerTransport = class extends Transport {
|
|
1270
|
-
/**
|
|
1271
|
-
* The options for this transport.
|
|
1272
|
-
*/
|
|
1273
|
-
options;
|
|
1274
|
-
/**
|
|
1275
|
-
* Optional handshake options for the server.
|
|
1276
|
-
*/
|
|
1277
|
-
handshakeExtensions;
|
|
1278
|
-
/**
|
|
1279
|
-
* A map of session handshake data for each session.
|
|
1280
|
-
*/
|
|
1281
|
-
sessionHandshakeMetadata = /* @__PURE__ */ new Map();
|
|
1282
|
-
pendingSessions = /* @__PURE__ */ new Set();
|
|
1283
|
-
constructor(clientId, providedOptions) {
|
|
1284
|
-
super(clientId, providedOptions);
|
|
1285
|
-
this.options = {
|
|
1286
|
-
...defaultServerTransportOptions,
|
|
1287
|
-
...providedOptions
|
|
1288
|
-
};
|
|
1289
|
-
this.log?.info(`initiated server transport`, {
|
|
1290
|
-
clientId: this.clientId,
|
|
1291
|
-
protocolVersion: PROTOCOL_VERSION
|
|
1292
|
-
});
|
|
1293
|
-
}
|
|
1294
|
-
extendHandshake(options) {
|
|
1295
|
-
this.handshakeExtensions = options;
|
|
1296
|
-
}
|
|
1297
|
-
send(to, msg) {
|
|
1298
|
-
if (this.getStatus() === "closed") {
|
|
1299
|
-
const err = "transport is closed, cant send";
|
|
1300
|
-
this.log?.error(err, {
|
|
1301
|
-
clientId: this.clientId,
|
|
1302
|
-
transportMessage: msg,
|
|
1303
|
-
tags: ["invariant-violation"]
|
|
1304
|
-
});
|
|
1305
|
-
throw new Error(err);
|
|
1306
|
-
}
|
|
1307
|
-
const session = this.sessions.get(to);
|
|
1308
|
-
if (!session) {
|
|
1309
|
-
const err = `session to ${to} does not exist`;
|
|
1310
|
-
this.log?.error(err, {
|
|
1311
|
-
clientId: this.clientId,
|
|
1312
|
-
transportMessage: msg,
|
|
1313
|
-
tags: ["invariant-violation"]
|
|
1314
|
-
});
|
|
1315
|
-
throw new Error(err);
|
|
1316
|
-
}
|
|
1317
|
-
return session.send(msg);
|
|
1318
|
-
}
|
|
1319
|
-
deletePendingSession(pendingSession) {
|
|
1320
|
-
pendingSession.close();
|
|
1321
|
-
this.pendingSessions.delete(pendingSession);
|
|
1322
|
-
}
|
|
1323
|
-
deleteSession(session) {
|
|
1324
|
-
this.sessionHandshakeMetadata.delete(session.to);
|
|
1325
|
-
super.deleteSession(session);
|
|
1326
|
-
}
|
|
1327
|
-
handleConnection(conn) {
|
|
1328
|
-
if (this.getStatus() !== "open")
|
|
1329
|
-
return;
|
|
1330
|
-
this.log?.info(`new incoming connection`, {
|
|
1331
|
-
...conn.loggingMetadata,
|
|
1332
|
-
clientId: this.clientId
|
|
1333
|
-
});
|
|
1334
|
-
let receivedHandshake = false;
|
|
1335
|
-
const pendingSession = SessionStateGraph.entrypoints.WaitingForHandshake(
|
|
1336
|
-
this.clientId,
|
|
1337
|
-
conn,
|
|
1338
|
-
{
|
|
1339
|
-
onConnectionClosed: () => {
|
|
1340
|
-
this.log?.warn(
|
|
1341
|
-
`connection from unknown closed before handshake finished`,
|
|
1342
|
-
pendingSession.loggingMetadata
|
|
1343
|
-
);
|
|
1344
|
-
this.deletePendingSession(pendingSession);
|
|
1345
|
-
},
|
|
1346
|
-
onConnectionErrored: (err) => {
|
|
1347
|
-
const errorString = coerceErrorString(err);
|
|
1348
|
-
this.log?.warn(
|
|
1349
|
-
`connection from unknown errored before handshake finished: ${errorString}`,
|
|
1350
|
-
pendingSession.loggingMetadata
|
|
1351
|
-
);
|
|
1352
|
-
this.deletePendingSession(pendingSession);
|
|
1353
|
-
},
|
|
1354
|
-
onHandshakeTimeout: () => {
|
|
1355
|
-
this.log?.warn(
|
|
1356
|
-
`connection from unknown timed out before handshake finished`,
|
|
1357
|
-
pendingSession.loggingMetadata
|
|
1358
|
-
);
|
|
1359
|
-
this.deletePendingSession(pendingSession);
|
|
1360
|
-
},
|
|
1361
|
-
onHandshake: (msg) => {
|
|
1362
|
-
if (receivedHandshake) {
|
|
1363
|
-
this.log?.error(
|
|
1364
|
-
`received multiple handshake messages from pending session`,
|
|
1365
|
-
{
|
|
1366
|
-
...pendingSession.loggingMetadata,
|
|
1367
|
-
connectedTo: msg.from,
|
|
1368
|
-
transportMessage: msg
|
|
1369
|
-
}
|
|
1370
|
-
);
|
|
1371
|
-
this.deletePendingSession(pendingSession);
|
|
1372
|
-
return;
|
|
1373
|
-
}
|
|
1374
|
-
receivedHandshake = true;
|
|
1375
|
-
void this.onHandshakeRequest(pendingSession, msg);
|
|
1376
|
-
},
|
|
1377
|
-
onInvalidHandshake: (reason) => {
|
|
1378
|
-
this.log?.error(
|
|
1379
|
-
`invalid handshake: ${reason}`,
|
|
1380
|
-
pendingSession.loggingMetadata
|
|
1381
|
-
);
|
|
1382
|
-
this.deletePendingSession(pendingSession);
|
|
1383
|
-
this.protocolError(ProtocolError.HandshakeFailed, reason);
|
|
1384
|
-
}
|
|
1385
|
-
},
|
|
1386
|
-
this.options,
|
|
1387
|
-
this.log
|
|
1388
|
-
);
|
|
1389
|
-
this.pendingSessions.add(pendingSession);
|
|
1390
|
-
}
|
|
1391
|
-
rejectHandshakeRequest(session, to, reason, code, metadata) {
|
|
1392
|
-
session.conn.telemetry?.span.setStatus({
|
|
1393
|
-
code: import_api3.SpanStatusCode.ERROR,
|
|
1394
|
-
message: reason
|
|
1395
|
-
});
|
|
1396
|
-
this.log?.warn(reason, metadata);
|
|
1397
|
-
session.sendHandshake(
|
|
1398
|
-
handshakeResponseMessage({
|
|
1399
|
-
from: this.clientId,
|
|
1400
|
-
to,
|
|
1401
|
-
status: {
|
|
1402
|
-
ok: false,
|
|
1403
|
-
code,
|
|
1404
|
-
reason
|
|
1405
|
-
}
|
|
1406
|
-
})
|
|
1407
|
-
);
|
|
1408
|
-
this.protocolError(ProtocolError.HandshakeFailed, reason);
|
|
1409
|
-
this.deletePendingSession(session);
|
|
1410
|
-
}
|
|
1411
|
-
async onHandshakeRequest(session, msg) {
|
|
1412
|
-
if (!import_value2.Value.Check(ControlMessageHandshakeRequestSchema, msg.payload)) {
|
|
1413
|
-
this.rejectHandshakeRequest(
|
|
1414
|
-
session,
|
|
1415
|
-
msg.from,
|
|
1416
|
-
"received invalid handshake request",
|
|
1417
|
-
"MALFORMED_HANDSHAKE",
|
|
1418
|
-
{
|
|
1419
|
-
...session.loggingMetadata,
|
|
1420
|
-
transportMessage: msg,
|
|
1421
|
-
connectedTo: msg.from,
|
|
1422
|
-
validationErrors: [
|
|
1423
|
-
...import_value2.Value.Errors(ControlMessageHandshakeRequestSchema, msg.payload)
|
|
1424
|
-
]
|
|
1425
|
-
}
|
|
1426
|
-
);
|
|
1427
|
-
return;
|
|
1428
|
-
}
|
|
1429
|
-
const gotVersion = msg.payload.protocolVersion;
|
|
1430
|
-
if (gotVersion !== PROTOCOL_VERSION) {
|
|
1431
|
-
this.rejectHandshakeRequest(
|
|
1432
|
-
session,
|
|
1433
|
-
msg.from,
|
|
1434
|
-
`expected protocol version ${PROTOCOL_VERSION}, got ${gotVersion}`,
|
|
1435
|
-
"PROTOCOL_VERSION_MISMATCH",
|
|
1436
|
-
{
|
|
1437
|
-
...session.loggingMetadata,
|
|
1438
|
-
connectedTo: msg.from,
|
|
1439
|
-
transportMessage: msg
|
|
1440
|
-
}
|
|
1441
|
-
);
|
|
1442
|
-
return;
|
|
1443
|
-
}
|
|
1444
|
-
let oldSession = this.sessions.get(msg.from);
|
|
1445
|
-
const parsedMetadata = await this.validateHandshakeMetadata(
|
|
1446
|
-
session,
|
|
1447
|
-
oldSession,
|
|
1448
|
-
msg.payload.metadata,
|
|
1449
|
-
msg.from
|
|
1450
|
-
);
|
|
1451
|
-
if (parsedMetadata === false) {
|
|
1452
|
-
return;
|
|
1453
|
-
}
|
|
1454
|
-
let connectCase = "new session";
|
|
1455
|
-
if (oldSession && oldSession.id === msg.payload.sessionId) {
|
|
1456
|
-
connectCase = "transparent reconnection";
|
|
1457
|
-
const clientNextExpectedSeq = msg.payload.expectedSessionState.nextExpectedSeq;
|
|
1458
|
-
const clientNextSentSeq = msg.payload.expectedSessionState.nextSentSeq ?? 0;
|
|
1459
|
-
const ourNextSeq = oldSession.nextSeq();
|
|
1460
|
-
const ourAck = oldSession.ack;
|
|
1461
|
-
if (clientNextSentSeq > ourAck) {
|
|
1462
|
-
this.rejectHandshakeRequest(
|
|
1463
|
-
session,
|
|
1464
|
-
msg.from,
|
|
1465
|
-
`client is in the future: server wanted next message to be ${ourAck} but client would have sent ${clientNextSentSeq}`,
|
|
1466
|
-
"SESSION_STATE_MISMATCH",
|
|
1467
|
-
{
|
|
1468
|
-
...session.loggingMetadata,
|
|
1469
|
-
connectedTo: msg.from,
|
|
1470
|
-
transportMessage: msg
|
|
1471
|
-
}
|
|
1472
|
-
);
|
|
1473
|
-
return;
|
|
1474
|
-
}
|
|
1475
|
-
if (ourNextSeq > clientNextExpectedSeq) {
|
|
1476
|
-
this.rejectHandshakeRequest(
|
|
1477
|
-
session,
|
|
1478
|
-
msg.from,
|
|
1479
|
-
`server is in the future: client wanted next message to be ${clientNextExpectedSeq} but server would have sent ${ourNextSeq}`,
|
|
1480
|
-
"SESSION_STATE_MISMATCH",
|
|
1481
|
-
{
|
|
1482
|
-
...session.loggingMetadata,
|
|
1483
|
-
connectedTo: msg.from,
|
|
1484
|
-
transportMessage: msg
|
|
1485
|
-
}
|
|
1486
|
-
);
|
|
1487
|
-
return;
|
|
1488
|
-
}
|
|
1489
|
-
if (oldSession.state === "Connected" /* Connected */) {
|
|
1490
|
-
const noConnectionSession = SessionStateGraph.transition.ConnectedToNoConnection(oldSession, {
|
|
1491
|
-
onSessionGracePeriodElapsed: () => {
|
|
1492
|
-
this.onSessionGracePeriodElapsed(noConnectionSession);
|
|
1493
|
-
}
|
|
1494
|
-
});
|
|
1495
|
-
oldSession = noConnectionSession;
|
|
1496
|
-
} else if (oldSession.state === "Handshaking" /* Handshaking */) {
|
|
1497
|
-
const noConnectionSession = SessionStateGraph.transition.HandshakingToNoConnection(oldSession, {
|
|
1498
|
-
onSessionGracePeriodElapsed: () => {
|
|
1499
|
-
this.onSessionGracePeriodElapsed(noConnectionSession);
|
|
1500
|
-
}
|
|
1501
|
-
});
|
|
1502
|
-
oldSession = noConnectionSession;
|
|
1503
|
-
} else if (oldSession.state === "Connecting" /* Connecting */) {
|
|
1504
|
-
const noConnectionSession = SessionStateGraph.transition.ConnectingToNoConnection(oldSession, {
|
|
1505
|
-
onSessionGracePeriodElapsed: () => {
|
|
1506
|
-
this.onSessionGracePeriodElapsed(noConnectionSession);
|
|
1507
|
-
}
|
|
1508
|
-
});
|
|
1509
|
-
oldSession = noConnectionSession;
|
|
1510
|
-
}
|
|
1511
|
-
this.updateSession(oldSession);
|
|
1512
|
-
} else if (oldSession) {
|
|
1513
|
-
connectCase = "hard reconnection";
|
|
1514
|
-
this.deleteSession(oldSession);
|
|
1515
|
-
oldSession = void 0;
|
|
1516
|
-
} else {
|
|
1517
|
-
connectCase = "unknown session";
|
|
1518
|
-
const clientNextExpectedSeq = msg.payload.expectedSessionState.nextExpectedSeq;
|
|
1519
|
-
const clientNextSentSeq = msg.payload.expectedSessionState.nextSentSeq ?? 0;
|
|
1520
|
-
if (clientNextSentSeq > 0 || clientNextExpectedSeq > 0) {
|
|
1521
|
-
this.rejectHandshakeRequest(
|
|
1522
|
-
session,
|
|
1523
|
-
msg.from,
|
|
1524
|
-
`client is trying to reconnect to a session the server don't know about: ${msg.payload.sessionId}`,
|
|
1525
|
-
"SESSION_STATE_MISMATCH",
|
|
1526
|
-
{
|
|
1527
|
-
...session.loggingMetadata,
|
|
1528
|
-
connectedTo: msg.from,
|
|
1529
|
-
transportMessage: msg
|
|
1530
|
-
}
|
|
1531
|
-
);
|
|
1532
|
-
return;
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1535
|
-
const sessionId = msg.payload.sessionId;
|
|
1536
|
-
this.log?.info(
|
|
1537
|
-
`handshake from ${msg.from} ok (${connectCase}), responding with handshake success`,
|
|
1538
|
-
{
|
|
1539
|
-
...session.loggingMetadata,
|
|
1540
|
-
connectedTo: msg.from
|
|
1541
|
-
}
|
|
1542
|
-
);
|
|
1543
|
-
const responseMsg = handshakeResponseMessage({
|
|
1544
|
-
from: this.clientId,
|
|
1545
|
-
to: msg.from,
|
|
1546
|
-
status: {
|
|
1547
|
-
ok: true,
|
|
1548
|
-
sessionId
|
|
1549
|
-
}
|
|
1550
|
-
});
|
|
1551
|
-
session.sendHandshake(responseMsg);
|
|
1552
|
-
const connectedSession = SessionStateGraph.transition.WaitingForHandshakeToConnected(
|
|
1553
|
-
session,
|
|
1554
|
-
// by this point oldSession is either no connection or we dont have an old session
|
|
1555
|
-
oldSession,
|
|
1556
|
-
sessionId,
|
|
1557
|
-
msg.from,
|
|
1558
|
-
msg.tracing,
|
|
1559
|
-
{
|
|
1560
|
-
onConnectionErrored: (err) => {
|
|
1561
|
-
const errStr = coerceErrorString(err);
|
|
1562
|
-
this.log?.warn(
|
|
1563
|
-
`connection to ${connectedSession.to} errored: ${errStr}`,
|
|
1564
|
-
connectedSession.loggingMetadata
|
|
1565
|
-
);
|
|
1566
|
-
},
|
|
1567
|
-
onConnectionClosed: () => {
|
|
1568
|
-
this.log?.info(
|
|
1569
|
-
`connection to ${connectedSession.to} closed`,
|
|
1570
|
-
connectedSession.loggingMetadata
|
|
1571
|
-
);
|
|
1572
|
-
this.onConnClosed(connectedSession);
|
|
1573
|
-
},
|
|
1574
|
-
onMessage: (msg2) => this.handleMsg(msg2),
|
|
1575
|
-
onInvalidMessage: (reason) => {
|
|
1576
|
-
this.protocolError(ProtocolError.MessageOrderingViolated, reason);
|
|
1577
|
-
this.deleteSession(connectedSession);
|
|
1578
|
-
}
|
|
1579
|
-
}
|
|
1580
|
-
);
|
|
1581
|
-
this.sessionHandshakeMetadata.set(connectedSession.to, parsedMetadata);
|
|
1582
|
-
this.updateSession(connectedSession);
|
|
1583
|
-
this.pendingSessions.delete(session);
|
|
1584
|
-
connectedSession.startActiveHeartbeat();
|
|
1585
|
-
}
|
|
1586
|
-
async validateHandshakeMetadata(handshakingSession, existingSession, rawMetadata, from) {
|
|
1587
|
-
let parsedMetadata = {};
|
|
1588
|
-
if (this.handshakeExtensions) {
|
|
1589
|
-
if (!import_value2.Value.Check(this.handshakeExtensions.schema, rawMetadata)) {
|
|
1590
|
-
this.rejectHandshakeRequest(
|
|
1591
|
-
handshakingSession,
|
|
1592
|
-
from,
|
|
1593
|
-
"received malformed handshake metadata",
|
|
1594
|
-
"MALFORMED_HANDSHAKE_META",
|
|
1595
|
-
{
|
|
1596
|
-
...handshakingSession.loggingMetadata,
|
|
1597
|
-
connectedTo: from,
|
|
1598
|
-
validationErrors: [
|
|
1599
|
-
...import_value2.Value.Errors(this.handshakeExtensions.schema, rawMetadata)
|
|
1600
|
-
]
|
|
1601
|
-
}
|
|
1602
|
-
);
|
|
1603
|
-
return false;
|
|
1604
|
-
}
|
|
1605
|
-
const previousParsedMetadata = existingSession ? this.sessionHandshakeMetadata.get(existingSession.to) : void 0;
|
|
1606
|
-
parsedMetadata = await this.handshakeExtensions.validate(
|
|
1607
|
-
rawMetadata,
|
|
1608
|
-
previousParsedMetadata
|
|
1609
|
-
);
|
|
1610
|
-
if (parsedMetadata === false) {
|
|
1611
|
-
this.rejectHandshakeRequest(
|
|
1612
|
-
handshakingSession,
|
|
1613
|
-
from,
|
|
1614
|
-
"rejected by handshake handler",
|
|
1615
|
-
"REJECTED_BY_CUSTOM_HANDLER",
|
|
1616
|
-
{
|
|
1617
|
-
...handshakingSession.loggingMetadata,
|
|
1618
|
-
connectedTo: from,
|
|
1619
|
-
clientId: this.clientId
|
|
1620
|
-
}
|
|
1621
|
-
);
|
|
1622
|
-
return false;
|
|
1623
|
-
}
|
|
1624
|
-
}
|
|
1625
|
-
return parsedMetadata;
|
|
1626
|
-
}
|
|
1627
|
-
};
|
|
1628
|
-
|
|
1629
|
-
// transport/impls/uds/server.ts
|
|
1630
|
-
var UnixDomainSocketServerTransport = class extends ServerTransport {
|
|
1631
|
-
server;
|
|
1632
|
-
constructor(server, clientId, providedOptions) {
|
|
1633
|
-
super(clientId, providedOptions);
|
|
1634
|
-
this.server = server;
|
|
1635
|
-
server.addListener("connection", this.connectionHandler);
|
|
1636
|
-
}
|
|
1637
|
-
connectionHandler = (sock) => {
|
|
1638
|
-
const conn = new UdsConnection(sock);
|
|
1639
|
-
this.handleConnection(conn);
|
|
1640
|
-
};
|
|
1641
|
-
close() {
|
|
1642
|
-
super.close();
|
|
1643
|
-
this.server.removeListener("connection", this.connectionHandler);
|
|
1644
|
-
}
|
|
1645
|
-
};
|
|
1646
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
1647
|
-
0 && (module.exports = {
|
|
1648
|
-
UnixDomainSocketServerTransport
|
|
1649
|
-
});
|
|
1650
|
-
//# sourceMappingURL=server.cjs.map
|