@replit/river 0.16.1 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -11
- package/dist/{chunk-Q6WPGM3K.js → chunk-7IQO434V.js} +11 -3
- package/dist/{chunk-7SPCAA6Q.js → chunk-LQMPJI3S.js} +101 -97
- package/dist/{chunk-GFRAOY75.js → chunk-VH3NGOXQ.js} +8 -17
- package/dist/{chunk-L65XWBX2.js → chunk-VJRLJ3JU.js} +1 -1
- package/dist/{chunk-XLJGKNV2.js → chunk-Y6DLSCKU.js} +1 -1
- package/dist/{connection-94896f3b.d.ts → connection-0767dc6b.d.ts} +1 -1
- package/dist/{connection-99346822.d.ts → connection-f31edbcd.d.ts} +1 -1
- package/dist/{index-2e402bb8.d.ts → index-8df0bdfb.d.ts} +27 -31
- package/dist/{procedures-f0226890.d.ts → procedures-b5ddb54d.d.ts} +1 -1
- package/dist/router/index.cjs +12 -4
- package/dist/router/index.d.cts +8 -4
- package/dist/router/index.d.ts +8 -4
- package/dist/router/index.js +2 -2
- package/dist/transport/impls/uds/client.cjs +80 -69
- package/dist/transport/impls/uds/client.d.cts +2 -2
- package/dist/transport/impls/uds/client.d.ts +2 -2
- package/dist/transport/impls/uds/client.js +3 -3
- package/dist/transport/impls/uds/server.cjs +82 -94
- package/dist/transport/impls/uds/server.d.cts +2 -2
- package/dist/transport/impls/uds/server.d.ts +2 -2
- package/dist/transport/impls/uds/server.js +3 -3
- package/dist/transport/impls/ws/client.cjs +80 -69
- package/dist/transport/impls/ws/client.d.cts +2 -2
- package/dist/transport/impls/ws/client.d.ts +2 -2
- package/dist/transport/impls/ws/client.js +3 -3
- package/dist/transport/impls/ws/server.cjs +82 -94
- package/dist/transport/impls/ws/server.d.cts +2 -2
- package/dist/transport/impls/ws/server.d.ts +2 -2
- package/dist/transport/impls/ws/server.js +3 -3
- package/dist/transport/index.cjs +107 -115
- package/dist/transport/index.d.cts +1 -1
- package/dist/transport/index.d.ts +1 -1
- package/dist/transport/index.js +2 -2
- package/dist/util/testHelpers.cjs +45 -18
- package/dist/util/testHelpers.d.cts +4 -9
- package/dist/util/testHelpers.d.ts +4 -9
- package/dist/util/testHelpers.js +8 -14
- package/package.json +1 -1
package/dist/transport/index.cjs
CHANGED
|
@@ -55,18 +55,18 @@ var ControlMessageAckSchema = import_typebox.Type.Object({
|
|
|
55
55
|
var ControlMessageCloseSchema = import_typebox.Type.Object({
|
|
56
56
|
type: import_typebox.Type.Literal("CLOSE")
|
|
57
57
|
});
|
|
58
|
-
var PROTOCOL_VERSION = "v1";
|
|
58
|
+
var PROTOCOL_VERSION = "v1.1";
|
|
59
59
|
var ControlMessageHandshakeRequestSchema = import_typebox.Type.Object({
|
|
60
60
|
type: import_typebox.Type.Literal("HANDSHAKE_REQ"),
|
|
61
61
|
protocolVersion: import_typebox.Type.String(),
|
|
62
|
-
|
|
62
|
+
sessionId: import_typebox.Type.String()
|
|
63
63
|
});
|
|
64
64
|
var ControlMessageHandshakeResponseSchema = import_typebox.Type.Object({
|
|
65
65
|
type: import_typebox.Type.Literal("HANDSHAKE_RESP"),
|
|
66
66
|
status: import_typebox.Type.Union([
|
|
67
67
|
import_typebox.Type.Object({
|
|
68
68
|
ok: import_typebox.Type.Literal(true),
|
|
69
|
-
|
|
69
|
+
sessionId: import_typebox.Type.String()
|
|
70
70
|
}),
|
|
71
71
|
import_typebox.Type.Object({
|
|
72
72
|
ok: import_typebox.Type.Literal(false),
|
|
@@ -83,7 +83,7 @@ var ControlMessagePayloadSchema = import_typebox.Type.Union([
|
|
|
83
83
|
var OpaqueTransportMessageSchema = TransportMessageSchema(
|
|
84
84
|
import_typebox.Type.Unknown()
|
|
85
85
|
);
|
|
86
|
-
function handshakeRequestMessage(from, to,
|
|
86
|
+
function handshakeRequestMessage(from, to, sessionId) {
|
|
87
87
|
return {
|
|
88
88
|
id: (0, import_nanoid.nanoid)(),
|
|
89
89
|
from,
|
|
@@ -95,11 +95,11 @@ function handshakeRequestMessage(from, to, instanceId) {
|
|
|
95
95
|
payload: {
|
|
96
96
|
type: "HANDSHAKE_REQ",
|
|
97
97
|
protocolVersion: PROTOCOL_VERSION,
|
|
98
|
-
|
|
98
|
+
sessionId
|
|
99
99
|
}
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
|
-
function handshakeResponseMessage(from,
|
|
102
|
+
function handshakeResponseMessage(from, to, status) {
|
|
103
103
|
return {
|
|
104
104
|
id: (0, import_nanoid.nanoid)(),
|
|
105
105
|
from,
|
|
@@ -108,18 +108,9 @@ function handshakeResponseMessage(from, instanceId, to, ok, reason) {
|
|
|
108
108
|
ack: 0,
|
|
109
109
|
streamId: (0, import_nanoid.nanoid)(),
|
|
110
110
|
controlFlags: 0,
|
|
111
|
-
payload:
|
|
112
|
-
type: "HANDSHAKE_RESP",
|
|
113
|
-
status: {
|
|
114
|
-
ok: true,
|
|
115
|
-
instanceId
|
|
116
|
-
}
|
|
117
|
-
} : {
|
|
111
|
+
payload: {
|
|
118
112
|
type: "HANDSHAKE_RESP",
|
|
119
|
-
status
|
|
120
|
-
ok: false,
|
|
121
|
-
reason: reason ?? "Unknown reason"
|
|
122
|
-
}
|
|
113
|
+
status
|
|
123
114
|
}
|
|
124
115
|
};
|
|
125
116
|
}
|
|
@@ -134,7 +125,8 @@ var log;
|
|
|
134
125
|
var ProtocolError = {
|
|
135
126
|
RetriesExceeded: "conn_retry_exceeded",
|
|
136
127
|
HandshakeFailed: "handshake_failed",
|
|
137
|
-
UseAfterDestroy: "use_after_destroy"
|
|
128
|
+
UseAfterDestroy: "use_after_destroy",
|
|
129
|
+
MessageOrderingViolated: "message_ordering_violated"
|
|
138
130
|
};
|
|
139
131
|
var EventDispatcher = class {
|
|
140
132
|
eventListeners = {};
|
|
@@ -189,7 +181,12 @@ var Session = class {
|
|
|
189
181
|
/**
|
|
190
182
|
* The unique ID of this session.
|
|
191
183
|
*/
|
|
192
|
-
|
|
184
|
+
id;
|
|
185
|
+
/**
|
|
186
|
+
* What the other side advertised as their session ID
|
|
187
|
+
* for this session.
|
|
188
|
+
*/
|
|
189
|
+
advertisedSessionId;
|
|
193
190
|
/**
|
|
194
191
|
* Number of messages we've sent along this session (excluding handshake and acks)
|
|
195
192
|
*/
|
|
@@ -211,11 +208,11 @@ var Session = class {
|
|
|
211
208
|
* The interval for sending heartbeats.
|
|
212
209
|
*/
|
|
213
210
|
heartbeat;
|
|
214
|
-
constructor(
|
|
211
|
+
constructor(conn, from, to, options) {
|
|
212
|
+
this.id = `session-${nanoid2(12)}`;
|
|
215
213
|
this.options = options;
|
|
216
|
-
this.debugId = `sess-${unsafeId()}`;
|
|
217
214
|
this.from = from;
|
|
218
|
-
this.to =
|
|
215
|
+
this.to = to;
|
|
219
216
|
this.connection = conn;
|
|
220
217
|
this.codec = options.codec;
|
|
221
218
|
this.heartbeatMisses = 0;
|
|
@@ -255,7 +252,7 @@ var Session = class {
|
|
|
255
252
|
log?.info(
|
|
256
253
|
`${this.from} -- closing connection (id: ${this.connection.debugId}) to ${this.to} due to inactivity`
|
|
257
254
|
);
|
|
258
|
-
this.closeStaleConnection(
|
|
255
|
+
this.closeStaleConnection();
|
|
259
256
|
}
|
|
260
257
|
return;
|
|
261
258
|
}
|
|
@@ -286,33 +283,37 @@ var Session = class {
|
|
|
286
283
|
log?.debug(`${this.from} -- resending ${msg.id} (seq: ${msg.seq})`);
|
|
287
284
|
const ok = this.connection.send(this.codec.toBuffer(msg));
|
|
288
285
|
if (!ok) {
|
|
289
|
-
const msg2 = `${this.from} -- failed to send buffered message to ${this.to} in session (id: ${this.
|
|
286
|
+
const msg2 = `${this.from} -- failed to send buffered message to ${this.to} in session (id: ${this.id}) (if you hit this code path something is seriously wrong)`;
|
|
290
287
|
log?.error(msg2);
|
|
291
288
|
throw new Error(msg2);
|
|
292
289
|
}
|
|
293
290
|
}
|
|
294
291
|
}
|
|
295
292
|
updateBookkeeping(ack, seq) {
|
|
293
|
+
if (seq + 1 < this.ack) {
|
|
294
|
+
log?.error(`${this.from} -- received stale seq ${seq} + 1 < ${this.ack}`);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
296
297
|
this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq > ack);
|
|
297
298
|
this.ack = seq + 1;
|
|
298
299
|
}
|
|
299
300
|
closeStaleConnection(conn) {
|
|
300
|
-
if (
|
|
301
|
+
if (this.connection === void 0 || this.connection === conn)
|
|
301
302
|
return;
|
|
302
303
|
log?.info(
|
|
303
|
-
`${this.from} -- closing old inner connection (id: ${this.connection.debugId}) from session (id: ${this.
|
|
304
|
+
`${this.from} -- closing old inner connection (id: ${this.connection.debugId}) from session (id: ${this.id}) to ${this.to}`
|
|
304
305
|
);
|
|
305
306
|
this.connection.close();
|
|
306
307
|
this.connection = void 0;
|
|
307
308
|
}
|
|
308
309
|
replaceWithNewConnection(newConn) {
|
|
309
|
-
this.closeStaleConnection(
|
|
310
|
+
this.closeStaleConnection(newConn);
|
|
310
311
|
this.cancelGrace();
|
|
311
312
|
this.connection = newConn;
|
|
312
313
|
}
|
|
313
314
|
beginGrace(cb) {
|
|
314
315
|
log?.info(
|
|
315
|
-
`${this.from} -- starting ${this.options.sessionDisconnectGraceMs}ms grace period until session (id: ${this.
|
|
316
|
+
`${this.from} -- starting ${this.options.sessionDisconnectGraceMs}ms grace period until session (id: ${this.id}) to ${this.to} is closed`
|
|
316
317
|
);
|
|
317
318
|
this.disconnectionGrace = setTimeout(() => {
|
|
318
319
|
this.close();
|
|
@@ -323,11 +324,12 @@ var Session = class {
|
|
|
323
324
|
cancelGrace() {
|
|
324
325
|
this.heartbeatMisses = 0;
|
|
325
326
|
clearTimeout(this.disconnectionGrace);
|
|
327
|
+
this.disconnectionGrace = void 0;
|
|
326
328
|
}
|
|
327
329
|
// closed when we want to discard the whole session
|
|
328
330
|
// (i.e. shutdown or session disconnect)
|
|
329
331
|
close() {
|
|
330
|
-
this.closeStaleConnection(
|
|
332
|
+
this.closeStaleConnection();
|
|
331
333
|
this.cancelGrace();
|
|
332
334
|
this.resetBufferedMessages();
|
|
333
335
|
clearInterval(this.heartbeat);
|
|
@@ -356,9 +358,6 @@ var Session = class {
|
|
|
356
358
|
}
|
|
357
359
|
};
|
|
358
360
|
|
|
359
|
-
// transport/transport.ts
|
|
360
|
-
var import_nanoid3 = require("nanoid");
|
|
361
|
-
|
|
362
361
|
// util/stringify.ts
|
|
363
362
|
function coerceErrorString(err) {
|
|
364
363
|
if (err instanceof Error) {
|
|
@@ -505,17 +504,10 @@ var defaultConnectionRetryOptions = {
|
|
|
505
504
|
budgetRestoreIntervalMs: 200
|
|
506
505
|
};
|
|
507
506
|
var defaultClientTransportOptions = {
|
|
508
|
-
|
|
509
|
-
...
|
|
507
|
+
...defaultTransportOptions,
|
|
508
|
+
...defaultConnectionRetryOptions
|
|
510
509
|
};
|
|
511
510
|
var Transport = class {
|
|
512
|
-
/**
|
|
513
|
-
* Unique per instance of the transport.
|
|
514
|
-
* This allows us to distinguish reconnects to different
|
|
515
|
-
* transports.
|
|
516
|
-
*/
|
|
517
|
-
instanceId = (0, import_nanoid3.nanoid)();
|
|
518
|
-
connectedInstanceIds = /* @__PURE__ */ new Map();
|
|
519
511
|
/**
|
|
520
512
|
* A flag indicating whether the transport has been destroyed.
|
|
521
513
|
* A destroyed transport will not attempt to reconnect and cannot be used again.
|
|
@@ -568,41 +560,41 @@ var Transport = class {
|
|
|
568
560
|
* and we know the identity of the connected client.
|
|
569
561
|
* @param conn The connection object.
|
|
570
562
|
*/
|
|
571
|
-
onConnect(conn, connectedTo,
|
|
563
|
+
onConnect(conn, connectedTo, advertisedSessionId) {
|
|
572
564
|
this.eventDispatcher.dispatchEvent("connectionStatus", {
|
|
573
565
|
status: "connect",
|
|
574
566
|
conn
|
|
575
567
|
});
|
|
576
568
|
let oldSession = this.sessions.get(connectedTo);
|
|
577
|
-
|
|
578
|
-
if (oldSession && lastInstanceId !== void 0 && lastInstanceId !== instanceId) {
|
|
569
|
+
if (oldSession?.advertisedSessionId && oldSession.advertisedSessionId !== advertisedSessionId) {
|
|
579
570
|
log?.warn(
|
|
580
|
-
`${this.clientId} -- connection from ${connectedTo} is a different
|
|
571
|
+
`${this.clientId} -- connection from ${connectedTo} is a different session (id: ${advertisedSessionId}, last connected to: ${oldSession.advertisedSessionId}), starting a new session`
|
|
581
572
|
);
|
|
582
573
|
oldSession.close();
|
|
583
574
|
this.deleteSession(oldSession);
|
|
584
575
|
oldSession = void 0;
|
|
585
576
|
}
|
|
586
|
-
this.connectedInstanceIds.set(connectedTo, instanceId);
|
|
587
577
|
if (oldSession === void 0) {
|
|
588
578
|
const newSession = this.createSession(connectedTo, conn);
|
|
579
|
+
newSession.advertisedSessionId = advertisedSessionId;
|
|
589
580
|
log?.info(
|
|
590
|
-
`${this.clientId} -- new connection (id: ${conn.debugId}) for new session (id: ${newSession.
|
|
581
|
+
`${this.clientId} -- new connection (id: ${conn.debugId}) for new session (id: ${newSession.id}) to ${connectedTo}`
|
|
591
582
|
);
|
|
592
583
|
return newSession;
|
|
593
584
|
}
|
|
594
585
|
log?.info(
|
|
595
|
-
`${this.clientId} -- new connection (id: ${conn.debugId}) for existing session (id: ${oldSession.
|
|
586
|
+
`${this.clientId} -- new connection (id: ${conn.debugId}) for existing session (id: ${oldSession.id}) to ${connectedTo}`
|
|
596
587
|
);
|
|
597
588
|
oldSession.replaceWithNewConnection(conn);
|
|
598
589
|
oldSession.sendBufferedMessages();
|
|
590
|
+
oldSession.advertisedSessionId = advertisedSessionId;
|
|
599
591
|
return oldSession;
|
|
600
592
|
}
|
|
601
|
-
createSession(
|
|
593
|
+
createSession(to, conn) {
|
|
602
594
|
const session = new Session(
|
|
603
|
-
this.clientId,
|
|
604
|
-
connectedTo,
|
|
605
595
|
conn,
|
|
596
|
+
this.clientId,
|
|
597
|
+
to,
|
|
606
598
|
this.options
|
|
607
599
|
);
|
|
608
600
|
this.sessions.set(session.to, session);
|
|
@@ -612,10 +604,20 @@ var Transport = class {
|
|
|
612
604
|
});
|
|
613
605
|
return session;
|
|
614
606
|
}
|
|
607
|
+
getOrCreateSession(to, conn) {
|
|
608
|
+
let session = this.sessions.get(to);
|
|
609
|
+
if (!session) {
|
|
610
|
+
session = this.createSession(to, conn);
|
|
611
|
+
log?.info(
|
|
612
|
+
`${this.clientId} -- no session for ${to}, created a new one (id: ${session.id})`
|
|
613
|
+
);
|
|
614
|
+
}
|
|
615
|
+
return session;
|
|
616
|
+
}
|
|
615
617
|
deleteSession(session) {
|
|
616
618
|
this.sessions.delete(session.to);
|
|
617
619
|
log?.info(
|
|
618
|
-
`${this.clientId} -- session ${session.
|
|
620
|
+
`${this.clientId} -- session ${session.id} disconnect from ${session.to}`
|
|
619
621
|
);
|
|
620
622
|
this.eventDispatcher.dispatchEvent("sessionStatus", {
|
|
621
623
|
status: "disconnect",
|
|
@@ -683,11 +685,14 @@ var Transport = class {
|
|
|
683
685
|
)}`
|
|
684
686
|
);
|
|
685
687
|
} else {
|
|
688
|
+
const errMsg = `received out-of-order msg (got seq: ${msg.seq}, wanted seq: ${session.nextExpectedSeq})`;
|
|
686
689
|
log?.error(
|
|
687
|
-
`${this.clientId} --
|
|
690
|
+
`${this.clientId} -- fatal: ${errMsg}, marking connection as dead: ${JSON.stringify(
|
|
691
|
+
msg
|
|
692
|
+
)}`
|
|
688
693
|
);
|
|
694
|
+
this.protocolError(ProtocolError.MessageOrderingViolated, errMsg);
|
|
689
695
|
session.close();
|
|
690
|
-
this.deleteSession(session);
|
|
691
696
|
}
|
|
692
697
|
return;
|
|
693
698
|
}
|
|
@@ -734,14 +739,7 @@ var Transport = class {
|
|
|
734
739
|
);
|
|
735
740
|
return void 0;
|
|
736
741
|
}
|
|
737
|
-
|
|
738
|
-
if (!session) {
|
|
739
|
-
session = this.createSession(to, void 0);
|
|
740
|
-
log?.info(
|
|
741
|
-
`${this.clientId} -- no session for ${to}, created a new one (id: ${session.debugId})`
|
|
742
|
-
);
|
|
743
|
-
}
|
|
744
|
-
return session.send(msg);
|
|
742
|
+
return this.getOrCreateSession(to).send(msg);
|
|
745
743
|
}
|
|
746
744
|
// control helpers
|
|
747
745
|
sendCloseStream(to, streamId) {
|
|
@@ -793,7 +791,13 @@ var ClientTransport = class extends Transport {
|
|
|
793
791
|
*/
|
|
794
792
|
inflightConnectionPromises;
|
|
795
793
|
retryBudget;
|
|
796
|
-
|
|
794
|
+
/**
|
|
795
|
+
* A flag indicating whether the transport should automatically reconnect
|
|
796
|
+
* when a connection is dropped.
|
|
797
|
+
* Realistically, this should always be true for clients unless you are writing
|
|
798
|
+
* tests or a special case where you don't want to reconnect.
|
|
799
|
+
*/
|
|
800
|
+
reconnectOnConnectionDrop = true;
|
|
797
801
|
constructor(clientId, providedOptions) {
|
|
798
802
|
super(clientId, providedOptions);
|
|
799
803
|
this.options = {
|
|
@@ -801,21 +805,20 @@ var ClientTransport = class extends Transport {
|
|
|
801
805
|
...providedOptions
|
|
802
806
|
};
|
|
803
807
|
this.inflightConnectionPromises = /* @__PURE__ */ new Map();
|
|
804
|
-
this.retryBudget = new LeakyBucketRateLimit(
|
|
805
|
-
this.options.connectionRetryOptions
|
|
806
|
-
);
|
|
808
|
+
this.retryBudget = new LeakyBucketRateLimit(this.options);
|
|
807
809
|
}
|
|
808
810
|
handleConnection(conn, to) {
|
|
809
811
|
if (this.state !== "open")
|
|
810
812
|
return;
|
|
811
813
|
let session = void 0;
|
|
812
814
|
const handshakeHandler = (data) => {
|
|
813
|
-
const
|
|
814
|
-
if (!
|
|
815
|
+
const maybeSession = this.receiveHandshakeResponseMessage(data, conn);
|
|
816
|
+
if (!maybeSession) {
|
|
815
817
|
conn.close();
|
|
816
818
|
return;
|
|
819
|
+
} else {
|
|
820
|
+
session = maybeSession;
|
|
817
821
|
}
|
|
818
|
-
session = this.onConnect(conn, handshake.from, handshake.instanceId);
|
|
819
822
|
conn.removeDataListener(handshakeHandler);
|
|
820
823
|
conn.addDataListener((data2) => {
|
|
821
824
|
const parsed = this.parseMsg(data2);
|
|
@@ -835,7 +838,7 @@ var ClientTransport = class extends Transport {
|
|
|
835
838
|
`${this.clientId} -- connection (id: ${conn.debugId}) to ${to} disconnected`
|
|
836
839
|
);
|
|
837
840
|
this.inflightConnectionPromises.delete(to);
|
|
838
|
-
if (this.
|
|
841
|
+
if (this.reconnectOnConnectionDrop) {
|
|
839
842
|
void this.connect(to);
|
|
840
843
|
}
|
|
841
844
|
});
|
|
@@ -845,7 +848,7 @@ var ClientTransport = class extends Transport {
|
|
|
845
848
|
);
|
|
846
849
|
});
|
|
847
850
|
}
|
|
848
|
-
receiveHandshakeResponseMessage(data) {
|
|
851
|
+
receiveHandshakeResponseMessage(data, conn) {
|
|
849
852
|
const parsed = this.parseMsg(data);
|
|
850
853
|
if (!parsed) {
|
|
851
854
|
this.protocolError(
|
|
@@ -878,12 +881,14 @@ var ClientTransport = class extends Transport {
|
|
|
878
881
|
);
|
|
879
882
|
return false;
|
|
880
883
|
}
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
+
log?.debug(`${this.clientId} -- handshake from ${parsed.from} ok`);
|
|
885
|
+
const session = this.onConnect(
|
|
886
|
+
conn,
|
|
887
|
+
parsed.from,
|
|
888
|
+
parsed.payload.status.sessionId
|
|
884
889
|
);
|
|
885
890
|
this.retryBudget.startRestoringBudget(parsed.from);
|
|
886
|
-
return
|
|
891
|
+
return session;
|
|
887
892
|
}
|
|
888
893
|
/**
|
|
889
894
|
* Manually attempts to connect to a client.
|
|
@@ -941,7 +946,7 @@ var ClientTransport = class extends Transport {
|
|
|
941
946
|
} catch (error) {
|
|
942
947
|
this.inflightConnectionPromises.delete(to);
|
|
943
948
|
const errStr = coerceErrorString(error);
|
|
944
|
-
if (!this.
|
|
949
|
+
if (!this.reconnectOnConnectionDrop || !canProceedWithConnection()) {
|
|
945
950
|
log?.warn(`${this.clientId} -- connection to ${to} failed (${errStr})`);
|
|
946
951
|
} else {
|
|
947
952
|
log?.warn(
|
|
@@ -952,11 +957,8 @@ var ClientTransport = class extends Transport {
|
|
|
952
957
|
}
|
|
953
958
|
}
|
|
954
959
|
sendHandshake(to, conn) {
|
|
955
|
-
const
|
|
956
|
-
|
|
957
|
-
to,
|
|
958
|
-
this.instanceId
|
|
959
|
-
);
|
|
960
|
+
const session = this.getOrCreateSession(to, conn);
|
|
961
|
+
const requestMsg = handshakeRequestMessage(this.clientId, to, session.id);
|
|
960
962
|
log?.debug(`${this.clientId} -- sending handshake request to ${to}`);
|
|
961
963
|
conn.send(this.codec.toBuffer(requestMsg));
|
|
962
964
|
}
|
|
@@ -969,7 +971,7 @@ var ServerTransport = class extends Transport {
|
|
|
969
971
|
constructor(clientId, providedOptions) {
|
|
970
972
|
super(clientId, providedOptions);
|
|
971
973
|
log?.info(
|
|
972
|
-
`${this.clientId} -- initiated server transport (
|
|
974
|
+
`${this.clientId} -- initiated server transport (protocol: ${PROTOCOL_VERSION})`
|
|
973
975
|
);
|
|
974
976
|
}
|
|
975
977
|
handleConnection(conn) {
|
|
@@ -981,12 +983,13 @@ var ServerTransport = class extends Transport {
|
|
|
981
983
|
let session = void 0;
|
|
982
984
|
const client = () => session?.to ?? "unknown";
|
|
983
985
|
const handshakeHandler = (data) => {
|
|
984
|
-
const
|
|
985
|
-
if (!
|
|
986
|
+
const maybeSession = this.receiveHandshakeRequestMessage(data, conn);
|
|
987
|
+
if (!maybeSession) {
|
|
986
988
|
conn.close();
|
|
987
989
|
return;
|
|
990
|
+
} else {
|
|
991
|
+
session = maybeSession;
|
|
988
992
|
}
|
|
989
|
-
session = this.onConnect(conn, handshake.from, handshake.instanceId);
|
|
990
993
|
conn.removeDataListener(handshakeHandler);
|
|
991
994
|
conn.addDataListener((data2) => {
|
|
992
995
|
const parsed = this.parseMsg(data2);
|
|
@@ -1024,18 +1027,13 @@ var ServerTransport = class extends Transport {
|
|
|
1024
1027
|
return false;
|
|
1025
1028
|
}
|
|
1026
1029
|
if (!import_value.Value.Check(ControlMessageHandshakeRequestSchema, parsed.payload)) {
|
|
1027
|
-
const
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
);
|
|
1030
|
+
const reason = "received invalid handshake msg";
|
|
1031
|
+
const responseMsg2 = handshakeResponseMessage(this.clientId, parsed.from, {
|
|
1032
|
+
ok: false,
|
|
1033
|
+
reason
|
|
1034
|
+
});
|
|
1033
1035
|
conn.send(this.codec.toBuffer(responseMsg2));
|
|
1034
|
-
log?.warn(
|
|
1035
|
-
`${this.clientId} -- received invalid handshake msg: ${JSON.stringify(
|
|
1036
|
-
parsed
|
|
1037
|
-
)}`
|
|
1038
|
-
);
|
|
1036
|
+
log?.warn(`${this.clientId} -- ${reason}: ${JSON.stringify(parsed)}`);
|
|
1039
1037
|
this.protocolError(
|
|
1040
1038
|
ProtocolError.HandshakeFailed,
|
|
1041
1039
|
"invalid handshake request"
|
|
@@ -1044,34 +1042,28 @@ var ServerTransport = class extends Transport {
|
|
|
1044
1042
|
}
|
|
1045
1043
|
const gotVersion = parsed.payload.protocolVersion;
|
|
1046
1044
|
if (gotVersion !== PROTOCOL_VERSION) {
|
|
1047
|
-
const
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
);
|
|
1045
|
+
const reason = `incorrect version (got: ${gotVersion} wanted ${PROTOCOL_VERSION})`;
|
|
1046
|
+
const responseMsg2 = handshakeResponseMessage(this.clientId, parsed.from, {
|
|
1047
|
+
ok: false,
|
|
1048
|
+
reason
|
|
1049
|
+
});
|
|
1053
1050
|
conn.send(this.codec.toBuffer(responseMsg2));
|
|
1054
1051
|
log?.warn(
|
|
1055
1052
|
`${this.clientId} -- received handshake msg with incompatible protocol version (got: ${gotVersion}, expected: ${PROTOCOL_VERSION})`
|
|
1056
1053
|
);
|
|
1057
|
-
this.protocolError(
|
|
1058
|
-
ProtocolError.HandshakeFailed,
|
|
1059
|
-
`incorrect version (got: ${gotVersion} wanted ${PROTOCOL_VERSION})`
|
|
1060
|
-
);
|
|
1054
|
+
this.protocolError(ProtocolError.HandshakeFailed, reason);
|
|
1061
1055
|
return false;
|
|
1062
1056
|
}
|
|
1063
|
-
const
|
|
1057
|
+
const session = this.getOrCreateSession(parsed.from, conn);
|
|
1064
1058
|
log?.debug(
|
|
1065
|
-
`${this.clientId} -- handshake from ${parsed.from} ok
|
|
1066
|
-
);
|
|
1067
|
-
const responseMsg = handshakeResponseMessage(
|
|
1068
|
-
this.clientId,
|
|
1069
|
-
this.instanceId,
|
|
1070
|
-
parsed.from,
|
|
1071
|
-
true
|
|
1059
|
+
`${this.clientId} -- handshake from ${parsed.from} ok, responding with handshake success`
|
|
1072
1060
|
);
|
|
1061
|
+
const responseMsg = handshakeResponseMessage(this.clientId, parsed.from, {
|
|
1062
|
+
ok: true,
|
|
1063
|
+
sessionId: session.id
|
|
1064
|
+
});
|
|
1073
1065
|
conn.send(this.codec.toBuffer(responseMsg));
|
|
1074
|
-
return
|
|
1066
|
+
return this.onConnect(conn, parsed.from, parsed.payload.sessionId);
|
|
1075
1067
|
}
|
|
1076
1068
|
};
|
|
1077
1069
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { a as ClientTransport, c as ClientTransportOptions, C as Connection,
|
|
1
|
+
export { a as ClientTransport, c as ClientTransportOptions, C as Connection, n as EventHandler, E as EventMap, m as EventTypes, O as OpaqueTransportMessage, i as OpaqueTransportMessageSchema, o as ProtocolError, p as ProtocolErrorType, d as ServerTransport, f as Session, T as Transport, b as TransportClientId, j as TransportMessage, h as TransportMessageSchema, e as TransportOptions, g as TransportStatus, l as isStreamClose, k as isStreamOpen } from '../index-8df0bdfb.js';
|
|
2
2
|
import '../types-3e5768ec.js';
|
|
3
3
|
import '@sinclair/typebox';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { a as ClientTransport, c as ClientTransportOptions, C as Connection,
|
|
1
|
+
export { a as ClientTransport, c as ClientTransportOptions, C as Connection, n as EventHandler, E as EventMap, m as EventTypes, O as OpaqueTransportMessage, i as OpaqueTransportMessageSchema, o as ProtocolError, p as ProtocolErrorType, d as ServerTransport, f as Session, T as Transport, b as TransportClientId, j as TransportMessage, h as TransportMessageSchema, e as TransportOptions, g as TransportStatus, l as isStreamClose, k as isStreamOpen } from '../index-8df0bdfb.js';
|
|
2
2
|
import '../types-3e5768ec.js';
|
|
3
3
|
import '@sinclair/typebox';
|
package/dist/transport/index.js
CHANGED
|
@@ -6,11 +6,11 @@ import {
|
|
|
6
6
|
ServerTransport,
|
|
7
7
|
Session,
|
|
8
8
|
Transport
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-LQMPJI3S.js";
|
|
10
10
|
import {
|
|
11
11
|
OpaqueTransportMessageSchema,
|
|
12
12
|
TransportMessageSchema
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-VH3NGOXQ.js";
|
|
14
14
|
import "../chunk-H4BYJELI.js";
|
|
15
15
|
import "../chunk-GZ7HCLLM.js";
|
|
16
16
|
export {
|
|
@@ -49,6 +49,9 @@ module.exports = __toCommonJS(testHelpers_exports);
|
|
|
49
49
|
var import_isomorphic_ws = __toESM(require("isomorphic-ws"), 1);
|
|
50
50
|
var import_ws = require("ws");
|
|
51
51
|
|
|
52
|
+
// transport/transport.ts
|
|
53
|
+
var import_value = require("@sinclair/typebox/value");
|
|
54
|
+
|
|
52
55
|
// logging/index.ts
|
|
53
56
|
var log;
|
|
54
57
|
|
|
@@ -72,7 +75,12 @@ var Session = class {
|
|
|
72
75
|
/**
|
|
73
76
|
* The unique ID of this session.
|
|
74
77
|
*/
|
|
75
|
-
|
|
78
|
+
id;
|
|
79
|
+
/**
|
|
80
|
+
* What the other side advertised as their session ID
|
|
81
|
+
* for this session.
|
|
82
|
+
*/
|
|
83
|
+
advertisedSessionId;
|
|
76
84
|
/**
|
|
77
85
|
* Number of messages we've sent along this session (excluding handshake and acks)
|
|
78
86
|
*/
|
|
@@ -94,11 +102,11 @@ var Session = class {
|
|
|
94
102
|
* The interval for sending heartbeats.
|
|
95
103
|
*/
|
|
96
104
|
heartbeat;
|
|
97
|
-
constructor(
|
|
105
|
+
constructor(conn, from, to, options) {
|
|
106
|
+
this.id = `session-${nanoid(12)}`;
|
|
98
107
|
this.options = options;
|
|
99
|
-
this.debugId = `sess-${unsafeId()}`;
|
|
100
108
|
this.from = from;
|
|
101
|
-
this.to =
|
|
109
|
+
this.to = to;
|
|
102
110
|
this.connection = conn;
|
|
103
111
|
this.codec = options.codec;
|
|
104
112
|
this.heartbeatMisses = 0;
|
|
@@ -138,7 +146,7 @@ var Session = class {
|
|
|
138
146
|
log?.info(
|
|
139
147
|
`${this.from} -- closing connection (id: ${this.connection.debugId}) to ${this.to} due to inactivity`
|
|
140
148
|
);
|
|
141
|
-
this.closeStaleConnection(
|
|
149
|
+
this.closeStaleConnection();
|
|
142
150
|
}
|
|
143
151
|
return;
|
|
144
152
|
}
|
|
@@ -169,33 +177,37 @@ var Session = class {
|
|
|
169
177
|
log?.debug(`${this.from} -- resending ${msg.id} (seq: ${msg.seq})`);
|
|
170
178
|
const ok = this.connection.send(this.codec.toBuffer(msg));
|
|
171
179
|
if (!ok) {
|
|
172
|
-
const msg2 = `${this.from} -- failed to send buffered message to ${this.to} in session (id: ${this.
|
|
180
|
+
const msg2 = `${this.from} -- failed to send buffered message to ${this.to} in session (id: ${this.id}) (if you hit this code path something is seriously wrong)`;
|
|
173
181
|
log?.error(msg2);
|
|
174
182
|
throw new Error(msg2);
|
|
175
183
|
}
|
|
176
184
|
}
|
|
177
185
|
}
|
|
178
186
|
updateBookkeeping(ack, seq) {
|
|
187
|
+
if (seq + 1 < this.ack) {
|
|
188
|
+
log?.error(`${this.from} -- received stale seq ${seq} + 1 < ${this.ack}`);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
179
191
|
this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq > ack);
|
|
180
192
|
this.ack = seq + 1;
|
|
181
193
|
}
|
|
182
194
|
closeStaleConnection(conn) {
|
|
183
|
-
if (
|
|
195
|
+
if (this.connection === void 0 || this.connection === conn)
|
|
184
196
|
return;
|
|
185
197
|
log?.info(
|
|
186
|
-
`${this.from} -- closing old inner connection (id: ${this.connection.debugId}) from session (id: ${this.
|
|
198
|
+
`${this.from} -- closing old inner connection (id: ${this.connection.debugId}) from session (id: ${this.id}) to ${this.to}`
|
|
187
199
|
);
|
|
188
200
|
this.connection.close();
|
|
189
201
|
this.connection = void 0;
|
|
190
202
|
}
|
|
191
203
|
replaceWithNewConnection(newConn) {
|
|
192
|
-
this.closeStaleConnection(
|
|
204
|
+
this.closeStaleConnection(newConn);
|
|
193
205
|
this.cancelGrace();
|
|
194
206
|
this.connection = newConn;
|
|
195
207
|
}
|
|
196
208
|
beginGrace(cb) {
|
|
197
209
|
log?.info(
|
|
198
|
-
`${this.from} -- starting ${this.options.sessionDisconnectGraceMs}ms grace period until session (id: ${this.
|
|
210
|
+
`${this.from} -- starting ${this.options.sessionDisconnectGraceMs}ms grace period until session (id: ${this.id}) to ${this.to} is closed`
|
|
199
211
|
);
|
|
200
212
|
this.disconnectionGrace = setTimeout(() => {
|
|
201
213
|
this.close();
|
|
@@ -206,11 +218,12 @@ var Session = class {
|
|
|
206
218
|
cancelGrace() {
|
|
207
219
|
this.heartbeatMisses = 0;
|
|
208
220
|
clearTimeout(this.disconnectionGrace);
|
|
221
|
+
this.disconnectionGrace = void 0;
|
|
209
222
|
}
|
|
210
223
|
// closed when we want to discard the whole session
|
|
211
224
|
// (i.e. shutdown or session disconnect)
|
|
212
225
|
close() {
|
|
213
|
-
this.closeStaleConnection(
|
|
226
|
+
this.closeStaleConnection();
|
|
214
227
|
this.cancelGrace();
|
|
215
228
|
this.resetBufferedMessages();
|
|
216
229
|
clearInterval(this.heartbeat);
|
|
@@ -299,6 +312,25 @@ var NaiveJsonCodec = {
|
|
|
299
312
|
}
|
|
300
313
|
};
|
|
301
314
|
|
|
315
|
+
// transport/transport.ts
|
|
316
|
+
var defaultTransportOptions = {
|
|
317
|
+
heartbeatIntervalMs: 1e3,
|
|
318
|
+
heartbeatsUntilDead: 2,
|
|
319
|
+
sessionDisconnectGraceMs: 5e3,
|
|
320
|
+
codec: NaiveJsonCodec
|
|
321
|
+
};
|
|
322
|
+
var defaultConnectionRetryOptions = {
|
|
323
|
+
baseIntervalMs: 250,
|
|
324
|
+
maxJitterMs: 200,
|
|
325
|
+
maxBackoffMs: 32e3,
|
|
326
|
+
attemptBudgetCapacity: 5,
|
|
327
|
+
budgetRestoreIntervalMs: 200
|
|
328
|
+
};
|
|
329
|
+
var defaultClientTransportOptions = {
|
|
330
|
+
...defaultTransportOptions,
|
|
331
|
+
...defaultConnectionRetryOptions
|
|
332
|
+
};
|
|
333
|
+
|
|
302
334
|
// node_modules/p-defer/index.js
|
|
303
335
|
function pDefer() {
|
|
304
336
|
const deferred = {};
|
|
@@ -663,17 +695,12 @@ function catchProcError(err) {
|
|
|
663
695
|
}
|
|
664
696
|
};
|
|
665
697
|
}
|
|
666
|
-
var testingSessionOptions =
|
|
667
|
-
heartbeatIntervalMs: 1e3,
|
|
668
|
-
heartbeatsUntilDead: 2,
|
|
669
|
-
sessionDisconnectGraceMs: 5e3,
|
|
670
|
-
codec: NaiveJsonCodec
|
|
671
|
-
};
|
|
698
|
+
var testingSessionOptions = defaultTransportOptions;
|
|
672
699
|
function dummyCtx(state, extendedContext) {
|
|
673
700
|
const session = new Session(
|
|
701
|
+
void 0,
|
|
674
702
|
"client",
|
|
675
703
|
"SERVER",
|
|
676
|
-
void 0,
|
|
677
704
|
testingSessionOptions
|
|
678
705
|
);
|
|
679
706
|
return {
|