@replit/river 0.21.1 → 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.
Files changed (63) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunk-5WFL722S.js → chunk-3MFX6NXA.js} +94 -3
  3. package/dist/chunk-3MFX6NXA.js.map +1 -0
  4. package/dist/{chunk-NCXUFDVL.js → chunk-GCLEWC26.js} +328 -500
  5. package/dist/chunk-GCLEWC26.js.map +1 -0
  6. package/dist/chunk-HUBFYN37.js +60 -0
  7. package/dist/chunk-HUBFYN37.js.map +1 -0
  8. package/dist/{chunk-FDLAPYCK.js → chunk-S3YKQT4J.js} +2 -2
  9. package/dist/{chunk-JMXO5L2X.js → chunk-ZPBWKBM5.js} +344 -384
  10. package/dist/chunk-ZPBWKBM5.js.map +1 -0
  11. package/dist/{connection-76c5ed01.d.ts → connection-8b059ac4.d.ts} +6 -4
  12. package/dist/{connection-975b25c9.d.ts → connection-bbfe1147.d.ts} +1 -1
  13. package/dist/{index-dfad460e.d.ts → index-2ece5234.d.ts} +16 -7
  14. package/dist/logging/index.d.cts +2 -1
  15. package/dist/logging/index.d.ts +2 -1
  16. package/dist/router/index.cjs +373 -486
  17. package/dist/router/index.cjs.map +1 -1
  18. package/dist/router/index.d.cts +5 -4
  19. package/dist/router/index.d.ts +5 -4
  20. package/dist/router/index.js +4 -3
  21. package/dist/{services-7b716dcf.d.ts → services-acbcc441.d.ts} +1 -1
  22. package/dist/{services-9c496c6e.d.ts → services-cb01a7a8.d.ts} +1 -1
  23. package/dist/transport/impls/uds/client.cjs +186 -145
  24. package/dist/transport/impls/uds/client.cjs.map +1 -1
  25. package/dist/transport/impls/uds/client.d.cts +3 -2
  26. package/dist/transport/impls/uds/client.d.ts +3 -2
  27. package/dist/transport/impls/uds/client.js +3 -3
  28. package/dist/transport/impls/uds/server.cjs +281 -256
  29. package/dist/transport/impls/uds/server.cjs.map +1 -1
  30. package/dist/transport/impls/uds/server.d.cts +3 -2
  31. package/dist/transport/impls/uds/server.d.ts +3 -2
  32. package/dist/transport/impls/uds/server.js +3 -3
  33. package/dist/transport/impls/ws/client.cjs +240 -204
  34. package/dist/transport/impls/ws/client.cjs.map +1 -1
  35. package/dist/transport/impls/ws/client.d.cts +6 -6
  36. package/dist/transport/impls/ws/client.d.ts +6 -6
  37. package/dist/transport/impls/ws/client.js +33 -48
  38. package/dist/transport/impls/ws/client.js.map +1 -1
  39. package/dist/transport/impls/ws/server.cjs +303 -270
  40. package/dist/transport/impls/ws/server.cjs.map +1 -1
  41. package/dist/transport/impls/ws/server.d.cts +5 -4
  42. package/dist/transport/impls/ws/server.d.ts +5 -4
  43. package/dist/transport/impls/ws/server.js +3 -3
  44. package/dist/transport/impls/ws/server.js.map +1 -1
  45. package/dist/transport/index.cjs +390 -382
  46. package/dist/transport/index.cjs.map +1 -1
  47. package/dist/transport/index.d.cts +5 -5
  48. package/dist/transport/index.d.ts +5 -5
  49. package/dist/transport/index.js +2 -2
  50. package/dist/util/testHelpers.cjs +57 -7
  51. package/dist/util/testHelpers.cjs.map +1 -1
  52. package/dist/util/testHelpers.d.cts +14 -5
  53. package/dist/util/testHelpers.d.ts +14 -5
  54. package/dist/util/testHelpers.js +10 -4
  55. package/dist/util/testHelpers.js.map +1 -1
  56. package/dist/wslike-e0b32dd5.d.ts +40 -0
  57. package/package.json +4 -5
  58. package/dist/chunk-3Y7AB5EB.js +0 -42
  59. package/dist/chunk-3Y7AB5EB.js.map +0 -1
  60. package/dist/chunk-5WFL722S.js.map +0 -1
  61. package/dist/chunk-JMXO5L2X.js.map +0 -1
  62. package/dist/chunk-NCXUFDVL.js.map +0 -1
  63. /package/dist/{chunk-FDLAPYCK.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
- debugId;
202
+ id;
203
+ telemetry;
163
204
  constructor() {
164
- this.debugId = `conn-${unsafeId()}`;
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?.debugId
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,21 +341,25 @@ var Session = class {
297
341
  sendBufferedMessages(conn) {
298
342
  log?.info(`resending ${this.sendBuffer.length} buffered messages`, {
299
343
  ...this.loggingMetadata,
300
- connId: conn.debugId
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.debugId
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.debugId,
362
+ connId: conn.id,
315
363
  tags: ["invariant-violation"]
316
364
  });
317
365
  conn.close();
@@ -394,11 +442,6 @@ var Session = class {
394
442
  }
395
443
  };
396
444
 
397
- // tracing/index.ts
398
- var import_api = require("@opentelemetry/api");
399
- var tracer = import_api.trace.getTracer("river");
400
- var tracing_default = tracer;
401
-
402
445
  // util/stringify.ts
403
446
  function coerceErrorString(err) {
404
447
  if (err instanceof Error) {
@@ -531,6 +574,7 @@ var NaiveJsonCodec = {
531
574
  };
532
575
 
533
576
  // transport/transport.ts
577
+ var import_api3 = require("@opentelemetry/api");
534
578
  var defaultTransportOptions = {
535
579
  heartbeatIntervalMs: 1e3,
536
580
  heartbeatsUntilDead: 2,
@@ -609,17 +653,22 @@ var Transport = class {
609
653
  status: "connect",
610
654
  conn
611
655
  });
656
+ conn.telemetry = createConnectionTelemetryInfo(
657
+ conn,
658
+ session.telemetry.span
659
+ );
612
660
  if (isReconnect) {
613
661
  session.replaceWithNewConnection(conn);
614
662
  log?.info(`reconnected to ${connectedTo}`, session.loggingMetadata);
615
663
  }
616
664
  }
617
- createSession(to, conn) {
665
+ createSession(to, conn, propagationCtx) {
618
666
  const session = new Session(
619
667
  conn,
620
668
  this.clientId,
621
669
  to,
622
- this.options
670
+ this.options,
671
+ propagationCtx
623
672
  );
624
673
  this.sessions.set(session.to, session);
625
674
  this.eventDispatcher.dispatchEvent("sessionStatus", {
@@ -628,11 +677,11 @@ var Transport = class {
628
677
  });
629
678
  return session;
630
679
  }
631
- getOrCreateSession(to, conn, sessionId) {
680
+ getOrCreateSession(to, conn, sessionId, propagationCtx) {
632
681
  let session = this.sessions.get(to);
633
682
  let isReconnect = session !== void 0;
634
683
  if (session?.advertisedSessionId !== void 0 && sessionId !== void 0 && session.advertisedSessionId !== sessionId) {
635
- log?.warn(
684
+ log?.info(
636
685
  `session for ${to} already exists but has a different session id (expected: ${session.advertisedSessionId}, got: ${sessionId}), creating a new one`,
637
686
  session.loggingMetadata
638
687
  );
@@ -641,7 +690,7 @@ var Transport = class {
641
690
  session = void 0;
642
691
  }
643
692
  if (!session) {
644
- session = this.createSession(to, conn);
693
+ session = this.createSession(to, conn, propagationCtx);
645
694
  log?.info(
646
695
  `no session for ${to}, created a new one`,
647
696
  session.loggingMetadata
@@ -654,6 +703,7 @@ var Transport = class {
654
703
  }
655
704
  deleteSession(session) {
656
705
  session.close();
706
+ session.telemetry.span.end();
657
707
  this.sessions.delete(session.to);
658
708
  log?.info(
659
709
  `session ${session.id} disconnect from ${session.to}`,
@@ -670,12 +720,16 @@ var Transport = class {
670
720
  * @param connectedTo The peer we are connected to.
671
721
  */
672
722
  onDisconnect(conn, session) {
723
+ conn.telemetry?.span.end();
673
724
  this.eventDispatcher.dispatchEvent("connectionStatus", {
674
725
  status: "disconnect",
675
726
  conn
676
727
  });
677
728
  session.connection = void 0;
678
- session.beginGrace(() => this.deleteSession(session));
729
+ session.beginGrace(() => {
730
+ session.telemetry.span.addEvent("session grace period expired");
731
+ this.deleteSession(session);
732
+ });
679
733
  }
680
734
  /**
681
735
  * Parses a message from a Uint8Array into a {@link OpaqueTransportMessage}.
@@ -735,6 +789,10 @@ var Transport = class {
735
789
  tags: ["invariant-violation"]
736
790
  });
737
791
  this.protocolError(ProtocolError.MessageOrderingViolated, errMsg);
792
+ session.telemetry.span.setStatus({
793
+ code: import_api3.SpanStatusCode.ERROR,
794
+ message: "message order violated"
795
+ });
738
796
  session.close();
739
797
  }
740
798
  return;
@@ -862,7 +920,7 @@ var ClientTransport = class extends Transport {
862
920
  if (!session) {
863
921
  log?.warn(
864
922
  `connection to ${to} timed out waiting for handshake, closing`,
865
- { clientId: this.clientId, connectedTo: to, connId: conn.debugId }
923
+ { clientId: this.clientId, connectedTo: to, connId: conn.id }
866
924
  );
867
925
  conn.close();
868
926
  }
@@ -880,6 +938,10 @@ var ClientTransport = class extends Transport {
880
938
  conn.addDataListener((data2) => {
881
939
  const parsed = this.parseMsg(data2);
882
940
  if (!parsed) {
941
+ conn.telemetry?.span.setStatus({
942
+ code: import_api3.SpanStatusCode.ERROR,
943
+ message: "message parse failure"
944
+ });
883
945
  conn.close();
884
946
  return;
885
947
  }
@@ -902,6 +964,10 @@ var ClientTransport = class extends Transport {
902
964
  }
903
965
  });
904
966
  conn.addErrorListener((err) => {
967
+ conn.telemetry?.span.setStatus({
968
+ code: import_api3.SpanStatusCode.ERROR,
969
+ message: "connection error"
970
+ });
905
971
  log?.warn(`error in connection to ${to}: ${coerceErrorString(err)}`, {
906
972
  ...session?.loggingMetadata,
907
973
  clientId: this.clientId,
@@ -912,6 +978,10 @@ var ClientTransport = class extends Transport {
912
978
  receiveHandshakeResponseMessage(data, conn) {
913
979
  const parsed = this.parseMsg(data);
914
980
  if (!parsed) {
981
+ conn.telemetry?.span.setStatus({
982
+ code: import_api3.SpanStatusCode.ERROR,
983
+ message: "non-transport message"
984
+ });
915
985
  this.protocolError(
916
986
  ProtocolError.HandshakeFailed,
917
987
  "received non-transport message"
@@ -919,6 +989,10 @@ var ClientTransport = class extends Transport {
919
989
  return false;
920
990
  }
921
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
+ });
922
996
  log?.warn(`received invalid handshake resp`, {
923
997
  clientId: this.clientId,
924
998
  connectedTo: parsed.from,
@@ -931,7 +1005,11 @@ var ClientTransport = class extends Transport {
931
1005
  return false;
932
1006
  }
933
1007
  if (!parsed.payload.status.ok) {
934
- log?.warn(`received invalid handshake resp`, {
1008
+ conn.telemetry?.span.setStatus({
1009
+ code: import_api3.SpanStatusCode.ERROR,
1010
+ message: "handshake rejected"
1011
+ });
1012
+ log?.warn(`received handshake rejection`, {
935
1013
  clientId: this.clientId,
936
1014
  connectedTo: parsed.from,
937
1015
  fullTransportMessage: parsed
@@ -961,142 +1039,94 @@ var ClientTransport = class extends Transport {
961
1039
  * @param to The client ID of the node to connect to.
962
1040
  */
963
1041
  async connect(to) {
964
- return tracing_default.startActiveSpan(
965
- "connect",
966
- {
967
- attributes: {
968
- component: "river",
969
- "span.kind": "client"
970
- },
971
- kind: import_api2.SpanKind.CLIENT
972
- },
973
- async (span) => {
974
- try {
975
- await this.connectAttempt(to);
976
- } catch (e) {
977
- if (e instanceof Error) {
978
- span.recordException(e);
979
- } else {
980
- span.recordException(coerceErrorString(e));
981
- }
982
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
983
- } finally {
984
- span.end();
985
- }
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;
986
1058
  }
987
- );
988
- }
989
- async connectAttempt(to, attempt = 0) {
990
- const retry = await tracing_default.startActiveSpan(
991
- "connect",
992
- {
993
- attributes: {
994
- component: "river",
995
- "river.attempt": attempt,
996
- "span.kind": "client"
997
- },
998
- kind: import_api2.SpanKind.CLIENT
999
- },
1000
- 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) => {
1001
1070
  try {
1002
- const canProceedWithConnection = () => this.state === "open";
1071
+ span.addEvent("backoff", { backoffMs });
1072
+ await sleep;
1003
1073
  if (!canProceedWithConnection()) {
1004
- log?.info(
1005
- `transport state is no longer open, cancelling attempt to connect to ${to}`,
1006
- { clientId: this.clientId, connectedTo: to }
1007
- );
1008
- return false;
1074
+ throw new Error("transport state is no longer open");
1009
1075
  }
1010
- let reconnectPromise = this.inflightConnectionPromises.get(to);
1011
- if (!reconnectPromise) {
1012
- const budgetConsumed = this.retryBudget.getBudgetConsumed(to);
1013
- if (!this.retryBudget.hasBudget(to)) {
1014
- const errMsg = `tried to connect to ${to} but retry budget exceeded (more than ${budgetConsumed} attempts in the last ${this.retryBudget.totalBudgetRestoreTime}ms)`;
1015
- log?.warn(errMsg, { clientId: this.clientId, connectedTo: to });
1016
- this.protocolError(ProtocolError.RetriesExceeded, errMsg);
1017
- return false;
1018
- }
1019
- let sleep = Promise.resolve();
1020
- const backoffMs = this.retryBudget.getBackoffMs(to);
1021
- if (backoffMs > 0) {
1022
- sleep = new Promise((resolve) => setTimeout(resolve, backoffMs));
1023
- }
1024
- log?.info(
1025
- `attempting connection to ${to} (${backoffMs}ms backoff)`,
1026
- {
1027
- clientId: this.clientId,
1028
- connectedTo: to
1029
- }
1030
- );
1031
- this.retryBudget.consumeBudget(to);
1032
- reconnectPromise = sleep.then(() => {
1033
- if (!canProceedWithConnection()) {
1034
- throw new Error("transport state is no longer open");
1035
- }
1036
- }).then(() => this.createNewOutgoingConnection(to)).then((conn) => {
1037
- if (!canProceedWithConnection()) {
1038
- log?.info(
1039
- `transport state is no longer open, closing pre-handshake connection to ${to}`,
1040
- {
1041
- clientId: this.clientId,
1042
- connectedTo: to,
1043
- connId: conn.debugId
1044
- }
1045
- );
1046
- conn.close();
1047
- throw new Error("transport state is no longer open");
1048
- }
1049
- return this.sendHandshake(to, conn).then((ok) => {
1050
- if (!ok) {
1051
- conn.close();
1052
- throw new Error("failed to send handshake");
1053
- }
1054
- return conn;
1055
- });
1056
- });
1057
- this.inflightConnectionPromises.set(to, reconnectPromise);
1058
- } else {
1076
+ span.addEvent("connecting");
1077
+ const conn = await this.createNewOutgoingConnection(to);
1078
+ if (!canProceedWithConnection()) {
1059
1079
  log?.info(
1060
- `attempting connection to ${to} (reusing previous attempt)`,
1080
+ `transport state is no longer open, closing pre-handshake connection to ${to}`,
1061
1081
  {
1062
1082
  clientId: this.clientId,
1063
- connectedTo: to
1083
+ connectedTo: to,
1084
+ connId: conn.id
1064
1085
  }
1065
1086
  );
1087
+ conn.close();
1088
+ throw new Error("transport state is no longer open");
1066
1089
  }
1067
- try {
1068
- await reconnectPromise;
1069
- } catch (error) {
1070
- this.inflightConnectionPromises.delete(to);
1071
- const errStr = coerceErrorString(error);
1072
- if (!this.reconnectOnConnectionDrop || !canProceedWithConnection()) {
1073
- log?.warn(`connection to ${to} failed (${errStr})`, {
1074
- clientId: this.clientId,
1075
- connectedTo: to
1076
- });
1077
- } else {
1078
- log?.warn(`connection to ${to} failed (${errStr}), retrying`, {
1079
- clientId: this.clientId,
1080
- connectedTo: to
1081
- });
1082
- return true;
1083
- }
1084
- }
1085
- } catch (e) {
1086
- if (e instanceof Error) {
1087
- span.recordException(e);
1088
- } else {
1089
- 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");
1090
1095
  }
1091
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
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;
1092
1102
  } finally {
1093
1103
  span.end();
1094
1104
  }
1095
- return false;
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);
1096
1129
  }
1097
- );
1098
- if (retry) {
1099
- return this.connectAttempt(to, attempt + 1);
1100
1130
  }
1101
1131
  }
1102
1132
  deleteSession(session) {
@@ -1104,8 +1134,6 @@ var ClientTransport = class extends Transport {
1104
1134
  super.deleteSession(session);
1105
1135
  }
1106
1136
  async sendHandshake(to, conn) {
1107
- const tracing = { traceparent: "", tracestate: "" };
1108
- import_api2.propagation.inject(import_api2.context.active(), tracing);
1109
1137
  let metadata;
1110
1138
  if (this.options.handshake) {
1111
1139
  metadata = await this.options.handshake.get();
@@ -1119,6 +1147,10 @@ var ClientTransport = class extends Transport {
1119
1147
  ProtocolError.HandshakeFailed,
1120
1148
  "handshake metadata did not match schema"
1121
1149
  );
1150
+ conn.telemetry?.span.setStatus({
1151
+ code: import_api3.SpanStatusCode.ERROR,
1152
+ message: "handshake meta mismatch"
1153
+ });
1122
1154
  return false;
1123
1155
  }
1124
1156
  }
@@ -1128,7 +1160,7 @@ var ClientTransport = class extends Transport {
1128
1160
  to,
1129
1161
  session.id,
1130
1162
  metadata,
1131
- tracing
1163
+ getPropagationContext(session.telemetry.ctx)
1132
1164
  );
1133
1165
  log?.debug(`sending handshake request to ${to}`, {
1134
1166
  clientId: this.clientId,
@@ -1144,13 +1176,31 @@ var ClientTransport = class extends Transport {
1144
1176
  };
1145
1177
 
1146
1178
  // transport/impls/ws/connection.ts
1147
- var import_agnostic_ws = __toESM(require("agnostic-ws"), 1);
1148
1179
  var WebSocketConnection = class extends Connection {
1180
+ errorCb = null;
1181
+ closeCb = null;
1149
1182
  ws;
1150
1183
  constructor(ws) {
1151
1184
  super();
1152
1185
  this.ws = ws;
1153
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
+ };
1154
1204
  }
1155
1205
  addDataListener(cb) {
1156
1206
  this.ws.onmessage = (msg) => cb(msg.data);
@@ -1159,13 +1209,13 @@ var WebSocketConnection = class extends Connection {
1159
1209
  this.ws.onmessage = null;
1160
1210
  }
1161
1211
  addCloseListener(cb) {
1162
- this.ws.onclose = cb;
1212
+ this.closeCb = cb;
1163
1213
  }
1164
1214
  addErrorListener(cb) {
1165
- this.ws.onerror = (err) => cb(err.error);
1215
+ this.errorCb = cb;
1166
1216
  }
1167
1217
  send(payload) {
1168
- if (this.ws.readyState === import_agnostic_ws.default.OPEN) {
1218
+ if (this.ws.readyState === this.ws.OPEN) {
1169
1219
  this.ws.send(payload);
1170
1220
  return true;
1171
1221
  } else {
@@ -1182,7 +1232,7 @@ var WebSocketClientTransport = class extends ClientTransport {
1182
1232
  /**
1183
1233
  * A function that returns a Promise that resolves to a websocket URL.
1184
1234
  */
1185
- urlGetter;
1235
+ wsGetter;
1186
1236
  /**
1187
1237
  * Creates a new WebSocketClientTransport instance.
1188
1238
  * @param wsGetter A function that returns a Promise that resolves to a WebSocket instance.
@@ -1190,53 +1240,39 @@ var WebSocketClientTransport = class extends ClientTransport {
1190
1240
  * @param serverId The ID of the server this transport is connecting to.
1191
1241
  * @param providedOptions An optional object containing configuration options for the transport.
1192
1242
  */
1193
- constructor(urlGetter, clientId, providedOptions) {
1243
+ constructor(wsGetter, clientId, providedOptions) {
1194
1244
  super(clientId, providedOptions);
1195
- this.urlGetter = urlGetter;
1245
+ this.wsGetter = wsGetter;
1196
1246
  }
1197
1247
  async createNewOutgoingConnection(to) {
1198
- const wsRes = await new Promise((resolve) => {
1199
- log?.info(`establishing a new websocket to ${to}`, {
1200
- clientId: this.clientId,
1201
- connectedTo: to
1202
- });
1203
- Promise.resolve(this.urlGetter(to)).then((url) => new import_agnostic_ws2.default(url)).then((ws) => {
1204
- if (ws.readyState === import_agnostic_ws2.default.OPEN) {
1205
- resolve({ ws });
1206
- return;
1207
- }
1208
- if (ws.readyState === import_agnostic_ws2.default.CLOSING || ws.readyState === import_agnostic_ws2.default.CLOSED) {
1209
- resolve({ err: "ws is closing or closed" });
1210
- return;
1211
- }
1212
- ws.onopen = () => {
1213
- resolve({ ws });
1214
- };
1215
- ws.onclose = (evt) => {
1216
- resolve({ err: evt.reason });
1217
- };
1218
- ws.onerror = (evt) => {
1219
- const err = evt.error;
1220
- resolve({
1221
- err: `${err.name}: ${err.message}`
1222
- });
1223
- };
1224
- }).catch((e) => {
1225
- const reason = e instanceof Error ? e.message : "unknown reason";
1226
- resolve({ err: `couldn't get a new websocket: ${reason}` });
1227
- });
1248
+ log?.info(`establishing a new websocket to ${to}`, {
1249
+ clientId: this.clientId,
1250
+ connectedTo: to
1228
1251
  });
1229
- if ("ws" in wsRes) {
1230
- const conn = new WebSocketConnection(wsRes.ws);
1231
- log?.info(`raw websocket to ${to} ok, starting handshake`, {
1232
- clientId: this.clientId,
1233
- connectedTo: to
1234
- });
1235
- this.handleConnection(conn, to);
1236
- return conn;
1237
- } else {
1238
- throw new Error(wsRes.err);
1239
- }
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;
1240
1276
  }
1241
1277
  };
1242
1278
  // Annotate the CommonJS export names for ESM import in node: