@replit/river 0.200.5 → 0.201.0
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-Z7Q5CDXD.js → chunk-52DVJUVZ.js} +2 -2
- package/dist/{chunk-64J442AK.js → chunk-7IUEEQP7.js} +10 -10
- package/dist/chunk-7IUEEQP7.js.map +1 -0
- package/dist/{chunk-WN7GEBMX.js → chunk-OZ3ITXW5.js} +5 -7
- package/dist/chunk-OZ3ITXW5.js.map +1 -0
- package/dist/{chunk-3FMY7VTM.js → chunk-PJ4GJ5CU.js} +332 -3
- package/dist/chunk-PJ4GJ5CU.js.map +1 -0
- package/dist/{chunk-MSJGPQRT.js → chunk-UBUD2LMZ.js} +4 -6
- package/dist/chunk-UBUD2LMZ.js.map +1 -0
- package/dist/{client-ba6815ae.d.ts → client-a32692b0.d.ts} +2 -2
- package/dist/{connection-d217c989.d.ts → connection-48d021ca.d.ts} +2 -2
- package/dist/{context-8d1ed9a1.d.ts → context-8d263a7f.d.ts} +2 -2
- package/dist/logging/index.d.cts +1 -1
- package/dist/logging/index.d.ts +1 -1
- package/dist/{message-45658364.d.ts → message-3def9ded.d.ts} +1 -1
- package/dist/router/index.cjs +2 -2
- package/dist/router/index.cjs.map +1 -1
- package/dist/router/index.d.cts +8 -8
- package/dist/router/index.d.ts +8 -8
- package/dist/router/index.js +318 -40
- package/dist/router/index.js.map +1 -1
- package/dist/{server-eb7d2cfd.d.ts → server-48d90a77.d.ts} +2 -2
- package/dist/{services-94e0afc3.d.ts → services-e71ea921.d.ts} +4 -4
- package/dist/testUtil/index.cjs +2616 -0
- package/dist/testUtil/index.cjs.map +1 -0
- package/dist/{util/testHelpers.d.ts → testUtil/index.d.cts} +27 -18
- package/dist/{util/testHelpers.d.cts → testUtil/index.d.ts} +27 -18
- package/dist/testUtil/index.js +370 -0
- package/dist/testUtil/index.js.map +1 -0
- package/dist/transport/impls/ws/client.cjs +2 -2
- package/dist/transport/impls/ws/client.cjs.map +1 -1
- package/dist/transport/impls/ws/client.d.cts +4 -4
- package/dist/transport/impls/ws/client.d.ts +4 -4
- package/dist/transport/impls/ws/client.js +4 -5
- package/dist/transport/impls/ws/client.js.map +1 -1
- package/dist/transport/impls/ws/server.cjs +2 -2
- package/dist/transport/impls/ws/server.cjs.map +1 -1
- package/dist/transport/impls/ws/server.d.cts +4 -4
- package/dist/transport/impls/ws/server.d.ts +4 -4
- package/dist/transport/impls/ws/server.js +4 -5
- package/dist/transport/impls/ws/server.js.map +1 -1
- package/dist/transport/index.cjs +2 -2
- package/dist/transport/index.cjs.map +1 -1
- package/dist/transport/index.d.cts +4 -4
- package/dist/transport/index.d.ts +4 -4
- package/dist/transport/index.js +6 -8
- package/package.json +3 -3
- package/dist/chunk-3FMY7VTM.js.map +0 -1
- package/dist/chunk-64J442AK.js.map +0 -1
- package/dist/chunk-7Z5MSOKL.js +0 -340
- package/dist/chunk-7Z5MSOKL.js.map +0 -1
- package/dist/chunk-MSJGPQRT.js.map +0 -1
- package/dist/chunk-WN7GEBMX.js.map +0 -1
- package/dist/chunk-ZVWJN6V2.js +0 -307
- package/dist/chunk-ZVWJN6V2.js.map +0 -1
- package/dist/util/testHelpers.cjs +0 -1563
- package/dist/util/testHelpers.cjs.map +0 -1
- package/dist/util/testHelpers.js +0 -250
- package/dist/util/testHelpers.js.map +0 -1
- /package/dist/{chunk-Z7Q5CDXD.js.map → chunk-52DVJUVZ.js.map} +0 -0
|
@@ -1,1563 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
|
|
30
|
-
// util/testHelpers.ts
|
|
31
|
-
var testHelpers_exports = {};
|
|
32
|
-
__export(testHelpers_exports, {
|
|
33
|
-
asClientRpc: () => asClientRpc,
|
|
34
|
-
asClientStream: () => asClientStream,
|
|
35
|
-
asClientSubscription: () => asClientSubscription,
|
|
36
|
-
asClientUpload: () => asClientUpload,
|
|
37
|
-
closeAllConnections: () => closeAllConnections,
|
|
38
|
-
createDummyTransportMessage: () => createDummyTransportMessage,
|
|
39
|
-
createLocalWebSocketClient: () => createLocalWebSocketClient,
|
|
40
|
-
createWebSocketServer: () => createWebSocketServer,
|
|
41
|
-
dummySession: () => dummySession,
|
|
42
|
-
getClientSendFn: () => getClientSendFn,
|
|
43
|
-
getReadableIterator: () => getReadableIterator,
|
|
44
|
-
getServerSendFn: () => getServerSendFn,
|
|
45
|
-
getTransportConnections: () => getTransportConnections,
|
|
46
|
-
isReadableDone: () => isReadableDone,
|
|
47
|
-
numberOfConnections: () => numberOfConnections,
|
|
48
|
-
onWsServerReady: () => onWsServerReady,
|
|
49
|
-
payloadToTransportMessage: () => payloadToTransportMessage,
|
|
50
|
-
readNextResult: () => readNextResult,
|
|
51
|
-
testingClientSessionOptions: () => testingClientSessionOptions,
|
|
52
|
-
testingSessionOptions: () => testingSessionOptions,
|
|
53
|
-
waitForMessage: () => waitForMessage
|
|
54
|
-
});
|
|
55
|
-
module.exports = __toCommonJS(testHelpers_exports);
|
|
56
|
-
var import_ws = __toESM(require("ws"), 1);
|
|
57
|
-
|
|
58
|
-
// router/result.ts
|
|
59
|
-
var import_typebox = require("@sinclair/typebox");
|
|
60
|
-
var AnyResultSchema = import_typebox.Type.Union([
|
|
61
|
-
import_typebox.Type.Object({
|
|
62
|
-
ok: import_typebox.Type.Literal(false),
|
|
63
|
-
payload: import_typebox.Type.Object({
|
|
64
|
-
code: import_typebox.Type.String(),
|
|
65
|
-
message: import_typebox.Type.String(),
|
|
66
|
-
extras: import_typebox.Type.Optional(import_typebox.Type.Unknown())
|
|
67
|
-
})
|
|
68
|
-
}),
|
|
69
|
-
import_typebox.Type.Object({
|
|
70
|
-
ok: import_typebox.Type.Literal(true),
|
|
71
|
-
payload: import_typebox.Type.Unknown()
|
|
72
|
-
})
|
|
73
|
-
]);
|
|
74
|
-
function Ok(payload) {
|
|
75
|
-
return {
|
|
76
|
-
ok: true,
|
|
77
|
-
payload
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
function Err(error) {
|
|
81
|
-
return {
|
|
82
|
-
ok: false,
|
|
83
|
-
payload: error
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// transport/message.ts
|
|
88
|
-
var import_typebox2 = require("@sinclair/typebox");
|
|
89
|
-
|
|
90
|
-
// transport/id.ts
|
|
91
|
-
var import_nanoid = require("nanoid");
|
|
92
|
-
var alphabet = (0, import_nanoid.customAlphabet)(
|
|
93
|
-
"1234567890abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ"
|
|
94
|
-
);
|
|
95
|
-
var generateId = () => alphabet(12);
|
|
96
|
-
|
|
97
|
-
// transport/message.ts
|
|
98
|
-
var TransportMessageSchema = (t) => import_typebox2.Type.Object({
|
|
99
|
-
id: import_typebox2.Type.String(),
|
|
100
|
-
from: import_typebox2.Type.String(),
|
|
101
|
-
to: import_typebox2.Type.String(),
|
|
102
|
-
seq: import_typebox2.Type.Integer(),
|
|
103
|
-
ack: import_typebox2.Type.Integer(),
|
|
104
|
-
serviceName: import_typebox2.Type.Optional(import_typebox2.Type.String()),
|
|
105
|
-
procedureName: import_typebox2.Type.Optional(import_typebox2.Type.String()),
|
|
106
|
-
streamId: import_typebox2.Type.String(),
|
|
107
|
-
controlFlags: import_typebox2.Type.Integer(),
|
|
108
|
-
tracing: import_typebox2.Type.Optional(
|
|
109
|
-
import_typebox2.Type.Object({
|
|
110
|
-
traceparent: import_typebox2.Type.String(),
|
|
111
|
-
tracestate: import_typebox2.Type.String()
|
|
112
|
-
})
|
|
113
|
-
),
|
|
114
|
-
payload: t
|
|
115
|
-
});
|
|
116
|
-
var ControlMessageAckSchema = import_typebox2.Type.Object({
|
|
117
|
-
type: import_typebox2.Type.Literal("ACK")
|
|
118
|
-
});
|
|
119
|
-
var ControlMessageCloseSchema = import_typebox2.Type.Object({
|
|
120
|
-
type: import_typebox2.Type.Literal("CLOSE")
|
|
121
|
-
});
|
|
122
|
-
var currentProtocolVersion = "v2.0";
|
|
123
|
-
var ControlMessageHandshakeRequestSchema = import_typebox2.Type.Object({
|
|
124
|
-
type: import_typebox2.Type.Literal("HANDSHAKE_REQ"),
|
|
125
|
-
protocolVersion: import_typebox2.Type.String(),
|
|
126
|
-
sessionId: import_typebox2.Type.String(),
|
|
127
|
-
/**
|
|
128
|
-
* Specifies what the server's expected session state (from the pov of the client). This can be
|
|
129
|
-
* used by the server to know whether this is a new or a reestablished connection, and whether it
|
|
130
|
-
* is compatible with what it already has.
|
|
131
|
-
*/
|
|
132
|
-
expectedSessionState: import_typebox2.Type.Object({
|
|
133
|
-
// what the client expects the server to send next
|
|
134
|
-
nextExpectedSeq: import_typebox2.Type.Integer(),
|
|
135
|
-
nextSentSeq: import_typebox2.Type.Integer()
|
|
136
|
-
}),
|
|
137
|
-
metadata: import_typebox2.Type.Optional(import_typebox2.Type.Unknown())
|
|
138
|
-
});
|
|
139
|
-
var HandshakeErrorRetriableResponseCodes = import_typebox2.Type.Union([
|
|
140
|
-
import_typebox2.Type.Literal("SESSION_STATE_MISMATCH")
|
|
141
|
-
]);
|
|
142
|
-
var HandshakeErrorCustomHandlerFatalResponseCodes = import_typebox2.Type.Union([
|
|
143
|
-
// The custom validation handler rejected the handler because the client is unsupported.
|
|
144
|
-
import_typebox2.Type.Literal("REJECTED_UNSUPPORTED_CLIENT"),
|
|
145
|
-
// The custom validation handler rejected the handshake.
|
|
146
|
-
import_typebox2.Type.Literal("REJECTED_BY_CUSTOM_HANDLER")
|
|
147
|
-
]);
|
|
148
|
-
var HandshakeErrorFatalResponseCodes = import_typebox2.Type.Union([
|
|
149
|
-
HandshakeErrorCustomHandlerFatalResponseCodes,
|
|
150
|
-
// The ciient sent a handshake that doesn't comply with the extended handshake metadata.
|
|
151
|
-
import_typebox2.Type.Literal("MALFORMED_HANDSHAKE_META"),
|
|
152
|
-
// The ciient sent a handshake that doesn't comply with ControlMessageHandshakeRequestSchema.
|
|
153
|
-
import_typebox2.Type.Literal("MALFORMED_HANDSHAKE"),
|
|
154
|
-
// The client's protocol version does not match the server's.
|
|
155
|
-
import_typebox2.Type.Literal("PROTOCOL_VERSION_MISMATCH")
|
|
156
|
-
]);
|
|
157
|
-
var HandshakeErrorResponseCodes = import_typebox2.Type.Union([
|
|
158
|
-
HandshakeErrorRetriableResponseCodes,
|
|
159
|
-
HandshakeErrorFatalResponseCodes
|
|
160
|
-
]);
|
|
161
|
-
var ControlMessageHandshakeResponseSchema = import_typebox2.Type.Object({
|
|
162
|
-
type: import_typebox2.Type.Literal("HANDSHAKE_RESP"),
|
|
163
|
-
status: import_typebox2.Type.Union([
|
|
164
|
-
import_typebox2.Type.Object({
|
|
165
|
-
ok: import_typebox2.Type.Literal(true),
|
|
166
|
-
sessionId: import_typebox2.Type.String()
|
|
167
|
-
}),
|
|
168
|
-
import_typebox2.Type.Object({
|
|
169
|
-
ok: import_typebox2.Type.Literal(false),
|
|
170
|
-
reason: import_typebox2.Type.String(),
|
|
171
|
-
code: HandshakeErrorResponseCodes
|
|
172
|
-
})
|
|
173
|
-
])
|
|
174
|
-
});
|
|
175
|
-
var ControlMessagePayloadSchema = import_typebox2.Type.Union([
|
|
176
|
-
ControlMessageCloseSchema,
|
|
177
|
-
ControlMessageAckSchema,
|
|
178
|
-
ControlMessageHandshakeRequestSchema,
|
|
179
|
-
ControlMessageHandshakeResponseSchema
|
|
180
|
-
]);
|
|
181
|
-
var OpaqueTransportMessageSchema = TransportMessageSchema(
|
|
182
|
-
import_typebox2.Type.Unknown()
|
|
183
|
-
);
|
|
184
|
-
function isAck(controlFlag) {
|
|
185
|
-
return (controlFlag & 1 /* AckBit */) === 1 /* AckBit */;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// util/stringify.ts
|
|
189
|
-
function coerceErrorString(err) {
|
|
190
|
-
if (err instanceof Error) {
|
|
191
|
-
return err.message || "unknown reason";
|
|
192
|
-
}
|
|
193
|
-
return `[coerced to error] ${String(err)}`;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// router/streams.ts
|
|
197
|
-
var ReadableBrokenError = {
|
|
198
|
-
code: "READABLE_BROKEN",
|
|
199
|
-
message: "Readable was broken before it is fully consumed"
|
|
200
|
-
};
|
|
201
|
-
function createPromiseWithResolvers() {
|
|
202
|
-
let resolve;
|
|
203
|
-
let reject;
|
|
204
|
-
const promise = new Promise((res, rej) => {
|
|
205
|
-
resolve = res;
|
|
206
|
-
reject = rej;
|
|
207
|
-
});
|
|
208
|
-
return {
|
|
209
|
-
promise,
|
|
210
|
-
// @ts-expect-error promise callbacks are sync
|
|
211
|
-
resolve,
|
|
212
|
-
// @ts-expect-error promise callbacks are sync
|
|
213
|
-
reject
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
var ReadableImpl = class {
|
|
217
|
-
/**
|
|
218
|
-
* Whether the {@link Readable} is closed.
|
|
219
|
-
*
|
|
220
|
-
* Closed {@link Readable}s are done receiving values, but that doesn't affect
|
|
221
|
-
* any other aspect of the {@link Readable} such as it's consumability.
|
|
222
|
-
*/
|
|
223
|
-
closed = false;
|
|
224
|
-
/**
|
|
225
|
-
* Whether the {@link Readable} is locked.
|
|
226
|
-
*
|
|
227
|
-
* @see {@link Readable}'s typedoc to understand locking
|
|
228
|
-
*/
|
|
229
|
-
locked = false;
|
|
230
|
-
/**
|
|
231
|
-
* Whether {@link break} was called.
|
|
232
|
-
*
|
|
233
|
-
* @see {@link break} for more information
|
|
234
|
-
*/
|
|
235
|
-
broken = false;
|
|
236
|
-
/**
|
|
237
|
-
* This flag allows us to avoid emitting a {@link ReadableBrokenError} after {@link break} was called
|
|
238
|
-
* in cases where the {@link queue} is fully consumed and {@link ReadableImpl} is {@link closed}. This is just an
|
|
239
|
-
* ergonomic feature to avoid emitting an error in our iteration when we don't have to.
|
|
240
|
-
*/
|
|
241
|
-
brokenWithValuesLeftToRead = false;
|
|
242
|
-
/**
|
|
243
|
-
* A list of values that have been pushed to the {@link ReadableImpl} but not yet emitted to the user.
|
|
244
|
-
*/
|
|
245
|
-
queue = [];
|
|
246
|
-
/**
|
|
247
|
-
* Used by methods in the class to signal to the iterator that it
|
|
248
|
-
* should check for the next value.
|
|
249
|
-
*/
|
|
250
|
-
next = null;
|
|
251
|
-
[Symbol.asyncIterator]() {
|
|
252
|
-
if (this.locked) {
|
|
253
|
-
throw new TypeError("Readable is already locked");
|
|
254
|
-
}
|
|
255
|
-
this.locked = true;
|
|
256
|
-
let didSignalBreak = false;
|
|
257
|
-
return {
|
|
258
|
-
next: async () => {
|
|
259
|
-
if (didSignalBreak) {
|
|
260
|
-
return {
|
|
261
|
-
done: true,
|
|
262
|
-
value: void 0
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
while (this.queue.length === 0) {
|
|
266
|
-
if (this.closed && !this.brokenWithValuesLeftToRead) {
|
|
267
|
-
return {
|
|
268
|
-
done: true,
|
|
269
|
-
value: void 0
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
if (this.broken) {
|
|
273
|
-
didSignalBreak = true;
|
|
274
|
-
return {
|
|
275
|
-
done: false,
|
|
276
|
-
value: Err(ReadableBrokenError)
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
if (!this.next) {
|
|
280
|
-
this.next = createPromiseWithResolvers();
|
|
281
|
-
}
|
|
282
|
-
await this.next.promise;
|
|
283
|
-
this.next = null;
|
|
284
|
-
}
|
|
285
|
-
const value = this.queue.shift();
|
|
286
|
-
return { done: false, value };
|
|
287
|
-
},
|
|
288
|
-
return: () => {
|
|
289
|
-
this.break();
|
|
290
|
-
return { done: true, value: void 0 };
|
|
291
|
-
}
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
async collect() {
|
|
295
|
-
const array = [];
|
|
296
|
-
for await (const value of this) {
|
|
297
|
-
array.push(value);
|
|
298
|
-
}
|
|
299
|
-
return array;
|
|
300
|
-
}
|
|
301
|
-
break() {
|
|
302
|
-
if (this.broken) {
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
this.locked = true;
|
|
306
|
-
this.broken = true;
|
|
307
|
-
this.brokenWithValuesLeftToRead = this.queue.length > 0;
|
|
308
|
-
this.queue.length = 0;
|
|
309
|
-
this.next?.resolve();
|
|
310
|
-
}
|
|
311
|
-
isReadable() {
|
|
312
|
-
return !this.locked && !this.broken;
|
|
313
|
-
}
|
|
314
|
-
/**
|
|
315
|
-
* @internal meant for use within river, not exposed as a public API
|
|
316
|
-
*
|
|
317
|
-
* Pushes a value to be read.
|
|
318
|
-
*/
|
|
319
|
-
_pushValue(value) {
|
|
320
|
-
if (this.broken) {
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
if (this.closed) {
|
|
324
|
-
throw new Error("Cannot push to closed Readable");
|
|
325
|
-
}
|
|
326
|
-
this.queue.push(value);
|
|
327
|
-
this.next?.resolve();
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* @internal meant for use within river, not exposed as a public API
|
|
331
|
-
*
|
|
332
|
-
* Triggers the close of the {@link Readable}. Make sure to push all remaining
|
|
333
|
-
* values before calling this method.
|
|
334
|
-
*/
|
|
335
|
-
_triggerClose() {
|
|
336
|
-
if (this.closed) {
|
|
337
|
-
throw new Error("Unexpected closing multiple times");
|
|
338
|
-
}
|
|
339
|
-
this.closed = true;
|
|
340
|
-
this.next?.resolve();
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* @internal meant for use within river, not exposed as a public API
|
|
344
|
-
*/
|
|
345
|
-
_hasValuesInQueue() {
|
|
346
|
-
return this.queue.length > 0;
|
|
347
|
-
}
|
|
348
|
-
/**
|
|
349
|
-
* @internal meant for use within river, not exposed as a public API
|
|
350
|
-
*/
|
|
351
|
-
isClosed() {
|
|
352
|
-
return this.closed;
|
|
353
|
-
}
|
|
354
|
-
};
|
|
355
|
-
var WritableImpl = class {
|
|
356
|
-
/**
|
|
357
|
-
* Passed via constructor to pass on calls to {@link write}
|
|
358
|
-
*/
|
|
359
|
-
writeCb;
|
|
360
|
-
/**
|
|
361
|
-
* Passed via constructor to pass on calls to {@link close}
|
|
362
|
-
*/
|
|
363
|
-
closeCb;
|
|
364
|
-
/**
|
|
365
|
-
* Whether {@link close} was called, and {@link Writable} is not writable anymore.
|
|
366
|
-
*/
|
|
367
|
-
closed = false;
|
|
368
|
-
constructor(callbacks) {
|
|
369
|
-
this.writeCb = callbacks.writeCb;
|
|
370
|
-
this.closeCb = callbacks.closeCb;
|
|
371
|
-
}
|
|
372
|
-
write(value) {
|
|
373
|
-
if (this.closed) {
|
|
374
|
-
throw new Error("Cannot write to closed Writable");
|
|
375
|
-
}
|
|
376
|
-
this.writeCb(value);
|
|
377
|
-
}
|
|
378
|
-
isWritable() {
|
|
379
|
-
return !this.closed;
|
|
380
|
-
}
|
|
381
|
-
close() {
|
|
382
|
-
if (this.closed) {
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
this.closed = true;
|
|
386
|
-
this.writeCb = () => void 0;
|
|
387
|
-
this.closeCb();
|
|
388
|
-
this.closeCb = () => void 0;
|
|
389
|
-
}
|
|
390
|
-
/**
|
|
391
|
-
* @internal meant for use within river, not exposed as a public API
|
|
392
|
-
*/
|
|
393
|
-
isClosed() {
|
|
394
|
-
return this.closed;
|
|
395
|
-
}
|
|
396
|
-
};
|
|
397
|
-
|
|
398
|
-
// codec/json.ts
|
|
399
|
-
var encoder = new TextEncoder();
|
|
400
|
-
var decoder = new TextDecoder();
|
|
401
|
-
function uint8ArrayToBase64(uint8Array) {
|
|
402
|
-
let binary = "";
|
|
403
|
-
uint8Array.forEach((byte) => {
|
|
404
|
-
binary += String.fromCharCode(byte);
|
|
405
|
-
});
|
|
406
|
-
return btoa(binary);
|
|
407
|
-
}
|
|
408
|
-
function base64ToUint8Array(base64) {
|
|
409
|
-
const binaryString = atob(base64);
|
|
410
|
-
const uint8Array = new Uint8Array(binaryString.length);
|
|
411
|
-
for (let i = 0; i < binaryString.length; i++) {
|
|
412
|
-
uint8Array[i] = binaryString.charCodeAt(i);
|
|
413
|
-
}
|
|
414
|
-
return uint8Array;
|
|
415
|
-
}
|
|
416
|
-
var NaiveJsonCodec = {
|
|
417
|
-
toBuffer: (obj) => {
|
|
418
|
-
return encoder.encode(
|
|
419
|
-
JSON.stringify(obj, function replacer(key) {
|
|
420
|
-
const val = this[key];
|
|
421
|
-
if (val instanceof Uint8Array) {
|
|
422
|
-
return { $t: uint8ArrayToBase64(val) };
|
|
423
|
-
} else {
|
|
424
|
-
return val;
|
|
425
|
-
}
|
|
426
|
-
})
|
|
427
|
-
);
|
|
428
|
-
},
|
|
429
|
-
fromBuffer: (buff) => {
|
|
430
|
-
try {
|
|
431
|
-
const parsed = JSON.parse(
|
|
432
|
-
decoder.decode(buff),
|
|
433
|
-
function reviver(_key, val) {
|
|
434
|
-
if (val?.$t) {
|
|
435
|
-
return base64ToUint8Array(val.$t);
|
|
436
|
-
} else {
|
|
437
|
-
return val;
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
);
|
|
441
|
-
if (typeof parsed === "object")
|
|
442
|
-
return parsed;
|
|
443
|
-
return null;
|
|
444
|
-
} catch {
|
|
445
|
-
return null;
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
};
|
|
449
|
-
|
|
450
|
-
// transport/options.ts
|
|
451
|
-
var defaultTransportOptions = {
|
|
452
|
-
heartbeatIntervalMs: 1e3,
|
|
453
|
-
heartbeatsUntilDead: 2,
|
|
454
|
-
sessionDisconnectGraceMs: 5e3,
|
|
455
|
-
connectionTimeoutMs: 2e3,
|
|
456
|
-
handshakeTimeoutMs: 1e3,
|
|
457
|
-
enableTransparentSessionReconnects: true,
|
|
458
|
-
codec: NaiveJsonCodec
|
|
459
|
-
};
|
|
460
|
-
var defaultConnectionRetryOptions = {
|
|
461
|
-
baseIntervalMs: 150,
|
|
462
|
-
maxJitterMs: 200,
|
|
463
|
-
maxBackoffMs: 32e3,
|
|
464
|
-
attemptBudgetCapacity: 5,
|
|
465
|
-
budgetRestoreIntervalMs: 200
|
|
466
|
-
};
|
|
467
|
-
var defaultClientTransportOptions = {
|
|
468
|
-
...defaultTransportOptions,
|
|
469
|
-
...defaultConnectionRetryOptions
|
|
470
|
-
};
|
|
471
|
-
var defaultServerTransportOptions = {
|
|
472
|
-
...defaultTransportOptions
|
|
473
|
-
};
|
|
474
|
-
|
|
475
|
-
// transport/sessionStateMachine/common.ts
|
|
476
|
-
var import_value = require("@sinclair/typebox/value");
|
|
477
|
-
var ERR_CONSUMED = `session state has been consumed and is no longer valid`;
|
|
478
|
-
var StateMachineState = class {
|
|
479
|
-
/*
|
|
480
|
-
* Whether this state has been consumed
|
|
481
|
-
* and we've moved on to another state
|
|
482
|
-
*/
|
|
483
|
-
_isConsumed;
|
|
484
|
-
close() {
|
|
485
|
-
this._handleClose();
|
|
486
|
-
}
|
|
487
|
-
constructor() {
|
|
488
|
-
this._isConsumed = false;
|
|
489
|
-
return new Proxy(this, {
|
|
490
|
-
get(target, prop) {
|
|
491
|
-
if (prop === "_isConsumed" || prop === "id" || prop === "state") {
|
|
492
|
-
return Reflect.get(target, prop);
|
|
493
|
-
}
|
|
494
|
-
if (prop === "_handleStateExit") {
|
|
495
|
-
return () => {
|
|
496
|
-
target._isConsumed = true;
|
|
497
|
-
target._handleStateExit();
|
|
498
|
-
};
|
|
499
|
-
}
|
|
500
|
-
if (prop === "_handleClose") {
|
|
501
|
-
return () => {
|
|
502
|
-
target._isConsumed = true;
|
|
503
|
-
target._handleStateExit();
|
|
504
|
-
target._handleClose();
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
if (target._isConsumed) {
|
|
508
|
-
throw new Error(
|
|
509
|
-
`${ERR_CONSUMED}: getting ${prop.toString()} on consumed state`
|
|
510
|
-
);
|
|
511
|
-
}
|
|
512
|
-
return Reflect.get(target, prop);
|
|
513
|
-
},
|
|
514
|
-
set(target, prop, value) {
|
|
515
|
-
if (target._isConsumed) {
|
|
516
|
-
throw new Error(
|
|
517
|
-
`${ERR_CONSUMED}: setting ${prop.toString()} on consumed state`
|
|
518
|
-
);
|
|
519
|
-
}
|
|
520
|
-
return Reflect.set(target, prop, value);
|
|
521
|
-
}
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
};
|
|
525
|
-
var CommonSession = class extends StateMachineState {
|
|
526
|
-
from;
|
|
527
|
-
options;
|
|
528
|
-
log;
|
|
529
|
-
constructor({ from, options, log }) {
|
|
530
|
-
super();
|
|
531
|
-
this.from = from;
|
|
532
|
-
this.options = options;
|
|
533
|
-
this.log = log;
|
|
534
|
-
}
|
|
535
|
-
parseMsg(msg) {
|
|
536
|
-
const parsedMsg = this.options.codec.fromBuffer(msg);
|
|
537
|
-
if (parsedMsg === null) {
|
|
538
|
-
const decodedBuffer = new TextDecoder().decode(Buffer.from(msg));
|
|
539
|
-
this.log?.error(
|
|
540
|
-
`received malformed msg: ${decodedBuffer}`,
|
|
541
|
-
this.loggingMetadata
|
|
542
|
-
);
|
|
543
|
-
return null;
|
|
544
|
-
}
|
|
545
|
-
if (!import_value.Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
|
|
546
|
-
this.log?.error(`received invalid msg: ${JSON.stringify(parsedMsg)}`, {
|
|
547
|
-
...this.loggingMetadata,
|
|
548
|
-
validationErrors: [
|
|
549
|
-
...import_value.Value.Errors(OpaqueTransportMessageSchema, parsedMsg)
|
|
550
|
-
]
|
|
551
|
-
});
|
|
552
|
-
return null;
|
|
553
|
-
}
|
|
554
|
-
return parsedMsg;
|
|
555
|
-
}
|
|
556
|
-
};
|
|
557
|
-
var IdentifiedSession = class extends CommonSession {
|
|
558
|
-
id;
|
|
559
|
-
telemetry;
|
|
560
|
-
to;
|
|
561
|
-
protocolVersion;
|
|
562
|
-
/**
|
|
563
|
-
* Index of the message we will send next (excluding handshake)
|
|
564
|
-
*/
|
|
565
|
-
seq;
|
|
566
|
-
/**
|
|
567
|
-
* Number of unique messages we've received this session (excluding handshake)
|
|
568
|
-
*/
|
|
569
|
-
ack;
|
|
570
|
-
sendBuffer;
|
|
571
|
-
constructor(props) {
|
|
572
|
-
const { id, to, seq, ack, sendBuffer, telemetry, log, protocolVersion } = props;
|
|
573
|
-
super(props);
|
|
574
|
-
this.id = id;
|
|
575
|
-
this.to = to;
|
|
576
|
-
this.seq = seq;
|
|
577
|
-
this.ack = ack;
|
|
578
|
-
this.sendBuffer = sendBuffer;
|
|
579
|
-
this.telemetry = telemetry;
|
|
580
|
-
this.log = log;
|
|
581
|
-
this.protocolVersion = protocolVersion;
|
|
582
|
-
}
|
|
583
|
-
get loggingMetadata() {
|
|
584
|
-
const spanContext = this.telemetry.span.spanContext();
|
|
585
|
-
const metadata = {
|
|
586
|
-
clientId: this.from,
|
|
587
|
-
connectedTo: this.to,
|
|
588
|
-
sessionId: this.id
|
|
589
|
-
};
|
|
590
|
-
if (this.telemetry.span.isRecording()) {
|
|
591
|
-
metadata.telemetry = {
|
|
592
|
-
traceId: spanContext.traceId,
|
|
593
|
-
spanId: spanContext.spanId
|
|
594
|
-
};
|
|
595
|
-
}
|
|
596
|
-
return metadata;
|
|
597
|
-
}
|
|
598
|
-
constructMsg(partialMsg) {
|
|
599
|
-
const msg = {
|
|
600
|
-
...partialMsg,
|
|
601
|
-
id: generateId(),
|
|
602
|
-
to: this.to,
|
|
603
|
-
from: this.from,
|
|
604
|
-
seq: this.seq,
|
|
605
|
-
ack: this.ack
|
|
606
|
-
};
|
|
607
|
-
this.seq++;
|
|
608
|
-
return msg;
|
|
609
|
-
}
|
|
610
|
-
nextSeq() {
|
|
611
|
-
return this.sendBuffer.length > 0 ? this.sendBuffer[0].seq : this.seq;
|
|
612
|
-
}
|
|
613
|
-
send(msg) {
|
|
614
|
-
const constructedMsg = this.constructMsg(msg);
|
|
615
|
-
this.sendBuffer.push(constructedMsg);
|
|
616
|
-
return constructedMsg.id;
|
|
617
|
-
}
|
|
618
|
-
_handleStateExit() {
|
|
619
|
-
}
|
|
620
|
-
_handleClose() {
|
|
621
|
-
this.sendBuffer.length = 0;
|
|
622
|
-
this.telemetry.span.end();
|
|
623
|
-
}
|
|
624
|
-
};
|
|
625
|
-
var IdentifiedSessionWithGracePeriod = class extends IdentifiedSession {
|
|
626
|
-
graceExpiryTime;
|
|
627
|
-
gracePeriodTimeout;
|
|
628
|
-
listeners;
|
|
629
|
-
constructor(props) {
|
|
630
|
-
super(props);
|
|
631
|
-
this.listeners = props.listeners;
|
|
632
|
-
this.graceExpiryTime = props.graceExpiryTime;
|
|
633
|
-
this.gracePeriodTimeout = setTimeout(() => {
|
|
634
|
-
this.listeners.onSessionGracePeriodElapsed();
|
|
635
|
-
}, this.graceExpiryTime - Date.now());
|
|
636
|
-
}
|
|
637
|
-
_handleStateExit() {
|
|
638
|
-
super._handleStateExit();
|
|
639
|
-
if (this.gracePeriodTimeout) {
|
|
640
|
-
clearTimeout(this.gracePeriodTimeout);
|
|
641
|
-
this.gracePeriodTimeout = void 0;
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
_handleClose() {
|
|
645
|
-
super._handleClose();
|
|
646
|
-
}
|
|
647
|
-
};
|
|
648
|
-
|
|
649
|
-
// transport/sessionStateMachine/SessionConnecting.ts
|
|
650
|
-
var SessionConnecting = class extends IdentifiedSessionWithGracePeriod {
|
|
651
|
-
state = "Connecting" /* Connecting */;
|
|
652
|
-
connPromise;
|
|
653
|
-
listeners;
|
|
654
|
-
connectionTimeout;
|
|
655
|
-
constructor(props) {
|
|
656
|
-
super(props);
|
|
657
|
-
this.connPromise = props.connPromise;
|
|
658
|
-
this.listeners = props.listeners;
|
|
659
|
-
this.connPromise.then(
|
|
660
|
-
(conn) => {
|
|
661
|
-
if (this._isConsumed)
|
|
662
|
-
return;
|
|
663
|
-
this.listeners.onConnectionEstablished(conn);
|
|
664
|
-
},
|
|
665
|
-
(err) => {
|
|
666
|
-
if (this._isConsumed)
|
|
667
|
-
return;
|
|
668
|
-
this.listeners.onConnectionFailed(err);
|
|
669
|
-
}
|
|
670
|
-
);
|
|
671
|
-
this.connectionTimeout = setTimeout(() => {
|
|
672
|
-
this.listeners.onConnectionTimeout();
|
|
673
|
-
}, this.options.connectionTimeoutMs);
|
|
674
|
-
}
|
|
675
|
-
// close a pending connection if it resolves, ignore errors if the promise
|
|
676
|
-
// ends up rejected anyways
|
|
677
|
-
bestEffortClose() {
|
|
678
|
-
const logger = this.log;
|
|
679
|
-
const metadata = this.loggingMetadata;
|
|
680
|
-
this.connPromise.then((conn) => {
|
|
681
|
-
conn.close();
|
|
682
|
-
logger?.info(
|
|
683
|
-
"connection eventually resolved but session has transitioned, closed connection",
|
|
684
|
-
{
|
|
685
|
-
...metadata,
|
|
686
|
-
...conn.loggingMetadata
|
|
687
|
-
}
|
|
688
|
-
);
|
|
689
|
-
}).catch(() => {
|
|
690
|
-
});
|
|
691
|
-
}
|
|
692
|
-
_handleStateExit() {
|
|
693
|
-
super._handleStateExit();
|
|
694
|
-
if (this.connectionTimeout) {
|
|
695
|
-
clearTimeout(this.connectionTimeout);
|
|
696
|
-
this.connectionTimeout = void 0;
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
_handleClose() {
|
|
700
|
-
this.bestEffortClose();
|
|
701
|
-
super._handleClose();
|
|
702
|
-
}
|
|
703
|
-
};
|
|
704
|
-
|
|
705
|
-
// transport/sessionStateMachine/SessionNoConnection.ts
|
|
706
|
-
var SessionNoConnection = class extends IdentifiedSessionWithGracePeriod {
|
|
707
|
-
state = "NoConnection" /* NoConnection */;
|
|
708
|
-
_handleClose() {
|
|
709
|
-
super._handleClose();
|
|
710
|
-
}
|
|
711
|
-
_handleStateExit() {
|
|
712
|
-
super._handleStateExit();
|
|
713
|
-
}
|
|
714
|
-
};
|
|
715
|
-
|
|
716
|
-
// tracing/index.ts
|
|
717
|
-
var import_api = require("@opentelemetry/api");
|
|
718
|
-
|
|
719
|
-
// package.json
|
|
720
|
-
var version = "0.200.5";
|
|
721
|
-
|
|
722
|
-
// tracing/index.ts
|
|
723
|
-
function createSessionTelemetryInfo(sessionId, to, from, propagationCtx) {
|
|
724
|
-
const parentCtx = propagationCtx ? import_api.propagation.extract(import_api.context.active(), propagationCtx) : import_api.context.active();
|
|
725
|
-
const span = tracer.startSpan(
|
|
726
|
-
`session ${sessionId}`,
|
|
727
|
-
{
|
|
728
|
-
attributes: {
|
|
729
|
-
component: "river",
|
|
730
|
-
"river.session.id": sessionId,
|
|
731
|
-
"river.session.to": to,
|
|
732
|
-
"river.session.from": from
|
|
733
|
-
}
|
|
734
|
-
},
|
|
735
|
-
parentCtx
|
|
736
|
-
);
|
|
737
|
-
const ctx = import_api.trace.setSpan(parentCtx, span);
|
|
738
|
-
return { span, ctx };
|
|
739
|
-
}
|
|
740
|
-
var tracer = import_api.trace.getTracer("river", version);
|
|
741
|
-
|
|
742
|
-
// transport/sessionStateMachine/SessionWaitingForHandshake.ts
|
|
743
|
-
var SessionWaitingForHandshake = class extends CommonSession {
|
|
744
|
-
state = "WaitingForHandshake" /* WaitingForHandshake */;
|
|
745
|
-
conn;
|
|
746
|
-
listeners;
|
|
747
|
-
handshakeTimeout;
|
|
748
|
-
constructor(props) {
|
|
749
|
-
super(props);
|
|
750
|
-
this.conn = props.conn;
|
|
751
|
-
this.listeners = props.listeners;
|
|
752
|
-
this.handshakeTimeout = setTimeout(() => {
|
|
753
|
-
this.listeners.onHandshakeTimeout();
|
|
754
|
-
}, this.options.handshakeTimeoutMs);
|
|
755
|
-
this.conn.addDataListener(this.onHandshakeData);
|
|
756
|
-
this.conn.addErrorListener(this.listeners.onConnectionErrored);
|
|
757
|
-
this.conn.addCloseListener(this.listeners.onConnectionClosed);
|
|
758
|
-
}
|
|
759
|
-
get loggingMetadata() {
|
|
760
|
-
return {
|
|
761
|
-
clientId: this.from,
|
|
762
|
-
connId: this.conn.id,
|
|
763
|
-
...this.conn.loggingMetadata
|
|
764
|
-
};
|
|
765
|
-
}
|
|
766
|
-
onHandshakeData = (msg) => {
|
|
767
|
-
const parsedMsg = this.parseMsg(msg);
|
|
768
|
-
if (parsedMsg === null) {
|
|
769
|
-
this.listeners.onInvalidHandshake(
|
|
770
|
-
"could not parse message",
|
|
771
|
-
"MALFORMED_HANDSHAKE"
|
|
772
|
-
);
|
|
773
|
-
return;
|
|
774
|
-
}
|
|
775
|
-
this.listeners.onHandshake(parsedMsg);
|
|
776
|
-
};
|
|
777
|
-
sendHandshake(msg) {
|
|
778
|
-
return this.conn.send(this.options.codec.toBuffer(msg));
|
|
779
|
-
}
|
|
780
|
-
_handleStateExit() {
|
|
781
|
-
this.conn.removeDataListener(this.onHandshakeData);
|
|
782
|
-
this.conn.removeErrorListener(this.listeners.onConnectionErrored);
|
|
783
|
-
this.conn.removeCloseListener(this.listeners.onConnectionClosed);
|
|
784
|
-
clearTimeout(this.handshakeTimeout);
|
|
785
|
-
this.handshakeTimeout = void 0;
|
|
786
|
-
}
|
|
787
|
-
_handleClose() {
|
|
788
|
-
this.conn.close();
|
|
789
|
-
}
|
|
790
|
-
};
|
|
791
|
-
|
|
792
|
-
// transport/sessionStateMachine/SessionHandshaking.ts
|
|
793
|
-
var SessionHandshaking = class extends IdentifiedSessionWithGracePeriod {
|
|
794
|
-
state = "Handshaking" /* Handshaking */;
|
|
795
|
-
conn;
|
|
796
|
-
listeners;
|
|
797
|
-
handshakeTimeout;
|
|
798
|
-
constructor(props) {
|
|
799
|
-
super(props);
|
|
800
|
-
this.conn = props.conn;
|
|
801
|
-
this.listeners = props.listeners;
|
|
802
|
-
this.handshakeTimeout = setTimeout(() => {
|
|
803
|
-
this.listeners.onHandshakeTimeout();
|
|
804
|
-
}, this.options.handshakeTimeoutMs);
|
|
805
|
-
this.conn.addDataListener(this.onHandshakeData);
|
|
806
|
-
this.conn.addErrorListener(this.listeners.onConnectionErrored);
|
|
807
|
-
this.conn.addCloseListener(this.listeners.onConnectionClosed);
|
|
808
|
-
}
|
|
809
|
-
get loggingMetadata() {
|
|
810
|
-
return {
|
|
811
|
-
...super.loggingMetadata,
|
|
812
|
-
...this.conn.loggingMetadata
|
|
813
|
-
};
|
|
814
|
-
}
|
|
815
|
-
onHandshakeData = (msg) => {
|
|
816
|
-
const parsedMsg = this.parseMsg(msg);
|
|
817
|
-
if (parsedMsg === null) {
|
|
818
|
-
this.listeners.onInvalidHandshake(
|
|
819
|
-
"could not parse message",
|
|
820
|
-
"MALFORMED_HANDSHAKE"
|
|
821
|
-
);
|
|
822
|
-
return;
|
|
823
|
-
}
|
|
824
|
-
this.listeners.onHandshake(parsedMsg);
|
|
825
|
-
};
|
|
826
|
-
sendHandshake(msg) {
|
|
827
|
-
return this.conn.send(this.options.codec.toBuffer(msg));
|
|
828
|
-
}
|
|
829
|
-
_handleStateExit() {
|
|
830
|
-
super._handleStateExit();
|
|
831
|
-
this.conn.removeDataListener(this.onHandshakeData);
|
|
832
|
-
this.conn.removeErrorListener(this.listeners.onConnectionErrored);
|
|
833
|
-
this.conn.removeCloseListener(this.listeners.onConnectionClosed);
|
|
834
|
-
if (this.handshakeTimeout) {
|
|
835
|
-
clearTimeout(this.handshakeTimeout);
|
|
836
|
-
this.handshakeTimeout = void 0;
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
_handleClose() {
|
|
840
|
-
super._handleClose();
|
|
841
|
-
this.conn.close();
|
|
842
|
-
}
|
|
843
|
-
};
|
|
844
|
-
|
|
845
|
-
// transport/sessionStateMachine/SessionConnected.ts
|
|
846
|
-
var import_api2 = require("@opentelemetry/api");
|
|
847
|
-
var SessionConnected = class extends IdentifiedSession {
|
|
848
|
-
state = "Connected" /* Connected */;
|
|
849
|
-
conn;
|
|
850
|
-
listeners;
|
|
851
|
-
heartbeatHandle;
|
|
852
|
-
heartbeatMisses = 0;
|
|
853
|
-
isActivelyHeartbeating;
|
|
854
|
-
updateBookkeeping(ack, seq) {
|
|
855
|
-
this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq >= ack);
|
|
856
|
-
this.ack = seq + 1;
|
|
857
|
-
this.heartbeatMisses = 0;
|
|
858
|
-
}
|
|
859
|
-
send(msg) {
|
|
860
|
-
const constructedMsg = this.constructMsg(msg);
|
|
861
|
-
this.sendBuffer.push(constructedMsg);
|
|
862
|
-
this.conn.send(this.options.codec.toBuffer(constructedMsg));
|
|
863
|
-
return constructedMsg.id;
|
|
864
|
-
}
|
|
865
|
-
constructor(props) {
|
|
866
|
-
super(props);
|
|
867
|
-
this.conn = props.conn;
|
|
868
|
-
this.listeners = props.listeners;
|
|
869
|
-
this.conn.addDataListener(this.onMessageData);
|
|
870
|
-
this.conn.addCloseListener(this.listeners.onConnectionClosed);
|
|
871
|
-
this.conn.addErrorListener(this.listeners.onConnectionErrored);
|
|
872
|
-
if (this.sendBuffer.length > 0) {
|
|
873
|
-
this.log?.info(
|
|
874
|
-
`sending ${this.sendBuffer.length} buffered messages, starting at seq ${this.nextSeq()}`,
|
|
875
|
-
this.loggingMetadata
|
|
876
|
-
);
|
|
877
|
-
for (const msg of this.sendBuffer) {
|
|
878
|
-
this.conn.send(this.options.codec.toBuffer(msg));
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
this.isActivelyHeartbeating = false;
|
|
882
|
-
this.heartbeatHandle = setInterval(() => {
|
|
883
|
-
const misses = this.heartbeatMisses;
|
|
884
|
-
const missDuration = misses * this.options.heartbeatIntervalMs;
|
|
885
|
-
if (misses >= this.options.heartbeatsUntilDead) {
|
|
886
|
-
this.log?.info(
|
|
887
|
-
`closing connection to ${this.to} due to inactivity (missed ${misses} heartbeats which is ${missDuration}ms)`,
|
|
888
|
-
this.loggingMetadata
|
|
889
|
-
);
|
|
890
|
-
this.telemetry.span.addEvent("closing connection due to inactivity");
|
|
891
|
-
this.conn.close();
|
|
892
|
-
clearInterval(this.heartbeatHandle);
|
|
893
|
-
this.heartbeatHandle = void 0;
|
|
894
|
-
return;
|
|
895
|
-
}
|
|
896
|
-
if (this.isActivelyHeartbeating) {
|
|
897
|
-
this.sendHeartbeat();
|
|
898
|
-
}
|
|
899
|
-
this.heartbeatMisses++;
|
|
900
|
-
}, this.options.heartbeatIntervalMs);
|
|
901
|
-
}
|
|
902
|
-
get loggingMetadata() {
|
|
903
|
-
return {
|
|
904
|
-
...super.loggingMetadata,
|
|
905
|
-
...this.conn.loggingMetadata
|
|
906
|
-
};
|
|
907
|
-
}
|
|
908
|
-
startActiveHeartbeat() {
|
|
909
|
-
this.isActivelyHeartbeating = true;
|
|
910
|
-
}
|
|
911
|
-
sendHeartbeat() {
|
|
912
|
-
this.log?.debug("sending heartbeat", this.loggingMetadata);
|
|
913
|
-
this.send({
|
|
914
|
-
streamId: "heartbeat",
|
|
915
|
-
controlFlags: 1 /* AckBit */,
|
|
916
|
-
payload: {
|
|
917
|
-
type: "ACK"
|
|
918
|
-
}
|
|
919
|
-
});
|
|
920
|
-
}
|
|
921
|
-
closeConnection() {
|
|
922
|
-
this.conn.removeDataListener(this.onMessageData);
|
|
923
|
-
this.conn.removeCloseListener(this.listeners.onConnectionClosed);
|
|
924
|
-
this.conn.removeErrorListener(this.listeners.onConnectionErrored);
|
|
925
|
-
this.conn.close();
|
|
926
|
-
}
|
|
927
|
-
onMessageData = (msg) => {
|
|
928
|
-
const parsedMsg = this.parseMsg(msg);
|
|
929
|
-
if (parsedMsg === null) {
|
|
930
|
-
this.listeners.onInvalidMessage("could not parse message");
|
|
931
|
-
return;
|
|
932
|
-
}
|
|
933
|
-
if (parsedMsg.seq !== this.ack) {
|
|
934
|
-
if (parsedMsg.seq < this.ack) {
|
|
935
|
-
this.log?.debug(
|
|
936
|
-
`received duplicate msg (got seq: ${parsedMsg.seq}, wanted seq: ${this.ack}), discarding`,
|
|
937
|
-
{
|
|
938
|
-
...this.loggingMetadata,
|
|
939
|
-
transportMessage: parsedMsg
|
|
940
|
-
}
|
|
941
|
-
);
|
|
942
|
-
} else {
|
|
943
|
-
const reason = `received out-of-order msg, closing connection (got seq: ${parsedMsg.seq}, wanted seq: ${this.ack})`;
|
|
944
|
-
this.log?.warn(reason, {
|
|
945
|
-
...this.loggingMetadata,
|
|
946
|
-
transportMessage: parsedMsg,
|
|
947
|
-
tags: ["invariant-violation"]
|
|
948
|
-
});
|
|
949
|
-
this.telemetry.span.setStatus({
|
|
950
|
-
code: import_api2.SpanStatusCode.ERROR,
|
|
951
|
-
message: reason
|
|
952
|
-
});
|
|
953
|
-
this.closeConnection();
|
|
954
|
-
}
|
|
955
|
-
return;
|
|
956
|
-
}
|
|
957
|
-
this.log?.debug(`received msg`, {
|
|
958
|
-
...this.loggingMetadata,
|
|
959
|
-
transportMessage: parsedMsg
|
|
960
|
-
});
|
|
961
|
-
this.updateBookkeeping(parsedMsg.ack, parsedMsg.seq);
|
|
962
|
-
if (!isAck(parsedMsg.controlFlags)) {
|
|
963
|
-
this.listeners.onMessage(parsedMsg);
|
|
964
|
-
return;
|
|
965
|
-
}
|
|
966
|
-
this.log?.debug(`discarding msg (ack bit set)`, {
|
|
967
|
-
...this.loggingMetadata,
|
|
968
|
-
transportMessage: parsedMsg
|
|
969
|
-
});
|
|
970
|
-
if (!this.isActivelyHeartbeating) {
|
|
971
|
-
this.sendHeartbeat();
|
|
972
|
-
}
|
|
973
|
-
};
|
|
974
|
-
_handleStateExit() {
|
|
975
|
-
super._handleStateExit();
|
|
976
|
-
this.conn.removeDataListener(this.onMessageData);
|
|
977
|
-
this.conn.removeCloseListener(this.listeners.onConnectionClosed);
|
|
978
|
-
this.conn.removeErrorListener(this.listeners.onConnectionErrored);
|
|
979
|
-
if (this.heartbeatHandle) {
|
|
980
|
-
clearInterval(this.heartbeatHandle);
|
|
981
|
-
this.heartbeatHandle = void 0;
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
_handleClose() {
|
|
985
|
-
super._handleClose();
|
|
986
|
-
this.conn.close();
|
|
987
|
-
}
|
|
988
|
-
};
|
|
989
|
-
|
|
990
|
-
// transport/sessionStateMachine/SessionBackingOff.ts
|
|
991
|
-
var SessionBackingOff = class extends IdentifiedSessionWithGracePeriod {
|
|
992
|
-
state = "BackingOff" /* BackingOff */;
|
|
993
|
-
listeners;
|
|
994
|
-
backoffTimeout;
|
|
995
|
-
constructor(props) {
|
|
996
|
-
super(props);
|
|
997
|
-
this.listeners = props.listeners;
|
|
998
|
-
this.backoffTimeout = setTimeout(() => {
|
|
999
|
-
this.listeners.onBackoffFinished();
|
|
1000
|
-
}, props.backoffMs);
|
|
1001
|
-
}
|
|
1002
|
-
_handleClose() {
|
|
1003
|
-
super._handleClose();
|
|
1004
|
-
}
|
|
1005
|
-
_handleStateExit() {
|
|
1006
|
-
super._handleStateExit();
|
|
1007
|
-
if (this.backoffTimeout) {
|
|
1008
|
-
clearTimeout(this.backoffTimeout);
|
|
1009
|
-
this.backoffTimeout = void 0;
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
};
|
|
1013
|
-
|
|
1014
|
-
// transport/sessionStateMachine/transitions.ts
|
|
1015
|
-
function inheritSharedSession(session) {
|
|
1016
|
-
return {
|
|
1017
|
-
id: session.id,
|
|
1018
|
-
from: session.from,
|
|
1019
|
-
to: session.to,
|
|
1020
|
-
seq: session.seq,
|
|
1021
|
-
ack: session.ack,
|
|
1022
|
-
sendBuffer: session.sendBuffer,
|
|
1023
|
-
telemetry: session.telemetry,
|
|
1024
|
-
options: session.options,
|
|
1025
|
-
log: session.log,
|
|
1026
|
-
protocolVersion: session.protocolVersion
|
|
1027
|
-
};
|
|
1028
|
-
}
|
|
1029
|
-
function inheritSharedSessionWithGrace(session) {
|
|
1030
|
-
return {
|
|
1031
|
-
...inheritSharedSession(session),
|
|
1032
|
-
graceExpiryTime: session.graceExpiryTime
|
|
1033
|
-
};
|
|
1034
|
-
}
|
|
1035
|
-
var SessionStateGraph = {
|
|
1036
|
-
entrypoints: {
|
|
1037
|
-
NoConnection: (to, from, listeners, options, protocolVersion, log) => {
|
|
1038
|
-
const id = `session-${generateId()}`;
|
|
1039
|
-
const telemetry = createSessionTelemetryInfo(id, to, from);
|
|
1040
|
-
const sendBuffer = [];
|
|
1041
|
-
const session = new SessionNoConnection({
|
|
1042
|
-
listeners,
|
|
1043
|
-
id,
|
|
1044
|
-
from,
|
|
1045
|
-
to,
|
|
1046
|
-
seq: 0,
|
|
1047
|
-
ack: 0,
|
|
1048
|
-
graceExpiryTime: Date.now() + options.sessionDisconnectGraceMs,
|
|
1049
|
-
sendBuffer,
|
|
1050
|
-
telemetry,
|
|
1051
|
-
options,
|
|
1052
|
-
protocolVersion,
|
|
1053
|
-
log
|
|
1054
|
-
});
|
|
1055
|
-
session.log?.info(`session ${session.id} created in NoConnection state`, {
|
|
1056
|
-
...session.loggingMetadata,
|
|
1057
|
-
tags: ["state-transition"]
|
|
1058
|
-
});
|
|
1059
|
-
return session;
|
|
1060
|
-
},
|
|
1061
|
-
WaitingForHandshake: (from, conn, listeners, options, log) => {
|
|
1062
|
-
const session = new SessionWaitingForHandshake({
|
|
1063
|
-
conn,
|
|
1064
|
-
listeners,
|
|
1065
|
-
from,
|
|
1066
|
-
options,
|
|
1067
|
-
log
|
|
1068
|
-
});
|
|
1069
|
-
session.log?.info(`session created in WaitingForHandshake state`, {
|
|
1070
|
-
...session.loggingMetadata,
|
|
1071
|
-
tags: ["state-transition"]
|
|
1072
|
-
});
|
|
1073
|
-
return session;
|
|
1074
|
-
}
|
|
1075
|
-
},
|
|
1076
|
-
// All of the transitions 'move'/'consume' the old session and return a new one.
|
|
1077
|
-
// After a session is transitioned, any usage of the old session will throw.
|
|
1078
|
-
transition: {
|
|
1079
|
-
// happy path transitions
|
|
1080
|
-
NoConnectionToBackingOff: (oldSession, backoffMs, listeners) => {
|
|
1081
|
-
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
1082
|
-
oldSession._handleStateExit();
|
|
1083
|
-
const session = new SessionBackingOff({
|
|
1084
|
-
backoffMs,
|
|
1085
|
-
listeners,
|
|
1086
|
-
...carriedState
|
|
1087
|
-
});
|
|
1088
|
-
session.log?.info(
|
|
1089
|
-
`session ${session.id} transition from NoConnection to BackingOff`,
|
|
1090
|
-
{
|
|
1091
|
-
...session.loggingMetadata,
|
|
1092
|
-
tags: ["state-transition"]
|
|
1093
|
-
}
|
|
1094
|
-
);
|
|
1095
|
-
return session;
|
|
1096
|
-
},
|
|
1097
|
-
BackingOffToConnecting: (oldSession, connPromise, listeners) => {
|
|
1098
|
-
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
1099
|
-
oldSession._handleStateExit();
|
|
1100
|
-
const session = new SessionConnecting({
|
|
1101
|
-
connPromise,
|
|
1102
|
-
listeners,
|
|
1103
|
-
...carriedState
|
|
1104
|
-
});
|
|
1105
|
-
session.log?.info(
|
|
1106
|
-
`session ${session.id} transition from BackingOff to Connecting`,
|
|
1107
|
-
{
|
|
1108
|
-
...session.loggingMetadata,
|
|
1109
|
-
tags: ["state-transition"]
|
|
1110
|
-
}
|
|
1111
|
-
);
|
|
1112
|
-
return session;
|
|
1113
|
-
},
|
|
1114
|
-
ConnectingToHandshaking: (oldSession, conn, listeners) => {
|
|
1115
|
-
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
1116
|
-
oldSession._handleStateExit();
|
|
1117
|
-
const session = new SessionHandshaking({
|
|
1118
|
-
conn,
|
|
1119
|
-
listeners,
|
|
1120
|
-
...carriedState
|
|
1121
|
-
});
|
|
1122
|
-
session.log?.info(
|
|
1123
|
-
`session ${session.id} transition from Connecting to Handshaking`,
|
|
1124
|
-
{
|
|
1125
|
-
...session.loggingMetadata,
|
|
1126
|
-
tags: ["state-transition"]
|
|
1127
|
-
}
|
|
1128
|
-
);
|
|
1129
|
-
return session;
|
|
1130
|
-
},
|
|
1131
|
-
HandshakingToConnected: (oldSession, listeners) => {
|
|
1132
|
-
const carriedState = inheritSharedSession(oldSession);
|
|
1133
|
-
const conn = oldSession.conn;
|
|
1134
|
-
oldSession._handleStateExit();
|
|
1135
|
-
const session = new SessionConnected({
|
|
1136
|
-
conn,
|
|
1137
|
-
listeners,
|
|
1138
|
-
...carriedState
|
|
1139
|
-
});
|
|
1140
|
-
session.log?.info(
|
|
1141
|
-
`session ${session.id} transition from Handshaking to Connected`,
|
|
1142
|
-
{
|
|
1143
|
-
...session.loggingMetadata,
|
|
1144
|
-
tags: ["state-transition"]
|
|
1145
|
-
}
|
|
1146
|
-
);
|
|
1147
|
-
return session;
|
|
1148
|
-
},
|
|
1149
|
-
WaitingForHandshakeToConnected: (pendingSession, oldSession, sessionId, to, propagationCtx, listeners, protocolVersion) => {
|
|
1150
|
-
const conn = pendingSession.conn;
|
|
1151
|
-
const { from, options } = pendingSession;
|
|
1152
|
-
const carriedState = oldSession ? (
|
|
1153
|
-
// old session exists, inherit state
|
|
1154
|
-
inheritSharedSession(oldSession)
|
|
1155
|
-
) : (
|
|
1156
|
-
// old session does not exist, create new state
|
|
1157
|
-
{
|
|
1158
|
-
id: sessionId,
|
|
1159
|
-
from,
|
|
1160
|
-
to,
|
|
1161
|
-
seq: 0,
|
|
1162
|
-
ack: 0,
|
|
1163
|
-
sendBuffer: [],
|
|
1164
|
-
telemetry: createSessionTelemetryInfo(
|
|
1165
|
-
sessionId,
|
|
1166
|
-
to,
|
|
1167
|
-
from,
|
|
1168
|
-
propagationCtx
|
|
1169
|
-
),
|
|
1170
|
-
options,
|
|
1171
|
-
log: pendingSession.log,
|
|
1172
|
-
protocolVersion
|
|
1173
|
-
}
|
|
1174
|
-
);
|
|
1175
|
-
pendingSession._handleStateExit();
|
|
1176
|
-
oldSession?._handleStateExit();
|
|
1177
|
-
const session = new SessionConnected({
|
|
1178
|
-
conn,
|
|
1179
|
-
listeners,
|
|
1180
|
-
...carriedState
|
|
1181
|
-
});
|
|
1182
|
-
session.log?.info(
|
|
1183
|
-
`session ${session.id} transition from WaitingForHandshake to Connected`,
|
|
1184
|
-
{
|
|
1185
|
-
...session.loggingMetadata,
|
|
1186
|
-
tags: ["state-transition"]
|
|
1187
|
-
}
|
|
1188
|
-
);
|
|
1189
|
-
return session;
|
|
1190
|
-
},
|
|
1191
|
-
// disconnect paths
|
|
1192
|
-
BackingOffToNoConnection: (oldSession, listeners) => {
|
|
1193
|
-
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
1194
|
-
oldSession._handleStateExit();
|
|
1195
|
-
const session = new SessionNoConnection({
|
|
1196
|
-
listeners,
|
|
1197
|
-
...carriedState
|
|
1198
|
-
});
|
|
1199
|
-
session.log?.info(
|
|
1200
|
-
`session ${session.id} transition from BackingOff to NoConnection`,
|
|
1201
|
-
{
|
|
1202
|
-
...session.loggingMetadata,
|
|
1203
|
-
tags: ["state-transition"]
|
|
1204
|
-
}
|
|
1205
|
-
);
|
|
1206
|
-
return session;
|
|
1207
|
-
},
|
|
1208
|
-
ConnectingToNoConnection: (oldSession, listeners) => {
|
|
1209
|
-
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
1210
|
-
oldSession.bestEffortClose();
|
|
1211
|
-
oldSession._handleStateExit();
|
|
1212
|
-
const session = new SessionNoConnection({
|
|
1213
|
-
listeners,
|
|
1214
|
-
...carriedState
|
|
1215
|
-
});
|
|
1216
|
-
session.log?.info(
|
|
1217
|
-
`session ${session.id} transition from Connecting to NoConnection`,
|
|
1218
|
-
{
|
|
1219
|
-
...session.loggingMetadata,
|
|
1220
|
-
tags: ["state-transition"]
|
|
1221
|
-
}
|
|
1222
|
-
);
|
|
1223
|
-
return session;
|
|
1224
|
-
},
|
|
1225
|
-
HandshakingToNoConnection: (oldSession, listeners) => {
|
|
1226
|
-
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
1227
|
-
oldSession.conn.close();
|
|
1228
|
-
oldSession._handleStateExit();
|
|
1229
|
-
const session = new SessionNoConnection({
|
|
1230
|
-
listeners,
|
|
1231
|
-
...carriedState
|
|
1232
|
-
});
|
|
1233
|
-
session.log?.info(
|
|
1234
|
-
`session ${session.id} transition from Handshaking to NoConnection`,
|
|
1235
|
-
{
|
|
1236
|
-
...session.loggingMetadata,
|
|
1237
|
-
tags: ["state-transition"]
|
|
1238
|
-
}
|
|
1239
|
-
);
|
|
1240
|
-
return session;
|
|
1241
|
-
},
|
|
1242
|
-
ConnectedToNoConnection: (oldSession, listeners) => {
|
|
1243
|
-
const carriedState = inheritSharedSession(oldSession);
|
|
1244
|
-
const graceExpiryTime = Date.now() + oldSession.options.sessionDisconnectGraceMs;
|
|
1245
|
-
oldSession.conn.close();
|
|
1246
|
-
oldSession._handleStateExit();
|
|
1247
|
-
const session = new SessionNoConnection({
|
|
1248
|
-
listeners,
|
|
1249
|
-
graceExpiryTime,
|
|
1250
|
-
...carriedState
|
|
1251
|
-
});
|
|
1252
|
-
session.log?.info(
|
|
1253
|
-
`session ${session.id} transition from Connected to NoConnection`,
|
|
1254
|
-
{
|
|
1255
|
-
...session.loggingMetadata,
|
|
1256
|
-
tags: ["state-transition"]
|
|
1257
|
-
}
|
|
1258
|
-
);
|
|
1259
|
-
return session;
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1262
|
-
};
|
|
1263
|
-
var transitions = SessionStateGraph.transition;
|
|
1264
|
-
var ClientSessionStateGraph = {
|
|
1265
|
-
entrypoint: SessionStateGraph.entrypoints.NoConnection,
|
|
1266
|
-
transition: {
|
|
1267
|
-
// happy paths
|
|
1268
|
-
// NoConnection -> BackingOff: attempt to connect
|
|
1269
|
-
NoConnectionToBackingOff: transitions.NoConnectionToBackingOff,
|
|
1270
|
-
// BackingOff -> Connecting: backoff period elapsed, start connection
|
|
1271
|
-
BackingOffToConnecting: transitions.BackingOffToConnecting,
|
|
1272
|
-
// Connecting -> Handshaking: connection established, start handshake
|
|
1273
|
-
ConnectingToHandshaking: transitions.ConnectingToHandshaking,
|
|
1274
|
-
// Handshaking -> Connected: handshake complete, session ready
|
|
1275
|
-
HandshakingToConnected: transitions.HandshakingToConnected,
|
|
1276
|
-
// disconnect paths
|
|
1277
|
-
// BackingOff -> NoConnection: unused
|
|
1278
|
-
BackingOffToNoConnection: transitions.BackingOffToNoConnection,
|
|
1279
|
-
// Connecting -> NoConnection: connection failed or connection timeout
|
|
1280
|
-
ConnectingToNoConnection: transitions.ConnectingToNoConnection,
|
|
1281
|
-
// Handshaking -> NoConnection: connection closed or handshake timeout
|
|
1282
|
-
HandshakingToNoConnection: transitions.HandshakingToNoConnection,
|
|
1283
|
-
// Connected -> NoConnection: connection closed
|
|
1284
|
-
ConnectedToNoConnection: transitions.ConnectedToNoConnection
|
|
1285
|
-
// destroy/close paths
|
|
1286
|
-
// NoConnection -> x: grace period elapsed
|
|
1287
|
-
// BackingOff -> x: grace period elapsed
|
|
1288
|
-
// Connecting -> x: grace period elapsed
|
|
1289
|
-
// Handshaking -> x: grace period elapsed or invalid handshake message or handshake rejection
|
|
1290
|
-
// Connected -> x: grace period elapsed or invalid message
|
|
1291
|
-
}
|
|
1292
|
-
};
|
|
1293
|
-
var ServerSessionStateGraph = {
|
|
1294
|
-
entrypoint: SessionStateGraph.entrypoints.WaitingForHandshake,
|
|
1295
|
-
transition: {
|
|
1296
|
-
// happy paths
|
|
1297
|
-
// WaitingForHandshake -> Connected: handshake complete, session ready
|
|
1298
|
-
WaitingForHandshakeToConnected: transitions.WaitingForHandshakeToConnected,
|
|
1299
|
-
// disconnect paths
|
|
1300
|
-
// Connected -> NoConnection: connection closed
|
|
1301
|
-
ConnectedToNoConnection: transitions.ConnectedToNoConnection
|
|
1302
|
-
// destroy/close paths
|
|
1303
|
-
// WaitingForHandshake -> x: handshake timeout elapsed or invalid handshake message or handshake rejection or connection closed
|
|
1304
|
-
}
|
|
1305
|
-
};
|
|
1306
|
-
|
|
1307
|
-
// router/errors.ts
|
|
1308
|
-
var import_typebox3 = require("@sinclair/typebox");
|
|
1309
|
-
var UNCAUGHT_ERROR_CODE = "UNCAUGHT_ERROR";
|
|
1310
|
-
var UNEXPECTED_DISCONNECT_CODE = "UNEXPECTED_DISCONNECT";
|
|
1311
|
-
var INVALID_REQUEST_CODE = "INVALID_REQUEST";
|
|
1312
|
-
var CANCEL_CODE = "CANCEL";
|
|
1313
|
-
var ReaderErrorSchema = import_typebox3.Type.Union([
|
|
1314
|
-
import_typebox3.Type.Object({
|
|
1315
|
-
code: import_typebox3.Type.Literal(UNCAUGHT_ERROR_CODE),
|
|
1316
|
-
message: import_typebox3.Type.String()
|
|
1317
|
-
}),
|
|
1318
|
-
import_typebox3.Type.Object({
|
|
1319
|
-
code: import_typebox3.Type.Literal(UNEXPECTED_DISCONNECT_CODE),
|
|
1320
|
-
message: import_typebox3.Type.String()
|
|
1321
|
-
}),
|
|
1322
|
-
import_typebox3.Type.Object({
|
|
1323
|
-
code: import_typebox3.Type.Literal(INVALID_REQUEST_CODE),
|
|
1324
|
-
message: import_typebox3.Type.String()
|
|
1325
|
-
}),
|
|
1326
|
-
import_typebox3.Type.Object({
|
|
1327
|
-
code: import_typebox3.Type.Literal(CANCEL_CODE),
|
|
1328
|
-
message: import_typebox3.Type.String()
|
|
1329
|
-
})
|
|
1330
|
-
]);
|
|
1331
|
-
|
|
1332
|
-
// util/testHelpers.ts
|
|
1333
|
-
function createLocalWebSocketClient(port) {
|
|
1334
|
-
const sock = new import_ws.default(`ws://localhost:${port}`);
|
|
1335
|
-
sock.binaryType = "arraybuffer";
|
|
1336
|
-
return sock;
|
|
1337
|
-
}
|
|
1338
|
-
function createWebSocketServer(server) {
|
|
1339
|
-
return new import_ws.WebSocketServer({ server });
|
|
1340
|
-
}
|
|
1341
|
-
function onWsServerReady(server) {
|
|
1342
|
-
return new Promise((resolve, reject) => {
|
|
1343
|
-
server.listen(() => {
|
|
1344
|
-
const addr = server.address();
|
|
1345
|
-
if (typeof addr === "object" && addr) {
|
|
1346
|
-
resolve(addr.port);
|
|
1347
|
-
} else {
|
|
1348
|
-
reject(new Error("couldn't find a port to allocate"));
|
|
1349
|
-
}
|
|
1350
|
-
});
|
|
1351
|
-
});
|
|
1352
|
-
}
|
|
1353
|
-
var readableIterators = /* @__PURE__ */ new WeakMap();
|
|
1354
|
-
function getReadableIterator(readable) {
|
|
1355
|
-
let iter = readableIterators.get(readable);
|
|
1356
|
-
if (!iter) {
|
|
1357
|
-
iter = readable[Symbol.asyncIterator]();
|
|
1358
|
-
readableIterators.set(readable, iter);
|
|
1359
|
-
}
|
|
1360
|
-
return iter;
|
|
1361
|
-
}
|
|
1362
|
-
async function readNextResult(readable) {
|
|
1363
|
-
const res = await getReadableIterator(readable).next();
|
|
1364
|
-
if (res.done) {
|
|
1365
|
-
throw new Error("readNext from a done Readable");
|
|
1366
|
-
}
|
|
1367
|
-
return res.value;
|
|
1368
|
-
}
|
|
1369
|
-
async function isReadableDone(readable) {
|
|
1370
|
-
const res = await getReadableIterator(readable).next();
|
|
1371
|
-
return res.done;
|
|
1372
|
-
}
|
|
1373
|
-
function payloadToTransportMessage(payload) {
|
|
1374
|
-
return {
|
|
1375
|
-
streamId: "stream",
|
|
1376
|
-
controlFlags: 0,
|
|
1377
|
-
payload
|
|
1378
|
-
};
|
|
1379
|
-
}
|
|
1380
|
-
function createDummyTransportMessage() {
|
|
1381
|
-
return payloadToTransportMessage({
|
|
1382
|
-
msg: "cool",
|
|
1383
|
-
test: Math.random()
|
|
1384
|
-
});
|
|
1385
|
-
}
|
|
1386
|
-
async function waitForMessage(t, filter, rejectMismatch) {
|
|
1387
|
-
return new Promise((resolve, reject) => {
|
|
1388
|
-
function cleanup() {
|
|
1389
|
-
t.removeEventListener("message", onMessage);
|
|
1390
|
-
}
|
|
1391
|
-
function onMessage(msg) {
|
|
1392
|
-
if (!filter || filter(msg)) {
|
|
1393
|
-
cleanup();
|
|
1394
|
-
resolve(msg.payload);
|
|
1395
|
-
} else if (rejectMismatch) {
|
|
1396
|
-
cleanup();
|
|
1397
|
-
reject(new Error("message didnt match the filter"));
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
t.addEventListener("message", onMessage);
|
|
1401
|
-
});
|
|
1402
|
-
}
|
|
1403
|
-
function catchProcError(err) {
|
|
1404
|
-
const errorMsg = coerceErrorString(err);
|
|
1405
|
-
return Err({ code: UNCAUGHT_ERROR_CODE, message: errorMsg });
|
|
1406
|
-
}
|
|
1407
|
-
var testingSessionOptions = defaultTransportOptions;
|
|
1408
|
-
var testingClientSessionOptions = defaultClientTransportOptions;
|
|
1409
|
-
function dummySession() {
|
|
1410
|
-
return SessionStateGraph.entrypoints.NoConnection(
|
|
1411
|
-
"client",
|
|
1412
|
-
"server",
|
|
1413
|
-
{
|
|
1414
|
-
onSessionGracePeriodElapsed: () => {
|
|
1415
|
-
}
|
|
1416
|
-
},
|
|
1417
|
-
testingSessionOptions,
|
|
1418
|
-
currentProtocolVersion
|
|
1419
|
-
);
|
|
1420
|
-
}
|
|
1421
|
-
function getClientSendFn(clientTransport, serverTransport) {
|
|
1422
|
-
const session = clientTransport.sessions.get(serverTransport.clientId) ?? clientTransport.createUnconnectedSession(serverTransport.clientId);
|
|
1423
|
-
return clientTransport.getSessionBoundSendFn(
|
|
1424
|
-
serverTransport.clientId,
|
|
1425
|
-
session.id
|
|
1426
|
-
);
|
|
1427
|
-
}
|
|
1428
|
-
function getServerSendFn(serverTransport, clientTransport) {
|
|
1429
|
-
const session = serverTransport.sessions.get(clientTransport.clientId);
|
|
1430
|
-
if (!session) {
|
|
1431
|
-
throw new Error("session not found");
|
|
1432
|
-
}
|
|
1433
|
-
return serverTransport.getSessionBoundSendFn(
|
|
1434
|
-
clientTransport.clientId,
|
|
1435
|
-
session.id
|
|
1436
|
-
);
|
|
1437
|
-
}
|
|
1438
|
-
function dummyCtx(state, session, extendedContext) {
|
|
1439
|
-
return {
|
|
1440
|
-
...extendedContext,
|
|
1441
|
-
state,
|
|
1442
|
-
sessionId: session.id,
|
|
1443
|
-
from: session.from,
|
|
1444
|
-
metadata: {},
|
|
1445
|
-
// TODO might wanna hook these up!
|
|
1446
|
-
cancel: () => void 0,
|
|
1447
|
-
signal: new AbortController().signal
|
|
1448
|
-
};
|
|
1449
|
-
}
|
|
1450
|
-
function asClientRpc(state, proc, extendedContext, session = dummySession()) {
|
|
1451
|
-
return async (msg) => {
|
|
1452
|
-
return proc.handler({
|
|
1453
|
-
ctx: dummyCtx(state, session, extendedContext),
|
|
1454
|
-
reqInit: msg
|
|
1455
|
-
}).catch(catchProcError);
|
|
1456
|
-
};
|
|
1457
|
-
}
|
|
1458
|
-
function createResponsePipe() {
|
|
1459
|
-
const readable = new ReadableImpl();
|
|
1460
|
-
const writable = new WritableImpl({
|
|
1461
|
-
writeCb: (v) => {
|
|
1462
|
-
readable._pushValue(v);
|
|
1463
|
-
},
|
|
1464
|
-
closeCb: () => {
|
|
1465
|
-
void Promise.resolve().then(() => {
|
|
1466
|
-
readable._triggerClose();
|
|
1467
|
-
});
|
|
1468
|
-
}
|
|
1469
|
-
});
|
|
1470
|
-
return { readable, writable };
|
|
1471
|
-
}
|
|
1472
|
-
function createRequestPipe() {
|
|
1473
|
-
const readable = new ReadableImpl();
|
|
1474
|
-
const writable = new WritableImpl({
|
|
1475
|
-
writeCb: (v) => {
|
|
1476
|
-
readable._pushValue(Ok(v));
|
|
1477
|
-
},
|
|
1478
|
-
closeCb: () => {
|
|
1479
|
-
void Promise.resolve().then(() => {
|
|
1480
|
-
readable._triggerClose();
|
|
1481
|
-
});
|
|
1482
|
-
}
|
|
1483
|
-
});
|
|
1484
|
-
return { readable, writable };
|
|
1485
|
-
}
|
|
1486
|
-
function asClientStream(state, proc, reqInit, extendedContext, session = dummySession()) {
|
|
1487
|
-
const requestPipe = createRequestPipe();
|
|
1488
|
-
const responsePipe = createResponsePipe();
|
|
1489
|
-
void proc.handler({
|
|
1490
|
-
ctx: dummyCtx(state, session, extendedContext),
|
|
1491
|
-
reqInit: reqInit ?? {},
|
|
1492
|
-
reqReadable: requestPipe.readable,
|
|
1493
|
-
resWritable: responsePipe.writable
|
|
1494
|
-
}).catch((err) => responsePipe.writable.write(catchProcError(err)));
|
|
1495
|
-
return {
|
|
1496
|
-
reqWritable: requestPipe.writable,
|
|
1497
|
-
resReadable: responsePipe.readable
|
|
1498
|
-
};
|
|
1499
|
-
}
|
|
1500
|
-
function asClientSubscription(state, proc, extendedContext, session = dummySession()) {
|
|
1501
|
-
const responsePipe = createResponsePipe();
|
|
1502
|
-
return (msg) => {
|
|
1503
|
-
void proc.handler({
|
|
1504
|
-
ctx: dummyCtx(state, session, extendedContext),
|
|
1505
|
-
reqInit: msg,
|
|
1506
|
-
resWritable: responsePipe.writable
|
|
1507
|
-
}).catch(
|
|
1508
|
-
(err) => responsePipe.writable.write(catchProcError(err))
|
|
1509
|
-
);
|
|
1510
|
-
return { resReadable: responsePipe.readable };
|
|
1511
|
-
};
|
|
1512
|
-
}
|
|
1513
|
-
function asClientUpload(state, proc, reqInit, extendedContext, session = dummySession()) {
|
|
1514
|
-
const requestPipe = createRequestPipe();
|
|
1515
|
-
const result = proc.handler({
|
|
1516
|
-
ctx: dummyCtx(state, session, extendedContext),
|
|
1517
|
-
reqInit: reqInit ?? {},
|
|
1518
|
-
reqReadable: requestPipe.readable
|
|
1519
|
-
}).catch(catchProcError);
|
|
1520
|
-
return { reqWritable: requestPipe.writable, finalize: () => result };
|
|
1521
|
-
}
|
|
1522
|
-
function getTransportConnections(transport) {
|
|
1523
|
-
const connections = [];
|
|
1524
|
-
for (const session of transport.sessions.values()) {
|
|
1525
|
-
if (session.state === "Connected" /* Connected */) {
|
|
1526
|
-
connections.push(session.conn);
|
|
1527
|
-
}
|
|
1528
|
-
}
|
|
1529
|
-
return connections;
|
|
1530
|
-
}
|
|
1531
|
-
function numberOfConnections(transport) {
|
|
1532
|
-
return getTransportConnections(transport).length;
|
|
1533
|
-
}
|
|
1534
|
-
function closeAllConnections(transport) {
|
|
1535
|
-
for (const conn of getTransportConnections(transport)) {
|
|
1536
|
-
conn.close();
|
|
1537
|
-
}
|
|
1538
|
-
}
|
|
1539
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
1540
|
-
0 && (module.exports = {
|
|
1541
|
-
asClientRpc,
|
|
1542
|
-
asClientStream,
|
|
1543
|
-
asClientSubscription,
|
|
1544
|
-
asClientUpload,
|
|
1545
|
-
closeAllConnections,
|
|
1546
|
-
createDummyTransportMessage,
|
|
1547
|
-
createLocalWebSocketClient,
|
|
1548
|
-
createWebSocketServer,
|
|
1549
|
-
dummySession,
|
|
1550
|
-
getClientSendFn,
|
|
1551
|
-
getReadableIterator,
|
|
1552
|
-
getServerSendFn,
|
|
1553
|
-
getTransportConnections,
|
|
1554
|
-
isReadableDone,
|
|
1555
|
-
numberOfConnections,
|
|
1556
|
-
onWsServerReady,
|
|
1557
|
-
payloadToTransportMessage,
|
|
1558
|
-
readNextResult,
|
|
1559
|
-
testingClientSessionOptions,
|
|
1560
|
-
testingSessionOptions,
|
|
1561
|
-
waitForMessage
|
|
1562
|
-
});
|
|
1563
|
-
//# sourceMappingURL=testHelpers.cjs.map
|