@replit/river 0.23.18 → 0.24.1
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 +17 -16
- package/dist/chunk-227EQHH5.js +653 -0
- package/dist/chunk-227EQHH5.js.map +1 -0
- package/dist/chunk-6YFPHVNO.js +277 -0
- package/dist/chunk-6YFPHVNO.js.map +1 -0
- package/dist/{chunk-7MJYOL32.js → chunk-BGJDNLTJ.js} +15 -23
- package/dist/chunk-BGJDNLTJ.js.map +1 -0
- package/dist/chunk-HXOQQXL4.js +382 -0
- package/dist/chunk-HXOQQXL4.js.map +1 -0
- package/dist/{chunk-R2HAS3GM.js → chunk-IYYQ7BII.js} +55 -41
- package/dist/chunk-IYYQ7BII.js.map +1 -0
- package/dist/{chunk-AVL32IMG.js → chunk-L664A3WA.js} +20 -16
- package/dist/chunk-L664A3WA.js.map +1 -0
- package/dist/{chunk-EV5HW4IC.js → chunk-M7E6LQO2.js} +66 -53
- package/dist/chunk-M7E6LQO2.js.map +1 -0
- package/dist/{chunk-6LCL2ZZF.js → chunk-TAH2GVTJ.js} +1 -1
- package/dist/chunk-TAH2GVTJ.js.map +1 -0
- package/dist/chunk-XOFF3UPL.js +399 -0
- package/dist/chunk-XOFF3UPL.js.map +1 -0
- package/dist/{client-5776a6bb.d.ts → client-2ba72e89.d.ts} +12 -15
- package/dist/connection-55cba970.d.ts +11 -0
- package/dist/{connection-bd35d442.d.ts → connection-c6db05d9.d.ts} +1 -5
- package/dist/{handshake-a947c234.d.ts → handshake-0b88e8fc.d.ts} +150 -184
- package/dist/logging/index.cjs.map +1 -1
- package/dist/logging/index.d.cts +1 -1
- package/dist/logging/index.d.ts +1 -1
- package/dist/logging/index.js +1 -1
- package/dist/{index-ea74cdbb.d.ts → message-e6c560fd.d.ts} +2 -2
- package/dist/router/index.cjs +105 -63
- package/dist/router/index.cjs.map +1 -1
- package/dist/router/index.d.cts +11 -10
- package/dist/router/index.d.ts +11 -10
- package/dist/router/index.js +2 -2
- package/dist/server-732e7014.d.ts +42 -0
- package/dist/{services-38b3f758.d.ts → services-adfd0bc3.d.ts} +3 -3
- package/dist/transport/impls/uds/client.cjs +1246 -1230
- package/dist/transport/impls/uds/client.cjs.map +1 -1
- package/dist/transport/impls/uds/client.d.cts +4 -4
- package/dist/transport/impls/uds/client.d.ts +4 -4
- package/dist/transport/impls/uds/client.js +7 -13
- package/dist/transport/impls/uds/client.js.map +1 -1
- package/dist/transport/impls/uds/server.cjs +1298 -1151
- package/dist/transport/impls/uds/server.cjs.map +1 -1
- package/dist/transport/impls/uds/server.d.cts +4 -4
- package/dist/transport/impls/uds/server.d.ts +4 -4
- package/dist/transport/impls/uds/server.js +6 -6
- package/dist/transport/impls/ws/client.cjs +976 -965
- package/dist/transport/impls/ws/client.cjs.map +1 -1
- package/dist/transport/impls/ws/client.d.cts +4 -4
- package/dist/transport/impls/ws/client.d.ts +4 -4
- package/dist/transport/impls/ws/client.js +6 -7
- package/dist/transport/impls/ws/client.js.map +1 -1
- package/dist/transport/impls/ws/server.cjs +1182 -1047
- package/dist/transport/impls/ws/server.cjs.map +1 -1
- package/dist/transport/impls/ws/server.d.cts +4 -4
- package/dist/transport/impls/ws/server.d.ts +4 -4
- package/dist/transport/impls/ws/server.js +6 -6
- package/dist/transport/index.cjs +1433 -1360
- 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 +9 -9
- package/dist/util/testHelpers.cjs +744 -310
- package/dist/util/testHelpers.cjs.map +1 -1
- package/dist/util/testHelpers.d.cts +9 -6
- package/dist/util/testHelpers.d.ts +9 -6
- package/dist/util/testHelpers.js +34 -10
- package/dist/util/testHelpers.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-6LCL2ZZF.js.map +0 -1
- package/dist/chunk-7MJYOL32.js.map +0 -1
- package/dist/chunk-AVL32IMG.js.map +0 -1
- package/dist/chunk-DPKOJQWF.js +0 -476
- package/dist/chunk-DPKOJQWF.js.map +0 -1
- package/dist/chunk-EV5HW4IC.js.map +0 -1
- package/dist/chunk-J6N6H2WU.js +0 -476
- package/dist/chunk-J6N6H2WU.js.map +0 -1
- package/dist/chunk-MW5JXLHY.js +0 -348
- package/dist/chunk-MW5JXLHY.js.map +0 -1
- package/dist/chunk-R2HAS3GM.js.map +0 -1
- package/dist/chunk-RJOWZIWB.js +0 -335
- package/dist/chunk-RJOWZIWB.js.map +0 -1
- package/dist/connection-df85db7e.d.ts +0 -17
- package/dist/server-53cd5b7e.d.ts +0 -24
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ProtocolError,
|
|
3
|
+
Transport
|
|
4
|
+
} from "./chunk-6YFPHVNO.js";
|
|
5
|
+
import {
|
|
6
|
+
SessionStateGraph,
|
|
7
|
+
defaultServerTransportOptions
|
|
8
|
+
} from "./chunk-227EQHH5.js";
|
|
9
|
+
import {
|
|
10
|
+
ControlMessageHandshakeRequestSchema,
|
|
11
|
+
PROTOCOL_VERSION,
|
|
12
|
+
coerceErrorString,
|
|
13
|
+
handshakeResponseMessage
|
|
14
|
+
} from "./chunk-IYYQ7BII.js";
|
|
15
|
+
|
|
16
|
+
// transport/server.ts
|
|
17
|
+
import { SpanStatusCode } from "@opentelemetry/api";
|
|
18
|
+
import { Value } from "@sinclair/typebox/value";
|
|
19
|
+
var ServerTransport = class extends Transport {
|
|
20
|
+
/**
|
|
21
|
+
* The options for this transport.
|
|
22
|
+
*/
|
|
23
|
+
options;
|
|
24
|
+
/**
|
|
25
|
+
* Optional handshake options for the server.
|
|
26
|
+
*/
|
|
27
|
+
handshakeExtensions;
|
|
28
|
+
/**
|
|
29
|
+
* A map of session handshake data for each session.
|
|
30
|
+
*/
|
|
31
|
+
sessionHandshakeMetadata = /* @__PURE__ */ new Map();
|
|
32
|
+
pendingSessions = /* @__PURE__ */ new Set();
|
|
33
|
+
constructor(clientId, providedOptions) {
|
|
34
|
+
super(clientId, providedOptions);
|
|
35
|
+
this.options = {
|
|
36
|
+
...defaultServerTransportOptions,
|
|
37
|
+
...providedOptions
|
|
38
|
+
};
|
|
39
|
+
this.log?.info(`initiated server transport`, {
|
|
40
|
+
clientId: this.clientId,
|
|
41
|
+
protocolVersion: PROTOCOL_VERSION
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
extendHandshake(options) {
|
|
45
|
+
this.handshakeExtensions = options;
|
|
46
|
+
}
|
|
47
|
+
send(to, msg) {
|
|
48
|
+
if (this.getStatus() === "closed") {
|
|
49
|
+
const err = "transport is closed, cant send";
|
|
50
|
+
this.log?.error(err, {
|
|
51
|
+
clientId: this.clientId,
|
|
52
|
+
transportMessage: msg,
|
|
53
|
+
tags: ["invariant-violation"]
|
|
54
|
+
});
|
|
55
|
+
throw new Error(err);
|
|
56
|
+
}
|
|
57
|
+
const session = this.sessions.get(to);
|
|
58
|
+
if (!session) {
|
|
59
|
+
const err = `session to ${to} does not exist`;
|
|
60
|
+
this.log?.error(err, {
|
|
61
|
+
clientId: this.clientId,
|
|
62
|
+
transportMessage: msg,
|
|
63
|
+
tags: ["invariant-violation"]
|
|
64
|
+
});
|
|
65
|
+
throw new Error(err);
|
|
66
|
+
}
|
|
67
|
+
return session.send(msg);
|
|
68
|
+
}
|
|
69
|
+
deletePendingSession(pendingSession) {
|
|
70
|
+
pendingSession.close();
|
|
71
|
+
this.pendingSessions.delete(pendingSession);
|
|
72
|
+
}
|
|
73
|
+
deleteSession(session) {
|
|
74
|
+
this.sessionHandshakeMetadata.delete(session.to);
|
|
75
|
+
super.deleteSession(session);
|
|
76
|
+
}
|
|
77
|
+
handleConnection(conn) {
|
|
78
|
+
if (this.getStatus() !== "open")
|
|
79
|
+
return;
|
|
80
|
+
this.log?.info(`new incoming connection`, {
|
|
81
|
+
...conn.loggingMetadata,
|
|
82
|
+
clientId: this.clientId
|
|
83
|
+
});
|
|
84
|
+
let receivedHandshake = false;
|
|
85
|
+
const pendingSession = SessionStateGraph.entrypoints.WaitingForHandshake(
|
|
86
|
+
this.clientId,
|
|
87
|
+
conn,
|
|
88
|
+
{
|
|
89
|
+
onConnectionClosed: () => {
|
|
90
|
+
this.log?.warn(
|
|
91
|
+
`connection from unknown closed before handshake finished`,
|
|
92
|
+
pendingSession.loggingMetadata
|
|
93
|
+
);
|
|
94
|
+
this.deletePendingSession(pendingSession);
|
|
95
|
+
},
|
|
96
|
+
onConnectionErrored: (err) => {
|
|
97
|
+
const errorString = coerceErrorString(err);
|
|
98
|
+
this.log?.warn(
|
|
99
|
+
`connection from unknown errored before handshake finished: ${errorString}`,
|
|
100
|
+
pendingSession.loggingMetadata
|
|
101
|
+
);
|
|
102
|
+
this.deletePendingSession(pendingSession);
|
|
103
|
+
},
|
|
104
|
+
onHandshakeTimeout: () => {
|
|
105
|
+
this.log?.warn(
|
|
106
|
+
`connection from unknown timed out before handshake finished`,
|
|
107
|
+
pendingSession.loggingMetadata
|
|
108
|
+
);
|
|
109
|
+
this.deletePendingSession(pendingSession);
|
|
110
|
+
},
|
|
111
|
+
onHandshake: (msg) => {
|
|
112
|
+
if (receivedHandshake) {
|
|
113
|
+
this.log?.error(
|
|
114
|
+
`received multiple handshake messages from pending session`,
|
|
115
|
+
{
|
|
116
|
+
...pendingSession.loggingMetadata,
|
|
117
|
+
connectedTo: msg.from,
|
|
118
|
+
transportMessage: msg
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
this.deletePendingSession(pendingSession);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
receivedHandshake = true;
|
|
125
|
+
void this.onHandshakeRequest(pendingSession, msg);
|
|
126
|
+
},
|
|
127
|
+
onInvalidHandshake: (reason) => {
|
|
128
|
+
this.log?.error(
|
|
129
|
+
`invalid handshake: ${reason}`,
|
|
130
|
+
pendingSession.loggingMetadata
|
|
131
|
+
);
|
|
132
|
+
this.deletePendingSession(pendingSession);
|
|
133
|
+
this.protocolError(ProtocolError.HandshakeFailed, reason);
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
this.options,
|
|
137
|
+
this.log
|
|
138
|
+
);
|
|
139
|
+
this.pendingSessions.add(pendingSession);
|
|
140
|
+
}
|
|
141
|
+
rejectHandshakeRequest(session, to, reason, code, metadata) {
|
|
142
|
+
session.conn.telemetry?.span.setStatus({
|
|
143
|
+
code: SpanStatusCode.ERROR,
|
|
144
|
+
message: reason
|
|
145
|
+
});
|
|
146
|
+
this.log?.warn(reason, metadata);
|
|
147
|
+
session.sendHandshake(
|
|
148
|
+
handshakeResponseMessage({
|
|
149
|
+
from: this.clientId,
|
|
150
|
+
to,
|
|
151
|
+
status: {
|
|
152
|
+
ok: false,
|
|
153
|
+
code,
|
|
154
|
+
reason
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
);
|
|
158
|
+
this.protocolError(ProtocolError.HandshakeFailed, reason);
|
|
159
|
+
this.deletePendingSession(session);
|
|
160
|
+
}
|
|
161
|
+
async onHandshakeRequest(session, msg) {
|
|
162
|
+
if (!Value.Check(ControlMessageHandshakeRequestSchema, msg.payload)) {
|
|
163
|
+
this.rejectHandshakeRequest(
|
|
164
|
+
session,
|
|
165
|
+
msg.from,
|
|
166
|
+
"received invalid handshake request",
|
|
167
|
+
"MALFORMED_HANDSHAKE",
|
|
168
|
+
{
|
|
169
|
+
...session.loggingMetadata,
|
|
170
|
+
transportMessage: msg,
|
|
171
|
+
connectedTo: msg.from,
|
|
172
|
+
validationErrors: [
|
|
173
|
+
...Value.Errors(ControlMessageHandshakeRequestSchema, msg.payload)
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const gotVersion = msg.payload.protocolVersion;
|
|
180
|
+
if (gotVersion !== PROTOCOL_VERSION) {
|
|
181
|
+
this.rejectHandshakeRequest(
|
|
182
|
+
session,
|
|
183
|
+
msg.from,
|
|
184
|
+
`expected protocol version ${PROTOCOL_VERSION}, got ${gotVersion}`,
|
|
185
|
+
"PROTOCOL_VERSION_MISMATCH",
|
|
186
|
+
{
|
|
187
|
+
...session.loggingMetadata,
|
|
188
|
+
connectedTo: msg.from,
|
|
189
|
+
transportMessage: msg
|
|
190
|
+
}
|
|
191
|
+
);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
let oldSession = this.sessions.get(msg.from);
|
|
195
|
+
const parsedMetadata = await this.validateHandshakeMetadata(
|
|
196
|
+
session,
|
|
197
|
+
oldSession,
|
|
198
|
+
msg.payload.metadata,
|
|
199
|
+
msg.from
|
|
200
|
+
);
|
|
201
|
+
if (parsedMetadata === false) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
let connectCase = "new session";
|
|
205
|
+
if (oldSession && oldSession.id === msg.payload.sessionId) {
|
|
206
|
+
connectCase = "transparent reconnection";
|
|
207
|
+
const clientNextExpectedSeq = msg.payload.expectedSessionState.nextExpectedSeq;
|
|
208
|
+
const clientNextSentSeq = msg.payload.expectedSessionState.nextSentSeq ?? 0;
|
|
209
|
+
const ourNextSeq = oldSession.nextSeq();
|
|
210
|
+
const ourAck = oldSession.ack;
|
|
211
|
+
if (clientNextSentSeq > ourAck) {
|
|
212
|
+
this.rejectHandshakeRequest(
|
|
213
|
+
session,
|
|
214
|
+
msg.from,
|
|
215
|
+
`client is in the future: server wanted next message to be ${ourAck} but client would have sent ${clientNextSentSeq}`,
|
|
216
|
+
"SESSION_STATE_MISMATCH",
|
|
217
|
+
{
|
|
218
|
+
...session.loggingMetadata,
|
|
219
|
+
connectedTo: msg.from,
|
|
220
|
+
transportMessage: msg
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (ourNextSeq > clientNextExpectedSeq) {
|
|
226
|
+
this.rejectHandshakeRequest(
|
|
227
|
+
session,
|
|
228
|
+
msg.from,
|
|
229
|
+
`server is in the future: client wanted next message to be ${clientNextExpectedSeq} but server would have sent ${ourNextSeq}`,
|
|
230
|
+
"SESSION_STATE_MISMATCH",
|
|
231
|
+
{
|
|
232
|
+
...session.loggingMetadata,
|
|
233
|
+
connectedTo: msg.from,
|
|
234
|
+
transportMessage: msg
|
|
235
|
+
}
|
|
236
|
+
);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
if (oldSession.state === "Connected" /* Connected */) {
|
|
240
|
+
const noConnectionSession = SessionStateGraph.transition.ConnectedToNoConnection(oldSession, {
|
|
241
|
+
onSessionGracePeriodElapsed: () => {
|
|
242
|
+
this.onSessionGracePeriodElapsed(noConnectionSession);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
oldSession = noConnectionSession;
|
|
246
|
+
} else if (oldSession.state === "Handshaking" /* Handshaking */) {
|
|
247
|
+
const noConnectionSession = SessionStateGraph.transition.HandshakingToNoConnection(oldSession, {
|
|
248
|
+
onSessionGracePeriodElapsed: () => {
|
|
249
|
+
this.onSessionGracePeriodElapsed(noConnectionSession);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
oldSession = noConnectionSession;
|
|
253
|
+
} else if (oldSession.state === "Connecting" /* Connecting */) {
|
|
254
|
+
const noConnectionSession = SessionStateGraph.transition.ConnectingToNoConnection(oldSession, {
|
|
255
|
+
onSessionGracePeriodElapsed: () => {
|
|
256
|
+
this.onSessionGracePeriodElapsed(noConnectionSession);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
oldSession = noConnectionSession;
|
|
260
|
+
}
|
|
261
|
+
this.updateSession(oldSession);
|
|
262
|
+
} else if (oldSession) {
|
|
263
|
+
connectCase = "hard reconnection";
|
|
264
|
+
this.deleteSession(oldSession);
|
|
265
|
+
oldSession = void 0;
|
|
266
|
+
} else {
|
|
267
|
+
connectCase = "unknown session";
|
|
268
|
+
const clientNextExpectedSeq = msg.payload.expectedSessionState.nextExpectedSeq;
|
|
269
|
+
const clientNextSentSeq = msg.payload.expectedSessionState.nextSentSeq ?? 0;
|
|
270
|
+
if (clientNextSentSeq > 0 || clientNextExpectedSeq > 0) {
|
|
271
|
+
this.rejectHandshakeRequest(
|
|
272
|
+
session,
|
|
273
|
+
msg.from,
|
|
274
|
+
`client is trying to reconnect to a session the server don't know about: ${msg.payload.sessionId}`,
|
|
275
|
+
"SESSION_STATE_MISMATCH",
|
|
276
|
+
{
|
|
277
|
+
...session.loggingMetadata,
|
|
278
|
+
connectedTo: msg.from,
|
|
279
|
+
transportMessage: msg
|
|
280
|
+
}
|
|
281
|
+
);
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
const sessionId = msg.payload.sessionId;
|
|
286
|
+
this.log?.info(
|
|
287
|
+
`handshake from ${msg.from} ok (${connectCase}), responding with handshake success`,
|
|
288
|
+
{
|
|
289
|
+
...session.loggingMetadata,
|
|
290
|
+
connectedTo: msg.from
|
|
291
|
+
}
|
|
292
|
+
);
|
|
293
|
+
const responseMsg = handshakeResponseMessage({
|
|
294
|
+
from: this.clientId,
|
|
295
|
+
to: msg.from,
|
|
296
|
+
status: {
|
|
297
|
+
ok: true,
|
|
298
|
+
sessionId
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
session.sendHandshake(responseMsg);
|
|
302
|
+
const connectedSession = SessionStateGraph.transition.WaitingForHandshakeToConnected(
|
|
303
|
+
session,
|
|
304
|
+
// by this point oldSession is either no connection or we dont have an old session
|
|
305
|
+
oldSession,
|
|
306
|
+
sessionId,
|
|
307
|
+
msg.from,
|
|
308
|
+
msg.tracing,
|
|
309
|
+
{
|
|
310
|
+
onConnectionErrored: (err) => {
|
|
311
|
+
const errStr = coerceErrorString(err);
|
|
312
|
+
this.log?.warn(
|
|
313
|
+
`connection to ${connectedSession.to} errored: ${errStr}`,
|
|
314
|
+
connectedSession.loggingMetadata
|
|
315
|
+
);
|
|
316
|
+
},
|
|
317
|
+
onConnectionClosed: () => {
|
|
318
|
+
this.log?.info(
|
|
319
|
+
`connection to ${connectedSession.to} closed`,
|
|
320
|
+
connectedSession.loggingMetadata
|
|
321
|
+
);
|
|
322
|
+
this.onConnClosed(connectedSession);
|
|
323
|
+
},
|
|
324
|
+
onMessage: (msg2) => this.handleMsg(msg2),
|
|
325
|
+
onInvalidMessage: (reason) => {
|
|
326
|
+
this.protocolError(ProtocolError.MessageOrderingViolated, reason);
|
|
327
|
+
this.deleteSession(connectedSession);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
);
|
|
331
|
+
this.sessionHandshakeMetadata.set(connectedSession.to, parsedMetadata);
|
|
332
|
+
this.updateSession(connectedSession);
|
|
333
|
+
this.pendingSessions.delete(session);
|
|
334
|
+
connectedSession.startActiveHeartbeat();
|
|
335
|
+
}
|
|
336
|
+
async validateHandshakeMetadata(handshakingSession, existingSession, rawMetadata, from) {
|
|
337
|
+
let parsedMetadata = {};
|
|
338
|
+
if (this.handshakeExtensions) {
|
|
339
|
+
if (!Value.Check(this.handshakeExtensions.schema, rawMetadata)) {
|
|
340
|
+
this.rejectHandshakeRequest(
|
|
341
|
+
handshakingSession,
|
|
342
|
+
from,
|
|
343
|
+
"received malformed handshake metadata",
|
|
344
|
+
"MALFORMED_HANDSHAKE_META",
|
|
345
|
+
{
|
|
346
|
+
...handshakingSession.loggingMetadata,
|
|
347
|
+
connectedTo: from,
|
|
348
|
+
validationErrors: [
|
|
349
|
+
...Value.Errors(this.handshakeExtensions.schema, rawMetadata)
|
|
350
|
+
]
|
|
351
|
+
}
|
|
352
|
+
);
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
const previousParsedMetadata = existingSession ? this.sessionHandshakeMetadata.get(existingSession.to) : void 0;
|
|
356
|
+
parsedMetadata = await this.handshakeExtensions.validate(
|
|
357
|
+
rawMetadata,
|
|
358
|
+
previousParsedMetadata
|
|
359
|
+
);
|
|
360
|
+
if (parsedMetadata === false) {
|
|
361
|
+
this.rejectHandshakeRequest(
|
|
362
|
+
handshakingSession,
|
|
363
|
+
from,
|
|
364
|
+
"rejected by handshake handler",
|
|
365
|
+
"REJECTED_BY_CUSTOM_HANDLER",
|
|
366
|
+
{
|
|
367
|
+
...handshakingSession.loggingMetadata,
|
|
368
|
+
connectedTo: from,
|
|
369
|
+
clientId: this.clientId
|
|
370
|
+
}
|
|
371
|
+
);
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return parsedMetadata;
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
export {
|
|
380
|
+
ServerTransport
|
|
381
|
+
};
|
|
382
|
+
//# sourceMappingURL=chunk-HXOQQXL4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../transport/server.ts"],"sourcesContent":["import { SpanStatusCode } from '@opentelemetry/api';\nimport { ParsedMetadata } from '../router/context';\nimport { ServerHandshakeOptions } from '../router/handshake';\nimport {\n ControlMessageHandshakeRequestSchema,\n HandshakeErrorResponseCodes,\n OpaqueTransportMessage,\n PROTOCOL_VERSION,\n PartialTransportMessage,\n TransportClientId,\n handshakeResponseMessage,\n} from './message';\nimport {\n ProvidedServerTransportOptions,\n ServerTransportOptions,\n defaultServerTransportOptions,\n} from './options';\nimport { Transport } from './transport';\nimport { coerceErrorString } from '../util/stringify';\nimport { Static } from '@sinclair/typebox';\nimport { Value } from '@sinclair/typebox/value';\nimport { ProtocolError } from './events';\nimport { Connection } from './connection';\nimport { MessageMetadata } from '../logging';\nimport { SessionWaitingForHandshake } from './sessionStateMachine/SessionWaitingForHandshake';\nimport { Session, SessionState } from './sessionStateMachine/common';\nimport { SessionStateGraph } from './sessionStateMachine/transitions';\n\nexport abstract class ServerTransport<\n ConnType extends Connection,\n> extends Transport<ConnType> {\n /**\n * The options for this transport.\n */\n protected options: ServerTransportOptions;\n\n /**\n * Optional handshake options for the server.\n */\n handshakeExtensions?: ServerHandshakeOptions;\n\n /**\n * A map of session handshake data for each session.\n */\n sessionHandshakeMetadata = new Map<TransportClientId, ParsedMetadata>();\n pendingSessions = new Set<SessionWaitingForHandshake<ConnType>>();\n\n constructor(\n clientId: TransportClientId,\n providedOptions?: ProvidedServerTransportOptions,\n ) {\n super(clientId, providedOptions);\n this.options = {\n ...defaultServerTransportOptions,\n ...providedOptions,\n };\n this.log?.info(`initiated server transport`, {\n clientId: this.clientId,\n protocolVersion: PROTOCOL_VERSION,\n });\n }\n\n extendHandshake(options: ServerHandshakeOptions) {\n this.handshakeExtensions = options;\n }\n\n send(to: string, msg: PartialTransportMessage): string {\n if (this.getStatus() === 'closed') {\n const err = 'transport is closed, cant send';\n this.log?.error(err, {\n clientId: this.clientId,\n transportMessage: msg,\n tags: ['invariant-violation'],\n });\n\n throw new Error(err);\n }\n\n const session = this.sessions.get(to);\n if (!session) {\n const err = `session to ${to} does not exist`;\n this.log?.error(err, {\n clientId: this.clientId,\n transportMessage: msg,\n tags: ['invariant-violation'],\n });\n\n throw new Error(err);\n }\n\n return session.send(msg);\n }\n\n protected deletePendingSession(\n pendingSession: SessionWaitingForHandshake<ConnType>,\n ) {\n pendingSession.close();\n // we don't dispatch a session disconnect event\n // for a non-identified session, just delete directly\n\n this.pendingSessions.delete(pendingSession);\n }\n\n protected deleteSession(session: Session<ConnType>): void {\n this.sessionHandshakeMetadata.delete(session.to);\n super.deleteSession(session);\n }\n\n protected handleConnection(conn: ConnType) {\n if (this.getStatus() !== 'open') return;\n\n this.log?.info(`new incoming connection`, {\n ...conn.loggingMetadata,\n clientId: this.clientId,\n });\n\n let receivedHandshake = false;\n const pendingSession = SessionStateGraph.entrypoints.WaitingForHandshake(\n this.clientId,\n conn,\n {\n onConnectionClosed: () => {\n this.log?.warn(\n `connection from unknown closed before handshake finished`,\n pendingSession.loggingMetadata,\n );\n\n this.deletePendingSession(pendingSession);\n },\n onConnectionErrored: (err) => {\n const errorString = coerceErrorString(err);\n this.log?.warn(\n `connection from unknown errored before handshake finished: ${errorString}`,\n pendingSession.loggingMetadata,\n );\n\n this.deletePendingSession(pendingSession);\n },\n onHandshakeTimeout: () => {\n this.log?.warn(\n `connection from unknown timed out before handshake finished`,\n pendingSession.loggingMetadata,\n );\n\n this.deletePendingSession(pendingSession);\n },\n onHandshake: (msg) => {\n if (receivedHandshake) {\n this.log?.error(\n `received multiple handshake messages from pending session`,\n {\n ...pendingSession.loggingMetadata,\n connectedTo: msg.from,\n transportMessage: msg,\n },\n );\n\n this.deletePendingSession(pendingSession);\n return;\n }\n\n // let this resolve async, we just need to make sure its only\n // called once so we don't race while transitioning to connected\n // onHandshakeRequest is async as custom validation may be async\n receivedHandshake = true;\n void this.onHandshakeRequest(pendingSession, msg);\n },\n onInvalidHandshake: (reason) => {\n this.log?.error(\n `invalid handshake: ${reason}`,\n pendingSession.loggingMetadata,\n );\n this.deletePendingSession(pendingSession);\n this.protocolError(ProtocolError.HandshakeFailed, reason);\n },\n },\n this.options,\n this.log,\n );\n\n this.pendingSessions.add(pendingSession);\n }\n\n private rejectHandshakeRequest(\n session: SessionWaitingForHandshake<ConnType>,\n to: TransportClientId,\n reason: string,\n code: Static<typeof HandshakeErrorResponseCodes>,\n metadata: MessageMetadata,\n ) {\n session.conn.telemetry?.span.setStatus({\n code: SpanStatusCode.ERROR,\n message: reason,\n });\n\n this.log?.warn(reason, metadata);\n\n session.sendHandshake(\n handshakeResponseMessage({\n from: this.clientId,\n to,\n status: {\n ok: false,\n code,\n reason,\n },\n }),\n );\n\n this.protocolError(ProtocolError.HandshakeFailed, reason);\n this.deletePendingSession(session);\n }\n\n protected async onHandshakeRequest(\n session: SessionWaitingForHandshake<ConnType>,\n msg: OpaqueTransportMessage,\n ) {\n // invariant: msg is a handshake request\n if (!Value.Check(ControlMessageHandshakeRequestSchema, msg.payload)) {\n this.rejectHandshakeRequest(\n session,\n msg.from,\n 'received invalid handshake request',\n 'MALFORMED_HANDSHAKE',\n {\n ...session.loggingMetadata,\n transportMessage: msg,\n connectedTo: msg.from,\n validationErrors: [\n ...Value.Errors(ControlMessageHandshakeRequestSchema, msg.payload),\n ],\n },\n );\n\n return;\n }\n\n // invariant: handshake request passes all the validation\n const gotVersion = msg.payload.protocolVersion;\n if (gotVersion !== PROTOCOL_VERSION) {\n this.rejectHandshakeRequest(\n session,\n msg.from,\n `expected protocol version ${PROTOCOL_VERSION}, got ${gotVersion}`,\n 'PROTOCOL_VERSION_MISMATCH',\n {\n ...session.loggingMetadata,\n connectedTo: msg.from,\n transportMessage: msg,\n },\n );\n\n return;\n }\n\n let oldSession = this.sessions.get(msg.from);\n\n // invariant: must pass custom validation if defined\n const parsedMetadata = await this.validateHandshakeMetadata(\n session,\n oldSession,\n msg.payload.metadata,\n msg.from,\n );\n\n if (parsedMetadata === false) {\n return;\n }\n\n // 4 connect cases\n // 1. new session\n // we dont have a session and the client is requesting a new one\n // we can create the session as normal\n // 2. client is reconnecting to an existing session but we don't have it\n // reject this handshake, there's nothing we can do to salvage it\n // 3. transparent reconnect (old session exists and is the same as the client wants)\n // assign to old session\n // 4. hard reconnect (oldSession exists but but the client wants a new one)\n // we close the old session and create a new one\n let connectCase:\n | 'new session'\n | 'unknown session'\n | 'transparent reconnection'\n | 'hard reconnection' = 'new session';\n if (oldSession && oldSession.id === msg.payload.sessionId) {\n connectCase = 'transparent reconnection';\n\n // invariant: ordering must be correct\n const clientNextExpectedSeq =\n msg.payload.expectedSessionState.nextExpectedSeq;\n // TODO: remove nullish coalescing when we're sure this is always set\n const clientNextSentSeq =\n msg.payload.expectedSessionState.nextSentSeq ?? 0;\n const ourNextSeq = oldSession.nextSeq();\n const ourAck = oldSession.ack;\n\n // two incorrect cases where we cannot permit a reconnect:\n // - if the client is about to send a message in the future w.r.t to the server\n // - client.seq > server.ack => nextSentSeq > oldSession.ack\n if (clientNextSentSeq > ourAck) {\n this.rejectHandshakeRequest(\n session,\n msg.from,\n `client is in the future: server wanted next message to be ${ourAck} but client would have sent ${clientNextSentSeq}`,\n 'SESSION_STATE_MISMATCH',\n {\n ...session.loggingMetadata,\n connectedTo: msg.from,\n transportMessage: msg,\n },\n );\n\n return;\n }\n\n // - if the server is about to send a message in the future w.r.t to the client\n // - server.seq > client.ack => oldSession.nextSeq() > nextExpectedSeq\n if (ourNextSeq > clientNextExpectedSeq) {\n this.rejectHandshakeRequest(\n session,\n msg.from,\n `server is in the future: client wanted next message to be ${clientNextExpectedSeq} but server would have sent ${ourNextSeq}`,\n 'SESSION_STATE_MISMATCH',\n {\n ...session.loggingMetadata,\n connectedTo: msg.from,\n transportMessage: msg,\n },\n );\n\n return;\n }\n\n // transparent reconnect seems ok, proceed by transitioning old session\n // to not connected\n if (oldSession.state === SessionState.Connected) {\n const noConnectionSession =\n SessionStateGraph.transition.ConnectedToNoConnection(oldSession, {\n onSessionGracePeriodElapsed: () => {\n this.onSessionGracePeriodElapsed(noConnectionSession);\n },\n });\n\n oldSession = noConnectionSession;\n } else if (oldSession.state === SessionState.Handshaking) {\n const noConnectionSession =\n SessionStateGraph.transition.HandshakingToNoConnection(oldSession, {\n onSessionGracePeriodElapsed: () => {\n this.onSessionGracePeriodElapsed(noConnectionSession);\n },\n });\n\n oldSession = noConnectionSession;\n } else if (oldSession.state === SessionState.Connecting) {\n const noConnectionSession =\n SessionStateGraph.transition.ConnectingToNoConnection(oldSession, {\n onSessionGracePeriodElapsed: () => {\n this.onSessionGracePeriodElapsed(noConnectionSession);\n },\n });\n\n oldSession = noConnectionSession;\n }\n\n this.updateSession(oldSession);\n } else if (oldSession) {\n connectCase = 'hard reconnection';\n\n // just nuke the old session entirely and proceed as if this was new\n this.deleteSession(oldSession);\n oldSession = undefined;\n } else {\n connectCase = 'unknown session';\n\n const clientNextExpectedSeq =\n msg.payload.expectedSessionState.nextExpectedSeq;\n // TODO: remove nullish coalescing when we're sure this is always set\n const clientNextSentSeq =\n msg.payload.expectedSessionState.nextSentSeq ?? 0;\n\n if (clientNextSentSeq > 0 || clientNextExpectedSeq > 0) {\n // we don't have a session, but the client is trying to reconnect\n // to an old session. we can't do anything about this, so we reject\n this.rejectHandshakeRequest(\n session,\n msg.from,\n `client is trying to reconnect to a session the server don't know about: ${msg.payload.sessionId}`,\n 'SESSION_STATE_MISMATCH',\n {\n ...session.loggingMetadata,\n connectedTo: msg.from,\n transportMessage: msg,\n },\n );\n return;\n }\n }\n\n // from this point on, we're committed to connecting\n const sessionId = msg.payload.sessionId;\n this.log?.info(\n `handshake from ${msg.from} ok (${connectCase}), responding with handshake success`,\n {\n ...session.loggingMetadata,\n connectedTo: msg.from,\n },\n );\n const responseMsg = handshakeResponseMessage({\n from: this.clientId,\n to: msg.from,\n status: {\n ok: true,\n sessionId,\n },\n });\n session.sendHandshake(responseMsg);\n\n // transition\n const connectedSession =\n SessionStateGraph.transition.WaitingForHandshakeToConnected(\n session,\n // by this point oldSession is either no connection or we dont have an old session\n oldSession,\n sessionId,\n msg.from,\n msg.tracing,\n {\n onConnectionErrored: (err) => {\n // just log, when we error we also emit close\n const errStr = coerceErrorString(err);\n this.log?.warn(\n `connection to ${connectedSession.to} errored: ${errStr}`,\n connectedSession.loggingMetadata,\n );\n },\n onConnectionClosed: () => {\n this.log?.info(\n `connection to ${connectedSession.to} closed`,\n connectedSession.loggingMetadata,\n );\n this.onConnClosed(connectedSession);\n },\n onMessage: (msg) => this.handleMsg(msg),\n onInvalidMessage: (reason) => {\n this.protocolError(ProtocolError.MessageOrderingViolated, reason);\n this.deleteSession(connectedSession);\n },\n },\n );\n\n this.sessionHandshakeMetadata.set(connectedSession.to, parsedMetadata);\n this.updateSession(connectedSession);\n this.pendingSessions.delete(session);\n connectedSession.startActiveHeartbeat();\n }\n\n private async validateHandshakeMetadata(\n handshakingSession: SessionWaitingForHandshake<ConnType>,\n existingSession: Session<ConnType> | undefined,\n rawMetadata: Static<\n typeof ControlMessageHandshakeRequestSchema\n >['metadata'],\n from: TransportClientId,\n ): Promise<ParsedMetadata | false> {\n let parsedMetadata: ParsedMetadata = {};\n if (this.handshakeExtensions) {\n // check that the metadata that was sent is the correct shape\n if (!Value.Check(this.handshakeExtensions.schema, rawMetadata)) {\n this.rejectHandshakeRequest(\n handshakingSession,\n from,\n 'received malformed handshake metadata',\n 'MALFORMED_HANDSHAKE_META',\n {\n ...handshakingSession.loggingMetadata,\n connectedTo: from,\n validationErrors: [\n ...Value.Errors(this.handshakeExtensions.schema, rawMetadata),\n ],\n },\n );\n\n return false;\n }\n\n const previousParsedMetadata = existingSession\n ? this.sessionHandshakeMetadata.get(existingSession.to)\n : undefined;\n\n parsedMetadata = await this.handshakeExtensions.validate(\n rawMetadata,\n previousParsedMetadata,\n );\n\n // handler rejected the connection\n if (parsedMetadata === false) {\n this.rejectHandshakeRequest(\n handshakingSession,\n from,\n 'rejected by handshake handler',\n 'REJECTED_BY_CUSTOM_HANDLER',\n {\n ...handshakingSession.loggingMetadata,\n connectedTo: from,\n clientId: this.clientId,\n },\n );\n\n return false;\n }\n }\n\n return parsedMetadata;\n }\n}\n"],"mappings":"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","names":["msg"]}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
// transport/id.ts
|
|
2
|
+
import { customAlphabet } from "nanoid";
|
|
3
|
+
var alphabet = customAlphabet(
|
|
4
|
+
"1234567890abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ"
|
|
5
|
+
);
|
|
6
|
+
var generateId = () => alphabet(12);
|
|
7
|
+
|
|
1
8
|
// transport/message.ts
|
|
2
9
|
import { Type } from "@sinclair/typebox";
|
|
3
|
-
import { nanoid } from "nanoid";
|
|
4
10
|
var TransportMessageSchema = (t) => Type.Object({
|
|
5
11
|
id: Type.String(),
|
|
6
12
|
from: Type.String(),
|
|
@@ -35,18 +41,29 @@ var ControlMessageHandshakeRequestSchema = Type.Object({
|
|
|
35
41
|
* used by the server to know whether this is a new or a reestablished connection, and whether it
|
|
36
42
|
* is compatible with what it already has.
|
|
37
43
|
*/
|
|
38
|
-
expectedSessionState: Type.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
})
|
|
47
|
-
),
|
|
44
|
+
expectedSessionState: Type.Object({
|
|
45
|
+
// what the client expects the server to send next
|
|
46
|
+
nextExpectedSeq: Type.Integer(),
|
|
47
|
+
// TODO: remove optional once we know all servers
|
|
48
|
+
// are nextSentSeq here
|
|
49
|
+
// what the server expects the client to send next
|
|
50
|
+
nextSentSeq: Type.Optional(Type.Integer())
|
|
51
|
+
}),
|
|
48
52
|
metadata: Type.Optional(Type.Unknown())
|
|
49
53
|
});
|
|
54
|
+
var HandshakeErrorRetriableResponseCodes = Type.Union([
|
|
55
|
+
Type.Literal("SESSION_STATE_MISMATCH")
|
|
56
|
+
]);
|
|
57
|
+
var HandshakeErrorFatalResponseCodes = Type.Union([
|
|
58
|
+
Type.Literal("MALFORMED_HANDSHAKE_META"),
|
|
59
|
+
Type.Literal("MALFORMED_HANDSHAKE"),
|
|
60
|
+
Type.Literal("PROTOCOL_VERSION_MISMATCH"),
|
|
61
|
+
Type.Literal("REJECTED_BY_CUSTOM_HANDLER")
|
|
62
|
+
]);
|
|
63
|
+
var HandshakeErrorResponseCodes = Type.Union([
|
|
64
|
+
HandshakeErrorRetriableResponseCodes,
|
|
65
|
+
HandshakeErrorFatalResponseCodes
|
|
66
|
+
]);
|
|
50
67
|
var ControlMessageHandshakeResponseSchema = Type.Object({
|
|
51
68
|
type: Type.Literal("HANDSHAKE_RESP"),
|
|
52
69
|
status: Type.Union([
|
|
@@ -56,7 +73,10 @@ var ControlMessageHandshakeResponseSchema = Type.Object({
|
|
|
56
73
|
}),
|
|
57
74
|
Type.Object({
|
|
58
75
|
ok: Type.Literal(false),
|
|
59
|
-
reason: Type.String()
|
|
76
|
+
reason: Type.String(),
|
|
77
|
+
// TODO: remove optional once we know all servers
|
|
78
|
+
// are sending code here
|
|
79
|
+
code: Type.Optional(HandshakeErrorResponseCodes)
|
|
60
80
|
})
|
|
61
81
|
])
|
|
62
82
|
});
|
|
@@ -78,12 +98,12 @@ function handshakeRequestMessage({
|
|
|
78
98
|
tracing
|
|
79
99
|
}) {
|
|
80
100
|
return {
|
|
81
|
-
id:
|
|
101
|
+
id: generateId(),
|
|
82
102
|
from,
|
|
83
103
|
to,
|
|
84
104
|
seq: 0,
|
|
85
105
|
ack: 0,
|
|
86
|
-
streamId:
|
|
106
|
+
streamId: generateId(),
|
|
87
107
|
controlFlags: 0,
|
|
88
108
|
tracing,
|
|
89
109
|
payload: {
|
|
@@ -95,19 +115,18 @@ function handshakeRequestMessage({
|
|
|
95
115
|
}
|
|
96
116
|
};
|
|
97
117
|
}
|
|
98
|
-
var SESSION_STATE_MISMATCH = "session state mismatch";
|
|
99
118
|
function handshakeResponseMessage({
|
|
100
119
|
from,
|
|
101
120
|
to,
|
|
102
121
|
status
|
|
103
122
|
}) {
|
|
104
123
|
return {
|
|
105
|
-
id:
|
|
124
|
+
id: generateId(),
|
|
106
125
|
from,
|
|
107
126
|
to,
|
|
108
127
|
seq: 0,
|
|
109
128
|
ack: 0,
|
|
110
|
-
streamId:
|
|
129
|
+
streamId: generateId(),
|
|
111
130
|
controlFlags: 0,
|
|
112
131
|
payload: {
|
|
113
132
|
type: "HANDSHAKE_RESP",
|
|
@@ -115,6 +134,15 @@ function handshakeResponseMessage({
|
|
|
115
134
|
}
|
|
116
135
|
};
|
|
117
136
|
}
|
|
137
|
+
function closeStreamMessage(streamId) {
|
|
138
|
+
return {
|
|
139
|
+
streamId,
|
|
140
|
+
controlFlags: 4 /* StreamClosedBit */,
|
|
141
|
+
payload: {
|
|
142
|
+
type: "CLOSE"
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
118
146
|
function isAck(controlFlag) {
|
|
119
147
|
return (controlFlag & 1 /* AckBit */) === 1 /* AckBit */;
|
|
120
148
|
}
|
|
@@ -132,7 +160,7 @@ function isStreamClose(controlFlag) {
|
|
|
132
160
|
}
|
|
133
161
|
|
|
134
162
|
// package.json
|
|
135
|
-
var version = "0.
|
|
163
|
+
var version = "0.24.1";
|
|
136
164
|
|
|
137
165
|
// util/stringify.ts
|
|
138
166
|
function coerceErrorString(err) {
|
|
@@ -157,16 +185,16 @@ function getPropagationContext(ctx) {
|
|
|
157
185
|
propagation.inject(ctx, tracing);
|
|
158
186
|
return tracing;
|
|
159
187
|
}
|
|
160
|
-
function createSessionTelemetryInfo(
|
|
188
|
+
function createSessionTelemetryInfo(sessionId, to, from, propagationCtx) {
|
|
161
189
|
const parentCtx = propagationCtx ? propagation.extract(context.active(), propagationCtx) : context.active();
|
|
162
190
|
const span = tracer.startSpan(
|
|
163
|
-
`session ${
|
|
191
|
+
`session ${sessionId}`,
|
|
164
192
|
{
|
|
165
193
|
attributes: {
|
|
166
194
|
component: "river",
|
|
167
|
-
"river.session.id":
|
|
168
|
-
"river.session.to":
|
|
169
|
-
"river.session.from":
|
|
195
|
+
"river.session.id": sessionId,
|
|
196
|
+
"river.session.to": to,
|
|
197
|
+
"river.session.from": from
|
|
170
198
|
}
|
|
171
199
|
},
|
|
172
200
|
parentCtx
|
|
@@ -174,21 +202,6 @@ function createSessionTelemetryInfo(session, propagationCtx) {
|
|
|
174
202
|
const ctx = trace.setSpan(parentCtx, span);
|
|
175
203
|
return { span, ctx };
|
|
176
204
|
}
|
|
177
|
-
function createConnectionTelemetryInfo(connection, info) {
|
|
178
|
-
const span = tracer.startSpan(
|
|
179
|
-
`connection ${connection.id}`,
|
|
180
|
-
{
|
|
181
|
-
attributes: {
|
|
182
|
-
component: "river",
|
|
183
|
-
"river.connection.id": connection.id
|
|
184
|
-
},
|
|
185
|
-
links: [{ context: info.span.spanContext() }]
|
|
186
|
-
},
|
|
187
|
-
info.ctx
|
|
188
|
-
);
|
|
189
|
-
const ctx = trace.setSpan(info.ctx, span);
|
|
190
|
-
return { span, ctx };
|
|
191
|
-
}
|
|
192
205
|
function createProcTelemetryInfo(transport, kind, serviceName, procedureName, streamId) {
|
|
193
206
|
const baseCtx = context.active();
|
|
194
207
|
const span = tracer.startSpan(
|
|
@@ -243,25 +256,26 @@ var tracer = trace.getTracer("river", version);
|
|
|
243
256
|
var tracing_default = tracer;
|
|
244
257
|
|
|
245
258
|
export {
|
|
259
|
+
generateId,
|
|
246
260
|
TransportMessageSchema,
|
|
247
261
|
PROTOCOL_VERSION,
|
|
248
262
|
ControlMessageHandshakeRequestSchema,
|
|
263
|
+
HandshakeErrorRetriableResponseCodes,
|
|
249
264
|
ControlMessageHandshakeResponseSchema,
|
|
250
265
|
ControlMessagePayloadSchema,
|
|
251
266
|
OpaqueTransportMessageSchema,
|
|
252
267
|
handshakeRequestMessage,
|
|
253
|
-
SESSION_STATE_MISMATCH,
|
|
254
268
|
handshakeResponseMessage,
|
|
269
|
+
closeStreamMessage,
|
|
255
270
|
isAck,
|
|
256
271
|
isStreamOpen,
|
|
257
272
|
isStreamClose,
|
|
258
273
|
version,
|
|
259
274
|
getPropagationContext,
|
|
260
275
|
createSessionTelemetryInfo,
|
|
261
|
-
createConnectionTelemetryInfo,
|
|
262
276
|
createProcTelemetryInfo,
|
|
263
277
|
createHandlerSpan,
|
|
264
278
|
tracing_default,
|
|
265
279
|
coerceErrorString
|
|
266
280
|
};
|
|
267
|
-
//# sourceMappingURL=chunk-
|
|
281
|
+
//# sourceMappingURL=chunk-IYYQ7BII.js.map
|