@replit/river 0.23.12 → 0.23.14

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 (75) hide show
  1. package/dist/{chunk-3AW3IXVD.js → chunk-4PVU7J25.js} +1 -21
  2. package/dist/chunk-4PVU7J25.js.map +1 -0
  3. package/dist/{chunk-HDBVL7EF.js → chunk-BEALFLCB.js} +2 -2
  4. package/dist/chunk-D2DHRRBN.js +476 -0
  5. package/dist/chunk-D2DHRRBN.js.map +1 -0
  6. package/dist/{chunk-7RUKEUKE.js → chunk-GCCRVSMR.js} +33 -4
  7. package/dist/chunk-GCCRVSMR.js.map +1 -0
  8. package/dist/{chunk-XZ6IOBM5.js → chunk-GN4YEXT7.js} +2 -2
  9. package/dist/chunk-GN4YEXT7.js.map +1 -0
  10. package/dist/chunk-O2AVDJCQ.js +335 -0
  11. package/dist/chunk-O2AVDJCQ.js.map +1 -0
  12. package/dist/chunk-OTVTKAN6.js +451 -0
  13. package/dist/chunk-OTVTKAN6.js.map +1 -0
  14. package/dist/chunk-WUL63FR6.js +335 -0
  15. package/dist/chunk-WUL63FR6.js.map +1 -0
  16. package/dist/{chunk-H6KTH6W6.js → chunk-YCLZWES2.js} +2 -2
  17. package/dist/client-e13979ac.d.ts +52 -0
  18. package/dist/codec/index.js +20 -2
  19. package/dist/codec/index.js.map +1 -1
  20. package/dist/{connection-8debd45f.d.ts → connection-5d0978ce.d.ts} +1 -1
  21. package/dist/{connection-581558f8.d.ts → connection-e57e98ea.d.ts} +1 -1
  22. package/dist/{transport-47af1c81.d.ts → handshake-5665ffd3.d.ts} +101 -153
  23. package/dist/{index-60f03cb7.d.ts → index-ea74cdbb.d.ts} +1 -1
  24. package/dist/logging/index.d.cts +1 -1
  25. package/dist/logging/index.d.ts +1 -1
  26. package/dist/router/index.cjs +16 -1
  27. package/dist/router/index.cjs.map +1 -1
  28. package/dist/router/index.d.cts +8 -6
  29. package/dist/router/index.d.ts +8 -6
  30. package/dist/router/index.js +2 -2
  31. package/dist/server-1cfc88d1.d.ts +24 -0
  32. package/dist/{services-ca72c9f8.d.ts → services-86c4d10d.d.ts} +3 -2
  33. package/dist/transport/impls/uds/client.cjs +303 -180
  34. package/dist/transport/impls/uds/client.cjs.map +1 -1
  35. package/dist/transport/impls/uds/client.d.cts +6 -5
  36. package/dist/transport/impls/uds/client.d.ts +6 -5
  37. package/dist/transport/impls/uds/client.js +6 -4
  38. package/dist/transport/impls/uds/client.js.map +1 -1
  39. package/dist/transport/impls/uds/server.cjs +396 -234
  40. package/dist/transport/impls/uds/server.cjs.map +1 -1
  41. package/dist/transport/impls/uds/server.d.cts +6 -5
  42. package/dist/transport/impls/uds/server.d.ts +6 -5
  43. package/dist/transport/impls/uds/server.js +8 -6
  44. package/dist/transport/impls/uds/server.js.map +1 -1
  45. package/dist/transport/impls/ws/client.cjs +305 -182
  46. package/dist/transport/impls/ws/client.cjs.map +1 -1
  47. package/dist/transport/impls/ws/client.d.cts +6 -5
  48. package/dist/transport/impls/ws/client.d.ts +6 -5
  49. package/dist/transport/impls/ws/client.js +6 -4
  50. package/dist/transport/impls/ws/client.js.map +1 -1
  51. package/dist/transport/impls/ws/server.cjs +350 -188
  52. package/dist/transport/impls/ws/server.cjs.map +1 -1
  53. package/dist/transport/impls/ws/server.d.cts +4 -3
  54. package/dist/transport/impls/ws/server.d.ts +4 -3
  55. package/dist/transport/impls/ws/server.js +8 -6
  56. package/dist/transport/impls/ws/server.js.map +1 -1
  57. package/dist/transport/index.cjs +338 -142
  58. package/dist/transport/index.cjs.map +1 -1
  59. package/dist/transport/index.d.cts +4 -2
  60. package/dist/transport/index.d.ts +4 -2
  61. package/dist/transport/index.js +14 -8
  62. package/dist/util/testHelpers.cjs +10 -6
  63. package/dist/util/testHelpers.cjs.map +1 -1
  64. package/dist/util/testHelpers.d.cts +5 -4
  65. package/dist/util/testHelpers.d.ts +5 -4
  66. package/dist/util/testHelpers.js +4 -5
  67. package/dist/util/testHelpers.js.map +1 -1
  68. package/package.json +13 -14
  69. package/dist/chunk-3AW3IXVD.js.map +0 -1
  70. package/dist/chunk-7RUKEUKE.js.map +0 -1
  71. package/dist/chunk-VRU4IKRT.js +0 -1392
  72. package/dist/chunk-VRU4IKRT.js.map +0 -1
  73. package/dist/chunk-XZ6IOBM5.js.map +0 -1
  74. /package/dist/{chunk-HDBVL7EF.js.map → chunk-BEALFLCB.js.map} +0 -0
  75. /package/dist/{chunk-H6KTH6W6.js.map → chunk-YCLZWES2.js.map} +0 -0
@@ -66,6 +66,21 @@ var ControlMessageHandshakeRequestSchema = import_typebox.Type.Object({
66
66
  type: import_typebox.Type.Literal("HANDSHAKE_REQ"),
67
67
  protocolVersion: import_typebox.Type.String(),
68
68
  sessionId: import_typebox.Type.String(),
69
+ /**
70
+ * Specifies what the server's expected session state (from the pov of the client). This can be
71
+ * used by the server to know whether this is a new or a reestablished connection, and whether it
72
+ * is compatible with what it already has.
73
+ */
74
+ expectedSessionState: import_typebox.Type.Optional(
75
+ import_typebox.Type.Object({
76
+ /**
77
+ * reconnect is set to true if the client explicitly wants to reestablish an existing
78
+ * connection.
79
+ */
80
+ reconnect: import_typebox.Type.Boolean(),
81
+ nextExpectedSeq: import_typebox.Type.Integer()
82
+ })
83
+ ),
69
84
  metadata: import_typebox.Type.Optional(import_typebox.Type.Unknown())
70
85
  });
71
86
  var ControlMessageHandshakeResponseSchema = import_typebox.Type.Object({
@@ -90,7 +105,14 @@ var ControlMessagePayloadSchema = import_typebox.Type.Union([
90
105
  var OpaqueTransportMessageSchema = TransportMessageSchema(
91
106
  import_typebox.Type.Unknown()
92
107
  );
93
- function handshakeRequestMessage(from, to, sessionId, metadata, tracing) {
108
+ function handshakeRequestMessage({
109
+ from,
110
+ to,
111
+ sessionId,
112
+ expectedSessionState,
113
+ metadata,
114
+ tracing
115
+ }) {
94
116
  return {
95
117
  id: (0, import_nanoid.nanoid)(),
96
118
  from,
@@ -104,11 +126,17 @@ function handshakeRequestMessage(from, to, sessionId, metadata, tracing) {
104
126
  type: "HANDSHAKE_REQ",
105
127
  protocolVersion: PROTOCOL_VERSION,
106
128
  sessionId,
129
+ expectedSessionState,
107
130
  metadata
108
131
  }
109
132
  };
110
133
  }
111
- function handshakeResponseMessage(from, to, status) {
134
+ var SESSION_STATE_MISMATCH = "session state mismatch";
135
+ function handshakeResponseMessage({
136
+ from,
137
+ to,
138
+ status
139
+ }) {
112
140
  return {
113
141
  id: (0, import_nanoid.nanoid)(),
114
142
  from,
@@ -224,7 +252,7 @@ var import_nanoid2 = require("nanoid");
224
252
  var import_api = require("@opentelemetry/api");
225
253
 
226
254
  // package.json
227
- var version = "0.23.12";
255
+ var version = "0.23.14";
228
256
 
229
257
  // tracing/index.ts
230
258
  function getPropagationContext(ctx) {
@@ -538,9 +566,17 @@ var Session = class {
538
566
  get connected() {
539
567
  return this.connection !== void 0;
540
568
  }
569
+ get nextExpectedAck() {
570
+ return this.seq;
571
+ }
541
572
  get nextExpectedSeq() {
542
573
  return this.ack;
543
574
  }
575
+ // This is only used in tests to make the session misbehave.
576
+ /* @internal */
577
+ advanceAckForTesting(by) {
578
+ this.ack += by;
579
+ }
544
580
  constructMsg(partialMsg) {
545
581
  const msg = {
546
582
  ...partialMsg,
@@ -559,84 +595,8 @@ var Session = class {
559
595
  }
560
596
  };
561
597
 
562
- // util/stringify.ts
563
- function coerceErrorString(err) {
564
- if (err instanceof Error) {
565
- return err.message || "unknown reason";
566
- }
567
- return `[coerced to error] ${String(err)}`;
568
- }
569
-
570
- // transport/rateLimit.ts
571
- var LeakyBucketRateLimit = class {
572
- budgetConsumed;
573
- intervalHandles;
574
- options;
575
- constructor(options) {
576
- this.options = options;
577
- this.budgetConsumed = /* @__PURE__ */ new Map();
578
- this.intervalHandles = /* @__PURE__ */ new Map();
579
- }
580
- getBackoffMs(user) {
581
- if (!this.budgetConsumed.has(user))
582
- return 0;
583
- const exponent = Math.max(0, this.getBudgetConsumed(user) - 1);
584
- const jitter = Math.floor(Math.random() * this.options.maxJitterMs);
585
- const backoffMs = Math.min(
586
- this.options.baseIntervalMs * 2 ** exponent,
587
- this.options.maxBackoffMs
588
- );
589
- return backoffMs + jitter;
590
- }
591
- get totalBudgetRestoreTime() {
592
- return this.options.budgetRestoreIntervalMs * this.options.attemptBudgetCapacity;
593
- }
594
- consumeBudget(user) {
595
- this.stopLeak(user);
596
- this.budgetConsumed.set(user, this.getBudgetConsumed(user) + 1);
597
- }
598
- getBudgetConsumed(user) {
599
- return this.budgetConsumed.get(user) ?? 0;
600
- }
601
- hasBudget(user) {
602
- return this.getBudgetConsumed(user) < this.options.attemptBudgetCapacity;
603
- }
604
- startRestoringBudget(user) {
605
- if (this.intervalHandles.has(user)) {
606
- return;
607
- }
608
- const restoreBudgetForUser = () => {
609
- const currentBudget = this.budgetConsumed.get(user);
610
- if (!currentBudget) {
611
- this.stopLeak(user);
612
- return;
613
- }
614
- const newBudget = currentBudget - 1;
615
- if (newBudget === 0) {
616
- this.budgetConsumed.delete(user);
617
- return;
618
- }
619
- this.budgetConsumed.set(user, newBudget);
620
- };
621
- const intervalHandle = setInterval(
622
- restoreBudgetForUser,
623
- this.options.budgetRestoreIntervalMs
624
- );
625
- this.intervalHandles.set(user, intervalHandle);
626
- }
627
- stopLeak(user) {
628
- if (!this.intervalHandles.has(user)) {
629
- return;
630
- }
631
- clearInterval(this.intervalHandles.get(user));
632
- this.intervalHandles.delete(user);
633
- }
634
- close() {
635
- for (const user of this.intervalHandles.keys()) {
636
- this.stopLeak(user);
637
- }
638
- }
639
- };
598
+ // transport/transport.ts
599
+ var import_api3 = require("@opentelemetry/api");
640
600
 
641
601
  // codec/json.ts
642
602
  var encoder = new TextEncoder();
@@ -690,8 +650,7 @@ var NaiveJsonCodec = {
690
650
  }
691
651
  };
692
652
 
693
- // transport/transport.ts
694
- var import_api3 = require("@opentelemetry/api");
653
+ // transport/options.ts
695
654
  var defaultTransportOptions = {
696
655
  heartbeatIntervalMs: 1e3,
697
656
  heartbeatsUntilDead: 2,
@@ -712,6 +671,8 @@ var defaultClientTransportOptions = {
712
671
  var defaultServerTransportOptions = {
713
672
  ...defaultTransportOptions
714
673
  };
674
+
675
+ // transport/transport.ts
715
676
  var Transport = class {
716
677
  /**
717
678
  * The status of the transport.
@@ -802,6 +763,49 @@ var Transport = class {
802
763
  });
803
764
  return session;
804
765
  }
766
+ createNewSession({
767
+ to,
768
+ conn,
769
+ sessionId,
770
+ propagationCtx
771
+ }) {
772
+ let session = this.sessions.get(to);
773
+ if (session !== void 0) {
774
+ this.log?.info(
775
+ `session for ${to} already exists, replacing it with a new session as requested`,
776
+ session.loggingMetadata
777
+ );
778
+ this.deleteSession({
779
+ session,
780
+ closeHandshakingConnection: false
781
+ });
782
+ session = void 0;
783
+ }
784
+ session = this.createSession(to, conn, propagationCtx);
785
+ session.advertisedSessionId = sessionId;
786
+ this.log?.info(`created new session for ${to}`, session.loggingMetadata);
787
+ return session;
788
+ }
789
+ getExistingSession({
790
+ to,
791
+ sessionId,
792
+ nextExpectedSeq
793
+ }) {
794
+ const session = this.sessions.get(to);
795
+ if (
796
+ // reject this request if there was no previous session to replace
797
+ session === void 0 || // or if both parties do not agree about the next expected sequence number
798
+ session.nextExpectedAck < nextExpectedSeq || // or if both parties do not agree on the advertised session id
799
+ session.advertisedSessionId !== sessionId
800
+ ) {
801
+ return false;
802
+ }
803
+ this.log?.info(
804
+ `reused existing session for ${to}`,
805
+ session.loggingMetadata
806
+ );
807
+ return session;
808
+ }
805
809
  getOrCreateSession({
806
810
  to,
807
811
  conn,
@@ -866,6 +870,16 @@ var Transport = class {
866
870
  * @param connectedTo The peer we are connected to.
867
871
  */
868
872
  onDisconnect(conn, session) {
873
+ if (session.connection !== void 0 && session.connection.id !== conn.id) {
874
+ session.telemetry.span.addEvent("onDisconnect race");
875
+ this.log?.warn("onDisconnect race", {
876
+ clientId: this.clientId,
877
+ ...session.loggingMetadata,
878
+ ...conn.loggingMetadata,
879
+ tags: ["invariant-violation"]
880
+ });
881
+ return;
882
+ }
869
883
  conn.telemetry?.span.end();
870
884
  this.eventDispatcher.dispatchEvent("connectionStatus", {
871
885
  status: "disconnect",
@@ -873,6 +887,16 @@ var Transport = class {
873
887
  });
874
888
  session.connection = void 0;
875
889
  session.beginGrace(() => {
890
+ if (session.connection !== void 0) {
891
+ session.telemetry.span.addEvent("session grace period race");
892
+ this.log?.warn("session grace period race", {
893
+ clientId: this.clientId,
894
+ ...session.loggingMetadata,
895
+ ...conn.loggingMetadata,
896
+ tags: ["invariant-violation"]
897
+ });
898
+ return;
899
+ }
876
900
  session.telemetry.span.addEvent("session grace period expired");
877
901
  this.deleteSession({
878
902
  session,
@@ -1040,6 +1064,91 @@ var Transport = class {
1040
1064
  return this.status;
1041
1065
  }
1042
1066
  };
1067
+
1068
+ // transport/client.ts
1069
+ var import_api4 = require("@opentelemetry/api");
1070
+
1071
+ // transport/rateLimit.ts
1072
+ var LeakyBucketRateLimit = class {
1073
+ budgetConsumed;
1074
+ intervalHandles;
1075
+ options;
1076
+ constructor(options) {
1077
+ this.options = options;
1078
+ this.budgetConsumed = /* @__PURE__ */ new Map();
1079
+ this.intervalHandles = /* @__PURE__ */ new Map();
1080
+ }
1081
+ getBackoffMs(user) {
1082
+ if (!this.budgetConsumed.has(user))
1083
+ return 0;
1084
+ const exponent = Math.max(0, this.getBudgetConsumed(user) - 1);
1085
+ const jitter = Math.floor(Math.random() * this.options.maxJitterMs);
1086
+ const backoffMs = Math.min(
1087
+ this.options.baseIntervalMs * 2 ** exponent,
1088
+ this.options.maxBackoffMs
1089
+ );
1090
+ return backoffMs + jitter;
1091
+ }
1092
+ get totalBudgetRestoreTime() {
1093
+ return this.options.budgetRestoreIntervalMs * this.options.attemptBudgetCapacity;
1094
+ }
1095
+ consumeBudget(user) {
1096
+ this.stopLeak(user);
1097
+ this.budgetConsumed.set(user, this.getBudgetConsumed(user) + 1);
1098
+ }
1099
+ getBudgetConsumed(user) {
1100
+ return this.budgetConsumed.get(user) ?? 0;
1101
+ }
1102
+ hasBudget(user) {
1103
+ return this.getBudgetConsumed(user) < this.options.attemptBudgetCapacity;
1104
+ }
1105
+ startRestoringBudget(user) {
1106
+ if (this.intervalHandles.has(user)) {
1107
+ return;
1108
+ }
1109
+ const restoreBudgetForUser = () => {
1110
+ const currentBudget = this.budgetConsumed.get(user);
1111
+ if (!currentBudget) {
1112
+ this.stopLeak(user);
1113
+ return;
1114
+ }
1115
+ const newBudget = currentBudget - 1;
1116
+ if (newBudget === 0) {
1117
+ this.budgetConsumed.delete(user);
1118
+ return;
1119
+ }
1120
+ this.budgetConsumed.set(user, newBudget);
1121
+ };
1122
+ const intervalHandle = setInterval(
1123
+ restoreBudgetForUser,
1124
+ this.options.budgetRestoreIntervalMs
1125
+ );
1126
+ this.intervalHandles.set(user, intervalHandle);
1127
+ }
1128
+ stopLeak(user) {
1129
+ if (!this.intervalHandles.has(user)) {
1130
+ return;
1131
+ }
1132
+ clearInterval(this.intervalHandles.get(user));
1133
+ this.intervalHandles.delete(user);
1134
+ }
1135
+ close() {
1136
+ for (const user of this.intervalHandles.keys()) {
1137
+ this.stopLeak(user);
1138
+ }
1139
+ }
1140
+ };
1141
+
1142
+ // util/stringify.ts
1143
+ function coerceErrorString(err) {
1144
+ if (err instanceof Error) {
1145
+ return err.message || "unknown reason";
1146
+ }
1147
+ return `[coerced to error] ${String(err)}`;
1148
+ }
1149
+
1150
+ // transport/client.ts
1151
+ var import_value2 = require("@sinclair/typebox/value");
1043
1152
  var ClientTransport = class extends Transport {
1044
1153
  /**
1045
1154
  * The options for this transport.
@@ -1100,7 +1209,7 @@ var ClientTransport = class extends Transport {
1100
1209
  const parsed = this.parseMsg(data2, conn);
1101
1210
  if (!parsed) {
1102
1211
  conn.telemetry?.span.setStatus({
1103
- code: import_api3.SpanStatusCode.ERROR,
1212
+ code: import_api4.SpanStatusCode.ERROR,
1104
1213
  message: "message parse failure"
1105
1214
  });
1106
1215
  conn.close();
@@ -1131,7 +1240,7 @@ var ClientTransport = class extends Transport {
1131
1240
  });
1132
1241
  conn.addErrorListener((err) => {
1133
1242
  conn.telemetry?.span.setStatus({
1134
- code: import_api3.SpanStatusCode.ERROR,
1243
+ code: import_api4.SpanStatusCode.ERROR,
1135
1244
  message: "connection error"
1136
1245
  });
1137
1246
  this.log?.warn(
@@ -1149,7 +1258,7 @@ var ClientTransport = class extends Transport {
1149
1258
  const parsed = this.parseMsg(data, conn);
1150
1259
  if (!parsed) {
1151
1260
  conn.telemetry?.span.setStatus({
1152
- code: import_api3.SpanStatusCode.ERROR,
1261
+ code: import_api4.SpanStatusCode.ERROR,
1153
1262
  message: "non-transport message"
1154
1263
  });
1155
1264
  this.protocolError(
@@ -1158,9 +1267,9 @@ var ClientTransport = class extends Transport {
1158
1267
  );
1159
1268
  return false;
1160
1269
  }
1161
- if (!import_value.Value.Check(ControlMessageHandshakeResponseSchema, parsed.payload)) {
1270
+ if (!import_value2.Value.Check(ControlMessageHandshakeResponseSchema, parsed.payload)) {
1162
1271
  conn.telemetry?.span.setStatus({
1163
- code: import_api3.SpanStatusCode.ERROR,
1272
+ code: import_api4.SpanStatusCode.ERROR,
1164
1273
  message: "invalid handshake response"
1165
1274
  });
1166
1275
  this.log?.warn(`received invalid handshake resp`, {
@@ -1169,7 +1278,7 @@ var ClientTransport = class extends Transport {
1169
1278
  connectedTo: parsed.from,
1170
1279
  transportMessage: parsed,
1171
1280
  validationErrors: [
1172
- ...import_value.Value.Errors(
1281
+ ...import_value2.Value.Errors(
1173
1282
  ControlMessageHandshakeResponseSchema,
1174
1283
  parsed.payload
1175
1284
  )
@@ -1181,31 +1290,47 @@ var ClientTransport = class extends Transport {
1181
1290
  );
1182
1291
  return false;
1183
1292
  }
1293
+ const previousSession = this.sessions.get(parsed.from);
1184
1294
  if (!parsed.payload.status.ok) {
1185
- conn.telemetry?.span.setStatus({
1186
- code: import_api3.SpanStatusCode.ERROR,
1187
- message: "handshake rejected"
1188
- });
1189
- this.log?.warn(`received handshake rejection`, {
1190
- ...conn.loggingMetadata,
1191
- clientId: this.clientId,
1192
- connectedTo: parsed.from,
1193
- transportMessage: parsed
1194
- });
1295
+ if (parsed.payload.status.reason === SESSION_STATE_MISMATCH) {
1296
+ if (previousSession) {
1297
+ this.deleteSession({
1298
+ session: previousSession,
1299
+ closeHandshakingConnection: true
1300
+ });
1301
+ }
1302
+ conn.telemetry?.span.setStatus({
1303
+ code: import_api4.SpanStatusCode.ERROR,
1304
+ message: parsed.payload.status.reason
1305
+ });
1306
+ } else {
1307
+ conn.telemetry?.span.setStatus({
1308
+ code: import_api4.SpanStatusCode.ERROR,
1309
+ message: "handshake rejected"
1310
+ });
1311
+ }
1312
+ this.log?.warn(
1313
+ `received handshake rejection: ${parsed.payload.status.reason}`,
1314
+ {
1315
+ ...conn.loggingMetadata,
1316
+ clientId: this.clientId,
1317
+ connectedTo: parsed.from,
1318
+ transportMessage: parsed
1319
+ }
1320
+ );
1195
1321
  this.protocolError(
1196
1322
  ProtocolError.HandshakeFailed,
1197
1323
  parsed.payload.status.reason
1198
1324
  );
1199
1325
  return false;
1200
1326
  }
1201
- const previousSession = this.sessions.get(parsed.from);
1202
1327
  if (previousSession?.advertisedSessionId && previousSession.advertisedSessionId !== parsed.payload.status.sessionId) {
1203
1328
  this.deleteSession({
1204
1329
  session: previousSession,
1205
1330
  closeHandshakingConnection: true
1206
1331
  });
1207
1332
  conn.telemetry?.span.setStatus({
1208
- code: import_api3.SpanStatusCode.ERROR,
1333
+ code: import_api4.SpanStatusCode.ERROR,
1209
1334
  message: "session id mismatch"
1210
1335
  });
1211
1336
  this.log?.warn(`handshake from ${parsed.from} session id mismatch`, {
@@ -1305,7 +1430,7 @@ var ClientTransport = class extends Transport {
1305
1430
  } catch (err) {
1306
1431
  const errStr = coerceErrorString(err);
1307
1432
  span.recordException(errStr);
1308
- span.setStatus({ code: import_api3.SpanStatusCode.ERROR });
1433
+ span.setStatus({ code: import_api4.SpanStatusCode.ERROR });
1309
1434
  throw err;
1310
1435
  } finally {
1311
1436
  span.end();
@@ -1356,13 +1481,13 @@ var ClientTransport = class extends Transport {
1356
1481
  let metadata = void 0;
1357
1482
  if (this.handshakeExtensions) {
1358
1483
  metadata = await this.handshakeExtensions.construct();
1359
- if (!import_value.Value.Check(this.handshakeExtensions.schema, metadata)) {
1484
+ if (!import_value2.Value.Check(this.handshakeExtensions.schema, metadata)) {
1360
1485
  this.log?.error(`constructed handshake metadata did not match schema`, {
1361
1486
  ...conn.loggingMetadata,
1362
1487
  clientId: this.clientId,
1363
1488
  connectedTo: to,
1364
1489
  validationErrors: [
1365
- ...import_value.Value.Errors(this.handshakeExtensions.schema, metadata)
1490
+ ...import_value2.Value.Errors(this.handshakeExtensions.schema, metadata)
1366
1491
  ],
1367
1492
  tags: ["invariant-violation"]
1368
1493
  });
@@ -1371,20 +1496,24 @@ var ClientTransport = class extends Transport {
1371
1496
  "handshake metadata did not match schema"
1372
1497
  );
1373
1498
  conn.telemetry?.span.setStatus({
1374
- code: import_api3.SpanStatusCode.ERROR,
1499
+ code: import_api4.SpanStatusCode.ERROR,
1375
1500
  message: "handshake meta mismatch"
1376
1501
  });
1377
1502
  return false;
1378
1503
  }
1379
1504
  }
1380
1505
  const { session } = this.getOrCreateSession({ to, handshakingConn: conn });
1381
- const requestMsg = handshakeRequestMessage(
1382
- this.clientId,
1506
+ const requestMsg = handshakeRequestMessage({
1507
+ from: this.clientId,
1383
1508
  to,
1384
- session.id,
1509
+ sessionId: session.id,
1510
+ expectedSessionState: {
1511
+ reconnect: session.advertisedSessionId !== void 0,
1512
+ nextExpectedSeq: session.nextExpectedSeq
1513
+ },
1385
1514
  metadata,
1386
- getPropagationContext(session.telemetry.ctx)
1387
- );
1515
+ tracing: getPropagationContext(session.telemetry.ctx)
1516
+ });
1388
1517
  this.log?.debug(`sending handshake request to ${to}`, {
1389
1518
  ...conn.loggingMetadata,
1390
1519
  clientId: this.clientId,
@@ -1399,6 +1528,10 @@ var ClientTransport = class extends Transport {
1399
1528
  super.close();
1400
1529
  }
1401
1530
  };
1531
+
1532
+ // transport/server.ts
1533
+ var import_api5 = require("@opentelemetry/api");
1534
+ var import_value3 = require("@sinclair/typebox/value");
1402
1535
  var ServerTransport = class extends Transport {
1403
1536
  /**
1404
1537
  * The options for this transport.
@@ -1447,7 +1580,7 @@ var ServerTransport = class extends Transport {
1447
1580
  }
1448
1581
  );
1449
1582
  conn.telemetry?.span.setStatus({
1450
- code: import_api3.SpanStatusCode.ERROR,
1583
+ code: import_api5.SpanStatusCode.ERROR,
1451
1584
  message: "handshake timeout"
1452
1585
  });
1453
1586
  conn.close();
@@ -1498,7 +1631,7 @@ var ServerTransport = class extends Transport {
1498
1631
  });
1499
1632
  conn.addErrorListener((err) => {
1500
1633
  conn.telemetry?.span.setStatus({
1501
- code: import_api3.SpanStatusCode.ERROR,
1634
+ code: import_api5.SpanStatusCode.ERROR,
1502
1635
  message: "connection error"
1503
1636
  });
1504
1637
  if (!session)
@@ -1512,22 +1645,26 @@ var ServerTransport = class extends Transport {
1512
1645
  async validateHandshakeMetadata(conn, session, rawMetadata, from) {
1513
1646
  let parsedMetadata = {};
1514
1647
  if (this.handshakeExtensions) {
1515
- if (!import_value.Value.Check(this.handshakeExtensions.schema, rawMetadata)) {
1648
+ if (!import_value3.Value.Check(this.handshakeExtensions.schema, rawMetadata)) {
1516
1649
  conn.telemetry?.span.setStatus({
1517
- code: import_api3.SpanStatusCode.ERROR,
1650
+ code: import_api5.SpanStatusCode.ERROR,
1518
1651
  message: "malformed handshake meta"
1519
1652
  });
1520
1653
  const reason = "received malformed handshake metadata";
1521
- const responseMsg = handshakeResponseMessage(this.clientId, from, {
1522
- ok: false,
1523
- reason
1654
+ const responseMsg = handshakeResponseMessage({
1655
+ from: this.clientId,
1656
+ to: from,
1657
+ status: {
1658
+ ok: false,
1659
+ reason
1660
+ }
1524
1661
  });
1525
1662
  conn.send(this.codec.toBuffer(responseMsg));
1526
1663
  this.log?.warn(`received malformed handshake metadata from ${from}`, {
1527
1664
  ...conn.loggingMetadata,
1528
1665
  clientId: this.clientId,
1529
1666
  validationErrors: [
1530
- ...import_value.Value.Errors(this.handshakeExtensions.schema, rawMetadata)
1667
+ ...import_value3.Value.Errors(this.handshakeExtensions.schema, rawMetadata)
1531
1668
  ]
1532
1669
  });
1533
1670
  this.protocolError(ProtocolError.HandshakeFailed, reason);
@@ -1541,12 +1678,16 @@ var ServerTransport = class extends Transport {
1541
1678
  if (parsedMetadata === false) {
1542
1679
  const reason = "rejected by handshake handler";
1543
1680
  conn.telemetry?.span.setStatus({
1544
- code: import_api3.SpanStatusCode.ERROR,
1681
+ code: import_api5.SpanStatusCode.ERROR,
1545
1682
  message: reason
1546
1683
  });
1547
- const responseMsg = handshakeResponseMessage(this.clientId, from, {
1548
- ok: false,
1549
- reason
1684
+ const responseMsg = handshakeResponseMessage({
1685
+ from: this.clientId,
1686
+ to: from,
1687
+ status: {
1688
+ ok: false,
1689
+ reason
1690
+ }
1550
1691
  });
1551
1692
  conn.send(this.codec.toBuffer(responseMsg));
1552
1693
  this.log?.warn(`rejected handshake from ${from}`, {
@@ -1563,7 +1704,7 @@ var ServerTransport = class extends Transport {
1563
1704
  const parsed = this.parseMsg(data, conn);
1564
1705
  if (!parsed) {
1565
1706
  conn.telemetry?.span.setStatus({
1566
- code: import_api3.SpanStatusCode.ERROR,
1707
+ code: import_api5.SpanStatusCode.ERROR,
1567
1708
  message: "non-transport message"
1568
1709
  });
1569
1710
  this.protocolError(
@@ -1572,15 +1713,19 @@ var ServerTransport = class extends Transport {
1572
1713
  );
1573
1714
  return false;
1574
1715
  }
1575
- if (!import_value.Value.Check(ControlMessageHandshakeRequestSchema, parsed.payload)) {
1716
+ if (!import_value3.Value.Check(ControlMessageHandshakeRequestSchema, parsed.payload)) {
1576
1717
  conn.telemetry?.span.setStatus({
1577
- code: import_api3.SpanStatusCode.ERROR,
1718
+ code: import_api5.SpanStatusCode.ERROR,
1578
1719
  message: "invalid handshake request"
1579
1720
  });
1580
1721
  const reason = "received invalid handshake msg";
1581
- const responseMsg2 = handshakeResponseMessage(this.clientId, parsed.from, {
1582
- ok: false,
1583
- reason
1722
+ const responseMsg2 = handshakeResponseMessage({
1723
+ from: this.clientId,
1724
+ to: parsed.from,
1725
+ status: {
1726
+ ok: false,
1727
+ reason
1728
+ }
1584
1729
  });
1585
1730
  conn.send(this.codec.toBuffer(responseMsg2));
1586
1731
  this.log?.warn(reason, {
@@ -1590,7 +1735,7 @@ var ServerTransport = class extends Transport {
1590
1735
  // before passing it to user-land
1591
1736
  transportMessage: parsed,
1592
1737
  validationErrors: [
1593
- ...import_value.Value.Errors(ControlMessageHandshakeRequestSchema, parsed.payload)
1738
+ ...import_value3.Value.Errors(ControlMessageHandshakeRequestSchema, parsed.payload)
1594
1739
  ]
1595
1740
  });
1596
1741
  this.protocolError(
@@ -1602,13 +1747,17 @@ var ServerTransport = class extends Transport {
1602
1747
  const gotVersion = parsed.payload.protocolVersion;
1603
1748
  if (gotVersion !== PROTOCOL_VERSION) {
1604
1749
  conn.telemetry?.span.setStatus({
1605
- code: import_api3.SpanStatusCode.ERROR,
1750
+ code: import_api5.SpanStatusCode.ERROR,
1606
1751
  message: "incorrect protocol version"
1607
1752
  });
1608
1753
  const reason = `incorrect version (got: ${gotVersion} wanted ${PROTOCOL_VERSION})`;
1609
- const responseMsg2 = handshakeResponseMessage(this.clientId, parsed.from, {
1610
- ok: false,
1611
- reason
1754
+ const responseMsg2 = handshakeResponseMessage({
1755
+ from: this.clientId,
1756
+ to: parsed.from,
1757
+ status: {
1758
+ ok: false,
1759
+ reason
1760
+ }
1612
1761
  });
1613
1762
  conn.send(this.codec.toBuffer(responseMsg2));
1614
1763
  this.log?.warn(
@@ -1628,20 +1777,67 @@ var ServerTransport = class extends Transport {
1628
1777
  if (parsedMetadata === false) {
1629
1778
  return false;
1630
1779
  }
1631
- const { session, isTransparentReconnect } = this.getOrCreateSession({
1632
- to: parsed.from,
1633
- conn,
1634
- sessionId: parsed.payload.sessionId,
1635
- propagationCtx: parsed.tracing
1636
- });
1780
+ let session;
1781
+ let isTransparentReconnect;
1782
+ if (!parsed.payload.expectedSessionState) {
1783
+ ({ session, isTransparentReconnect } = this.getOrCreateSession({
1784
+ to: parsed.from,
1785
+ conn,
1786
+ sessionId: parsed.payload.sessionId,
1787
+ propagationCtx: parsed.tracing
1788
+ }));
1789
+ } else if (parsed.payload.expectedSessionState.reconnect) {
1790
+ const existingSession = this.getExistingSession({
1791
+ to: parsed.from,
1792
+ sessionId: parsed.payload.sessionId,
1793
+ nextExpectedSeq: parsed.payload.expectedSessionState.nextExpectedSeq
1794
+ });
1795
+ if (existingSession === false) {
1796
+ conn.telemetry?.span.setStatus({
1797
+ code: import_api5.SpanStatusCode.ERROR,
1798
+ message: SESSION_STATE_MISMATCH
1799
+ });
1800
+ const reason = SESSION_STATE_MISMATCH;
1801
+ const responseMsg2 = handshakeResponseMessage({
1802
+ from: this.clientId,
1803
+ to: parsed.from,
1804
+ status: {
1805
+ ok: false,
1806
+ reason
1807
+ }
1808
+ });
1809
+ conn.send(this.codec.toBuffer(responseMsg2));
1810
+ this.log?.warn(
1811
+ `'received handshake msg with incompatible existing session state: ${parsed.payload.sessionId}`,
1812
+ { ...conn.loggingMetadata, clientId: this.clientId }
1813
+ );
1814
+ this.protocolError(ProtocolError.HandshakeFailed, reason);
1815
+ return false;
1816
+ }
1817
+ session = existingSession;
1818
+ isTransparentReconnect = false;
1819
+ } else {
1820
+ const createdSession = this.createNewSession({
1821
+ to: parsed.from,
1822
+ conn,
1823
+ sessionId: parsed.payload.sessionId,
1824
+ propagationCtx: parsed.tracing
1825
+ });
1826
+ session = createdSession;
1827
+ isTransparentReconnect = false;
1828
+ }
1637
1829
  this.sessionHandshakeMetadata.set(session, parsedMetadata);
1638
1830
  this.log?.debug(
1639
1831
  `handshake from ${parsed.from} ok, responding with handshake success`,
1640
1832
  conn.loggingMetadata
1641
1833
  );
1642
- const responseMsg = handshakeResponseMessage(this.clientId, parsed.from, {
1643
- ok: true,
1644
- sessionId: session.id
1834
+ const responseMsg = handshakeResponseMessage({
1835
+ from: this.clientId,
1836
+ to: parsed.from,
1837
+ status: {
1838
+ ok: true,
1839
+ sessionId: session.id
1840
+ }
1645
1841
  });
1646
1842
  conn.send(this.codec.toBuffer(responseMsg));
1647
1843
  this.onConnect(conn, session, isTransparentReconnect);