@replit/river 0.21.0 → 0.22.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 +1 -1
- package/dist/{chunk-5WFL722S.js → chunk-3MFX6NXA.js} +94 -3
- package/dist/chunk-3MFX6NXA.js.map +1 -0
- package/dist/{chunk-NFV77C2M.js → chunk-GCLEWC26.js} +340 -507
- package/dist/chunk-GCLEWC26.js.map +1 -0
- package/dist/chunk-HUBFYN37.js +60 -0
- package/dist/chunk-HUBFYN37.js.map +1 -0
- package/dist/{chunk-DT5JS6TM.js → chunk-OTQNCLFH.js} +1 -1
- package/dist/chunk-OTQNCLFH.js.map +1 -0
- package/dist/{chunk-MJR36SUY.js → chunk-S3YKQT4J.js} +2 -2
- package/dist/{chunk-QU2EE6YU.js → chunk-ZPBWKBM5.js} +361 -394
- package/dist/chunk-ZPBWKBM5.js.map +1 -0
- package/dist/{connection-8a71dbe2.d.ts → connection-8b059ac4.d.ts} +6 -4
- package/dist/{connection-d49d5d56.d.ts → connection-bbfe1147.d.ts} +1 -1
- package/dist/{index-3ac92295.d.ts → index-2ece5234.d.ts} +18 -7
- package/dist/logging/index.cjs.map +1 -1
- package/dist/logging/index.d.cts +2 -1
- package/dist/logging/index.d.ts +2 -1
- package/dist/logging/index.js +1 -1
- package/dist/router/index.cjs +384 -492
- package/dist/router/index.cjs.map +1 -1
- package/dist/router/index.d.cts +5 -4
- package/dist/router/index.d.ts +5 -4
- package/dist/router/index.js +5 -4
- package/dist/{services-abc077db.d.ts → services-acbcc441.d.ts} +1 -1
- package/dist/{services-8496d6e8.d.ts → services-cb01a7a8.d.ts} +1 -1
- package/dist/transport/impls/uds/client.cjs +202 -155
- package/dist/transport/impls/uds/client.cjs.map +1 -1
- package/dist/transport/impls/uds/client.d.cts +3 -2
- package/dist/transport/impls/uds/client.d.ts +3 -2
- package/dist/transport/impls/uds/client.js +4 -4
- package/dist/transport/impls/uds/server.cjs +295 -264
- package/dist/transport/impls/uds/server.cjs.map +1 -1
- package/dist/transport/impls/uds/server.d.cts +3 -2
- package/dist/transport/impls/uds/server.d.ts +3 -2
- package/dist/transport/impls/uds/server.js +4 -4
- package/dist/transport/impls/ws/client.cjs +256 -214
- package/dist/transport/impls/ws/client.cjs.map +1 -1
- package/dist/transport/impls/ws/client.d.cts +6 -6
- package/dist/transport/impls/ws/client.d.ts +6 -6
- package/dist/transport/impls/ws/client.js +34 -49
- package/dist/transport/impls/ws/client.js.map +1 -1
- package/dist/transport/impls/ws/server.cjs +317 -278
- 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 +4 -4
- package/dist/transport/impls/ws/server.js.map +1 -1
- package/dist/transport/index.cjs +406 -391
- package/dist/transport/index.cjs.map +1 -1
- package/dist/transport/index.d.cts +5 -5
- package/dist/transport/index.d.ts +5 -5
- package/dist/transport/index.js +3 -3
- package/dist/util/testHelpers.cjs +71 -19
- package/dist/util/testHelpers.cjs.map +1 -1
- package/dist/util/testHelpers.d.cts +20 -8
- package/dist/util/testHelpers.d.ts +20 -8
- package/dist/util/testHelpers.js +13 -12
- package/dist/util/testHelpers.js.map +1 -1
- package/dist/wslike-e0b32dd5.d.ts +40 -0
- package/package.json +4 -5
- package/dist/chunk-2ERP6FUE.js +0 -42
- package/dist/chunk-2ERP6FUE.js.map +0 -1
- package/dist/chunk-5WFL722S.js.map +0 -1
- package/dist/chunk-DT5JS6TM.js.map +0 -1
- package/dist/chunk-NFV77C2M.js.map +0 -1
- package/dist/chunk-QU2EE6YU.js.map +0 -1
- /package/dist/{chunk-MJR36SUY.js.map → chunk-S3YKQT4J.js.map} +0 -0
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
19
|
|
|
30
20
|
// transport/impls/ws/client.ts
|
|
@@ -33,11 +23,9 @@ __export(client_exports, {
|
|
|
33
23
|
WebSocketClientTransport: () => WebSocketClientTransport
|
|
34
24
|
});
|
|
35
25
|
module.exports = __toCommonJS(client_exports);
|
|
36
|
-
var import_agnostic_ws2 = __toESM(require("agnostic-ws"), 1);
|
|
37
26
|
|
|
38
27
|
// transport/transport.ts
|
|
39
28
|
var import_value = require("@sinclair/typebox/value");
|
|
40
|
-
var import_api2 = require("@opentelemetry/api");
|
|
41
29
|
|
|
42
30
|
// transport/message.ts
|
|
43
31
|
var import_typebox = require("@sinclair/typebox");
|
|
@@ -156,17 +144,71 @@ var EventDispatcher = class {
|
|
|
156
144
|
|
|
157
145
|
// transport/session.ts
|
|
158
146
|
var import_nanoid2 = require("nanoid");
|
|
147
|
+
|
|
148
|
+
// tracing/index.ts
|
|
149
|
+
var import_api = require("@opentelemetry/api");
|
|
150
|
+
|
|
151
|
+
// package.json
|
|
152
|
+
var version = "0.22.0";
|
|
153
|
+
|
|
154
|
+
// tracing/index.ts
|
|
155
|
+
function getPropagationContext(ctx) {
|
|
156
|
+
const tracing = {
|
|
157
|
+
traceparent: "",
|
|
158
|
+
tracestate: ""
|
|
159
|
+
};
|
|
160
|
+
import_api.propagation.inject(ctx, tracing);
|
|
161
|
+
return tracing;
|
|
162
|
+
}
|
|
163
|
+
function createSessionTelemetryInfo(session, propagationCtx) {
|
|
164
|
+
const ctx = propagationCtx ? import_api.propagation.extract(import_api.context.active(), propagationCtx) : import_api.context.active();
|
|
165
|
+
const span = tracer.startSpan(
|
|
166
|
+
`session ${session.id}`,
|
|
167
|
+
{
|
|
168
|
+
attributes: {
|
|
169
|
+
component: "river",
|
|
170
|
+
"river.session.id": session.id,
|
|
171
|
+
"river.session.to": session.to,
|
|
172
|
+
"river.session.from": session.from
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
ctx
|
|
176
|
+
);
|
|
177
|
+
return { span, ctx };
|
|
178
|
+
}
|
|
179
|
+
function createConnectionTelemetryInfo(connection, sessionSpan) {
|
|
180
|
+
const ctx = import_api.trace.setSpan(import_api.context.active(), sessionSpan);
|
|
181
|
+
const span = tracer.startSpan(
|
|
182
|
+
`connection ${connection.id}`,
|
|
183
|
+
{
|
|
184
|
+
attributes: {
|
|
185
|
+
component: "river",
|
|
186
|
+
"river.connection.id": connection.id
|
|
187
|
+
},
|
|
188
|
+
links: [{ context: sessionSpan.spanContext() }]
|
|
189
|
+
},
|
|
190
|
+
ctx
|
|
191
|
+
);
|
|
192
|
+
return { span, ctx };
|
|
193
|
+
}
|
|
194
|
+
var tracer = import_api.trace.getTracer("river", version);
|
|
195
|
+
var tracing_default = tracer;
|
|
196
|
+
|
|
197
|
+
// transport/session.ts
|
|
198
|
+
var import_api2 = require("@opentelemetry/api");
|
|
159
199
|
var nanoid2 = (0, import_nanoid2.customAlphabet)("1234567890abcdefghijklmnopqrstuvxyz", 6);
|
|
160
200
|
var unsafeId = () => nanoid2();
|
|
161
201
|
var Connection = class {
|
|
162
|
-
|
|
202
|
+
id;
|
|
203
|
+
telemetry;
|
|
163
204
|
constructor() {
|
|
164
|
-
this.
|
|
205
|
+
this.id = `conn-${nanoid2(12)}`;
|
|
165
206
|
}
|
|
166
207
|
};
|
|
167
208
|
var Session = class {
|
|
168
209
|
codec;
|
|
169
210
|
options;
|
|
211
|
+
telemetry;
|
|
170
212
|
/**
|
|
171
213
|
* The buffer of messages that have been sent but not yet acknowledged.
|
|
172
214
|
*/
|
|
@@ -213,7 +255,7 @@ var Session = class {
|
|
|
213
255
|
* The interval for sending heartbeats.
|
|
214
256
|
*/
|
|
215
257
|
heartbeat;
|
|
216
|
-
constructor(conn, from, to, options) {
|
|
258
|
+
constructor(conn, from, to, options, propagationCtx) {
|
|
217
259
|
this.id = `session-${nanoid2(12)}`;
|
|
218
260
|
this.options = options;
|
|
219
261
|
this.from = from;
|
|
@@ -225,13 +267,14 @@ var Session = class {
|
|
|
225
267
|
() => this.sendHeartbeat(),
|
|
226
268
|
options.heartbeatIntervalMs
|
|
227
269
|
);
|
|
270
|
+
this.telemetry = createSessionTelemetryInfo(this, propagationCtx);
|
|
228
271
|
}
|
|
229
272
|
get loggingMetadata() {
|
|
230
273
|
return {
|
|
231
274
|
clientId: this.from,
|
|
232
275
|
connectedTo: this.to,
|
|
233
276
|
sessionId: this.id,
|
|
234
|
-
connId: this.connection?.
|
|
277
|
+
connId: this.connection?.id
|
|
235
278
|
};
|
|
236
279
|
}
|
|
237
280
|
/**
|
|
@@ -276,6 +319,7 @@ var Session = class {
|
|
|
276
319
|
`closing connection to ${this.to} due to inactivity (missed ${misses} heartbeats which is ${missDuration}ms)`,
|
|
277
320
|
this.loggingMetadata
|
|
278
321
|
);
|
|
322
|
+
this.telemetry.span.addEvent("closing connection due to inactivity");
|
|
279
323
|
this.closeStaleConnection();
|
|
280
324
|
}
|
|
281
325
|
return;
|
|
@@ -297,32 +341,38 @@ var Session = class {
|
|
|
297
341
|
sendBufferedMessages(conn) {
|
|
298
342
|
log?.info(`resending ${this.sendBuffer.length} buffered messages`, {
|
|
299
343
|
...this.loggingMetadata,
|
|
300
|
-
connId: conn.
|
|
344
|
+
connId: conn.id
|
|
301
345
|
});
|
|
302
346
|
for (const msg of this.sendBuffer) {
|
|
303
347
|
log?.debug(`resending msg`, {
|
|
304
348
|
...this.loggingMetadata,
|
|
305
349
|
fullTransportMessage: msg,
|
|
306
|
-
connId: conn.
|
|
350
|
+
connId: conn.id
|
|
307
351
|
});
|
|
308
352
|
const ok = conn.send(this.codec.toBuffer(msg));
|
|
309
353
|
if (!ok) {
|
|
310
354
|
const errMsg = `failed to send buffered message to ${this.to} (sus, this is a fresh connection)`;
|
|
355
|
+
conn.telemetry?.span.setStatus({
|
|
356
|
+
code: import_api2.SpanStatusCode.ERROR,
|
|
357
|
+
message: errMsg
|
|
358
|
+
});
|
|
311
359
|
log?.error(errMsg, {
|
|
312
360
|
...this.loggingMetadata,
|
|
313
361
|
fullTransportMessage: msg,
|
|
314
|
-
connId: conn.
|
|
362
|
+
connId: conn.id,
|
|
363
|
+
tags: ["invariant-violation"]
|
|
315
364
|
});
|
|
316
|
-
|
|
365
|
+
conn.close();
|
|
366
|
+
return;
|
|
317
367
|
}
|
|
318
368
|
}
|
|
319
369
|
}
|
|
320
370
|
updateBookkeeping(ack, seq) {
|
|
321
371
|
if (seq + 1 < this.ack) {
|
|
322
|
-
log?.error(
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
);
|
|
372
|
+
log?.error(`received stale seq ${seq} + 1 < ${this.ack}`, {
|
|
373
|
+
...this.loggingMetadata,
|
|
374
|
+
tags: ["invariant-violation"]
|
|
375
|
+
});
|
|
326
376
|
return;
|
|
327
377
|
}
|
|
328
378
|
this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq >= ack);
|
|
@@ -392,11 +442,6 @@ var Session = class {
|
|
|
392
442
|
}
|
|
393
443
|
};
|
|
394
444
|
|
|
395
|
-
// tracing/index.ts
|
|
396
|
-
var import_api = require("@opentelemetry/api");
|
|
397
|
-
var tracer = import_api.trace.getTracer("river");
|
|
398
|
-
var tracing_default = tracer;
|
|
399
|
-
|
|
400
445
|
// util/stringify.ts
|
|
401
446
|
function coerceErrorString(err) {
|
|
402
447
|
if (err instanceof Error) {
|
|
@@ -529,6 +574,7 @@ var NaiveJsonCodec = {
|
|
|
529
574
|
};
|
|
530
575
|
|
|
531
576
|
// transport/transport.ts
|
|
577
|
+
var import_api3 = require("@opentelemetry/api");
|
|
532
578
|
var defaultTransportOptions = {
|
|
533
579
|
heartbeatIntervalMs: 1e3,
|
|
534
580
|
heartbeatsUntilDead: 2,
|
|
@@ -607,17 +653,22 @@ var Transport = class {
|
|
|
607
653
|
status: "connect",
|
|
608
654
|
conn
|
|
609
655
|
});
|
|
656
|
+
conn.telemetry = createConnectionTelemetryInfo(
|
|
657
|
+
conn,
|
|
658
|
+
session.telemetry.span
|
|
659
|
+
);
|
|
610
660
|
if (isReconnect) {
|
|
611
661
|
session.replaceWithNewConnection(conn);
|
|
612
662
|
log?.info(`reconnected to ${connectedTo}`, session.loggingMetadata);
|
|
613
663
|
}
|
|
614
664
|
}
|
|
615
|
-
createSession(to, conn) {
|
|
665
|
+
createSession(to, conn, propagationCtx) {
|
|
616
666
|
const session = new Session(
|
|
617
667
|
conn,
|
|
618
668
|
this.clientId,
|
|
619
669
|
to,
|
|
620
|
-
this.options
|
|
670
|
+
this.options,
|
|
671
|
+
propagationCtx
|
|
621
672
|
);
|
|
622
673
|
this.sessions.set(session.to, session);
|
|
623
674
|
this.eventDispatcher.dispatchEvent("sessionStatus", {
|
|
@@ -626,11 +677,11 @@ var Transport = class {
|
|
|
626
677
|
});
|
|
627
678
|
return session;
|
|
628
679
|
}
|
|
629
|
-
getOrCreateSession(to, conn, sessionId) {
|
|
680
|
+
getOrCreateSession(to, conn, sessionId, propagationCtx) {
|
|
630
681
|
let session = this.sessions.get(to);
|
|
631
682
|
let isReconnect = session !== void 0;
|
|
632
683
|
if (session?.advertisedSessionId !== void 0 && sessionId !== void 0 && session.advertisedSessionId !== sessionId) {
|
|
633
|
-
log?.
|
|
684
|
+
log?.info(
|
|
634
685
|
`session for ${to} already exists but has a different session id (expected: ${session.advertisedSessionId}, got: ${sessionId}), creating a new one`,
|
|
635
686
|
session.loggingMetadata
|
|
636
687
|
);
|
|
@@ -639,7 +690,7 @@ var Transport = class {
|
|
|
639
690
|
session = void 0;
|
|
640
691
|
}
|
|
641
692
|
if (!session) {
|
|
642
|
-
session = this.createSession(to, conn);
|
|
693
|
+
session = this.createSession(to, conn, propagationCtx);
|
|
643
694
|
log?.info(
|
|
644
695
|
`no session for ${to}, created a new one`,
|
|
645
696
|
session.loggingMetadata
|
|
@@ -652,6 +703,7 @@ var Transport = class {
|
|
|
652
703
|
}
|
|
653
704
|
deleteSession(session) {
|
|
654
705
|
session.close();
|
|
706
|
+
session.telemetry.span.end();
|
|
655
707
|
this.sessions.delete(session.to);
|
|
656
708
|
log?.info(
|
|
657
709
|
`session ${session.id} disconnect from ${session.to}`,
|
|
@@ -668,12 +720,16 @@ var Transport = class {
|
|
|
668
720
|
* @param connectedTo The peer we are connected to.
|
|
669
721
|
*/
|
|
670
722
|
onDisconnect(conn, session) {
|
|
723
|
+
conn.telemetry?.span.end();
|
|
671
724
|
this.eventDispatcher.dispatchEvent("connectionStatus", {
|
|
672
725
|
status: "disconnect",
|
|
673
726
|
conn
|
|
674
727
|
});
|
|
675
728
|
session.connection = void 0;
|
|
676
|
-
session.beginGrace(() =>
|
|
729
|
+
session.beginGrace(() => {
|
|
730
|
+
session.telemetry.span.addEvent("session grace period expired");
|
|
731
|
+
this.deleteSession(session);
|
|
732
|
+
});
|
|
677
733
|
}
|
|
678
734
|
/**
|
|
679
735
|
* Parses a message from a Uint8Array into a {@link OpaqueTransportMessage}.
|
|
@@ -707,9 +763,10 @@ var Transport = class {
|
|
|
707
763
|
return;
|
|
708
764
|
const session = this.sessions.get(msg.from);
|
|
709
765
|
if (!session) {
|
|
710
|
-
log?.error(`
|
|
766
|
+
log?.error(`no existing session for ${msg.from}`, {
|
|
711
767
|
clientId: this.clientId,
|
|
712
|
-
fullTransportMessage: msg
|
|
768
|
+
fullTransportMessage: msg,
|
|
769
|
+
tags: ["invariant-violation"]
|
|
713
770
|
});
|
|
714
771
|
return;
|
|
715
772
|
}
|
|
@@ -728,9 +785,14 @@ var Transport = class {
|
|
|
728
785
|
const errMsg = `received out-of-order msg (got seq: ${msg.seq}, wanted seq: ${session.nextExpectedSeq})`;
|
|
729
786
|
log?.error(`${errMsg}, marking connection as dead`, {
|
|
730
787
|
clientId: this.clientId,
|
|
731
|
-
fullTransportMessage: msg
|
|
788
|
+
fullTransportMessage: msg,
|
|
789
|
+
tags: ["invariant-violation"]
|
|
732
790
|
});
|
|
733
791
|
this.protocolError(ProtocolError.MessageOrderingViolated, errMsg);
|
|
792
|
+
session.telemetry.span.setStatus({
|
|
793
|
+
code: import_api3.SpanStatusCode.ERROR,
|
|
794
|
+
message: "message order violated"
|
|
795
|
+
});
|
|
734
796
|
session.close();
|
|
735
797
|
}
|
|
736
798
|
return;
|
|
@@ -772,7 +834,8 @@ var Transport = class {
|
|
|
772
834
|
const err = "transport is destroyed, cant send";
|
|
773
835
|
log?.error(err, {
|
|
774
836
|
clientId: this.clientId,
|
|
775
|
-
partialTransportMessage: msg
|
|
837
|
+
partialTransportMessage: msg,
|
|
838
|
+
tags: ["invariant-violation"]
|
|
776
839
|
});
|
|
777
840
|
this.protocolError(ProtocolError.UseAfterDestroy, err);
|
|
778
841
|
return void 0;
|
|
@@ -857,7 +920,7 @@ var ClientTransport = class extends Transport {
|
|
|
857
920
|
if (!session) {
|
|
858
921
|
log?.warn(
|
|
859
922
|
`connection to ${to} timed out waiting for handshake, closing`,
|
|
860
|
-
{ clientId: this.clientId, connectedTo: to, connId: conn.
|
|
923
|
+
{ clientId: this.clientId, connectedTo: to, connId: conn.id }
|
|
861
924
|
);
|
|
862
925
|
conn.close();
|
|
863
926
|
}
|
|
@@ -875,6 +938,10 @@ var ClientTransport = class extends Transport {
|
|
|
875
938
|
conn.addDataListener((data2) => {
|
|
876
939
|
const parsed = this.parseMsg(data2);
|
|
877
940
|
if (!parsed) {
|
|
941
|
+
conn.telemetry?.span.setStatus({
|
|
942
|
+
code: import_api3.SpanStatusCode.ERROR,
|
|
943
|
+
message: "message parse failure"
|
|
944
|
+
});
|
|
878
945
|
conn.close();
|
|
879
946
|
return;
|
|
880
947
|
}
|
|
@@ -897,6 +964,10 @@ var ClientTransport = class extends Transport {
|
|
|
897
964
|
}
|
|
898
965
|
});
|
|
899
966
|
conn.addErrorListener((err) => {
|
|
967
|
+
conn.telemetry?.span.setStatus({
|
|
968
|
+
code: import_api3.SpanStatusCode.ERROR,
|
|
969
|
+
message: "connection error"
|
|
970
|
+
});
|
|
900
971
|
log?.warn(`error in connection to ${to}: ${coerceErrorString(err)}`, {
|
|
901
972
|
...session?.loggingMetadata,
|
|
902
973
|
clientId: this.clientId,
|
|
@@ -907,6 +978,10 @@ var ClientTransport = class extends Transport {
|
|
|
907
978
|
receiveHandshakeResponseMessage(data, conn) {
|
|
908
979
|
const parsed = this.parseMsg(data);
|
|
909
980
|
if (!parsed) {
|
|
981
|
+
conn.telemetry?.span.setStatus({
|
|
982
|
+
code: import_api3.SpanStatusCode.ERROR,
|
|
983
|
+
message: "non-transport message"
|
|
984
|
+
});
|
|
910
985
|
this.protocolError(
|
|
911
986
|
ProtocolError.HandshakeFailed,
|
|
912
987
|
"received non-transport message"
|
|
@@ -914,6 +989,10 @@ var ClientTransport = class extends Transport {
|
|
|
914
989
|
return false;
|
|
915
990
|
}
|
|
916
991
|
if (!import_value.Value.Check(ControlMessageHandshakeResponseSchema, parsed.payload)) {
|
|
992
|
+
conn.telemetry?.span.setStatus({
|
|
993
|
+
code: import_api3.SpanStatusCode.ERROR,
|
|
994
|
+
message: "invalid handshake response"
|
|
995
|
+
});
|
|
917
996
|
log?.warn(`received invalid handshake resp`, {
|
|
918
997
|
clientId: this.clientId,
|
|
919
998
|
connectedTo: parsed.from,
|
|
@@ -926,7 +1005,11 @@ var ClientTransport = class extends Transport {
|
|
|
926
1005
|
return false;
|
|
927
1006
|
}
|
|
928
1007
|
if (!parsed.payload.status.ok) {
|
|
929
|
-
|
|
1008
|
+
conn.telemetry?.span.setStatus({
|
|
1009
|
+
code: import_api3.SpanStatusCode.ERROR,
|
|
1010
|
+
message: "handshake rejected"
|
|
1011
|
+
});
|
|
1012
|
+
log?.warn(`received handshake rejection`, {
|
|
930
1013
|
clientId: this.clientId,
|
|
931
1014
|
connectedTo: parsed.from,
|
|
932
1015
|
fullTransportMessage: parsed
|
|
@@ -956,142 +1039,94 @@ var ClientTransport = class extends Transport {
|
|
|
956
1039
|
* @param to The client ID of the node to connect to.
|
|
957
1040
|
*/
|
|
958
1041
|
async connect(to) {
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
span.recordException(coerceErrorString(e));
|
|
976
|
-
}
|
|
977
|
-
span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
|
|
978
|
-
} finally {
|
|
979
|
-
span.end();
|
|
980
|
-
}
|
|
1042
|
+
const canProceedWithConnection = () => this.state === "open";
|
|
1043
|
+
if (!canProceedWithConnection()) {
|
|
1044
|
+
log?.info(
|
|
1045
|
+
`transport state is no longer open, cancelling attempt to connect to ${to}`,
|
|
1046
|
+
{ clientId: this.clientId, connectedTo: to }
|
|
1047
|
+
);
|
|
1048
|
+
return;
|
|
1049
|
+
}
|
|
1050
|
+
let reconnectPromise = this.inflightConnectionPromises.get(to);
|
|
1051
|
+
if (!reconnectPromise) {
|
|
1052
|
+
const budgetConsumed = this.retryBudget.getBudgetConsumed(to);
|
|
1053
|
+
if (!this.retryBudget.hasBudget(to)) {
|
|
1054
|
+
const errMsg = `tried to connect to ${to} but retry budget exceeded (more than ${budgetConsumed} attempts in the last ${this.retryBudget.totalBudgetRestoreTime}ms)`;
|
|
1055
|
+
log?.warn(errMsg, { clientId: this.clientId, connectedTo: to });
|
|
1056
|
+
this.protocolError(ProtocolError.RetriesExceeded, errMsg);
|
|
1057
|
+
return;
|
|
981
1058
|
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
{
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
kind: import_api2.SpanKind.CLIENT
|
|
994
|
-
},
|
|
995
|
-
async (span) => {
|
|
1059
|
+
let sleep = Promise.resolve();
|
|
1060
|
+
const backoffMs = this.retryBudget.getBackoffMs(to);
|
|
1061
|
+
if (backoffMs > 0) {
|
|
1062
|
+
sleep = new Promise((resolve) => setTimeout(resolve, backoffMs));
|
|
1063
|
+
}
|
|
1064
|
+
log?.info(`attempting connection to ${to} (${backoffMs}ms backoff)`, {
|
|
1065
|
+
clientId: this.clientId,
|
|
1066
|
+
connectedTo: to
|
|
1067
|
+
});
|
|
1068
|
+
this.retryBudget.consumeBudget(to);
|
|
1069
|
+
reconnectPromise = tracing_default.startActiveSpan("connect", async (span) => {
|
|
996
1070
|
try {
|
|
997
|
-
|
|
1071
|
+
span.addEvent("backoff", { backoffMs });
|
|
1072
|
+
await sleep;
|
|
998
1073
|
if (!canProceedWithConnection()) {
|
|
999
|
-
|
|
1000
|
-
`transport state is no longer open, cancelling attempt to connect to ${to}`,
|
|
1001
|
-
{ clientId: this.clientId, connectedTo: to }
|
|
1002
|
-
);
|
|
1003
|
-
return false;
|
|
1074
|
+
throw new Error("transport state is no longer open");
|
|
1004
1075
|
}
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
if (!this.retryBudget.hasBudget(to)) {
|
|
1009
|
-
const errMsg = `tried to connect to ${to} but retry budget exceeded (more than ${budgetConsumed} attempts in the last ${this.retryBudget.totalBudgetRestoreTime}ms)`;
|
|
1010
|
-
log?.warn(errMsg, { clientId: this.clientId, connectedTo: to });
|
|
1011
|
-
this.protocolError(ProtocolError.RetriesExceeded, errMsg);
|
|
1012
|
-
return false;
|
|
1013
|
-
}
|
|
1014
|
-
let sleep = Promise.resolve();
|
|
1015
|
-
const backoffMs = this.retryBudget.getBackoffMs(to);
|
|
1016
|
-
if (backoffMs > 0) {
|
|
1017
|
-
sleep = new Promise((resolve) => setTimeout(resolve, backoffMs));
|
|
1018
|
-
}
|
|
1019
|
-
log?.info(
|
|
1020
|
-
`attempting connection to ${to} (${backoffMs}ms backoff)`,
|
|
1021
|
-
{
|
|
1022
|
-
clientId: this.clientId,
|
|
1023
|
-
connectedTo: to
|
|
1024
|
-
}
|
|
1025
|
-
);
|
|
1026
|
-
this.retryBudget.consumeBudget(to);
|
|
1027
|
-
reconnectPromise = sleep.then(() => {
|
|
1028
|
-
if (!canProceedWithConnection()) {
|
|
1029
|
-
throw new Error("transport state is no longer open");
|
|
1030
|
-
}
|
|
1031
|
-
}).then(() => this.createNewOutgoingConnection(to)).then((conn) => {
|
|
1032
|
-
if (!canProceedWithConnection()) {
|
|
1033
|
-
log?.info(
|
|
1034
|
-
`transport state is no longer open, closing pre-handshake connection to ${to}`,
|
|
1035
|
-
{
|
|
1036
|
-
clientId: this.clientId,
|
|
1037
|
-
connectedTo: to,
|
|
1038
|
-
connId: conn.debugId
|
|
1039
|
-
}
|
|
1040
|
-
);
|
|
1041
|
-
conn.close();
|
|
1042
|
-
throw new Error("transport state is no longer open");
|
|
1043
|
-
}
|
|
1044
|
-
return this.sendHandshake(to, conn).then((ok) => {
|
|
1045
|
-
if (!ok) {
|
|
1046
|
-
conn.close();
|
|
1047
|
-
throw new Error("failed to send handshake");
|
|
1048
|
-
}
|
|
1049
|
-
return conn;
|
|
1050
|
-
});
|
|
1051
|
-
});
|
|
1052
|
-
this.inflightConnectionPromises.set(to, reconnectPromise);
|
|
1053
|
-
} else {
|
|
1076
|
+
span.addEvent("connecting");
|
|
1077
|
+
const conn = await this.createNewOutgoingConnection(to);
|
|
1078
|
+
if (!canProceedWithConnection()) {
|
|
1054
1079
|
log?.info(
|
|
1055
|
-
`
|
|
1080
|
+
`transport state is no longer open, closing pre-handshake connection to ${to}`,
|
|
1056
1081
|
{
|
|
1057
1082
|
clientId: this.clientId,
|
|
1058
|
-
connectedTo: to
|
|
1083
|
+
connectedTo: to,
|
|
1084
|
+
connId: conn.id
|
|
1059
1085
|
}
|
|
1060
1086
|
);
|
|
1087
|
+
conn.close();
|
|
1088
|
+
throw new Error("transport state is no longer open");
|
|
1061
1089
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
if (!this.reconnectOnConnectionDrop || !canProceedWithConnection()) {
|
|
1068
|
-
log?.warn(`connection to ${to} failed (${errStr})`, {
|
|
1069
|
-
clientId: this.clientId,
|
|
1070
|
-
connectedTo: to
|
|
1071
|
-
});
|
|
1072
|
-
} else {
|
|
1073
|
-
log?.warn(`connection to ${to} failed (${errStr}), retrying`, {
|
|
1074
|
-
clientId: this.clientId,
|
|
1075
|
-
connectedTo: to
|
|
1076
|
-
});
|
|
1077
|
-
return true;
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
|
-
} catch (e) {
|
|
1081
|
-
if (e instanceof Error) {
|
|
1082
|
-
span.recordException(e);
|
|
1083
|
-
} else {
|
|
1084
|
-
span.recordException(coerceErrorString(e));
|
|
1090
|
+
span.addEvent("sending handshake");
|
|
1091
|
+
const ok = await this.sendHandshake(to, conn);
|
|
1092
|
+
if (!ok) {
|
|
1093
|
+
conn.close();
|
|
1094
|
+
throw new Error("failed to send handshake");
|
|
1085
1095
|
}
|
|
1086
|
-
|
|
1096
|
+
return conn;
|
|
1097
|
+
} catch (err) {
|
|
1098
|
+
const errStr = coerceErrorString(err);
|
|
1099
|
+
span.recordException(errStr);
|
|
1100
|
+
span.setStatus({ code: import_api3.SpanStatusCode.ERROR });
|
|
1101
|
+
throw err;
|
|
1087
1102
|
} finally {
|
|
1088
1103
|
span.end();
|
|
1089
1104
|
}
|
|
1090
|
-
|
|
1105
|
+
});
|
|
1106
|
+
this.inflightConnectionPromises.set(to, reconnectPromise);
|
|
1107
|
+
} else {
|
|
1108
|
+
log?.info(`attempting connection to ${to} (reusing previous attempt)`, {
|
|
1109
|
+
clientId: this.clientId,
|
|
1110
|
+
connectedTo: to
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
try {
|
|
1114
|
+
await reconnectPromise;
|
|
1115
|
+
} catch (error) {
|
|
1116
|
+
this.inflightConnectionPromises.delete(to);
|
|
1117
|
+
const errStr = coerceErrorString(error);
|
|
1118
|
+
if (!this.reconnectOnConnectionDrop || !canProceedWithConnection()) {
|
|
1119
|
+
log?.warn(`connection to ${to} failed (${errStr})`, {
|
|
1120
|
+
clientId: this.clientId,
|
|
1121
|
+
connectedTo: to
|
|
1122
|
+
});
|
|
1123
|
+
} else {
|
|
1124
|
+
log?.warn(`connection to ${to} failed (${errStr}), retrying`, {
|
|
1125
|
+
clientId: this.clientId,
|
|
1126
|
+
connectedTo: to
|
|
1127
|
+
});
|
|
1128
|
+
return this.connect(to);
|
|
1091
1129
|
}
|
|
1092
|
-
);
|
|
1093
|
-
if (retry) {
|
|
1094
|
-
return this.connectAttempt(to, attempt + 1);
|
|
1095
1130
|
}
|
|
1096
1131
|
}
|
|
1097
1132
|
deleteSession(session) {
|
|
@@ -1099,20 +1134,23 @@ var ClientTransport = class extends Transport {
|
|
|
1099
1134
|
super.deleteSession(session);
|
|
1100
1135
|
}
|
|
1101
1136
|
async sendHandshake(to, conn) {
|
|
1102
|
-
const tracing = { traceparent: "", tracestate: "" };
|
|
1103
|
-
import_api2.propagation.inject(import_api2.context.active(), tracing);
|
|
1104
1137
|
let metadata;
|
|
1105
1138
|
if (this.options.handshake) {
|
|
1106
1139
|
metadata = await this.options.handshake.get();
|
|
1107
1140
|
if (!import_value.Value.Check(this.options.handshake.schema, metadata)) {
|
|
1108
1141
|
log?.error(`handshake metadata did not match schema`, {
|
|
1109
1142
|
clientId: this.clientId,
|
|
1110
|
-
connectedTo: to
|
|
1143
|
+
connectedTo: to,
|
|
1144
|
+
tags: ["invariant-violation"]
|
|
1111
1145
|
});
|
|
1112
1146
|
this.protocolError(
|
|
1113
1147
|
ProtocolError.HandshakeFailed,
|
|
1114
1148
|
"handshake metadata did not match schema"
|
|
1115
1149
|
);
|
|
1150
|
+
conn.telemetry?.span.setStatus({
|
|
1151
|
+
code: import_api3.SpanStatusCode.ERROR,
|
|
1152
|
+
message: "handshake meta mismatch"
|
|
1153
|
+
});
|
|
1116
1154
|
return false;
|
|
1117
1155
|
}
|
|
1118
1156
|
}
|
|
@@ -1122,7 +1160,7 @@ var ClientTransport = class extends Transport {
|
|
|
1122
1160
|
to,
|
|
1123
1161
|
session.id,
|
|
1124
1162
|
metadata,
|
|
1125
|
-
|
|
1163
|
+
getPropagationContext(session.telemetry.ctx)
|
|
1126
1164
|
);
|
|
1127
1165
|
log?.debug(`sending handshake request to ${to}`, {
|
|
1128
1166
|
clientId: this.clientId,
|
|
@@ -1138,13 +1176,31 @@ var ClientTransport = class extends Transport {
|
|
|
1138
1176
|
};
|
|
1139
1177
|
|
|
1140
1178
|
// transport/impls/ws/connection.ts
|
|
1141
|
-
var import_agnostic_ws = __toESM(require("agnostic-ws"), 1);
|
|
1142
1179
|
var WebSocketConnection = class extends Connection {
|
|
1180
|
+
errorCb = null;
|
|
1181
|
+
closeCb = null;
|
|
1143
1182
|
ws;
|
|
1144
1183
|
constructor(ws) {
|
|
1145
1184
|
super();
|
|
1146
1185
|
this.ws = ws;
|
|
1147
1186
|
this.ws.binaryType = "arraybuffer";
|
|
1187
|
+
let didError = false;
|
|
1188
|
+
this.ws.onerror = () => {
|
|
1189
|
+
didError = true;
|
|
1190
|
+
};
|
|
1191
|
+
this.ws.onclose = ({ code, reason }) => {
|
|
1192
|
+
if (didError && this.errorCb) {
|
|
1193
|
+
this.errorCb(
|
|
1194
|
+
new Error(
|
|
1195
|
+
`websocket closed with code and reason: ${code} - ${reason}`
|
|
1196
|
+
)
|
|
1197
|
+
);
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1200
|
+
if (this.closeCb) {
|
|
1201
|
+
this.closeCb();
|
|
1202
|
+
}
|
|
1203
|
+
};
|
|
1148
1204
|
}
|
|
1149
1205
|
addDataListener(cb) {
|
|
1150
1206
|
this.ws.onmessage = (msg) => cb(msg.data);
|
|
@@ -1153,13 +1209,13 @@ var WebSocketConnection = class extends Connection {
|
|
|
1153
1209
|
this.ws.onmessage = null;
|
|
1154
1210
|
}
|
|
1155
1211
|
addCloseListener(cb) {
|
|
1156
|
-
this.
|
|
1212
|
+
this.closeCb = cb;
|
|
1157
1213
|
}
|
|
1158
1214
|
addErrorListener(cb) {
|
|
1159
|
-
this.
|
|
1215
|
+
this.errorCb = cb;
|
|
1160
1216
|
}
|
|
1161
1217
|
send(payload) {
|
|
1162
|
-
if (this.ws.readyState ===
|
|
1218
|
+
if (this.ws.readyState === this.ws.OPEN) {
|
|
1163
1219
|
this.ws.send(payload);
|
|
1164
1220
|
return true;
|
|
1165
1221
|
} else {
|
|
@@ -1176,7 +1232,7 @@ var WebSocketClientTransport = class extends ClientTransport {
|
|
|
1176
1232
|
/**
|
|
1177
1233
|
* A function that returns a Promise that resolves to a websocket URL.
|
|
1178
1234
|
*/
|
|
1179
|
-
|
|
1235
|
+
wsGetter;
|
|
1180
1236
|
/**
|
|
1181
1237
|
* Creates a new WebSocketClientTransport instance.
|
|
1182
1238
|
* @param wsGetter A function that returns a Promise that resolves to a WebSocket instance.
|
|
@@ -1184,53 +1240,39 @@ var WebSocketClientTransport = class extends ClientTransport {
|
|
|
1184
1240
|
* @param serverId The ID of the server this transport is connecting to.
|
|
1185
1241
|
* @param providedOptions An optional object containing configuration options for the transport.
|
|
1186
1242
|
*/
|
|
1187
|
-
constructor(
|
|
1243
|
+
constructor(wsGetter, clientId, providedOptions) {
|
|
1188
1244
|
super(clientId, providedOptions);
|
|
1189
|
-
this.
|
|
1245
|
+
this.wsGetter = wsGetter;
|
|
1190
1246
|
}
|
|
1191
1247
|
async createNewOutgoingConnection(to) {
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
connectedTo: to
|
|
1196
|
-
});
|
|
1197
|
-
Promise.resolve(this.urlGetter(to)).then((url) => new import_agnostic_ws2.default(url)).then((ws) => {
|
|
1198
|
-
if (ws.readyState === import_agnostic_ws2.default.OPEN) {
|
|
1199
|
-
resolve({ ws });
|
|
1200
|
-
return;
|
|
1201
|
-
}
|
|
1202
|
-
if (ws.readyState === import_agnostic_ws2.default.CLOSING || ws.readyState === import_agnostic_ws2.default.CLOSED) {
|
|
1203
|
-
resolve({ err: "ws is closing or closed" });
|
|
1204
|
-
return;
|
|
1205
|
-
}
|
|
1206
|
-
ws.onopen = () => {
|
|
1207
|
-
resolve({ ws });
|
|
1208
|
-
};
|
|
1209
|
-
ws.onclose = (evt) => {
|
|
1210
|
-
resolve({ err: evt.reason });
|
|
1211
|
-
};
|
|
1212
|
-
ws.onerror = (evt) => {
|
|
1213
|
-
const err = evt.error;
|
|
1214
|
-
resolve({
|
|
1215
|
-
err: `${err.name}: ${err.message}`
|
|
1216
|
-
});
|
|
1217
|
-
};
|
|
1218
|
-
}).catch((e) => {
|
|
1219
|
-
const reason = e instanceof Error ? e.message : "unknown reason";
|
|
1220
|
-
resolve({ err: `couldn't get a new websocket: ${reason}` });
|
|
1221
|
-
});
|
|
1248
|
+
log?.info(`establishing a new websocket to ${to}`, {
|
|
1249
|
+
clientId: this.clientId,
|
|
1250
|
+
connectedTo: to
|
|
1222
1251
|
});
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1252
|
+
const ws = await this.wsGetter(to);
|
|
1253
|
+
await new Promise((resolve, reject) => {
|
|
1254
|
+
if (ws.readyState === ws.OPEN) {
|
|
1255
|
+
resolve();
|
|
1256
|
+
return;
|
|
1257
|
+
}
|
|
1258
|
+
if (ws.readyState === ws.CLOSING || ws.readyState === ws.CLOSED) {
|
|
1259
|
+
reject(new Error("ws is closing or closed"));
|
|
1260
|
+
return;
|
|
1261
|
+
}
|
|
1262
|
+
ws.onopen = () => {
|
|
1263
|
+
resolve();
|
|
1264
|
+
};
|
|
1265
|
+
ws.onclose = (evt) => {
|
|
1266
|
+
reject(new Error(evt.reason));
|
|
1267
|
+
};
|
|
1268
|
+
});
|
|
1269
|
+
const conn = new WebSocketConnection(ws);
|
|
1270
|
+
log?.info(`raw websocket to ${to} ok, starting handshake`, {
|
|
1271
|
+
clientId: this.clientId,
|
|
1272
|
+
connectedTo: to
|
|
1273
|
+
});
|
|
1274
|
+
this.handleConnection(conn, to);
|
|
1275
|
+
return conn;
|
|
1234
1276
|
}
|
|
1235
1277
|
};
|
|
1236
1278
|
// Annotate the CommonJS export names for ESM import in node:
|