@replit/river 0.23.18 → 0.24.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.
Files changed (84) hide show
  1. package/README.md +17 -16
  2. package/dist/chunk-227EQHH5.js +653 -0
  3. package/dist/chunk-227EQHH5.js.map +1 -0
  4. package/dist/chunk-6YFPHVNO.js +277 -0
  5. package/dist/chunk-6YFPHVNO.js.map +1 -0
  6. package/dist/{chunk-7MJYOL32.js → chunk-BGJDNLTJ.js} +15 -23
  7. package/dist/chunk-BGJDNLTJ.js.map +1 -0
  8. package/dist/chunk-HXOQQXL4.js +382 -0
  9. package/dist/chunk-HXOQQXL4.js.map +1 -0
  10. package/dist/{chunk-R2HAS3GM.js → chunk-IYYQ7BII.js} +55 -41
  11. package/dist/chunk-IYYQ7BII.js.map +1 -0
  12. package/dist/{chunk-AVL32IMG.js → chunk-L664A3WA.js} +20 -16
  13. package/dist/chunk-L664A3WA.js.map +1 -0
  14. package/dist/{chunk-EV5HW4IC.js → chunk-M7E6LQO2.js} +66 -53
  15. package/dist/chunk-M7E6LQO2.js.map +1 -0
  16. package/dist/{chunk-6LCL2ZZF.js → chunk-TAH2GVTJ.js} +1 -1
  17. package/dist/chunk-TAH2GVTJ.js.map +1 -0
  18. package/dist/chunk-XOFF3UPL.js +399 -0
  19. package/dist/chunk-XOFF3UPL.js.map +1 -0
  20. package/dist/{client-5776a6bb.d.ts → client-2ba72e89.d.ts} +12 -15
  21. package/dist/connection-55cba970.d.ts +11 -0
  22. package/dist/{connection-bd35d442.d.ts → connection-c6db05d9.d.ts} +1 -5
  23. package/dist/{handshake-a947c234.d.ts → handshake-0b88e8fc.d.ts} +150 -184
  24. package/dist/logging/index.cjs.map +1 -1
  25. package/dist/logging/index.d.cts +1 -1
  26. package/dist/logging/index.d.ts +1 -1
  27. package/dist/logging/index.js +1 -1
  28. package/dist/{index-ea74cdbb.d.ts → message-e6c560fd.d.ts} +2 -2
  29. package/dist/router/index.cjs +105 -63
  30. package/dist/router/index.cjs.map +1 -1
  31. package/dist/router/index.d.cts +11 -10
  32. package/dist/router/index.d.ts +11 -10
  33. package/dist/router/index.js +2 -2
  34. package/dist/server-732e7014.d.ts +42 -0
  35. package/dist/{services-38b3f758.d.ts → services-adfd0bc3.d.ts} +3 -3
  36. package/dist/transport/impls/uds/client.cjs +1246 -1230
  37. package/dist/transport/impls/uds/client.cjs.map +1 -1
  38. package/dist/transport/impls/uds/client.d.cts +4 -4
  39. package/dist/transport/impls/uds/client.d.ts +4 -4
  40. package/dist/transport/impls/uds/client.js +7 -13
  41. package/dist/transport/impls/uds/client.js.map +1 -1
  42. package/dist/transport/impls/uds/server.cjs +1298 -1151
  43. package/dist/transport/impls/uds/server.cjs.map +1 -1
  44. package/dist/transport/impls/uds/server.d.cts +4 -4
  45. package/dist/transport/impls/uds/server.d.ts +4 -4
  46. package/dist/transport/impls/uds/server.js +6 -6
  47. package/dist/transport/impls/ws/client.cjs +976 -965
  48. package/dist/transport/impls/ws/client.cjs.map +1 -1
  49. package/dist/transport/impls/ws/client.d.cts +4 -4
  50. package/dist/transport/impls/ws/client.d.ts +4 -4
  51. package/dist/transport/impls/ws/client.js +6 -7
  52. package/dist/transport/impls/ws/client.js.map +1 -1
  53. package/dist/transport/impls/ws/server.cjs +1182 -1047
  54. package/dist/transport/impls/ws/server.cjs.map +1 -1
  55. package/dist/transport/impls/ws/server.d.cts +4 -4
  56. package/dist/transport/impls/ws/server.d.ts +4 -4
  57. package/dist/transport/impls/ws/server.js +6 -6
  58. package/dist/transport/index.cjs +1433 -1360
  59. package/dist/transport/index.cjs.map +1 -1
  60. package/dist/transport/index.d.cts +5 -5
  61. package/dist/transport/index.d.ts +5 -5
  62. package/dist/transport/index.js +9 -9
  63. package/dist/util/testHelpers.cjs +744 -310
  64. package/dist/util/testHelpers.cjs.map +1 -1
  65. package/dist/util/testHelpers.d.cts +9 -6
  66. package/dist/util/testHelpers.d.ts +9 -6
  67. package/dist/util/testHelpers.js +34 -10
  68. package/dist/util/testHelpers.js.map +1 -1
  69. package/package.json +1 -1
  70. package/dist/chunk-6LCL2ZZF.js.map +0 -1
  71. package/dist/chunk-7MJYOL32.js.map +0 -1
  72. package/dist/chunk-AVL32IMG.js.map +0 -1
  73. package/dist/chunk-DPKOJQWF.js +0 -476
  74. package/dist/chunk-DPKOJQWF.js.map +0 -1
  75. package/dist/chunk-EV5HW4IC.js.map +0 -1
  76. package/dist/chunk-J6N6H2WU.js +0 -476
  77. package/dist/chunk-J6N6H2WU.js.map +0 -1
  78. package/dist/chunk-MW5JXLHY.js +0 -348
  79. package/dist/chunk-MW5JXLHY.js.map +0 -1
  80. package/dist/chunk-R2HAS3GM.js.map +0 -1
  81. package/dist/chunk-RJOWZIWB.js +0 -335
  82. package/dist/chunk-RJOWZIWB.js.map +0 -1
  83. package/dist/connection-df85db7e.d.ts +0 -17
  84. package/dist/server-53cd5b7e.d.ts +0 -24
@@ -1,476 +0,0 @@
1
- import {
2
- BaseLogger,
3
- createLogProxy
4
- } from "./chunk-6LCL2ZZF.js";
5
- import {
6
- Session,
7
- defaultTransportOptions
8
- } from "./chunk-MW5JXLHY.js";
9
- import {
10
- OpaqueTransportMessageSchema,
11
- createConnectionTelemetryInfo,
12
- isAck
13
- } from "./chunk-R2HAS3GM.js";
14
-
15
- // transport/events.ts
16
- var ProtocolError = {
17
- RetriesExceeded: "conn_retry_exceeded",
18
- HandshakeFailed: "handshake_failed",
19
- MessageOrderingViolated: "message_ordering_violated"
20
- };
21
- var EventDispatcher = class {
22
- eventListeners = {};
23
- removeAllListeners() {
24
- this.eventListeners = {};
25
- }
26
- numberOfListeners(eventType) {
27
- return this.eventListeners[eventType]?.size ?? 0;
28
- }
29
- addEventListener(eventType, handler) {
30
- if (!this.eventListeners[eventType]) {
31
- this.eventListeners[eventType] = /* @__PURE__ */ new Set();
32
- }
33
- this.eventListeners[eventType]?.add(handler);
34
- }
35
- removeEventListener(eventType, handler) {
36
- const handlers = this.eventListeners[eventType];
37
- if (handlers) {
38
- this.eventListeners[eventType]?.delete(handler);
39
- }
40
- }
41
- dispatchEvent(eventType, event) {
42
- const handlers = this.eventListeners[eventType];
43
- if (handlers) {
44
- const copy = [...handlers];
45
- for (const handler of copy) {
46
- handler(event);
47
- }
48
- }
49
- }
50
- };
51
-
52
- // transport/transport.ts
53
- import { Value } from "@sinclair/typebox/value";
54
- import { SpanStatusCode } from "@opentelemetry/api";
55
- var Transport = class {
56
- /**
57
- * The status of the transport.
58
- */
59
- status;
60
- /**
61
- * The {@link Codec} used to encode and decode messages.
62
- */
63
- codec;
64
- /**
65
- * The client ID of this transport.
66
- */
67
- clientId;
68
- /**
69
- * The map of {@link Session}s managed by this transport.
70
- */
71
- sessions;
72
- /**
73
- * The map of {@link Connection}s managed by this transport.
74
- */
75
- get connections() {
76
- return new Map(
77
- [...this.sessions].map(([client, session]) => [client, session.connection]).filter((entry) => entry[1] !== void 0)
78
- );
79
- }
80
- /**
81
- * The event dispatcher for handling events of type EventTypes.
82
- */
83
- eventDispatcher;
84
- /**
85
- * The options for this transport.
86
- */
87
- options;
88
- log;
89
- /**
90
- * Creates a new Transport instance.
91
- * This should also set up {@link onConnect}, and {@link onDisconnect} listeners.
92
- * @param codec The codec used to encode and decode messages.
93
- * @param clientId The client ID of this transport.
94
- */
95
- constructor(clientId, providedOptions) {
96
- this.options = { ...defaultTransportOptions, ...providedOptions };
97
- this.eventDispatcher = new EventDispatcher();
98
- this.sessions = /* @__PURE__ */ new Map();
99
- this.codec = this.options.codec;
100
- this.clientId = clientId;
101
- this.status = "open";
102
- }
103
- bindLogger(fn, level) {
104
- if (typeof fn === "function") {
105
- this.log = createLogProxy(new BaseLogger(fn, level));
106
- return;
107
- }
108
- this.log = createLogProxy(fn);
109
- }
110
- /**
111
- * Called when a new connection is established
112
- * and we know the identity of the connected client.
113
- * @param conn The connection object.
114
- */
115
- onConnect(conn, session, isTransparentReconnect) {
116
- this.eventDispatcher.dispatchEvent("connectionStatus", {
117
- status: "connect",
118
- conn
119
- });
120
- conn.telemetry = createConnectionTelemetryInfo(conn, session.telemetry);
121
- session.replaceWithNewConnection(conn, isTransparentReconnect);
122
- this.log?.info(`connected to ${session.to}`, {
123
- ...conn.loggingMetadata,
124
- ...session.loggingMetadata
125
- });
126
- }
127
- createSession(to, conn, propagationCtx) {
128
- const session = new Session(
129
- conn,
130
- this.clientId,
131
- to,
132
- this.options,
133
- propagationCtx
134
- );
135
- if (this.log) {
136
- session.bindLogger(this.log);
137
- }
138
- const currentSession = this.sessions.get(session.to);
139
- if (currentSession) {
140
- this.log?.warn(
141
- `session ${session.id} from ${session.to} surreptitiously replacing ${currentSession.id}`,
142
- {
143
- ...currentSession.loggingMetadata,
144
- tags: ["invariant-violation"]
145
- }
146
- );
147
- this.deleteSession({
148
- session: currentSession,
149
- closeHandshakingConnection: false
150
- });
151
- }
152
- this.sessions.set(session.to, session);
153
- this.eventDispatcher.dispatchEvent("sessionStatus", {
154
- status: "connect",
155
- session
156
- });
157
- return session;
158
- }
159
- createNewSession({
160
- to,
161
- conn,
162
- sessionId,
163
- propagationCtx
164
- }) {
165
- let session = this.sessions.get(to);
166
- if (session !== void 0) {
167
- this.log?.info(
168
- `session for ${to} already exists, replacing it with a new session as requested`,
169
- session.loggingMetadata
170
- );
171
- this.deleteSession({
172
- session,
173
- closeHandshakingConnection: false
174
- });
175
- session = void 0;
176
- }
177
- session = this.createSession(to, conn, propagationCtx);
178
- session.advertisedSessionId = sessionId;
179
- this.log?.info(`created new session for ${to}`, session.loggingMetadata);
180
- return session;
181
- }
182
- getExistingSession({
183
- to,
184
- sessionId,
185
- nextExpectedSeq
186
- }) {
187
- const session = this.sessions.get(to);
188
- if (
189
- // reject this request if there was no previous session to replace
190
- session === void 0 || // or if both parties do not agree about the next expected sequence number
191
- !session.nextExpectedSeqInRange(nextExpectedSeq) || // or if both parties do not agree on the advertised session id
192
- session.advertisedSessionId !== sessionId
193
- ) {
194
- return false;
195
- }
196
- this.log?.info(
197
- `reused existing session for ${to}`,
198
- session.loggingMetadata
199
- );
200
- return session;
201
- }
202
- getOrCreateSession({
203
- to,
204
- conn,
205
- handshakingConn,
206
- sessionId,
207
- propagationCtx
208
- }) {
209
- let session = this.sessions.get(to);
210
- const isReconnect = session !== void 0;
211
- let isTransparentReconnect = isReconnect;
212
- if (session?.advertisedSessionId !== void 0 && sessionId !== void 0 && session.advertisedSessionId !== sessionId) {
213
- this.log?.info(
214
- `session for ${to} already exists but has a different session id (expected: ${session.advertisedSessionId}, got: ${sessionId}), creating a new one`,
215
- session.loggingMetadata
216
- );
217
- this.deleteSession({
218
- session,
219
- closeHandshakingConnection: handshakingConn !== void 0,
220
- handshakingConn
221
- });
222
- isTransparentReconnect = false;
223
- session = void 0;
224
- }
225
- if (!session) {
226
- session = this.createSession(to, conn, propagationCtx);
227
- this.log?.info(
228
- `no session for ${to}, created a new one`,
229
- session.loggingMetadata
230
- );
231
- }
232
- if (sessionId !== void 0) {
233
- session.advertisedSessionId = sessionId;
234
- }
235
- if (handshakingConn !== void 0) {
236
- session.replaceWithNewHandshakingConnection(handshakingConn);
237
- }
238
- return { session, isReconnect, isTransparentReconnect };
239
- }
240
- deleteSession({
241
- session,
242
- closeHandshakingConnection,
243
- handshakingConn
244
- }) {
245
- if (closeHandshakingConnection) {
246
- session.closeHandshakingConnection(handshakingConn);
247
- }
248
- session.close();
249
- session.telemetry.span.end();
250
- const currentSession = this.sessions.get(session.to);
251
- if (currentSession && currentSession.id !== session.id) {
252
- this.log?.warn(
253
- `session ${session.id} disconnect from ${session.to}, mismatch with ${currentSession.id}`,
254
- {
255
- ...session.loggingMetadata,
256
- tags: ["invariant-violation"]
257
- }
258
- );
259
- return;
260
- }
261
- this.sessions.delete(session.to);
262
- this.log?.info(
263
- `session ${session.id} disconnect from ${session.to}`,
264
- session.loggingMetadata
265
- );
266
- this.eventDispatcher.dispatchEvent("sessionStatus", {
267
- status: "disconnect",
268
- session
269
- });
270
- }
271
- /**
272
- * The downstream implementation needs to call this when a connection is closed.
273
- * @param conn The connection object.
274
- * @param connectedTo The peer we are connected to.
275
- */
276
- onDisconnect(conn, session) {
277
- if (session.connection !== void 0 && session.connection.id !== conn.id) {
278
- session.telemetry.span.addEvent("onDisconnect race");
279
- this.log?.warn("onDisconnect race", {
280
- clientId: this.clientId,
281
- ...session.loggingMetadata,
282
- ...conn.loggingMetadata,
283
- tags: ["invariant-violation"]
284
- });
285
- return;
286
- }
287
- conn.telemetry?.span.end();
288
- this.eventDispatcher.dispatchEvent("connectionStatus", {
289
- status: "disconnect",
290
- conn
291
- });
292
- session.connection = void 0;
293
- session.beginGrace(() => {
294
- if (session.connection !== void 0) {
295
- session.telemetry.span.addEvent("session grace period race");
296
- this.log?.warn("session grace period race", {
297
- clientId: this.clientId,
298
- ...session.loggingMetadata,
299
- ...conn.loggingMetadata,
300
- tags: ["invariant-violation"]
301
- });
302
- return;
303
- }
304
- session.telemetry.span.addEvent("session grace period expired");
305
- this.deleteSession({
306
- session,
307
- closeHandshakingConnection: true,
308
- handshakingConn: conn
309
- });
310
- });
311
- }
312
- /**
313
- * Parses a message from a Uint8Array into a {@link OpaqueTransportMessage}.
314
- * @param msg The message to parse.
315
- * @returns The parsed message, or null if the message is malformed or invalid.
316
- */
317
- parseMsg(msg, conn) {
318
- const parsedMsg = this.codec.fromBuffer(msg);
319
- if (parsedMsg === null) {
320
- const decodedBuffer = new TextDecoder().decode(Buffer.from(msg));
321
- this.log?.error(
322
- `received malformed msg, killing conn: ${decodedBuffer}`,
323
- {
324
- clientId: this.clientId,
325
- ...conn.loggingMetadata
326
- }
327
- );
328
- return null;
329
- }
330
- if (!Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
331
- this.log?.error(`received invalid msg: ${JSON.stringify(parsedMsg)}`, {
332
- clientId: this.clientId,
333
- ...conn.loggingMetadata,
334
- validationErrors: [
335
- ...Value.Errors(OpaqueTransportMessageSchema, parsedMsg)
336
- ]
337
- });
338
- return null;
339
- }
340
- return parsedMsg;
341
- }
342
- /**
343
- * Called when a message is received by this transport.
344
- * You generally shouldn't need to override this in downstream transport implementations.
345
- * @param msg The received message.
346
- */
347
- handleMsg(msg, conn) {
348
- if (this.getStatus() !== "open")
349
- return;
350
- const session = this.sessions.get(msg.from);
351
- if (!session) {
352
- this.log?.error(`received message for unknown session from ${msg.from}`, {
353
- clientId: this.clientId,
354
- transportMessage: msg,
355
- ...conn.loggingMetadata,
356
- tags: ["invariant-violation"]
357
- });
358
- return;
359
- }
360
- session.cancelGrace();
361
- this.log?.debug(`received msg`, {
362
- clientId: this.clientId,
363
- transportMessage: msg,
364
- ...conn.loggingMetadata
365
- });
366
- if (msg.seq !== session.nextExpectedSeq) {
367
- if (msg.seq < session.nextExpectedSeq) {
368
- this.log?.debug(
369
- `received duplicate msg (got seq: ${msg.seq}, wanted seq: ${session.nextExpectedSeq}), discarding`,
370
- {
371
- clientId: this.clientId,
372
- transportMessage: msg,
373
- ...conn.loggingMetadata
374
- }
375
- );
376
- } else {
377
- const errMsg = `received out-of-order msg (got seq: ${msg.seq}, wanted seq: ${session.nextExpectedSeq})`;
378
- this.log?.error(`${errMsg}, marking connection as dead`, {
379
- clientId: this.clientId,
380
- transportMessage: msg,
381
- ...conn.loggingMetadata,
382
- tags: ["invariant-violation"]
383
- });
384
- this.protocolError(ProtocolError.MessageOrderingViolated, errMsg);
385
- session.telemetry.span.setStatus({
386
- code: SpanStatusCode.ERROR,
387
- message: "message order violated"
388
- });
389
- this.deleteSession({ session, closeHandshakingConnection: true });
390
- }
391
- return;
392
- }
393
- session.updateBookkeeping(msg.ack, msg.seq);
394
- if (!isAck(msg.controlFlags)) {
395
- this.eventDispatcher.dispatchEvent("message", msg);
396
- } else {
397
- this.log?.debug(`discarding msg (ack bit set)`, {
398
- clientId: this.clientId,
399
- transportMessage: msg,
400
- ...conn.loggingMetadata
401
- });
402
- }
403
- }
404
- /**
405
- * Adds a listener to this transport.
406
- * @param the type of event to listen for
407
- * @param handler The message handler to add.
408
- */
409
- addEventListener(type, handler) {
410
- this.eventDispatcher.addEventListener(type, handler);
411
- }
412
- /**
413
- * Removes a listener from this transport.
414
- * @param the type of event to un-listen on
415
- * @param handler The message handler to remove.
416
- */
417
- removeEventListener(type, handler) {
418
- this.eventDispatcher.removeEventListener(type, handler);
419
- }
420
- /**
421
- * Sends a message over this transport, delegating to the appropriate connection to actually
422
- * send the message.
423
- * @param msg The message to send.
424
- * @returns The ID of the sent message or undefined if it wasn't sent
425
- */
426
- send(to, msg) {
427
- if (this.getStatus() === "closed") {
428
- const err = "transport is closed, cant send";
429
- this.log?.error(err, {
430
- clientId: this.clientId,
431
- transportMessage: msg,
432
- tags: ["invariant-violation"]
433
- });
434
- throw new Error(err);
435
- }
436
- return this.getOrCreateSession({ to }).session.send(msg);
437
- }
438
- // control helpers
439
- sendCloseStream(to, streamId) {
440
- return this.send(to, {
441
- streamId,
442
- controlFlags: 4 /* StreamClosedBit */,
443
- payload: {
444
- type: "CLOSE"
445
- }
446
- });
447
- }
448
- protocolError(type, message) {
449
- this.eventDispatcher.dispatchEvent("protocolError", { type, message });
450
- }
451
- /**
452
- * Default close implementation for transports. You should override this in the downstream
453
- * implementation if you need to do any additional cleanup and call super.close() at the end.
454
- * Closes the transport. Any messages sent while the transport is closed will be silently discarded.
455
- */
456
- close() {
457
- this.status = "closed";
458
- for (const session of this.sessions.values()) {
459
- this.deleteSession({ session, closeHandshakingConnection: true });
460
- }
461
- this.eventDispatcher.dispatchEvent("transportStatus", {
462
- status: this.status
463
- });
464
- this.eventDispatcher.removeAllListeners();
465
- this.log?.info(`manually closed transport`, { clientId: this.clientId });
466
- }
467
- getStatus() {
468
- return this.status;
469
- }
470
- };
471
-
472
- export {
473
- ProtocolError,
474
- Transport
475
- };
476
- //# sourceMappingURL=chunk-J6N6H2WU.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../transport/events.ts","../transport/transport.ts"],"sourcesContent":["import { TransportStatus } from '.';\nimport { OpaqueTransportMessage } from './message';\nimport { Connection, Session } from './session';\n\ntype ConnectionStatus = 'connect' | 'disconnect';\nexport const ProtocolError = {\n RetriesExceeded: 'conn_retry_exceeded',\n HandshakeFailed: 'handshake_failed',\n MessageOrderingViolated: 'message_ordering_violated',\n} as const;\n\nexport type ProtocolErrorType =\n (typeof ProtocolError)[keyof typeof ProtocolError];\n\nexport interface EventMap {\n message: OpaqueTransportMessage;\n connectionStatus: {\n status: ConnectionStatus;\n conn: Connection;\n };\n sessionStatus: {\n status: ConnectionStatus;\n session: Session<Connection>;\n };\n protocolError: {\n type: ProtocolErrorType;\n message: string;\n };\n transportStatus: {\n status: TransportStatus;\n };\n}\n\nexport type EventTypes = keyof EventMap;\nexport type EventHandler<K extends EventTypes> = (\n event: EventMap[K],\n) => unknown;\n\nexport class EventDispatcher<T extends EventTypes> {\n private eventListeners: { [K in T]?: Set<EventHandler<K>> } = {};\n\n removeAllListeners() {\n this.eventListeners = {};\n }\n\n numberOfListeners<K extends T>(eventType: K) {\n return this.eventListeners[eventType]?.size ?? 0;\n }\n\n addEventListener<K extends T>(eventType: K, handler: EventHandler<K>) {\n if (!this.eventListeners[eventType]) {\n this.eventListeners[eventType] = new Set();\n }\n\n this.eventListeners[eventType]?.add(handler);\n }\n\n removeEventListener<K extends T>(eventType: K, handler: EventHandler<K>) {\n const handlers = this.eventListeners[eventType];\n if (handlers) {\n this.eventListeners[eventType]?.delete(handler);\n }\n }\n\n dispatchEvent<K extends T>(eventType: K, event: EventMap[K]) {\n const handlers = this.eventListeners[eventType];\n if (handlers) {\n // copying ensures that adding more listeners in a handler doesn't\n // affect the current dispatch.\n const copy = [...handlers];\n for (const handler of copy) {\n handler(event);\n }\n }\n }\n}\n","import { Codec } from '../codec/types';\nimport { Value } from '@sinclair/typebox/value';\nimport {\n OpaqueTransportMessage,\n OpaqueTransportMessageSchema,\n TransportClientId,\n PartialTransportMessage,\n ControlFlags,\n ControlMessagePayloadSchema,\n isAck,\n} from './message';\nimport {\n BaseLogger,\n LogFn,\n Logger,\n LoggingLevel,\n createLogProxy,\n} from '../logging/log';\nimport {\n EventDispatcher,\n EventHandler,\n EventTypes,\n ProtocolError,\n ProtocolErrorType,\n} from './events';\nimport { Connection, Session } from './session';\nimport { Static } from '@sinclair/typebox';\nimport { PropagationContext, createConnectionTelemetryInfo } from '../tracing';\nimport { SpanStatusCode } from '@opentelemetry/api';\nimport {\n ProvidedTransportOptions,\n TransportOptions,\n defaultTransportOptions,\n} from './options';\n\n/**\n * Represents the possible states of a transport.\n * @property {'open'} open - The transport is open and operational (note that this doesn't mean it is actively connected)\n * @property {'closed'} closed - The transport is permanently closed and cannot be reopened.\n */\nexport type TransportStatus = 'open' | 'closed';\n\n/**\n * Transports manage the lifecycle (creation/deletion) of sessions and connections. Its responsibilities include:\n *\n * 1) Constructing a new {@link Session} and {@link Connection} on {@link TransportMessage}s from new clients.\n * After constructing the {@link Connection}, {@link onConnect} is called which adds it to the connection map.\n * 2) Delegating message listening of the connection to the newly created {@link Connection}.\n * From this point on, the {@link Connection} is responsible for *reading* and *writing*\n * messages from the connection.\n * 3) When a connection is closed, the {@link Transport} calls {@link onDisconnect} which closes the\n * connection via {@link Connection.close} and removes it from the {@link connections} map.\n\n *\n * ```plaintext\n * ▲\n * incoming │\n * messages │\n * ▼\n * ┌─────────────┐ 1:N ┌───────────┐ 1:1* ┌────────────┐\n * │ Transport │ ◄─────► │ Session │ ◄─────► │ Connection │\n * └─────────────┘ └───────────┘ └────────────┘\n * ▲ * (may or may not be initialized yet)\n * │\n * ▼\n * ┌───────────┐\n * │ Message │\n * │ Listeners │\n * └───────────┘\n * ```\n * @abstract\n */\nexport abstract class Transport<ConnType extends Connection> {\n /**\n * The status of the transport.\n */\n private status: TransportStatus;\n\n /**\n * The {@link Codec} used to encode and decode messages.\n */\n codec: Codec;\n\n /**\n * The client ID of this transport.\n */\n clientId: TransportClientId;\n\n /**\n * The map of {@link Session}s managed by this transport.\n */\n sessions: Map<TransportClientId, Session<ConnType>>;\n\n /**\n * The map of {@link Connection}s managed by this transport.\n */\n get connections() {\n return new Map(\n [...this.sessions]\n .map(([client, session]) => [client, session.connection])\n .filter((entry): entry is [string, ConnType] => entry[1] !== undefined),\n );\n }\n\n /**\n * The event dispatcher for handling events of type EventTypes.\n */\n eventDispatcher: EventDispatcher<EventTypes>;\n\n /**\n * The options for this transport.\n */\n protected options: TransportOptions;\n log?: Logger;\n\n /**\n * Creates a new Transport instance.\n * This should also set up {@link onConnect}, and {@link onDisconnect} listeners.\n * @param codec The codec used to encode and decode messages.\n * @param clientId The client ID of this transport.\n */\n constructor(\n clientId: TransportClientId,\n providedOptions?: ProvidedTransportOptions,\n ) {\n this.options = { ...defaultTransportOptions, ...providedOptions };\n this.eventDispatcher = new EventDispatcher();\n this.sessions = new Map();\n this.codec = this.options.codec;\n this.clientId = clientId;\n this.status = 'open';\n }\n\n bindLogger(fn: LogFn | Logger, level?: LoggingLevel) {\n // construct logger from fn\n if (typeof fn === 'function') {\n this.log = createLogProxy(new BaseLogger(fn, level));\n return;\n }\n\n // object case, just assign\n this.log = createLogProxy(fn);\n }\n\n /**\n * This is called immediately after a new connection is established and we\n * may or may not know the identity of the connected client.\n * It should attach all the necessary listeners to the connection for lifecycle\n * events (i.e. data, close, error)\n *\n * This method is implemented by {@link ClientTransport} and {@link ServerTransport}.\n */\n protected abstract handleConnection(\n conn: ConnType,\n to: TransportClientId,\n ): void;\n\n /**\n * Called when a new connection is established\n * and we know the identity of the connected client.\n * @param conn The connection object.\n */\n protected onConnect(\n conn: ConnType,\n session: Session<ConnType>,\n isTransparentReconnect: boolean,\n ) {\n this.eventDispatcher.dispatchEvent('connectionStatus', {\n status: 'connect',\n conn,\n });\n\n conn.telemetry = createConnectionTelemetryInfo(conn, session.telemetry);\n\n session.replaceWithNewConnection(conn, isTransparentReconnect);\n\n this.log?.info(`connected to ${session.to}`, {\n ...conn.loggingMetadata,\n ...session.loggingMetadata,\n });\n }\n\n protected createSession(\n to: TransportClientId,\n conn?: ConnType,\n propagationCtx?: PropagationContext,\n ) {\n const session = new Session<ConnType>(\n conn,\n this.clientId,\n to,\n this.options,\n propagationCtx,\n );\n\n if (this.log) {\n session.bindLogger(this.log);\n }\n\n const currentSession = this.sessions.get(session.to);\n if (currentSession) {\n // something went very wrong, and we were asked to replace an active session with another one\n this.log?.warn(\n `session ${session.id} from ${session.to} surreptitiously replacing ${currentSession.id}`,\n {\n ...currentSession.loggingMetadata,\n tags: ['invariant-violation'],\n },\n );\n this.deleteSession({\n session: currentSession,\n closeHandshakingConnection: false,\n });\n }\n this.sessions.set(session.to, session);\n this.eventDispatcher.dispatchEvent('sessionStatus', {\n status: 'connect',\n session,\n });\n return session;\n }\n\n protected createNewSession({\n to,\n conn,\n sessionId,\n propagationCtx,\n }: {\n to: TransportClientId;\n conn: ConnType;\n sessionId: string;\n propagationCtx?: PropagationContext;\n }) {\n let session = this.sessions.get(to);\n if (session !== undefined) {\n // this is a new session. if the client already had one, delete it before continuing\n this.log?.info(\n `session for ${to} already exists, replacing it with a new session as requested`,\n session.loggingMetadata,\n );\n this.deleteSession({\n session,\n closeHandshakingConnection: false,\n });\n session = undefined;\n }\n\n session = this.createSession(to, conn, propagationCtx);\n session.advertisedSessionId = sessionId;\n this.log?.info(`created new session for ${to}`, session.loggingMetadata);\n\n return session;\n }\n\n protected getExistingSession({\n to,\n sessionId,\n nextExpectedSeq,\n }: {\n to: TransportClientId;\n sessionId: string;\n nextExpectedSeq: number;\n }) {\n const session = this.sessions.get(to);\n if (\n // reject this request if there was no previous session to replace\n session === undefined ||\n // or if both parties do not agree about the next expected sequence number\n !session.nextExpectedSeqInRange(nextExpectedSeq) ||\n // or if both parties do not agree on the advertised session id\n session.advertisedSessionId !== sessionId\n ) {\n return false;\n }\n\n this.log?.info(\n `reused existing session for ${to}`,\n session.loggingMetadata,\n );\n\n return session;\n }\n\n protected getOrCreateSession({\n to,\n conn,\n handshakingConn,\n sessionId,\n propagationCtx,\n }: {\n to: TransportClientId;\n conn?: ConnType;\n handshakingConn?: ConnType;\n sessionId?: string;\n propagationCtx?: PropagationContext;\n }) {\n let session = this.sessions.get(to);\n const isReconnect = session !== undefined;\n let isTransparentReconnect = isReconnect;\n\n if (\n session?.advertisedSessionId !== undefined &&\n sessionId !== undefined &&\n session.advertisedSessionId !== sessionId\n ) {\n this.log?.info(\n `session for ${to} already exists but has a different session id (expected: ${session.advertisedSessionId}, got: ${sessionId}), creating a new one`,\n session.loggingMetadata,\n );\n // note that here we are only interested in closing the handshaking connection if it _does\n // not_ match the current handshaking connection. otherwise we can be in a situation where we\n // can accidentally close the current connection and are never able to establish a full\n // handshake.\n this.deleteSession({\n session,\n closeHandshakingConnection: handshakingConn !== undefined,\n handshakingConn,\n });\n isTransparentReconnect = false;\n session = undefined;\n }\n\n if (!session) {\n session = this.createSession(to, conn, propagationCtx);\n this.log?.info(\n `no session for ${to}, created a new one`,\n session.loggingMetadata,\n );\n }\n\n if (sessionId !== undefined) {\n session.advertisedSessionId = sessionId;\n }\n\n if (handshakingConn !== undefined) {\n session.replaceWithNewHandshakingConnection(handshakingConn);\n }\n return { session, isReconnect, isTransparentReconnect };\n }\n\n protected deleteSession({\n session,\n closeHandshakingConnection,\n handshakingConn,\n }: {\n session: Session<ConnType>;\n closeHandshakingConnection: boolean;\n handshakingConn?: ConnType;\n }) {\n if (closeHandshakingConnection) {\n session.closeHandshakingConnection(handshakingConn);\n }\n session.close();\n session.telemetry.span.end();\n const currentSession = this.sessions.get(session.to);\n if (currentSession && currentSession.id !== session.id) {\n // something went very wrong, and we were asked to delete a session that was not the currently\n // active one\n this.log?.warn(\n `session ${session.id} disconnect from ${session.to}, mismatch with ${currentSession.id}`,\n {\n ...session.loggingMetadata,\n tags: ['invariant-violation'],\n },\n );\n return;\n }\n this.sessions.delete(session.to);\n this.log?.info(\n `session ${session.id} disconnect from ${session.to}`,\n session.loggingMetadata,\n );\n this.eventDispatcher.dispatchEvent('sessionStatus', {\n status: 'disconnect',\n session,\n });\n }\n\n /**\n * The downstream implementation needs to call this when a connection is closed.\n * @param conn The connection object.\n * @param connectedTo The peer we are connected to.\n */\n protected onDisconnect(conn: ConnType, session: Session<ConnType>) {\n if (session.connection !== undefined && session.connection.id !== conn.id) {\n // it is completely legal for us to receive the onDisconnect notification later down the line\n // and accidentally try to install the grace notification into an already-reconnected session.\n session.telemetry.span.addEvent('onDisconnect race');\n this.log?.warn('onDisconnect race', {\n clientId: this.clientId,\n ...session.loggingMetadata,\n ...conn.loggingMetadata,\n tags: ['invariant-violation'],\n });\n return;\n }\n conn.telemetry?.span.end();\n this.eventDispatcher.dispatchEvent('connectionStatus', {\n status: 'disconnect',\n conn,\n });\n\n session.connection = undefined;\n session.beginGrace(() => {\n if (session.connection !== undefined) {\n // if for whatever reason the session has a connection, it means that we accidentally\n // installed a grace period in a session that already had reconnected. oops.\n session.telemetry.span.addEvent('session grace period race');\n this.log?.warn('session grace period race', {\n clientId: this.clientId,\n ...session.loggingMetadata,\n ...conn.loggingMetadata,\n tags: ['invariant-violation'],\n });\n return;\n }\n session.telemetry.span.addEvent('session grace period expired');\n this.deleteSession({\n session,\n closeHandshakingConnection: true,\n handshakingConn: conn,\n });\n });\n }\n\n /**\n * Parses a message from a Uint8Array into a {@link OpaqueTransportMessage}.\n * @param msg The message to parse.\n * @returns The parsed message, or null if the message is malformed or invalid.\n */\n protected parseMsg(\n msg: Uint8Array,\n conn: ConnType,\n ): OpaqueTransportMessage | null {\n const parsedMsg = this.codec.fromBuffer(msg);\n\n if (parsedMsg === null) {\n const decodedBuffer = new TextDecoder().decode(Buffer.from(msg));\n this.log?.error(\n `received malformed msg, killing conn: ${decodedBuffer}`,\n {\n clientId: this.clientId,\n ...conn.loggingMetadata,\n },\n );\n return null;\n }\n\n if (!Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {\n this.log?.error(`received invalid msg: ${JSON.stringify(parsedMsg)}`, {\n clientId: this.clientId,\n ...conn.loggingMetadata,\n validationErrors: [\n ...Value.Errors(OpaqueTransportMessageSchema, parsedMsg),\n ],\n });\n return null;\n }\n\n return parsedMsg;\n }\n\n /**\n * Called when a message is received by this transport.\n * You generally shouldn't need to override this in downstream transport implementations.\n * @param msg The received message.\n */\n protected handleMsg(msg: OpaqueTransportMessage, conn: ConnType) {\n if (this.getStatus() !== 'open') return;\n const session = this.sessions.get(msg.from);\n if (!session) {\n this.log?.error(`received message for unknown session from ${msg.from}`, {\n clientId: this.clientId,\n transportMessage: msg,\n ...conn.loggingMetadata,\n tags: ['invariant-violation'],\n });\n return;\n }\n\n // got a msg so we know the other end is alive, reset the grace period\n session.cancelGrace();\n\n this.log?.debug(`received msg`, {\n clientId: this.clientId,\n transportMessage: msg,\n ...conn.loggingMetadata,\n });\n if (msg.seq !== session.nextExpectedSeq) {\n if (msg.seq < session.nextExpectedSeq) {\n this.log?.debug(\n `received duplicate msg (got seq: ${msg.seq}, wanted seq: ${session.nextExpectedSeq}), discarding`,\n {\n clientId: this.clientId,\n transportMessage: msg,\n ...conn.loggingMetadata,\n },\n );\n } else {\n const errMsg = `received out-of-order msg (got seq: ${msg.seq}, wanted seq: ${session.nextExpectedSeq})`;\n this.log?.error(`${errMsg}, marking connection as dead`, {\n clientId: this.clientId,\n transportMessage: msg,\n ...conn.loggingMetadata,\n tags: ['invariant-violation'],\n });\n this.protocolError(ProtocolError.MessageOrderingViolated, errMsg);\n session.telemetry.span.setStatus({\n code: SpanStatusCode.ERROR,\n message: 'message order violated',\n });\n this.deleteSession({ session, closeHandshakingConnection: true });\n }\n\n return;\n }\n\n session.updateBookkeeping(msg.ack, msg.seq);\n\n // don't dispatch explicit acks\n if (!isAck(msg.controlFlags)) {\n this.eventDispatcher.dispatchEvent('message', msg);\n } else {\n this.log?.debug(`discarding msg (ack bit set)`, {\n clientId: this.clientId,\n transportMessage: msg,\n ...conn.loggingMetadata,\n });\n }\n }\n\n /**\n * Adds a listener to this transport.\n * @param the type of event to listen for\n * @param handler The message handler to add.\n */\n addEventListener<K extends EventTypes, T extends EventHandler<K>>(\n type: K,\n handler: T,\n ): void {\n this.eventDispatcher.addEventListener(type, handler);\n }\n\n /**\n * Removes a listener from this transport.\n * @param the type of event to un-listen on\n * @param handler The message handler to remove.\n */\n removeEventListener<K extends EventTypes, T extends EventHandler<K>>(\n type: K,\n handler: T,\n ): void {\n this.eventDispatcher.removeEventListener(type, handler);\n }\n\n /**\n * Sends a message over this transport, delegating to the appropriate connection to actually\n * send the message.\n * @param msg The message to send.\n * @returns The ID of the sent message or undefined if it wasn't sent\n */\n\n send(to: TransportClientId, msg: PartialTransportMessage): string {\n if (this.getStatus() === 'closed') {\n const err = 'transport is closed, cant send';\n this.log?.error(err, {\n clientId: this.clientId,\n transportMessage: msg,\n tags: ['invariant-violation'],\n });\n\n throw new Error(err);\n }\n\n return this.getOrCreateSession({ to }).session.send(msg);\n }\n\n // control helpers\n sendCloseStream(to: TransportClientId, streamId: string) {\n return this.send(to, {\n streamId: streamId,\n controlFlags: ControlFlags.StreamClosedBit,\n payload: {\n type: 'CLOSE' as const,\n } satisfies Static<typeof ControlMessagePayloadSchema>,\n });\n }\n\n protected protocolError(type: ProtocolErrorType, message: string) {\n this.eventDispatcher.dispatchEvent('protocolError', { type, message });\n }\n\n /**\n * Default close implementation for transports. You should override this in the downstream\n * implementation if you need to do any additional cleanup and call super.close() at the end.\n * Closes the transport. Any messages sent while the transport is closed will be silently discarded.\n */\n close() {\n this.status = 'closed';\n\n for (const session of this.sessions.values()) {\n this.deleteSession({ session, closeHandshakingConnection: true });\n }\n\n this.eventDispatcher.dispatchEvent('transportStatus', {\n status: this.status,\n });\n\n this.eventDispatcher.removeAllListeners();\n\n this.log?.info(`manually closed transport`, { clientId: this.clientId });\n }\n\n getStatus(): TransportStatus {\n return this.status;\n }\n}\n"],"mappings":"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","names":[]}