@replit/river 0.207.2 → 0.207.3
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/adapter-f2b6e211.d.ts +46 -0
- package/dist/{chunk-4HE7UYRL.js → chunk-B7REV3ZV.js} +6 -5
- package/dist/{chunk-4HE7UYRL.js.map → chunk-B7REV3ZV.js.map} +1 -1
- package/dist/{chunk-24EWYOGK.js → chunk-BO7MFCO6.js} +1136 -143
- package/dist/chunk-BO7MFCO6.js.map +1 -0
- package/dist/{chunk-46IVOKJU.js → chunk-QGPYCXV4.js} +2 -2
- package/dist/{chunk-46IVOKJU.js.map → chunk-QGPYCXV4.js.map} +1 -1
- package/dist/codec/index.cjs +157 -23
- package/dist/codec/index.cjs.map +1 -1
- package/dist/codec/index.d.cts +5 -1
- package/dist/codec/index.d.ts +5 -1
- package/dist/codec/index.js +6 -20
- package/dist/codec/index.js.map +1 -1
- package/dist/{connection-a18e31d5.d.ts → connection-06d72f2e.d.ts} +3 -2
- package/dist/index-02554794.d.ts +37 -0
- package/dist/logging/index.d.cts +2 -1
- package/dist/logging/index.d.ts +2 -1
- package/dist/{message-ffacb98a.d.ts → message-01c3e85a.d.ts} +1 -35
- package/dist/router/index.cjs +1 -1
- package/dist/router/index.cjs.map +1 -1
- package/dist/router/index.d.cts +6 -5
- package/dist/router/index.d.ts +6 -5
- package/dist/router/index.js +1 -1
- package/dist/{services-43528f4b.d.ts → services-87887bc5.d.ts} +16 -12
- package/dist/testUtil/index.cjs +809 -657
- package/dist/testUtil/index.cjs.map +1 -1
- package/dist/testUtil/index.d.cts +4 -3
- package/dist/testUtil/index.d.ts +4 -3
- package/dist/testUtil/index.js +18 -13
- package/dist/testUtil/index.js.map +1 -1
- package/dist/transport/impls/ws/client.cjs +293 -204
- package/dist/transport/impls/ws/client.cjs.map +1 -1
- package/dist/transport/impls/ws/client.d.cts +5 -4
- package/dist/transport/impls/ws/client.d.ts +5 -4
- package/dist/transport/impls/ws/client.js +5 -7
- package/dist/transport/impls/ws/client.js.map +1 -1
- package/dist/transport/impls/ws/server.cjs +230 -128
- package/dist/transport/impls/ws/server.cjs.map +1 -1
- package/dist/transport/impls/ws/server.d.cts +5 -4
- package/dist/transport/impls/ws/server.d.ts +5 -4
- package/dist/transport/impls/ws/server.js +5 -7
- package/dist/transport/impls/ws/server.js.map +1 -1
- package/dist/transport/index.cjs +408 -270
- package/dist/transport/index.cjs.map +1 -1
- package/dist/transport/index.d.cts +7 -6
- package/dist/transport/index.d.ts +7 -6
- package/dist/transport/index.js +4 -9
- package/package.json +1 -1
- package/dist/chunk-24EWYOGK.js.map +0 -1
- package/dist/chunk-A7RGOVRV.js +0 -438
- package/dist/chunk-A7RGOVRV.js.map +0 -1
- package/dist/chunk-AJGIY2UB.js +0 -56
- package/dist/chunk-AJGIY2UB.js.map +0 -1
- package/dist/chunk-XV4RQ62N.js +0 -377
- package/dist/chunk-XV4RQ62N.js.map +0 -1
- package/dist/types-3e5768ec.d.ts +0 -20
package/dist/testUtil/index.cjs
CHANGED
|
@@ -235,23 +235,20 @@ var NaiveJsonCodec = {
|
|
|
235
235
|
);
|
|
236
236
|
},
|
|
237
237
|
fromBuffer: (buff) => {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
return val;
|
|
246
|
-
}
|
|
238
|
+
const parsed = JSON.parse(
|
|
239
|
+
decoder.decode(buff),
|
|
240
|
+
function reviver(_key, val) {
|
|
241
|
+
if (val?.$t) {
|
|
242
|
+
return base64ToUint8Array(val.$t);
|
|
243
|
+
} else {
|
|
244
|
+
return val;
|
|
247
245
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
} catch {
|
|
253
|
-
return null;
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
249
|
+
throw new Error("unpacked msg is not an object");
|
|
254
250
|
}
|
|
251
|
+
return parsed;
|
|
255
252
|
}
|
|
256
253
|
};
|
|
257
254
|
|
|
@@ -281,7 +278,6 @@ var defaultServerTransportOptions = {
|
|
|
281
278
|
};
|
|
282
279
|
|
|
283
280
|
// transport/sessionStateMachine/common.ts
|
|
284
|
-
var import_value = require("@sinclair/typebox/value");
|
|
285
281
|
var ERR_CONSUMED = `session state has been consumed and is no longer valid`;
|
|
286
282
|
var StateMachineState = class {
|
|
287
283
|
/*
|
|
@@ -341,34 +337,16 @@ var StateMachineState = class {
|
|
|
341
337
|
var CommonSession = class extends StateMachineState {
|
|
342
338
|
from;
|
|
343
339
|
options;
|
|
340
|
+
codec;
|
|
344
341
|
tracer;
|
|
345
342
|
log;
|
|
346
|
-
constructor({ from, options, log, tracer }) {
|
|
343
|
+
constructor({ from, options, log, tracer, codec }) {
|
|
347
344
|
super();
|
|
348
345
|
this.from = from;
|
|
349
346
|
this.options = options;
|
|
350
347
|
this.log = log;
|
|
351
348
|
this.tracer = tracer;
|
|
352
|
-
|
|
353
|
-
parseMsg(msg) {
|
|
354
|
-
const parsedMsg = this.options.codec.fromBuffer(msg);
|
|
355
|
-
if (parsedMsg === null) {
|
|
356
|
-
this.log?.error(
|
|
357
|
-
`received malformed msg: ${Buffer.from(msg).toString("base64")}`,
|
|
358
|
-
this.loggingMetadata
|
|
359
|
-
);
|
|
360
|
-
return null;
|
|
361
|
-
}
|
|
362
|
-
if (!import_value.Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
|
|
363
|
-
this.log?.error(`received invalid msg: ${JSON.stringify(parsedMsg)}`, {
|
|
364
|
-
...this.loggingMetadata,
|
|
365
|
-
validationErrors: [
|
|
366
|
-
...import_value.Value.Errors(OpaqueTransportMessageSchema, parsedMsg)
|
|
367
|
-
]
|
|
368
|
-
});
|
|
369
|
-
return null;
|
|
370
|
-
}
|
|
371
|
-
return parsedMsg;
|
|
349
|
+
this.codec = codec;
|
|
372
350
|
}
|
|
373
351
|
};
|
|
374
352
|
var IdentifiedSession = class extends CommonSession {
|
|
@@ -428,9 +406,6 @@ var IdentifiedSession = class extends CommonSession {
|
|
|
428
406
|
return metadata;
|
|
429
407
|
}
|
|
430
408
|
constructMsg(partialMsg) {
|
|
431
|
-
if (this._isConsumed) {
|
|
432
|
-
throw new Error(ERR_CONSUMED);
|
|
433
|
-
}
|
|
434
409
|
const msg = {
|
|
435
410
|
...partialMsg,
|
|
436
411
|
id: generateId(),
|
|
@@ -448,7 +423,10 @@ var IdentifiedSession = class extends CommonSession {
|
|
|
448
423
|
send(msg) {
|
|
449
424
|
const constructedMsg = this.constructMsg(msg);
|
|
450
425
|
this.sendBuffer.push(constructedMsg);
|
|
451
|
-
return
|
|
426
|
+
return {
|
|
427
|
+
ok: true,
|
|
428
|
+
value: constructedMsg.id
|
|
429
|
+
};
|
|
452
430
|
}
|
|
453
431
|
_handleStateExit() {
|
|
454
432
|
}
|
|
@@ -480,6 +458,23 @@ var IdentifiedSessionWithGracePeriod = class extends IdentifiedSession {
|
|
|
480
458
|
super._handleClose();
|
|
481
459
|
}
|
|
482
460
|
};
|
|
461
|
+
function sendMessage(conn, codec, msg) {
|
|
462
|
+
const buff = codec.toBuffer(msg);
|
|
463
|
+
if (!buff.ok) {
|
|
464
|
+
return buff;
|
|
465
|
+
}
|
|
466
|
+
const sent = conn.send(buff.value);
|
|
467
|
+
if (!sent) {
|
|
468
|
+
return {
|
|
469
|
+
ok: false,
|
|
470
|
+
reason: "failed to send message"
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
return {
|
|
474
|
+
ok: true,
|
|
475
|
+
value: msg.id
|
|
476
|
+
};
|
|
477
|
+
}
|
|
483
478
|
|
|
484
479
|
// transport/sessionStateMachine/SessionConnecting.ts
|
|
485
480
|
var SessionConnecting = class extends IdentifiedSessionWithGracePeriod {
|
|
@@ -532,8 +527,8 @@ var SessionConnecting = class extends IdentifiedSessionWithGracePeriod {
|
|
|
532
527
|
}
|
|
533
528
|
}
|
|
534
529
|
_handleClose() {
|
|
535
|
-
this.bestEffortClose();
|
|
536
530
|
super._handleClose();
|
|
531
|
+
this.bestEffortClose();
|
|
537
532
|
}
|
|
538
533
|
};
|
|
539
534
|
|
|
@@ -560,7 +555,7 @@ function coerceErrorString(err) {
|
|
|
560
555
|
}
|
|
561
556
|
|
|
562
557
|
// package.json
|
|
563
|
-
var version = "0.207.
|
|
558
|
+
var version = "0.207.3";
|
|
564
559
|
|
|
565
560
|
// tracing/index.ts
|
|
566
561
|
function getPropagationContext(ctx) {
|
|
@@ -632,18 +627,18 @@ var SessionWaitingForHandshake = class extends CommonSession {
|
|
|
632
627
|
};
|
|
633
628
|
}
|
|
634
629
|
onHandshakeData = (msg) => {
|
|
635
|
-
const
|
|
636
|
-
if (
|
|
630
|
+
const parsedMsgRes = this.codec.fromBuffer(msg);
|
|
631
|
+
if (!parsedMsgRes.ok) {
|
|
637
632
|
this.listeners.onInvalidHandshake(
|
|
638
|
-
|
|
633
|
+
`could not parse handshake message: ${parsedMsgRes.reason}`,
|
|
639
634
|
"MALFORMED_HANDSHAKE"
|
|
640
635
|
);
|
|
641
636
|
return;
|
|
642
637
|
}
|
|
643
|
-
this.listeners.onHandshake(
|
|
638
|
+
this.listeners.onHandshake(parsedMsgRes.value);
|
|
644
639
|
};
|
|
645
640
|
sendHandshake(msg) {
|
|
646
|
-
return this.conn
|
|
641
|
+
return sendMessage(this.conn, this.codec, msg);
|
|
647
642
|
}
|
|
648
643
|
_handleStateExit() {
|
|
649
644
|
this.conn.removeDataListener(this.onHandshakeData);
|
|
@@ -681,18 +676,18 @@ var SessionHandshaking = class extends IdentifiedSessionWithGracePeriod {
|
|
|
681
676
|
};
|
|
682
677
|
}
|
|
683
678
|
onHandshakeData = (msg) => {
|
|
684
|
-
const
|
|
685
|
-
if (
|
|
679
|
+
const parsedMsgRes = this.codec.fromBuffer(msg);
|
|
680
|
+
if (!parsedMsgRes.ok) {
|
|
686
681
|
this.listeners.onInvalidHandshake(
|
|
687
|
-
|
|
682
|
+
`could not parse handshake message: ${parsedMsgRes.reason}`,
|
|
688
683
|
"MALFORMED_HANDSHAKE"
|
|
689
684
|
);
|
|
690
685
|
return;
|
|
691
686
|
}
|
|
692
|
-
this.listeners.onHandshake(
|
|
687
|
+
this.listeners.onHandshake(parsedMsgRes.value);
|
|
693
688
|
};
|
|
694
689
|
sendHandshake(msg) {
|
|
695
|
-
return this.conn
|
|
690
|
+
return sendMessage(this.conn, this.codec, msg);
|
|
696
691
|
}
|
|
697
692
|
_handleStateExit() {
|
|
698
693
|
super._handleStateExit();
|
|
@@ -717,25 +712,15 @@ var SessionConnected = class extends IdentifiedSession {
|
|
|
717
712
|
conn;
|
|
718
713
|
listeners;
|
|
719
714
|
heartbeatHandle;
|
|
720
|
-
|
|
721
|
-
isActivelyHeartbeating;
|
|
722
|
-
lastConstructedMsgs = [];
|
|
723
|
-
pushLastConstructedMsgs = (msg) => {
|
|
724
|
-
const trackedMsg = {
|
|
725
|
-
id: msg.id,
|
|
726
|
-
seq: msg.seq,
|
|
727
|
-
streamId: msg.streamId,
|
|
728
|
-
stack: new Error().stack
|
|
729
|
-
};
|
|
730
|
-
this.lastConstructedMsgs.push(trackedMsg);
|
|
731
|
-
if (this.lastConstructedMsgs.length > 10) {
|
|
732
|
-
this.lastConstructedMsgs.shift();
|
|
733
|
-
}
|
|
734
|
-
};
|
|
715
|
+
heartbeatMissTimeout;
|
|
716
|
+
isActivelyHeartbeating = false;
|
|
735
717
|
updateBookkeeping(ack, seq) {
|
|
736
718
|
this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq >= ack);
|
|
737
719
|
this.ack = seq + 1;
|
|
738
|
-
this.
|
|
720
|
+
if (this.heartbeatMissTimeout) {
|
|
721
|
+
clearTimeout(this.heartbeatMissTimeout);
|
|
722
|
+
}
|
|
723
|
+
this.startMissingHeartbeatTimeout();
|
|
739
724
|
}
|
|
740
725
|
assertSendOrdering(constructedMsg) {
|
|
741
726
|
if (constructedMsg.seq > this.seqSent + 1) {
|
|
@@ -743,22 +728,22 @@ var SessionConnected = class extends IdentifiedSession {
|
|
|
743
728
|
this.log?.error(msg, {
|
|
744
729
|
...this.loggingMetadata,
|
|
745
730
|
transportMessage: constructedMsg,
|
|
746
|
-
tags: ["invariant-violation"]
|
|
747
|
-
extras: {
|
|
748
|
-
lastConstructedMsgs: this.lastConstructedMsgs
|
|
749
|
-
}
|
|
731
|
+
tags: ["invariant-violation"]
|
|
750
732
|
});
|
|
751
733
|
throw new Error(msg);
|
|
752
734
|
}
|
|
753
735
|
}
|
|
754
736
|
send(msg) {
|
|
755
737
|
const constructedMsg = this.constructMsg(msg);
|
|
756
|
-
this.pushLastConstructedMsgs(constructedMsg);
|
|
757
738
|
this.assertSendOrdering(constructedMsg);
|
|
758
739
|
this.sendBuffer.push(constructedMsg);
|
|
759
|
-
this.conn
|
|
740
|
+
const res = sendMessage(this.conn, this.codec, constructedMsg);
|
|
741
|
+
if (!res.ok) {
|
|
742
|
+
this.listeners.onMessageSendFailure(constructedMsg, res.reason);
|
|
743
|
+
return res;
|
|
744
|
+
}
|
|
760
745
|
this.seqSent = constructedMsg.seq;
|
|
761
|
-
return
|
|
746
|
+
return res;
|
|
762
747
|
}
|
|
763
748
|
constructor(props) {
|
|
764
749
|
super(props);
|
|
@@ -767,6 +752,8 @@ var SessionConnected = class extends IdentifiedSession {
|
|
|
767
752
|
this.conn.addDataListener(this.onMessageData);
|
|
768
753
|
this.conn.addCloseListener(this.listeners.onConnectionClosed);
|
|
769
754
|
this.conn.addErrorListener(this.listeners.onConnectionErrored);
|
|
755
|
+
}
|
|
756
|
+
sendBufferedMessages() {
|
|
770
757
|
if (this.sendBuffer.length > 0) {
|
|
771
758
|
this.log?.info(
|
|
772
759
|
`sending ${this.sendBuffer.length} buffered messages, starting at seq ${this.nextSeq()}`,
|
|
@@ -774,30 +761,15 @@ var SessionConnected = class extends IdentifiedSession {
|
|
|
774
761
|
);
|
|
775
762
|
for (const msg of this.sendBuffer) {
|
|
776
763
|
this.assertSendOrdering(msg);
|
|
777
|
-
this.conn
|
|
764
|
+
const res = sendMessage(this.conn, this.codec, msg);
|
|
765
|
+
if (!res.ok) {
|
|
766
|
+
this.listeners.onMessageSendFailure(msg, res.reason);
|
|
767
|
+
return res;
|
|
768
|
+
}
|
|
778
769
|
this.seqSent = msg.seq;
|
|
779
770
|
}
|
|
780
771
|
}
|
|
781
|
-
|
|
782
|
-
this.heartbeatHandle = setInterval(() => {
|
|
783
|
-
const misses = this.heartbeatMisses;
|
|
784
|
-
const missDuration = misses * this.options.heartbeatIntervalMs;
|
|
785
|
-
if (misses >= this.options.heartbeatsUntilDead) {
|
|
786
|
-
this.log?.info(
|
|
787
|
-
`closing connection to ${this.to} due to inactivity (missed ${misses} heartbeats which is ${missDuration}ms)`,
|
|
788
|
-
this.loggingMetadata
|
|
789
|
-
);
|
|
790
|
-
this.telemetry.span.addEvent("closing connection due to inactivity");
|
|
791
|
-
this.conn.close();
|
|
792
|
-
clearInterval(this.heartbeatHandle);
|
|
793
|
-
this.heartbeatHandle = void 0;
|
|
794
|
-
return;
|
|
795
|
-
}
|
|
796
|
-
if (this.isActivelyHeartbeating) {
|
|
797
|
-
this.sendHeartbeat();
|
|
798
|
-
}
|
|
799
|
-
this.heartbeatMisses++;
|
|
800
|
-
}, this.options.heartbeatIntervalMs);
|
|
772
|
+
return { ok: true, value: void 0 };
|
|
801
773
|
}
|
|
802
774
|
get loggingMetadata() {
|
|
803
775
|
return {
|
|
@@ -805,25 +777,46 @@ var SessionConnected = class extends IdentifiedSession {
|
|
|
805
777
|
...this.conn.loggingMetadata
|
|
806
778
|
};
|
|
807
779
|
}
|
|
780
|
+
startMissingHeartbeatTimeout() {
|
|
781
|
+
const maxMisses = this.options.heartbeatsUntilDead;
|
|
782
|
+
const missDuration = maxMisses * this.options.heartbeatIntervalMs;
|
|
783
|
+
this.heartbeatMissTimeout = setTimeout(() => {
|
|
784
|
+
this.log?.info(
|
|
785
|
+
`closing connection to ${this.to} due to inactivity (missed ${maxMisses} heartbeats which is ${missDuration}ms)`,
|
|
786
|
+
this.loggingMetadata
|
|
787
|
+
);
|
|
788
|
+
this.telemetry.span.addEvent(
|
|
789
|
+
"closing connection due to missing heartbeat"
|
|
790
|
+
);
|
|
791
|
+
this.conn.close();
|
|
792
|
+
}, missDuration);
|
|
793
|
+
}
|
|
808
794
|
startActiveHeartbeat() {
|
|
809
795
|
this.isActivelyHeartbeating = true;
|
|
796
|
+
this.heartbeatHandle = setInterval(() => {
|
|
797
|
+
this.sendHeartbeat();
|
|
798
|
+
}, this.options.heartbeatIntervalMs);
|
|
810
799
|
}
|
|
811
800
|
sendHeartbeat() {
|
|
812
801
|
this.log?.debug("sending heartbeat", this.loggingMetadata);
|
|
813
|
-
|
|
802
|
+
const heartbeat = {
|
|
814
803
|
streamId: "heartbeat",
|
|
815
804
|
controlFlags: 1 /* AckBit */,
|
|
816
805
|
payload: {
|
|
817
806
|
type: "ACK"
|
|
818
807
|
}
|
|
819
|
-
}
|
|
808
|
+
};
|
|
809
|
+
this.send(heartbeat);
|
|
820
810
|
}
|
|
821
811
|
onMessageData = (msg) => {
|
|
822
|
-
const
|
|
823
|
-
if (
|
|
824
|
-
this.listeners.onInvalidMessage(
|
|
812
|
+
const parsedMsgRes = this.codec.fromBuffer(msg);
|
|
813
|
+
if (!parsedMsgRes.ok) {
|
|
814
|
+
this.listeners.onInvalidMessage(
|
|
815
|
+
`could not parse message: ${parsedMsgRes.reason}`
|
|
816
|
+
);
|
|
825
817
|
return;
|
|
826
818
|
}
|
|
819
|
+
const parsedMsg = parsedMsgRes.value;
|
|
827
820
|
if (parsedMsg.seq !== this.ack) {
|
|
828
821
|
if (parsedMsg.seq < this.ack) {
|
|
829
822
|
this.log?.debug(
|
|
@@ -862,9 +855,7 @@ var SessionConnected = class extends IdentifiedSession {
|
|
|
862
855
|
transportMessage: parsedMsg
|
|
863
856
|
});
|
|
864
857
|
if (!this.isActivelyHeartbeating) {
|
|
865
|
-
|
|
866
|
-
this.sendHeartbeat();
|
|
867
|
-
});
|
|
858
|
+
this.sendHeartbeat();
|
|
868
859
|
}
|
|
869
860
|
};
|
|
870
861
|
_handleStateExit() {
|
|
@@ -876,6 +867,10 @@ var SessionConnected = class extends IdentifiedSession {
|
|
|
876
867
|
clearInterval(this.heartbeatHandle);
|
|
877
868
|
this.heartbeatHandle = void 0;
|
|
878
869
|
}
|
|
870
|
+
if (this.heartbeatMissTimeout) {
|
|
871
|
+
clearTimeout(this.heartbeatMissTimeout);
|
|
872
|
+
this.heartbeatMissTimeout = void 0;
|
|
873
|
+
}
|
|
879
874
|
}
|
|
880
875
|
_handleClose() {
|
|
881
876
|
super._handleClose();
|
|
@@ -907,425 +902,47 @@ var SessionBackingOff = class extends IdentifiedSessionWithGracePeriod {
|
|
|
907
902
|
}
|
|
908
903
|
};
|
|
909
904
|
|
|
910
|
-
//
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
905
|
+
// codec/adapter.ts
|
|
906
|
+
var import_value3 = require("@sinclair/typebox/value");
|
|
907
|
+
|
|
908
|
+
// logging/log.ts
|
|
909
|
+
var import_api3 = require("@opentelemetry/api");
|
|
910
|
+
var LoggingLevels = {
|
|
911
|
+
debug: -1,
|
|
912
|
+
info: 0,
|
|
913
|
+
warn: 1,
|
|
914
|
+
error: 2
|
|
915
|
+
};
|
|
916
|
+
var cleanedLogFn = (log) => {
|
|
917
|
+
return (msg, metadata) => {
|
|
918
|
+
if (metadata && !metadata.telemetry) {
|
|
919
|
+
const span = import_api3.trace.getSpan(import_api3.context.active());
|
|
920
|
+
if (span) {
|
|
921
|
+
metadata.telemetry = {
|
|
922
|
+
traceId: span.spanContext().traceId,
|
|
923
|
+
spanId: span.spanContext().spanId
|
|
924
|
+
};
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
if (!metadata?.transportMessage) {
|
|
928
|
+
log(msg, metadata);
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
const { payload, ...rest } = metadata.transportMessage;
|
|
932
|
+
metadata.transportMessage = rest;
|
|
933
|
+
log(msg, metadata);
|
|
931
934
|
};
|
|
932
|
-
}
|
|
933
|
-
var
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
to,
|
|
944
|
-
seq: 0,
|
|
945
|
-
ack: 0,
|
|
946
|
-
seqSent: 0,
|
|
947
|
-
graceExpiryTime: Date.now() + options.sessionDisconnectGraceMs,
|
|
948
|
-
sendBuffer,
|
|
949
|
-
telemetry,
|
|
950
|
-
options,
|
|
951
|
-
protocolVersion,
|
|
952
|
-
tracer,
|
|
953
|
-
log
|
|
954
|
-
});
|
|
955
|
-
session.log?.info(`session ${session.id} created in NoConnection state`, {
|
|
956
|
-
...session.loggingMetadata,
|
|
957
|
-
tags: ["state-transition"]
|
|
958
|
-
});
|
|
959
|
-
return session;
|
|
960
|
-
},
|
|
961
|
-
WaitingForHandshake: (from, conn, listeners, options, tracer, log) => {
|
|
962
|
-
const session = new SessionWaitingForHandshake({
|
|
963
|
-
conn,
|
|
964
|
-
listeners,
|
|
965
|
-
from,
|
|
966
|
-
options,
|
|
967
|
-
tracer,
|
|
968
|
-
log
|
|
969
|
-
});
|
|
970
|
-
session.log?.info(`session created in WaitingForHandshake state`, {
|
|
971
|
-
...session.loggingMetadata,
|
|
972
|
-
tags: ["state-transition"]
|
|
973
|
-
});
|
|
974
|
-
return session;
|
|
975
|
-
}
|
|
976
|
-
},
|
|
977
|
-
// All of the transitions 'move'/'consume' the old session and return a new one.
|
|
978
|
-
// After a session is transitioned, any usage of the old session will throw.
|
|
979
|
-
transition: {
|
|
980
|
-
// happy path transitions
|
|
981
|
-
NoConnectionToBackingOff: (oldSession, backoffMs, listeners) => {
|
|
982
|
-
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
983
|
-
oldSession._handleStateExit();
|
|
984
|
-
const session = new SessionBackingOff({
|
|
985
|
-
backoffMs,
|
|
986
|
-
listeners,
|
|
987
|
-
...carriedState
|
|
988
|
-
});
|
|
989
|
-
session.log?.info(
|
|
990
|
-
`session ${session.id} transition from NoConnection to BackingOff`,
|
|
991
|
-
{
|
|
992
|
-
...session.loggingMetadata,
|
|
993
|
-
tags: ["state-transition"]
|
|
994
|
-
}
|
|
995
|
-
);
|
|
996
|
-
return session;
|
|
997
|
-
},
|
|
998
|
-
BackingOffToConnecting: (oldSession, connPromise, listeners) => {
|
|
999
|
-
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
1000
|
-
oldSession._handleStateExit();
|
|
1001
|
-
const session = new SessionConnecting({
|
|
1002
|
-
connPromise,
|
|
1003
|
-
listeners,
|
|
1004
|
-
...carriedState
|
|
1005
|
-
});
|
|
1006
|
-
session.log?.info(
|
|
1007
|
-
`session ${session.id} transition from BackingOff to Connecting`,
|
|
1008
|
-
{
|
|
1009
|
-
...session.loggingMetadata,
|
|
1010
|
-
tags: ["state-transition"]
|
|
1011
|
-
}
|
|
1012
|
-
);
|
|
1013
|
-
return session;
|
|
1014
|
-
},
|
|
1015
|
-
ConnectingToHandshaking: (oldSession, conn, listeners) => {
|
|
1016
|
-
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
1017
|
-
oldSession._handleStateExit();
|
|
1018
|
-
const session = new SessionHandshaking({
|
|
1019
|
-
conn,
|
|
1020
|
-
listeners,
|
|
1021
|
-
...carriedState
|
|
1022
|
-
});
|
|
1023
|
-
conn.telemetry = createConnectionTelemetryInfo(
|
|
1024
|
-
session.tracer,
|
|
1025
|
-
conn,
|
|
1026
|
-
session.telemetry
|
|
1027
|
-
);
|
|
1028
|
-
session.log?.info(
|
|
1029
|
-
`session ${session.id} transition from Connecting to Handshaking`,
|
|
1030
|
-
{
|
|
1031
|
-
...session.loggingMetadata,
|
|
1032
|
-
tags: ["state-transition"]
|
|
1033
|
-
}
|
|
1034
|
-
);
|
|
1035
|
-
return session;
|
|
1036
|
-
},
|
|
1037
|
-
HandshakingToConnected: (oldSession, listeners) => {
|
|
1038
|
-
const carriedState = inheritSharedSession(oldSession);
|
|
1039
|
-
const conn = oldSession.conn;
|
|
1040
|
-
oldSession._handleStateExit();
|
|
1041
|
-
const session = new SessionConnected({
|
|
1042
|
-
conn,
|
|
1043
|
-
listeners,
|
|
1044
|
-
...carriedState
|
|
1045
|
-
});
|
|
1046
|
-
session.log?.info(
|
|
1047
|
-
`session ${session.id} transition from Handshaking to Connected`,
|
|
1048
|
-
{
|
|
1049
|
-
...session.loggingMetadata,
|
|
1050
|
-
tags: ["state-transition"]
|
|
1051
|
-
}
|
|
1052
|
-
);
|
|
1053
|
-
return session;
|
|
1054
|
-
},
|
|
1055
|
-
WaitingForHandshakeToConnected: (pendingSession, oldSession, sessionId, to, propagationCtx, listeners, protocolVersion) => {
|
|
1056
|
-
const conn = pendingSession.conn;
|
|
1057
|
-
const { from, options } = pendingSession;
|
|
1058
|
-
const carriedState = oldSession ? (
|
|
1059
|
-
// old session exists, inherit state
|
|
1060
|
-
inheritSharedSession(oldSession)
|
|
1061
|
-
) : (
|
|
1062
|
-
// old session does not exist, create new state
|
|
1063
|
-
{
|
|
1064
|
-
id: sessionId,
|
|
1065
|
-
from,
|
|
1066
|
-
to,
|
|
1067
|
-
seq: 0,
|
|
1068
|
-
ack: 0,
|
|
1069
|
-
seqSent: 0,
|
|
1070
|
-
sendBuffer: [],
|
|
1071
|
-
telemetry: createSessionTelemetryInfo(
|
|
1072
|
-
pendingSession.tracer,
|
|
1073
|
-
sessionId,
|
|
1074
|
-
to,
|
|
1075
|
-
from,
|
|
1076
|
-
propagationCtx
|
|
1077
|
-
),
|
|
1078
|
-
options,
|
|
1079
|
-
tracer: pendingSession.tracer,
|
|
1080
|
-
log: pendingSession.log,
|
|
1081
|
-
protocolVersion
|
|
1082
|
-
}
|
|
1083
|
-
);
|
|
1084
|
-
pendingSession._handleStateExit();
|
|
1085
|
-
oldSession?._handleStateExit();
|
|
1086
|
-
const session = new SessionConnected({
|
|
1087
|
-
conn,
|
|
1088
|
-
listeners,
|
|
1089
|
-
...carriedState
|
|
1090
|
-
});
|
|
1091
|
-
conn.telemetry = createConnectionTelemetryInfo(
|
|
1092
|
-
session.tracer,
|
|
1093
|
-
conn,
|
|
1094
|
-
session.telemetry
|
|
1095
|
-
);
|
|
1096
|
-
session.log?.info(
|
|
1097
|
-
`session ${session.id} transition from WaitingForHandshake to Connected`,
|
|
1098
|
-
{
|
|
1099
|
-
...session.loggingMetadata,
|
|
1100
|
-
tags: ["state-transition"]
|
|
1101
|
-
}
|
|
1102
|
-
);
|
|
1103
|
-
return session;
|
|
1104
|
-
},
|
|
1105
|
-
// disconnect paths
|
|
1106
|
-
BackingOffToNoConnection: (oldSession, listeners) => {
|
|
1107
|
-
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
1108
|
-
oldSession._handleStateExit();
|
|
1109
|
-
const session = new SessionNoConnection({
|
|
1110
|
-
listeners,
|
|
1111
|
-
...carriedState
|
|
1112
|
-
});
|
|
1113
|
-
session.log?.info(
|
|
1114
|
-
`session ${session.id} transition from BackingOff to NoConnection`,
|
|
1115
|
-
{
|
|
1116
|
-
...session.loggingMetadata,
|
|
1117
|
-
tags: ["state-transition"]
|
|
1118
|
-
}
|
|
1119
|
-
);
|
|
1120
|
-
return session;
|
|
1121
|
-
},
|
|
1122
|
-
ConnectingToNoConnection: (oldSession, listeners) => {
|
|
1123
|
-
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
1124
|
-
oldSession.bestEffortClose();
|
|
1125
|
-
oldSession._handleStateExit();
|
|
1126
|
-
const session = new SessionNoConnection({
|
|
1127
|
-
listeners,
|
|
1128
|
-
...carriedState
|
|
1129
|
-
});
|
|
1130
|
-
session.log?.info(
|
|
1131
|
-
`session ${session.id} transition from Connecting to NoConnection`,
|
|
1132
|
-
{
|
|
1133
|
-
...session.loggingMetadata,
|
|
1134
|
-
tags: ["state-transition"]
|
|
1135
|
-
}
|
|
1136
|
-
);
|
|
1137
|
-
return session;
|
|
1138
|
-
},
|
|
1139
|
-
HandshakingToNoConnection: (oldSession, listeners) => {
|
|
1140
|
-
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
1141
|
-
oldSession.conn.close();
|
|
1142
|
-
oldSession._handleStateExit();
|
|
1143
|
-
const session = new SessionNoConnection({
|
|
1144
|
-
listeners,
|
|
1145
|
-
...carriedState
|
|
1146
|
-
});
|
|
1147
|
-
session.log?.info(
|
|
1148
|
-
`session ${session.id} transition from Handshaking to NoConnection`,
|
|
1149
|
-
{
|
|
1150
|
-
...session.loggingMetadata,
|
|
1151
|
-
tags: ["state-transition"]
|
|
1152
|
-
}
|
|
1153
|
-
);
|
|
1154
|
-
return session;
|
|
1155
|
-
},
|
|
1156
|
-
ConnectedToNoConnection: (oldSession, listeners) => {
|
|
1157
|
-
const carriedState = inheritSharedSession(oldSession);
|
|
1158
|
-
const graceExpiryTime = Date.now() + oldSession.options.sessionDisconnectGraceMs;
|
|
1159
|
-
oldSession.conn.close();
|
|
1160
|
-
oldSession._handleStateExit();
|
|
1161
|
-
const session = new SessionNoConnection({
|
|
1162
|
-
listeners,
|
|
1163
|
-
graceExpiryTime,
|
|
1164
|
-
...carriedState
|
|
1165
|
-
});
|
|
1166
|
-
session.log?.info(
|
|
1167
|
-
`session ${session.id} transition from Connected to NoConnection`,
|
|
1168
|
-
{
|
|
1169
|
-
...session.loggingMetadata,
|
|
1170
|
-
tags: ["state-transition"]
|
|
1171
|
-
}
|
|
1172
|
-
);
|
|
1173
|
-
return session;
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
};
|
|
1177
|
-
var transitions = SessionStateGraph.transition;
|
|
1178
|
-
var ClientSessionStateGraph = {
|
|
1179
|
-
entrypoint: SessionStateGraph.entrypoints.NoConnection,
|
|
1180
|
-
transition: {
|
|
1181
|
-
// happy paths
|
|
1182
|
-
// NoConnection -> BackingOff: attempt to connect
|
|
1183
|
-
NoConnectionToBackingOff: transitions.NoConnectionToBackingOff,
|
|
1184
|
-
// BackingOff -> Connecting: backoff period elapsed, start connection
|
|
1185
|
-
BackingOffToConnecting: transitions.BackingOffToConnecting,
|
|
1186
|
-
// Connecting -> Handshaking: connection established, start handshake
|
|
1187
|
-
ConnectingToHandshaking: transitions.ConnectingToHandshaking,
|
|
1188
|
-
// Handshaking -> Connected: handshake complete, session ready
|
|
1189
|
-
HandshakingToConnected: transitions.HandshakingToConnected,
|
|
1190
|
-
// disconnect paths
|
|
1191
|
-
// BackingOff -> NoConnection: unused
|
|
1192
|
-
BackingOffToNoConnection: transitions.BackingOffToNoConnection,
|
|
1193
|
-
// Connecting -> NoConnection: connection failed or connection timeout
|
|
1194
|
-
ConnectingToNoConnection: transitions.ConnectingToNoConnection,
|
|
1195
|
-
// Handshaking -> NoConnection: connection closed or handshake timeout
|
|
1196
|
-
HandshakingToNoConnection: transitions.HandshakingToNoConnection,
|
|
1197
|
-
// Connected -> NoConnection: connection closed
|
|
1198
|
-
ConnectedToNoConnection: transitions.ConnectedToNoConnection
|
|
1199
|
-
// destroy/close paths
|
|
1200
|
-
// NoConnection -> x: grace period elapsed
|
|
1201
|
-
// BackingOff -> x: grace period elapsed
|
|
1202
|
-
// Connecting -> x: grace period elapsed
|
|
1203
|
-
// Handshaking -> x: grace period elapsed or invalid handshake message or handshake rejection
|
|
1204
|
-
// Connected -> x: grace period elapsed or invalid message
|
|
1205
|
-
}
|
|
1206
|
-
};
|
|
1207
|
-
var ServerSessionStateGraph = {
|
|
1208
|
-
entrypoint: SessionStateGraph.entrypoints.WaitingForHandshake,
|
|
1209
|
-
transition: {
|
|
1210
|
-
// happy paths
|
|
1211
|
-
// WaitingForHandshake -> Connected: handshake complete, session ready
|
|
1212
|
-
WaitingForHandshakeToConnected: transitions.WaitingForHandshakeToConnected,
|
|
1213
|
-
// disconnect paths
|
|
1214
|
-
// Connected -> NoConnection: connection closed
|
|
1215
|
-
ConnectedToNoConnection: transitions.ConnectedToNoConnection
|
|
1216
|
-
// destroy/close paths
|
|
1217
|
-
// WaitingForHandshake -> x: handshake timeout elapsed or invalid handshake message or handshake rejection or connection closed
|
|
1218
|
-
}
|
|
1219
|
-
};
|
|
1220
|
-
|
|
1221
|
-
// transport/client.ts
|
|
1222
|
-
var import_api4 = require("@opentelemetry/api");
|
|
1223
|
-
|
|
1224
|
-
// transport/rateLimit.ts
|
|
1225
|
-
var LeakyBucketRateLimit = class {
|
|
1226
|
-
budgetConsumed;
|
|
1227
|
-
intervalHandle;
|
|
1228
|
-
options;
|
|
1229
|
-
constructor(options) {
|
|
1230
|
-
this.options = options;
|
|
1231
|
-
this.budgetConsumed = 0;
|
|
1232
|
-
}
|
|
1233
|
-
getBackoffMs() {
|
|
1234
|
-
if (this.getBudgetConsumed() === 0) {
|
|
1235
|
-
return 0;
|
|
1236
|
-
}
|
|
1237
|
-
const exponent = Math.max(0, this.getBudgetConsumed() - 1);
|
|
1238
|
-
const jitter = Math.floor(Math.random() * this.options.maxJitterMs);
|
|
1239
|
-
const backoffMs = Math.min(
|
|
1240
|
-
this.options.baseIntervalMs * 2 ** exponent,
|
|
1241
|
-
this.options.maxBackoffMs
|
|
1242
|
-
);
|
|
1243
|
-
return backoffMs + jitter;
|
|
1244
|
-
}
|
|
1245
|
-
get totalBudgetRestoreTime() {
|
|
1246
|
-
return this.options.budgetRestoreIntervalMs * this.options.attemptBudgetCapacity;
|
|
1247
|
-
}
|
|
1248
|
-
consumeBudget() {
|
|
1249
|
-
this.stopLeak();
|
|
1250
|
-
this.budgetConsumed = this.getBudgetConsumed() + 1;
|
|
1251
|
-
}
|
|
1252
|
-
getBudgetConsumed() {
|
|
1253
|
-
return this.budgetConsumed;
|
|
1254
|
-
}
|
|
1255
|
-
hasBudget() {
|
|
1256
|
-
return this.getBudgetConsumed() < this.options.attemptBudgetCapacity;
|
|
1257
|
-
}
|
|
1258
|
-
startRestoringBudget() {
|
|
1259
|
-
if (this.intervalHandle) {
|
|
1260
|
-
return;
|
|
1261
|
-
}
|
|
1262
|
-
const restoreBudgetForUser = () => {
|
|
1263
|
-
const currentBudget = this.budgetConsumed;
|
|
1264
|
-
if (!currentBudget) {
|
|
1265
|
-
this.stopLeak();
|
|
1266
|
-
return;
|
|
1267
|
-
}
|
|
1268
|
-
const newBudget = currentBudget - 1;
|
|
1269
|
-
if (newBudget === 0) {
|
|
1270
|
-
return;
|
|
1271
|
-
}
|
|
1272
|
-
this.budgetConsumed = newBudget;
|
|
1273
|
-
};
|
|
1274
|
-
this.intervalHandle = setInterval(
|
|
1275
|
-
restoreBudgetForUser,
|
|
1276
|
-
this.options.budgetRestoreIntervalMs
|
|
1277
|
-
);
|
|
1278
|
-
}
|
|
1279
|
-
stopLeak() {
|
|
1280
|
-
if (!this.intervalHandle) {
|
|
1281
|
-
return;
|
|
1282
|
-
}
|
|
1283
|
-
clearInterval(this.intervalHandle);
|
|
1284
|
-
this.intervalHandle = void 0;
|
|
1285
|
-
}
|
|
1286
|
-
close() {
|
|
1287
|
-
this.stopLeak();
|
|
1288
|
-
}
|
|
1289
|
-
};
|
|
1290
|
-
|
|
1291
|
-
// logging/log.ts
|
|
1292
|
-
var import_api3 = require("@opentelemetry/api");
|
|
1293
|
-
var LoggingLevels = {
|
|
1294
|
-
debug: -1,
|
|
1295
|
-
info: 0,
|
|
1296
|
-
warn: 1,
|
|
1297
|
-
error: 2
|
|
1298
|
-
};
|
|
1299
|
-
var cleanedLogFn = (log) => {
|
|
1300
|
-
return (msg, metadata) => {
|
|
1301
|
-
if (metadata && !metadata.telemetry) {
|
|
1302
|
-
const span = import_api3.trace.getSpan(import_api3.context.active());
|
|
1303
|
-
if (span) {
|
|
1304
|
-
metadata.telemetry = {
|
|
1305
|
-
traceId: span.spanContext().traceId,
|
|
1306
|
-
spanId: span.spanContext().spanId
|
|
1307
|
-
};
|
|
1308
|
-
}
|
|
1309
|
-
}
|
|
1310
|
-
if (!metadata?.transportMessage) {
|
|
1311
|
-
log(msg, metadata);
|
|
1312
|
-
return;
|
|
1313
|
-
}
|
|
1314
|
-
const { payload, ...rest } = metadata.transportMessage;
|
|
1315
|
-
metadata.transportMessage = rest;
|
|
1316
|
-
log(msg, metadata);
|
|
1317
|
-
};
|
|
1318
|
-
};
|
|
1319
|
-
var BaseLogger = class {
|
|
1320
|
-
minLevel;
|
|
1321
|
-
output;
|
|
1322
|
-
constructor(output, minLevel = "info") {
|
|
1323
|
-
this.minLevel = minLevel;
|
|
1324
|
-
this.output = output;
|
|
1325
|
-
}
|
|
1326
|
-
debug(msg, metadata) {
|
|
1327
|
-
if (LoggingLevels[this.minLevel] <= LoggingLevels.debug) {
|
|
1328
|
-
this.output(msg, metadata ?? {}, "debug");
|
|
935
|
+
};
|
|
936
|
+
var BaseLogger = class {
|
|
937
|
+
minLevel;
|
|
938
|
+
output;
|
|
939
|
+
constructor(output, minLevel = "info") {
|
|
940
|
+
this.minLevel = minLevel;
|
|
941
|
+
this.output = output;
|
|
942
|
+
}
|
|
943
|
+
debug(msg, metadata) {
|
|
944
|
+
if (LoggingLevels[this.minLevel] <= LoggingLevels.debug) {
|
|
945
|
+
this.output(msg, metadata ?? {}, "debug");
|
|
1329
946
|
}
|
|
1330
947
|
}
|
|
1331
948
|
info(msg, metadata) {
|
|
@@ -1356,7 +973,8 @@ var ProtocolError = {
|
|
|
1356
973
|
RetriesExceeded: "conn_retry_exceeded",
|
|
1357
974
|
HandshakeFailed: "handshake_failed",
|
|
1358
975
|
MessageOrderingViolated: "message_ordering_violated",
|
|
1359
|
-
InvalidMessage: "invalid_message"
|
|
976
|
+
InvalidMessage: "invalid_message",
|
|
977
|
+
MessageSendFailure: "message_send_failure"
|
|
1360
978
|
};
|
|
1361
979
|
var EventDispatcher = class {
|
|
1362
980
|
eventListeners = {};
|
|
@@ -1599,18 +1217,92 @@ var Transport = class {
|
|
|
1599
1217
|
);
|
|
1600
1218
|
}
|
|
1601
1219
|
const sameSession = session.id === sessionId;
|
|
1602
|
-
if (!sameSession) {
|
|
1220
|
+
if (!sameSession || session._isConsumed) {
|
|
1603
1221
|
throw new Error(
|
|
1604
1222
|
`session scope for ${sessionId} has ended (transition), can't send`
|
|
1605
1223
|
);
|
|
1606
1224
|
}
|
|
1607
|
-
|
|
1225
|
+
const res = session.send(msg);
|
|
1226
|
+
if (!res.ok) {
|
|
1227
|
+
throw new Error(res.reason);
|
|
1228
|
+
}
|
|
1229
|
+
return res.value;
|
|
1608
1230
|
};
|
|
1609
1231
|
}
|
|
1610
1232
|
};
|
|
1611
1233
|
|
|
1612
1234
|
// transport/client.ts
|
|
1613
|
-
var
|
|
1235
|
+
var import_api4 = require("@opentelemetry/api");
|
|
1236
|
+
|
|
1237
|
+
// transport/rateLimit.ts
|
|
1238
|
+
var LeakyBucketRateLimit = class {
|
|
1239
|
+
budgetConsumed;
|
|
1240
|
+
intervalHandle;
|
|
1241
|
+
options;
|
|
1242
|
+
constructor(options) {
|
|
1243
|
+
this.options = options;
|
|
1244
|
+
this.budgetConsumed = 0;
|
|
1245
|
+
}
|
|
1246
|
+
getBackoffMs() {
|
|
1247
|
+
if (this.getBudgetConsumed() === 0) {
|
|
1248
|
+
return 0;
|
|
1249
|
+
}
|
|
1250
|
+
const exponent = Math.max(0, this.getBudgetConsumed() - 1);
|
|
1251
|
+
const jitter = Math.floor(Math.random() * this.options.maxJitterMs);
|
|
1252
|
+
const backoffMs = Math.min(
|
|
1253
|
+
this.options.baseIntervalMs * 2 ** exponent,
|
|
1254
|
+
this.options.maxBackoffMs
|
|
1255
|
+
);
|
|
1256
|
+
return backoffMs + jitter;
|
|
1257
|
+
}
|
|
1258
|
+
get totalBudgetRestoreTime() {
|
|
1259
|
+
return this.options.budgetRestoreIntervalMs * this.options.attemptBudgetCapacity;
|
|
1260
|
+
}
|
|
1261
|
+
consumeBudget() {
|
|
1262
|
+
this.stopLeak();
|
|
1263
|
+
this.budgetConsumed = this.getBudgetConsumed() + 1;
|
|
1264
|
+
}
|
|
1265
|
+
getBudgetConsumed() {
|
|
1266
|
+
return this.budgetConsumed;
|
|
1267
|
+
}
|
|
1268
|
+
hasBudget() {
|
|
1269
|
+
return this.getBudgetConsumed() < this.options.attemptBudgetCapacity;
|
|
1270
|
+
}
|
|
1271
|
+
startRestoringBudget() {
|
|
1272
|
+
if (this.intervalHandle) {
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
const restoreBudgetForUser = () => {
|
|
1276
|
+
const currentBudget = this.budgetConsumed;
|
|
1277
|
+
if (!currentBudget) {
|
|
1278
|
+
this.stopLeak();
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1281
|
+
const newBudget = currentBudget - 1;
|
|
1282
|
+
if (newBudget === 0) {
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
this.budgetConsumed = newBudget;
|
|
1286
|
+
};
|
|
1287
|
+
this.intervalHandle = setInterval(
|
|
1288
|
+
restoreBudgetForUser,
|
|
1289
|
+
this.options.budgetRestoreIntervalMs
|
|
1290
|
+
);
|
|
1291
|
+
}
|
|
1292
|
+
stopLeak() {
|
|
1293
|
+
if (!this.intervalHandle) {
|
|
1294
|
+
return;
|
|
1295
|
+
}
|
|
1296
|
+
clearInterval(this.intervalHandle);
|
|
1297
|
+
this.intervalHandle = void 0;
|
|
1298
|
+
}
|
|
1299
|
+
close() {
|
|
1300
|
+
this.stopLeak();
|
|
1301
|
+
}
|
|
1302
|
+
};
|
|
1303
|
+
|
|
1304
|
+
// transport/client.ts
|
|
1305
|
+
var import_value = require("@sinclair/typebox/value");
|
|
1614
1306
|
var ClientTransport = class extends Transport {
|
|
1615
1307
|
/**
|
|
1616
1308
|
* The options for this transport.
|
|
@@ -1741,19 +1433,19 @@ var ClientTransport = class extends Transport {
|
|
|
1741
1433
|
this.deleteSession(session, { unhealthy: true });
|
|
1742
1434
|
}
|
|
1743
1435
|
onHandshakeResponse(session, msg) {
|
|
1744
|
-
if (!
|
|
1436
|
+
if (!import_value.Value.Check(ControlMessageHandshakeResponseSchema, msg.payload)) {
|
|
1745
1437
|
const reason = `received invalid handshake response`;
|
|
1746
1438
|
this.rejectHandshakeResponse(session, reason, {
|
|
1747
1439
|
...session.loggingMetadata,
|
|
1748
1440
|
transportMessage: msg,
|
|
1749
1441
|
validationErrors: [
|
|
1750
|
-
...
|
|
1442
|
+
...import_value.Value.Errors(ControlMessageHandshakeResponseSchema, msg.payload)
|
|
1751
1443
|
]
|
|
1752
1444
|
});
|
|
1753
1445
|
return;
|
|
1754
1446
|
}
|
|
1755
1447
|
if (!msg.payload.status.ok) {
|
|
1756
|
-
const retriable =
|
|
1448
|
+
const retriable = import_value.Value.Check(
|
|
1757
1449
|
HandshakeErrorRetriableResponseCodes,
|
|
1758
1450
|
msg.payload.status.code
|
|
1759
1451
|
);
|
|
@@ -1805,13 +1497,41 @@ var ClientTransport = class extends Transport {
|
|
|
1805
1497
|
this.handleMsg(msg2);
|
|
1806
1498
|
},
|
|
1807
1499
|
onInvalidMessage: (reason) => {
|
|
1808
|
-
this.
|
|
1500
|
+
this.log?.error(`invalid message: ${reason}`, {
|
|
1501
|
+
...connectedSession.loggingMetadata,
|
|
1502
|
+
transportMessage: msg
|
|
1503
|
+
});
|
|
1809
1504
|
this.protocolError({
|
|
1810
1505
|
type: ProtocolError.InvalidMessage,
|
|
1811
1506
|
message: reason
|
|
1812
1507
|
});
|
|
1508
|
+
this.deleteSession(connectedSession, { unhealthy: true });
|
|
1509
|
+
},
|
|
1510
|
+
onMessageSendFailure: (msg2, reason) => {
|
|
1511
|
+
this.log?.error(`failed to send message: ${reason}`, {
|
|
1512
|
+
...connectedSession.loggingMetadata,
|
|
1513
|
+
transportMessage: msg2
|
|
1514
|
+
});
|
|
1515
|
+
this.protocolError({
|
|
1516
|
+
type: ProtocolError.MessageSendFailure,
|
|
1517
|
+
message: reason
|
|
1518
|
+
});
|
|
1519
|
+
this.deleteSession(connectedSession, { unhealthy: true });
|
|
1813
1520
|
}
|
|
1814
1521
|
});
|
|
1522
|
+
const res = connectedSession.sendBufferedMessages();
|
|
1523
|
+
if (!res.ok) {
|
|
1524
|
+
this.log?.error(`failed to send buffered messages: ${res.reason}`, {
|
|
1525
|
+
...connectedSession.loggingMetadata,
|
|
1526
|
+
transportMessage: msg
|
|
1527
|
+
});
|
|
1528
|
+
this.protocolError({
|
|
1529
|
+
type: ProtocolError.MessageSendFailure,
|
|
1530
|
+
message: res.reason
|
|
1531
|
+
});
|
|
1532
|
+
this.deleteSession(connectedSession, { unhealthy: true });
|
|
1533
|
+
return;
|
|
1534
|
+
}
|
|
1815
1535
|
this.updateSession(connectedSession);
|
|
1816
1536
|
this.retryBudget.startRestoringBudget();
|
|
1817
1537
|
}
|
|
@@ -1950,7 +1670,18 @@ var ClientTransport = class extends Transport {
|
|
|
1950
1670
|
...session.loggingMetadata,
|
|
1951
1671
|
transportMessage: requestMsg
|
|
1952
1672
|
});
|
|
1953
|
-
session.sendHandshake(requestMsg);
|
|
1673
|
+
const res = session.sendHandshake(requestMsg);
|
|
1674
|
+
if (!res.ok) {
|
|
1675
|
+
this.log?.error(`failed to send handshake request: ${res.reason}`, {
|
|
1676
|
+
...session.loggingMetadata,
|
|
1677
|
+
transportMessage: requestMsg
|
|
1678
|
+
});
|
|
1679
|
+
this.protocolError({
|
|
1680
|
+
type: ProtocolError.MessageSendFailure,
|
|
1681
|
+
message: res.reason
|
|
1682
|
+
});
|
|
1683
|
+
this.deleteSession(session, { unhealthy: true });
|
|
1684
|
+
}
|
|
1954
1685
|
}
|
|
1955
1686
|
close() {
|
|
1956
1687
|
this.retryBudget.close();
|
|
@@ -1958,96 +1689,9 @@ var ClientTransport = class extends Transport {
|
|
|
1958
1689
|
}
|
|
1959
1690
|
};
|
|
1960
1691
|
|
|
1961
|
-
// transport/connection.ts
|
|
1962
|
-
var Connection = class {
|
|
1963
|
-
id;
|
|
1964
|
-
telemetry;
|
|
1965
|
-
constructor() {
|
|
1966
|
-
this.id = `conn-${generateId()}`;
|
|
1967
|
-
}
|
|
1968
|
-
get loggingMetadata() {
|
|
1969
|
-
const metadata = { connId: this.id };
|
|
1970
|
-
if (this.telemetry?.span.isRecording()) {
|
|
1971
|
-
const spanContext = this.telemetry.span.spanContext();
|
|
1972
|
-
metadata.telemetry = {
|
|
1973
|
-
traceId: spanContext.traceId,
|
|
1974
|
-
spanId: spanContext.spanId
|
|
1975
|
-
};
|
|
1976
|
-
}
|
|
1977
|
-
return metadata;
|
|
1978
|
-
}
|
|
1979
|
-
// can't use event emitter because we need this to work in both node + browser
|
|
1980
|
-
_dataListeners = /* @__PURE__ */ new Set();
|
|
1981
|
-
_closeListeners = /* @__PURE__ */ new Set();
|
|
1982
|
-
_errorListeners = /* @__PURE__ */ new Set();
|
|
1983
|
-
get dataListeners() {
|
|
1984
|
-
return [...this._dataListeners];
|
|
1985
|
-
}
|
|
1986
|
-
get closeListeners() {
|
|
1987
|
-
return [...this._closeListeners];
|
|
1988
|
-
}
|
|
1989
|
-
get errorListeners() {
|
|
1990
|
-
return [...this._errorListeners];
|
|
1991
|
-
}
|
|
1992
|
-
onData(msg) {
|
|
1993
|
-
for (const cb of this.dataListeners) {
|
|
1994
|
-
cb(msg);
|
|
1995
|
-
}
|
|
1996
|
-
}
|
|
1997
|
-
onError(err) {
|
|
1998
|
-
for (const cb of this.errorListeners) {
|
|
1999
|
-
cb(err);
|
|
2000
|
-
}
|
|
2001
|
-
}
|
|
2002
|
-
onClose() {
|
|
2003
|
-
for (const cb of this.closeListeners) {
|
|
2004
|
-
cb();
|
|
2005
|
-
}
|
|
2006
|
-
this.telemetry?.span.end();
|
|
2007
|
-
}
|
|
2008
|
-
/**
|
|
2009
|
-
* Handle adding a callback for when a message is received.
|
|
2010
|
-
* @param msg The message that was received.
|
|
2011
|
-
*/
|
|
2012
|
-
addDataListener(cb) {
|
|
2013
|
-
this._dataListeners.add(cb);
|
|
2014
|
-
}
|
|
2015
|
-
removeDataListener(cb) {
|
|
2016
|
-
this._dataListeners.delete(cb);
|
|
2017
|
-
}
|
|
2018
|
-
/**
|
|
2019
|
-
* Handle adding a callback for when the connection is closed.
|
|
2020
|
-
* This should also be called if an error happens and after notifying all the error listeners.
|
|
2021
|
-
* @param cb The callback to call when the connection is closed.
|
|
2022
|
-
*/
|
|
2023
|
-
addCloseListener(cb) {
|
|
2024
|
-
this._closeListeners.add(cb);
|
|
2025
|
-
}
|
|
2026
|
-
removeCloseListener(cb) {
|
|
2027
|
-
this._closeListeners.delete(cb);
|
|
2028
|
-
}
|
|
2029
|
-
/**
|
|
2030
|
-
* Handle adding a callback for when an error is received.
|
|
2031
|
-
* This should only be used for this.logging errors, all cleanup
|
|
2032
|
-
* should be delegated to addCloseListener.
|
|
2033
|
-
*
|
|
2034
|
-
* The implementer should take care such that the implemented
|
|
2035
|
-
* connection will call both the close and error callbacks
|
|
2036
|
-
* on an error.
|
|
2037
|
-
*
|
|
2038
|
-
* @param cb The callback to call when an error is received.
|
|
2039
|
-
*/
|
|
2040
|
-
addErrorListener(cb) {
|
|
2041
|
-
this._errorListeners.add(cb);
|
|
2042
|
-
}
|
|
2043
|
-
removeErrorListener(cb) {
|
|
2044
|
-
this._errorListeners.delete(cb);
|
|
2045
|
-
}
|
|
2046
|
-
};
|
|
2047
|
-
|
|
2048
1692
|
// transport/server.ts
|
|
2049
1693
|
var import_api5 = require("@opentelemetry/api");
|
|
2050
|
-
var
|
|
1694
|
+
var import_value2 = require("@sinclair/typebox/value");
|
|
2051
1695
|
var ServerTransport = class extends Transport {
|
|
2052
1696
|
/**
|
|
2053
1697
|
* The options for this transport.
|
|
@@ -2161,17 +1805,28 @@ var ServerTransport = class extends Transport {
|
|
|
2161
1805
|
message: reason
|
|
2162
1806
|
});
|
|
2163
1807
|
this.log?.warn(reason, metadata);
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
)
|
|
1808
|
+
const responseMsg = handshakeResponseMessage({
|
|
1809
|
+
from: this.clientId,
|
|
1810
|
+
to,
|
|
1811
|
+
status: {
|
|
1812
|
+
ok: false,
|
|
1813
|
+
code,
|
|
1814
|
+
reason
|
|
1815
|
+
}
|
|
1816
|
+
});
|
|
1817
|
+
const res = session.sendHandshake(responseMsg);
|
|
1818
|
+
if (!res.ok) {
|
|
1819
|
+
this.log?.error(`failed to send handshake response: ${res.reason}`, {
|
|
1820
|
+
...session.loggingMetadata,
|
|
1821
|
+
transportMessage: responseMsg
|
|
1822
|
+
});
|
|
1823
|
+
this.protocolError({
|
|
1824
|
+
type: ProtocolError.MessageSendFailure,
|
|
1825
|
+
message: res.reason
|
|
1826
|
+
});
|
|
1827
|
+
this.deletePendingSession(session);
|
|
1828
|
+
return;
|
|
1829
|
+
}
|
|
2175
1830
|
this.protocolError({
|
|
2176
1831
|
type: ProtocolError.HandshakeFailed,
|
|
2177
1832
|
code,
|
|
@@ -2180,7 +1835,7 @@ var ServerTransport = class extends Transport {
|
|
|
2180
1835
|
this.deletePendingSession(session);
|
|
2181
1836
|
}
|
|
2182
1837
|
async onHandshakeRequest(session, msg) {
|
|
2183
|
-
if (!
|
|
1838
|
+
if (!import_value2.Value.Check(ControlMessageHandshakeRequestSchema, msg.payload)) {
|
|
2184
1839
|
this.rejectHandshakeRequest(
|
|
2185
1840
|
session,
|
|
2186
1841
|
msg.from,
|
|
@@ -2191,7 +1846,7 @@ var ServerTransport = class extends Transport {
|
|
|
2191
1846
|
transportMessage: msg,
|
|
2192
1847
|
connectedTo: msg.from,
|
|
2193
1848
|
validationErrors: [
|
|
2194
|
-
...
|
|
1849
|
+
...import_value2.Value.Errors(ControlMessageHandshakeRequestSchema, msg.payload)
|
|
2195
1850
|
]
|
|
2196
1851
|
}
|
|
2197
1852
|
);
|
|
@@ -2214,7 +1869,7 @@ var ServerTransport = class extends Transport {
|
|
|
2214
1869
|
}
|
|
2215
1870
|
let parsedMetadata = {};
|
|
2216
1871
|
if (this.handshakeExtensions) {
|
|
2217
|
-
if (!
|
|
1872
|
+
if (!import_value2.Value.Check(this.handshakeExtensions.schema, msg.payload.metadata)) {
|
|
2218
1873
|
this.rejectHandshakeRequest(
|
|
2219
1874
|
session,
|
|
2220
1875
|
msg.from,
|
|
@@ -2224,7 +1879,7 @@ var ServerTransport = class extends Transport {
|
|
|
2224
1879
|
...session.loggingMetadata,
|
|
2225
1880
|
connectedTo: msg.from,
|
|
2226
1881
|
validationErrors: [
|
|
2227
|
-
...
|
|
1882
|
+
...import_value2.Value.Errors(
|
|
2228
1883
|
this.handshakeExtensions.schema,
|
|
2229
1884
|
msg.payload.metadata
|
|
2230
1885
|
)
|
|
@@ -2243,7 +1898,7 @@ var ServerTransport = class extends Transport {
|
|
|
2243
1898
|
if (session._isConsumed) {
|
|
2244
1899
|
return;
|
|
2245
1900
|
}
|
|
2246
|
-
if (
|
|
1901
|
+
if (import_value2.Value.Check(
|
|
2247
1902
|
HandshakeErrorCustomHandlerFatalResponseCodes,
|
|
2248
1903
|
parsedMetadataOrFailureCode
|
|
2249
1904
|
)) {
|
|
@@ -2355,7 +2010,20 @@ var ServerTransport = class extends Transport {
|
|
|
2355
2010
|
sessionId
|
|
2356
2011
|
}
|
|
2357
2012
|
});
|
|
2358
|
-
session.sendHandshake(responseMsg);
|
|
2013
|
+
const res = session.sendHandshake(responseMsg);
|
|
2014
|
+
if (!res.ok) {
|
|
2015
|
+
this.log?.error(`failed to send handshake response: ${res.reason}`, {
|
|
2016
|
+
...session.loggingMetadata,
|
|
2017
|
+
transportMessage: responseMsg
|
|
2018
|
+
});
|
|
2019
|
+
this.protocolError({
|
|
2020
|
+
type: ProtocolError.MessageSendFailure,
|
|
2021
|
+
message: res.reason
|
|
2022
|
+
});
|
|
2023
|
+
this.deletePendingSession(session);
|
|
2024
|
+
return;
|
|
2025
|
+
}
|
|
2026
|
+
this.pendingSessions.delete(session);
|
|
2359
2027
|
const connectedSession = ServerSessionStateGraph.transition.WaitingForHandshakeToConnected(
|
|
2360
2028
|
session,
|
|
2361
2029
|
// by this point oldSession is either no connection or we dont have an old session
|
|
@@ -2382,43 +2050,517 @@ var ServerTransport = class extends Transport {
|
|
|
2382
2050
|
this.handleMsg(msg2);
|
|
2383
2051
|
},
|
|
2384
2052
|
onInvalidMessage: (reason) => {
|
|
2053
|
+
this.log?.error(`invalid message: ${reason}`, {
|
|
2054
|
+
...connectedSession.loggingMetadata,
|
|
2055
|
+
transportMessage: msg
|
|
2056
|
+
});
|
|
2385
2057
|
this.protocolError({
|
|
2386
2058
|
type: ProtocolError.InvalidMessage,
|
|
2387
2059
|
message: reason
|
|
2388
2060
|
});
|
|
2389
2061
|
this.deleteSession(connectedSession, { unhealthy: true });
|
|
2062
|
+
},
|
|
2063
|
+
onMessageSendFailure: (msg2, reason) => {
|
|
2064
|
+
this.log?.error(`failed to send message: ${reason}`, {
|
|
2065
|
+
...connectedSession.loggingMetadata,
|
|
2066
|
+
transportMessage: msg2
|
|
2067
|
+
});
|
|
2068
|
+
this.protocolError({
|
|
2069
|
+
type: ProtocolError.MessageSendFailure,
|
|
2070
|
+
message: reason
|
|
2071
|
+
});
|
|
2072
|
+
this.deleteSession(connectedSession, { unhealthy: true });
|
|
2390
2073
|
}
|
|
2391
2074
|
},
|
|
2392
2075
|
gotVersion
|
|
2393
2076
|
);
|
|
2077
|
+
const bufferSendRes = connectedSession.sendBufferedMessages();
|
|
2078
|
+
if (!bufferSendRes.ok) {
|
|
2079
|
+
this.log?.error(
|
|
2080
|
+
`failed to send buffered messages: ${bufferSendRes.reason}`,
|
|
2081
|
+
{
|
|
2082
|
+
...connectedSession.loggingMetadata,
|
|
2083
|
+
transportMessage: msg
|
|
2084
|
+
}
|
|
2085
|
+
);
|
|
2086
|
+
this.protocolError({
|
|
2087
|
+
type: ProtocolError.MessageSendFailure,
|
|
2088
|
+
message: bufferSendRes.reason
|
|
2089
|
+
});
|
|
2090
|
+
this.deleteSession(connectedSession, { unhealthy: true });
|
|
2091
|
+
return;
|
|
2092
|
+
}
|
|
2394
2093
|
this.sessionHandshakeMetadata.set(connectedSession.to, parsedMetadata);
|
|
2395
2094
|
if (oldSession) {
|
|
2396
2095
|
this.updateSession(connectedSession);
|
|
2397
2096
|
} else {
|
|
2398
2097
|
this.createSession(connectedSession);
|
|
2399
2098
|
}
|
|
2400
|
-
this.pendingSessions.delete(session);
|
|
2401
2099
|
connectedSession.startActiveHeartbeat();
|
|
2402
2100
|
}
|
|
2403
2101
|
};
|
|
2404
2102
|
|
|
2405
|
-
//
|
|
2406
|
-
var
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
constructor(
|
|
2410
|
-
this.
|
|
2411
|
-
this.listeners = /* @__PURE__ */ new Set();
|
|
2103
|
+
// transport/connection.ts
|
|
2104
|
+
var Connection = class {
|
|
2105
|
+
id;
|
|
2106
|
+
telemetry;
|
|
2107
|
+
constructor() {
|
|
2108
|
+
this.id = `conn-${generateId()}`;
|
|
2412
2109
|
}
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2110
|
+
get loggingMetadata() {
|
|
2111
|
+
const metadata = { connId: this.id };
|
|
2112
|
+
if (this.telemetry?.span.isRecording()) {
|
|
2113
|
+
const spanContext = this.telemetry.span.spanContext();
|
|
2114
|
+
metadata.telemetry = {
|
|
2115
|
+
traceId: spanContext.traceId,
|
|
2116
|
+
spanId: spanContext.spanId
|
|
2117
|
+
};
|
|
2118
|
+
}
|
|
2119
|
+
return metadata;
|
|
2418
2120
|
}
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2121
|
+
// can't use event emitter because we need this to work in both node + browser
|
|
2122
|
+
_dataListeners = /* @__PURE__ */ new Set();
|
|
2123
|
+
_closeListeners = /* @__PURE__ */ new Set();
|
|
2124
|
+
_errorListeners = /* @__PURE__ */ new Set();
|
|
2125
|
+
get dataListeners() {
|
|
2126
|
+
return [...this._dataListeners];
|
|
2127
|
+
}
|
|
2128
|
+
get closeListeners() {
|
|
2129
|
+
return [...this._closeListeners];
|
|
2130
|
+
}
|
|
2131
|
+
get errorListeners() {
|
|
2132
|
+
return [...this._errorListeners];
|
|
2133
|
+
}
|
|
2134
|
+
onData(msg) {
|
|
2135
|
+
for (const cb of this.dataListeners) {
|
|
2136
|
+
cb(msg);
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
onError(err) {
|
|
2140
|
+
for (const cb of this.errorListeners) {
|
|
2141
|
+
cb(err);
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
onClose() {
|
|
2145
|
+
for (const cb of this.closeListeners) {
|
|
2146
|
+
cb();
|
|
2147
|
+
}
|
|
2148
|
+
this.telemetry?.span.end();
|
|
2149
|
+
}
|
|
2150
|
+
/**
|
|
2151
|
+
* Handle adding a callback for when a message is received.
|
|
2152
|
+
* @param msg The message that was received.
|
|
2153
|
+
*/
|
|
2154
|
+
addDataListener(cb) {
|
|
2155
|
+
this._dataListeners.add(cb);
|
|
2156
|
+
}
|
|
2157
|
+
removeDataListener(cb) {
|
|
2158
|
+
this._dataListeners.delete(cb);
|
|
2159
|
+
}
|
|
2160
|
+
/**
|
|
2161
|
+
* Handle adding a callback for when the connection is closed.
|
|
2162
|
+
* This should also be called if an error happens and after notifying all the error listeners.
|
|
2163
|
+
* @param cb The callback to call when the connection is closed.
|
|
2164
|
+
*/
|
|
2165
|
+
addCloseListener(cb) {
|
|
2166
|
+
this._closeListeners.add(cb);
|
|
2167
|
+
}
|
|
2168
|
+
removeCloseListener(cb) {
|
|
2169
|
+
this._closeListeners.delete(cb);
|
|
2170
|
+
}
|
|
2171
|
+
/**
|
|
2172
|
+
* Handle adding a callback for when an error is received.
|
|
2173
|
+
* This should only be used for this.logging errors, all cleanup
|
|
2174
|
+
* should be delegated to addCloseListener.
|
|
2175
|
+
*
|
|
2176
|
+
* The implementer should take care such that the implemented
|
|
2177
|
+
* connection will call both the close and error callbacks
|
|
2178
|
+
* on an error.
|
|
2179
|
+
*
|
|
2180
|
+
* @param cb The callback to call when an error is received.
|
|
2181
|
+
*/
|
|
2182
|
+
addErrorListener(cb) {
|
|
2183
|
+
this._errorListeners.add(cb);
|
|
2184
|
+
}
|
|
2185
|
+
removeErrorListener(cb) {
|
|
2186
|
+
this._errorListeners.delete(cb);
|
|
2187
|
+
}
|
|
2188
|
+
};
|
|
2189
|
+
|
|
2190
|
+
// codec/adapter.ts
|
|
2191
|
+
var CodecMessageAdapter = class {
|
|
2192
|
+
constructor(codec) {
|
|
2193
|
+
this.codec = codec;
|
|
2194
|
+
}
|
|
2195
|
+
toBuffer(msg) {
|
|
2196
|
+
try {
|
|
2197
|
+
return {
|
|
2198
|
+
ok: true,
|
|
2199
|
+
value: this.codec.toBuffer(msg)
|
|
2200
|
+
};
|
|
2201
|
+
} catch (e) {
|
|
2202
|
+
return {
|
|
2203
|
+
ok: false,
|
|
2204
|
+
reason: coerceErrorString(e)
|
|
2205
|
+
};
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
fromBuffer(buf) {
|
|
2209
|
+
try {
|
|
2210
|
+
const parsedMsg = this.codec.fromBuffer(buf);
|
|
2211
|
+
if (!import_value3.Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
|
|
2212
|
+
return {
|
|
2213
|
+
ok: false,
|
|
2214
|
+
reason: "transport message schema mismatch"
|
|
2215
|
+
};
|
|
2216
|
+
}
|
|
2217
|
+
return {
|
|
2218
|
+
ok: true,
|
|
2219
|
+
value: parsedMsg
|
|
2220
|
+
};
|
|
2221
|
+
} catch (e) {
|
|
2222
|
+
return {
|
|
2223
|
+
ok: false,
|
|
2224
|
+
reason: coerceErrorString(e)
|
|
2225
|
+
};
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
};
|
|
2229
|
+
|
|
2230
|
+
// transport/sessionStateMachine/transitions.ts
|
|
2231
|
+
function inheritSharedSession(session) {
|
|
2232
|
+
return {
|
|
2233
|
+
id: session.id,
|
|
2234
|
+
from: session.from,
|
|
2235
|
+
to: session.to,
|
|
2236
|
+
seq: session.seq,
|
|
2237
|
+
ack: session.ack,
|
|
2238
|
+
seqSent: session.seqSent,
|
|
2239
|
+
sendBuffer: session.sendBuffer,
|
|
2240
|
+
telemetry: session.telemetry,
|
|
2241
|
+
options: session.options,
|
|
2242
|
+
log: session.log,
|
|
2243
|
+
tracer: session.tracer,
|
|
2244
|
+
protocolVersion: session.protocolVersion,
|
|
2245
|
+
codec: session.codec
|
|
2246
|
+
};
|
|
2247
|
+
}
|
|
2248
|
+
function inheritSharedSessionWithGrace(session) {
|
|
2249
|
+
return {
|
|
2250
|
+
...inheritSharedSession(session),
|
|
2251
|
+
graceExpiryTime: session.graceExpiryTime
|
|
2252
|
+
};
|
|
2253
|
+
}
|
|
2254
|
+
var SessionStateGraph = {
|
|
2255
|
+
entrypoints: {
|
|
2256
|
+
NoConnection: (to, from, listeners, options, protocolVersion, tracer, log) => {
|
|
2257
|
+
const id = `session-${generateId()}`;
|
|
2258
|
+
const telemetry = createSessionTelemetryInfo(tracer, id, to, from);
|
|
2259
|
+
const sendBuffer = [];
|
|
2260
|
+
const session = new SessionNoConnection({
|
|
2261
|
+
listeners,
|
|
2262
|
+
id,
|
|
2263
|
+
from,
|
|
2264
|
+
to,
|
|
2265
|
+
seq: 0,
|
|
2266
|
+
ack: 0,
|
|
2267
|
+
seqSent: 0,
|
|
2268
|
+
graceExpiryTime: Date.now() + options.sessionDisconnectGraceMs,
|
|
2269
|
+
sendBuffer,
|
|
2270
|
+
telemetry,
|
|
2271
|
+
options,
|
|
2272
|
+
protocolVersion,
|
|
2273
|
+
tracer,
|
|
2274
|
+
log,
|
|
2275
|
+
codec: new CodecMessageAdapter(options.codec)
|
|
2276
|
+
});
|
|
2277
|
+
session.log?.info(`session ${session.id} created in NoConnection state`, {
|
|
2278
|
+
...session.loggingMetadata,
|
|
2279
|
+
tags: ["state-transition"]
|
|
2280
|
+
});
|
|
2281
|
+
return session;
|
|
2282
|
+
},
|
|
2283
|
+
WaitingForHandshake: (from, conn, listeners, options, tracer, log) => {
|
|
2284
|
+
const session = new SessionWaitingForHandshake({
|
|
2285
|
+
conn,
|
|
2286
|
+
listeners,
|
|
2287
|
+
from,
|
|
2288
|
+
options,
|
|
2289
|
+
tracer,
|
|
2290
|
+
log,
|
|
2291
|
+
codec: new CodecMessageAdapter(options.codec)
|
|
2292
|
+
});
|
|
2293
|
+
session.log?.info(`session created in WaitingForHandshake state`, {
|
|
2294
|
+
...session.loggingMetadata,
|
|
2295
|
+
tags: ["state-transition"]
|
|
2296
|
+
});
|
|
2297
|
+
return session;
|
|
2298
|
+
}
|
|
2299
|
+
},
|
|
2300
|
+
// All of the transitions 'move'/'consume' the old session and return a new one.
|
|
2301
|
+
// After a session is transitioned, any usage of the old session will throw.
|
|
2302
|
+
transition: {
|
|
2303
|
+
// happy path transitions
|
|
2304
|
+
NoConnectionToBackingOff: (oldSession, backoffMs, listeners) => {
|
|
2305
|
+
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
2306
|
+
oldSession._handleStateExit();
|
|
2307
|
+
const session = new SessionBackingOff({
|
|
2308
|
+
backoffMs,
|
|
2309
|
+
listeners,
|
|
2310
|
+
...carriedState
|
|
2311
|
+
});
|
|
2312
|
+
session.log?.info(
|
|
2313
|
+
`session ${session.id} transition from NoConnection to BackingOff`,
|
|
2314
|
+
{
|
|
2315
|
+
...session.loggingMetadata,
|
|
2316
|
+
tags: ["state-transition"]
|
|
2317
|
+
}
|
|
2318
|
+
);
|
|
2319
|
+
return session;
|
|
2320
|
+
},
|
|
2321
|
+
BackingOffToConnecting: (oldSession, connPromise, listeners) => {
|
|
2322
|
+
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
2323
|
+
oldSession._handleStateExit();
|
|
2324
|
+
const session = new SessionConnecting({
|
|
2325
|
+
connPromise,
|
|
2326
|
+
listeners,
|
|
2327
|
+
...carriedState
|
|
2328
|
+
});
|
|
2329
|
+
session.log?.info(
|
|
2330
|
+
`session ${session.id} transition from BackingOff to Connecting`,
|
|
2331
|
+
{
|
|
2332
|
+
...session.loggingMetadata,
|
|
2333
|
+
tags: ["state-transition"]
|
|
2334
|
+
}
|
|
2335
|
+
);
|
|
2336
|
+
return session;
|
|
2337
|
+
},
|
|
2338
|
+
ConnectingToHandshaking: (oldSession, conn, listeners) => {
|
|
2339
|
+
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
2340
|
+
oldSession._handleStateExit();
|
|
2341
|
+
const session = new SessionHandshaking({
|
|
2342
|
+
conn,
|
|
2343
|
+
listeners,
|
|
2344
|
+
...carriedState
|
|
2345
|
+
});
|
|
2346
|
+
conn.telemetry = createConnectionTelemetryInfo(
|
|
2347
|
+
session.tracer,
|
|
2348
|
+
conn,
|
|
2349
|
+
session.telemetry
|
|
2350
|
+
);
|
|
2351
|
+
session.log?.info(
|
|
2352
|
+
`session ${session.id} transition from Connecting to Handshaking`,
|
|
2353
|
+
{
|
|
2354
|
+
...session.loggingMetadata,
|
|
2355
|
+
tags: ["state-transition"]
|
|
2356
|
+
}
|
|
2357
|
+
);
|
|
2358
|
+
return session;
|
|
2359
|
+
},
|
|
2360
|
+
HandshakingToConnected: (oldSession, listeners) => {
|
|
2361
|
+
const carriedState = inheritSharedSession(oldSession);
|
|
2362
|
+
const conn = oldSession.conn;
|
|
2363
|
+
oldSession._handleStateExit();
|
|
2364
|
+
const session = new SessionConnected({
|
|
2365
|
+
conn,
|
|
2366
|
+
listeners,
|
|
2367
|
+
...carriedState
|
|
2368
|
+
});
|
|
2369
|
+
session.startMissingHeartbeatTimeout();
|
|
2370
|
+
session.log?.info(
|
|
2371
|
+
`session ${session.id} transition from Handshaking to Connected`,
|
|
2372
|
+
{
|
|
2373
|
+
...session.loggingMetadata,
|
|
2374
|
+
tags: ["state-transition"]
|
|
2375
|
+
}
|
|
2376
|
+
);
|
|
2377
|
+
return session;
|
|
2378
|
+
},
|
|
2379
|
+
WaitingForHandshakeToConnected: (pendingSession, oldSession, sessionId, to, propagationCtx, listeners, protocolVersion) => {
|
|
2380
|
+
const conn = pendingSession.conn;
|
|
2381
|
+
const { from, options } = pendingSession;
|
|
2382
|
+
const carriedState = oldSession ? (
|
|
2383
|
+
// old session exists, inherit state
|
|
2384
|
+
inheritSharedSession(oldSession)
|
|
2385
|
+
) : (
|
|
2386
|
+
// old session does not exist, create new state
|
|
2387
|
+
{
|
|
2388
|
+
id: sessionId,
|
|
2389
|
+
from,
|
|
2390
|
+
to,
|
|
2391
|
+
seq: 0,
|
|
2392
|
+
ack: 0,
|
|
2393
|
+
seqSent: 0,
|
|
2394
|
+
sendBuffer: [],
|
|
2395
|
+
telemetry: createSessionTelemetryInfo(
|
|
2396
|
+
pendingSession.tracer,
|
|
2397
|
+
sessionId,
|
|
2398
|
+
to,
|
|
2399
|
+
from,
|
|
2400
|
+
propagationCtx
|
|
2401
|
+
),
|
|
2402
|
+
options,
|
|
2403
|
+
tracer: pendingSession.tracer,
|
|
2404
|
+
log: pendingSession.log,
|
|
2405
|
+
protocolVersion,
|
|
2406
|
+
codec: new CodecMessageAdapter(options.codec)
|
|
2407
|
+
}
|
|
2408
|
+
);
|
|
2409
|
+
pendingSession._handleStateExit();
|
|
2410
|
+
oldSession?._handleStateExit();
|
|
2411
|
+
const session = new SessionConnected({
|
|
2412
|
+
conn,
|
|
2413
|
+
listeners,
|
|
2414
|
+
...carriedState
|
|
2415
|
+
});
|
|
2416
|
+
session.startMissingHeartbeatTimeout();
|
|
2417
|
+
conn.telemetry = createConnectionTelemetryInfo(
|
|
2418
|
+
session.tracer,
|
|
2419
|
+
conn,
|
|
2420
|
+
session.telemetry
|
|
2421
|
+
);
|
|
2422
|
+
session.log?.info(
|
|
2423
|
+
`session ${session.id} transition from WaitingForHandshake to Connected`,
|
|
2424
|
+
{
|
|
2425
|
+
...session.loggingMetadata,
|
|
2426
|
+
tags: ["state-transition"]
|
|
2427
|
+
}
|
|
2428
|
+
);
|
|
2429
|
+
return session;
|
|
2430
|
+
},
|
|
2431
|
+
// disconnect paths
|
|
2432
|
+
BackingOffToNoConnection: (oldSession, listeners) => {
|
|
2433
|
+
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
2434
|
+
oldSession._handleStateExit();
|
|
2435
|
+
const session = new SessionNoConnection({
|
|
2436
|
+
listeners,
|
|
2437
|
+
...carriedState
|
|
2438
|
+
});
|
|
2439
|
+
session.log?.info(
|
|
2440
|
+
`session ${session.id} transition from BackingOff to NoConnection`,
|
|
2441
|
+
{
|
|
2442
|
+
...session.loggingMetadata,
|
|
2443
|
+
tags: ["state-transition"]
|
|
2444
|
+
}
|
|
2445
|
+
);
|
|
2446
|
+
return session;
|
|
2447
|
+
},
|
|
2448
|
+
ConnectingToNoConnection: (oldSession, listeners) => {
|
|
2449
|
+
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
2450
|
+
oldSession.bestEffortClose();
|
|
2451
|
+
oldSession._handleStateExit();
|
|
2452
|
+
const session = new SessionNoConnection({
|
|
2453
|
+
listeners,
|
|
2454
|
+
...carriedState
|
|
2455
|
+
});
|
|
2456
|
+
session.log?.info(
|
|
2457
|
+
`session ${session.id} transition from Connecting to NoConnection`,
|
|
2458
|
+
{
|
|
2459
|
+
...session.loggingMetadata,
|
|
2460
|
+
tags: ["state-transition"]
|
|
2461
|
+
}
|
|
2462
|
+
);
|
|
2463
|
+
return session;
|
|
2464
|
+
},
|
|
2465
|
+
HandshakingToNoConnection: (oldSession, listeners) => {
|
|
2466
|
+
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
2467
|
+
oldSession.conn.close();
|
|
2468
|
+
oldSession._handleStateExit();
|
|
2469
|
+
const session = new SessionNoConnection({
|
|
2470
|
+
listeners,
|
|
2471
|
+
...carriedState
|
|
2472
|
+
});
|
|
2473
|
+
session.log?.info(
|
|
2474
|
+
`session ${session.id} transition from Handshaking to NoConnection`,
|
|
2475
|
+
{
|
|
2476
|
+
...session.loggingMetadata,
|
|
2477
|
+
tags: ["state-transition"]
|
|
2478
|
+
}
|
|
2479
|
+
);
|
|
2480
|
+
return session;
|
|
2481
|
+
},
|
|
2482
|
+
ConnectedToNoConnection: (oldSession, listeners) => {
|
|
2483
|
+
const carriedState = inheritSharedSession(oldSession);
|
|
2484
|
+
const graceExpiryTime = Date.now() + oldSession.options.sessionDisconnectGraceMs;
|
|
2485
|
+
oldSession.conn.close();
|
|
2486
|
+
oldSession._handleStateExit();
|
|
2487
|
+
const session = new SessionNoConnection({
|
|
2488
|
+
listeners,
|
|
2489
|
+
graceExpiryTime,
|
|
2490
|
+
...carriedState
|
|
2491
|
+
});
|
|
2492
|
+
session.log?.info(
|
|
2493
|
+
`session ${session.id} transition from Connected to NoConnection`,
|
|
2494
|
+
{
|
|
2495
|
+
...session.loggingMetadata,
|
|
2496
|
+
tags: ["state-transition"]
|
|
2497
|
+
}
|
|
2498
|
+
);
|
|
2499
|
+
return session;
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
};
|
|
2503
|
+
var transitions = SessionStateGraph.transition;
|
|
2504
|
+
var ClientSessionStateGraph = {
|
|
2505
|
+
entrypoint: SessionStateGraph.entrypoints.NoConnection,
|
|
2506
|
+
transition: {
|
|
2507
|
+
// happy paths
|
|
2508
|
+
// NoConnection -> BackingOff: attempt to connect
|
|
2509
|
+
NoConnectionToBackingOff: transitions.NoConnectionToBackingOff,
|
|
2510
|
+
// BackingOff -> Connecting: backoff period elapsed, start connection
|
|
2511
|
+
BackingOffToConnecting: transitions.BackingOffToConnecting,
|
|
2512
|
+
// Connecting -> Handshaking: connection established, start handshake
|
|
2513
|
+
ConnectingToHandshaking: transitions.ConnectingToHandshaking,
|
|
2514
|
+
// Handshaking -> Connected: handshake complete, session ready
|
|
2515
|
+
HandshakingToConnected: transitions.HandshakingToConnected,
|
|
2516
|
+
// disconnect paths
|
|
2517
|
+
// BackingOff -> NoConnection: unused
|
|
2518
|
+
BackingOffToNoConnection: transitions.BackingOffToNoConnection,
|
|
2519
|
+
// Connecting -> NoConnection: connection failed or connection timeout
|
|
2520
|
+
ConnectingToNoConnection: transitions.ConnectingToNoConnection,
|
|
2521
|
+
// Handshaking -> NoConnection: connection closed or handshake timeout
|
|
2522
|
+
HandshakingToNoConnection: transitions.HandshakingToNoConnection,
|
|
2523
|
+
// Connected -> NoConnection: connection closed
|
|
2524
|
+
ConnectedToNoConnection: transitions.ConnectedToNoConnection
|
|
2525
|
+
// destroy/close paths
|
|
2526
|
+
// NoConnection -> x: grace period elapsed
|
|
2527
|
+
// BackingOff -> x: grace period elapsed
|
|
2528
|
+
// Connecting -> x: grace period elapsed
|
|
2529
|
+
// Handshaking -> x: grace period elapsed or invalid handshake message or handshake rejection
|
|
2530
|
+
// Connected -> x: grace period elapsed or invalid message
|
|
2531
|
+
}
|
|
2532
|
+
};
|
|
2533
|
+
var ServerSessionStateGraph = {
|
|
2534
|
+
entrypoint: SessionStateGraph.entrypoints.WaitingForHandshake,
|
|
2535
|
+
transition: {
|
|
2536
|
+
// happy paths
|
|
2537
|
+
// WaitingForHandshake -> Connected: handshake complete, session ready
|
|
2538
|
+
WaitingForHandshakeToConnected: transitions.WaitingForHandshakeToConnected,
|
|
2539
|
+
// disconnect paths
|
|
2540
|
+
// Connected -> NoConnection: connection closed
|
|
2541
|
+
ConnectedToNoConnection: transitions.ConnectedToNoConnection
|
|
2542
|
+
// destroy/close paths
|
|
2543
|
+
// WaitingForHandshake -> x: handshake timeout elapsed or invalid handshake message or handshake rejection or connection closed
|
|
2544
|
+
}
|
|
2545
|
+
};
|
|
2546
|
+
|
|
2547
|
+
// testUtil/observable/observable.ts
|
|
2548
|
+
var Observable = class {
|
|
2549
|
+
value;
|
|
2550
|
+
listeners;
|
|
2551
|
+
constructor(initialValue) {
|
|
2552
|
+
this.value = initialValue;
|
|
2553
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
2554
|
+
}
|
|
2555
|
+
/**
|
|
2556
|
+
* Gets the current value of the observable.
|
|
2557
|
+
*/
|
|
2558
|
+
get() {
|
|
2559
|
+
return this.value;
|
|
2560
|
+
}
|
|
2561
|
+
/**
|
|
2562
|
+
* Sets the current value of the observable. All listeners will get an update with this value.
|
|
2563
|
+
* @param newValue - The new value to set.
|
|
2422
2564
|
*/
|
|
2423
2565
|
set(tx) {
|
|
2424
2566
|
const newValue = tx(this.value);
|
|
@@ -2488,6 +2630,16 @@ function duplexPair() {
|
|
|
2488
2630
|
const side1 = new DuplexSide();
|
|
2489
2631
|
side0[kInitOtherSide](side1);
|
|
2490
2632
|
side1[kInitOtherSide](side0);
|
|
2633
|
+
side0.on("close", () => {
|
|
2634
|
+
setImmediate(() => {
|
|
2635
|
+
side1.destroy();
|
|
2636
|
+
});
|
|
2637
|
+
});
|
|
2638
|
+
side1.on("close", () => {
|
|
2639
|
+
setImmediate(() => {
|
|
2640
|
+
side0.destroy();
|
|
2641
|
+
});
|
|
2642
|
+
});
|
|
2491
2643
|
return [side0, side1];
|
|
2492
2644
|
}
|
|
2493
2645
|
|
|
@@ -2600,14 +2752,14 @@ function createMockTransportNetwork(opts) {
|
|
|
2600
2752
|
transport.close();
|
|
2601
2753
|
}
|
|
2602
2754
|
for (const conn of Object.values(connections.get())) {
|
|
2603
|
-
conn.serverToClient.
|
|
2604
|
-
conn.clientToServer.
|
|
2755
|
+
conn.serverToClient.destroy();
|
|
2756
|
+
conn.clientToServer.destroy();
|
|
2605
2757
|
}
|
|
2606
2758
|
},
|
|
2607
2759
|
cleanup() {
|
|
2608
2760
|
for (const conn of Object.values(connections.get())) {
|
|
2609
|
-
conn.serverToClient.
|
|
2610
|
-
conn.clientToServer.
|
|
2761
|
+
conn.serverToClient.destroy();
|
|
2762
|
+
conn.clientToServer.destroy();
|
|
2611
2763
|
}
|
|
2612
2764
|
}
|
|
2613
2765
|
};
|