@replit/river 0.200.0-rc.7 → 0.200.0-rc.8
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/dist/{chunk-BZBEE2VR.js → chunk-3ROTSXAO.js} +14 -4
- package/dist/chunk-3ROTSXAO.js.map +1 -0
- package/dist/{chunk-VLW5OKZG.js → chunk-B5VE44UX.js} +2 -2
- package/dist/{chunk-CXPZSAU4.js → chunk-FAIV2RO2.js} +62 -36
- package/dist/chunk-FAIV2RO2.js.map +1 -0
- package/dist/{chunk-U4W75CMT.js → chunk-J54ZWTQM.js} +7 -6
- package/dist/chunk-J54ZWTQM.js.map +1 -0
- package/dist/{chunk-F2E7ILHW.js → chunk-XV5WUEIR.js} +70 -59
- package/dist/chunk-XV5WUEIR.js.map +1 -0
- package/dist/{chunk-3XKJOFZA.js → chunk-Y3JHOIJ7.js} +141 -50
- package/dist/chunk-Y3JHOIJ7.js.map +1 -0
- package/dist/{chunk-XIJVDPYY.js → chunk-Y4DP7WHM.js} +2 -2
- package/dist/{chunk-XIJVDPYY.js.map → chunk-Y4DP7WHM.js.map} +1 -1
- package/dist/{client-829bf1f9.d.ts → client-22a47343.d.ts} +3 -5
- package/dist/{connection-5e67d641.d.ts → connection-260e45a8.d.ts} +1 -1
- package/dist/{context-9eabf54f.d.ts → context-b4aff18f.d.ts} +90 -43
- package/dist/logging/index.d.cts +1 -1
- package/dist/logging/index.d.ts +1 -1
- package/dist/{message-fd349b27.d.ts → message-7d135e38.d.ts} +3 -1
- package/dist/router/index.cjs +12 -3
- package/dist/router/index.cjs.map +1 -1
- package/dist/router/index.d.cts +9 -8
- package/dist/router/index.d.ts +9 -8
- package/dist/router/index.js +2 -2
- package/dist/{server-d82a2d9b.d.ts → server-dd6a9853.d.ts} +27 -6
- package/dist/{services-6a446f04.d.ts → services-bd2c50c0.d.ts} +3 -3
- package/dist/transport/impls/ws/client.cjs +216 -88
- package/dist/transport/impls/ws/client.cjs.map +1 -1
- package/dist/transport/impls/ws/client.d.cts +5 -4
- package/dist/transport/impls/ws/client.d.ts +5 -4
- package/dist/transport/impls/ws/client.js +8 -7
- package/dist/transport/impls/ws/client.js.map +1 -1
- package/dist/transport/impls/ws/server.cjs +220 -109
- package/dist/transport/impls/ws/server.cjs.map +1 -1
- package/dist/transport/impls/ws/server.d.cts +5 -4
- package/dist/transport/impls/ws/server.d.ts +5 -4
- package/dist/transport/impls/ws/server.js +5 -5
- package/dist/transport/index.cjs +278 -141
- package/dist/transport/index.cjs.map +1 -1
- package/dist/transport/index.d.cts +5 -4
- package/dist/transport/index.d.ts +5 -4
- package/dist/transport/index.js +5 -5
- package/dist/util/testHelpers.cjs +151 -51
- package/dist/util/testHelpers.cjs.map +1 -1
- package/dist/util/testHelpers.d.cts +5 -4
- package/dist/util/testHelpers.d.ts +5 -4
- package/dist/util/testHelpers.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-3XKJOFZA.js.map +0 -1
- package/dist/chunk-BZBEE2VR.js.map +0 -1
- package/dist/chunk-CXPZSAU4.js.map +0 -1
- package/dist/chunk-F2E7ILHW.js.map +0 -1
- package/dist/chunk-U4W75CMT.js.map +0 -1
- /package/dist/{chunk-VLW5OKZG.js.map → chunk-B5VE44UX.js.map} +0 -0
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ProtocolError,
|
|
3
3
|
Transport
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-J54ZWTQM.js";
|
|
5
5
|
import {
|
|
6
6
|
ServerSessionStateGraph,
|
|
7
7
|
defaultServerTransportOptions
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-Y3JHOIJ7.js";
|
|
9
9
|
import {
|
|
10
10
|
ControlMessageHandshakeRequestSchema,
|
|
11
|
+
HandshakeErrorCustomHandlerFatalResponseCodes,
|
|
11
12
|
acceptedProtocolVersions,
|
|
12
13
|
coerceErrorString,
|
|
13
14
|
currentProtocolVersion,
|
|
14
15
|
handshakeResponseMessage
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-3ROTSXAO.js";
|
|
16
17
|
|
|
17
18
|
// transport/server.ts
|
|
18
19
|
import { SpanStatusCode } from "@opentelemetry/api";
|
|
@@ -127,13 +128,17 @@ var ServerTransport = class extends Transport {
|
|
|
127
128
|
receivedHandshake = true;
|
|
128
129
|
void this.onHandshakeRequest(pendingSession, msg);
|
|
129
130
|
},
|
|
130
|
-
onInvalidHandshake: (reason) => {
|
|
131
|
+
onInvalidHandshake: (reason, code) => {
|
|
131
132
|
this.log?.error(
|
|
132
133
|
`invalid handshake: ${reason}`,
|
|
133
134
|
pendingSession.loggingMetadata
|
|
134
135
|
);
|
|
135
136
|
this.deletePendingSession(pendingSession);
|
|
136
|
-
this.protocolError(
|
|
137
|
+
this.protocolError({
|
|
138
|
+
type: ProtocolError.HandshakeFailed,
|
|
139
|
+
code,
|
|
140
|
+
message: reason
|
|
141
|
+
});
|
|
137
142
|
}
|
|
138
143
|
},
|
|
139
144
|
this.options,
|
|
@@ -158,7 +163,11 @@ var ServerTransport = class extends Transport {
|
|
|
158
163
|
}
|
|
159
164
|
})
|
|
160
165
|
);
|
|
161
|
-
this.protocolError(
|
|
166
|
+
this.protocolError({
|
|
167
|
+
type: ProtocolError.HandshakeFailed,
|
|
168
|
+
code,
|
|
169
|
+
message: reason
|
|
170
|
+
});
|
|
162
171
|
this.deletePendingSession(session);
|
|
163
172
|
}
|
|
164
173
|
async onHandshakeRequest(session, msg) {
|
|
@@ -195,19 +204,58 @@ var ServerTransport = class extends Transport {
|
|
|
195
204
|
return;
|
|
196
205
|
}
|
|
197
206
|
let oldSession = this.sessions.get(msg.from);
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
207
|
+
let parsedMetadata = {};
|
|
208
|
+
if (this.handshakeExtensions) {
|
|
209
|
+
if (!Value.Check(this.handshakeExtensions.schema, msg.payload.metadata)) {
|
|
210
|
+
this.rejectHandshakeRequest(
|
|
211
|
+
session,
|
|
212
|
+
msg.from,
|
|
213
|
+
"received malformed handshake metadata",
|
|
214
|
+
"MALFORMED_HANDSHAKE_META",
|
|
215
|
+
{
|
|
216
|
+
...session.loggingMetadata,
|
|
217
|
+
connectedTo: msg.from,
|
|
218
|
+
validationErrors: [
|
|
219
|
+
...Value.Errors(
|
|
220
|
+
this.handshakeExtensions.schema,
|
|
221
|
+
msg.payload.metadata
|
|
222
|
+
)
|
|
223
|
+
]
|
|
224
|
+
}
|
|
225
|
+
);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const previousParsedMetadata = oldSession ? this.sessionHandshakeMetadata.get(oldSession.to) : void 0;
|
|
229
|
+
const parsedMetadataOrFailureCode = await this.handshakeExtensions.validate(
|
|
230
|
+
msg.payload.metadata,
|
|
231
|
+
previousParsedMetadata
|
|
232
|
+
);
|
|
233
|
+
if (session._isConsumed) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (Value.Check(
|
|
237
|
+
HandshakeErrorCustomHandlerFatalResponseCodes,
|
|
238
|
+
parsedMetadataOrFailureCode
|
|
239
|
+
)) {
|
|
240
|
+
this.rejectHandshakeRequest(
|
|
241
|
+
session,
|
|
242
|
+
msg.from,
|
|
243
|
+
"rejected by handshake handler",
|
|
244
|
+
parsedMetadataOrFailureCode,
|
|
245
|
+
{
|
|
246
|
+
...session.loggingMetadata,
|
|
247
|
+
connectedTo: msg.from,
|
|
248
|
+
clientId: this.clientId
|
|
249
|
+
}
|
|
250
|
+
);
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
parsedMetadata = parsedMetadataOrFailureCode;
|
|
206
254
|
}
|
|
207
255
|
let connectCase = "new session";
|
|
208
256
|
const clientNextExpectedSeq = msg.payload.expectedSessionState.nextExpectedSeq;
|
|
209
257
|
const clientNextSentSeq = msg.payload.expectedSessionState.nextSentSeq ?? 0;
|
|
210
|
-
if (oldSession && oldSession.id === msg.payload.sessionId) {
|
|
258
|
+
if (this.options.enableTransparentSessionReconnects && oldSession && oldSession.id === msg.payload.sessionId) {
|
|
211
259
|
connectCase = "transparent reconnection";
|
|
212
260
|
const ourNextSeq = oldSession.nextSeq();
|
|
213
261
|
const ourAck = oldSession.ack;
|
|
@@ -266,10 +314,11 @@ var ServerTransport = class extends Transport {
|
|
|
266
314
|
}
|
|
267
315
|
if (!oldSession && (clientNextSentSeq > 0 || clientNextExpectedSeq > 0)) {
|
|
268
316
|
connectCase = "unknown session";
|
|
317
|
+
const rejectionMessage = this.options.enableTransparentSessionReconnects ? `client is trying to reconnect to a session the server don't know about: ${msg.payload.sessionId}` : `client is attempting a transparent reconnect to a session but the server does not support it: ${msg.payload.sessionId}`;
|
|
269
318
|
this.rejectHandshakeRequest(
|
|
270
319
|
session,
|
|
271
320
|
msg.from,
|
|
272
|
-
|
|
321
|
+
rejectionMessage,
|
|
273
322
|
"SESSION_STATE_MISMATCH",
|
|
274
323
|
{
|
|
275
324
|
...session.loggingMetadata,
|
|
@@ -320,7 +369,10 @@ var ServerTransport = class extends Transport {
|
|
|
320
369
|
},
|
|
321
370
|
onMessage: (msg2) => this.handleMsg(msg2),
|
|
322
371
|
onInvalidMessage: (reason) => {
|
|
323
|
-
this.protocolError(
|
|
372
|
+
this.protocolError({
|
|
373
|
+
type: ProtocolError.MessageOrderingViolated,
|
|
374
|
+
message: reason
|
|
375
|
+
});
|
|
324
376
|
this.deleteSession(connectedSession);
|
|
325
377
|
}
|
|
326
378
|
},
|
|
@@ -331,50 +383,9 @@ var ServerTransport = class extends Transport {
|
|
|
331
383
|
this.pendingSessions.delete(session);
|
|
332
384
|
connectedSession.startActiveHeartbeat();
|
|
333
385
|
}
|
|
334
|
-
async validateHandshakeMetadata(handshakingSession, existingSession, rawMetadata, from) {
|
|
335
|
-
let parsedMetadata = {};
|
|
336
|
-
if (this.handshakeExtensions) {
|
|
337
|
-
if (!Value.Check(this.handshakeExtensions.schema, rawMetadata)) {
|
|
338
|
-
this.rejectHandshakeRequest(
|
|
339
|
-
handshakingSession,
|
|
340
|
-
from,
|
|
341
|
-
"received malformed handshake metadata",
|
|
342
|
-
"MALFORMED_HANDSHAKE_META",
|
|
343
|
-
{
|
|
344
|
-
...handshakingSession.loggingMetadata,
|
|
345
|
-
connectedTo: from,
|
|
346
|
-
validationErrors: [
|
|
347
|
-
...Value.Errors(this.handshakeExtensions.schema, rawMetadata)
|
|
348
|
-
]
|
|
349
|
-
}
|
|
350
|
-
);
|
|
351
|
-
return false;
|
|
352
|
-
}
|
|
353
|
-
const previousParsedMetadata = existingSession ? this.sessionHandshakeMetadata.get(existingSession.to) : void 0;
|
|
354
|
-
parsedMetadata = await this.handshakeExtensions.validate(
|
|
355
|
-
rawMetadata,
|
|
356
|
-
previousParsedMetadata
|
|
357
|
-
);
|
|
358
|
-
if (parsedMetadata === false) {
|
|
359
|
-
this.rejectHandshakeRequest(
|
|
360
|
-
handshakingSession,
|
|
361
|
-
from,
|
|
362
|
-
"rejected by handshake handler",
|
|
363
|
-
"REJECTED_BY_CUSTOM_HANDLER",
|
|
364
|
-
{
|
|
365
|
-
...handshakingSession.loggingMetadata,
|
|
366
|
-
connectedTo: from,
|
|
367
|
-
clientId: this.clientId
|
|
368
|
-
}
|
|
369
|
-
);
|
|
370
|
-
return false;
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
return parsedMetadata;
|
|
374
|
-
}
|
|
375
386
|
};
|
|
376
387
|
|
|
377
388
|
export {
|
|
378
389
|
ServerTransport
|
|
379
390
|
};
|
|
380
|
-
//# sourceMappingURL=chunk-
|
|
391
|
+
//# sourceMappingURL=chunk-XV5WUEIR.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 HandshakeErrorCustomHandlerFatalResponseCodes,\n HandshakeErrorResponseCodes,\n OpaqueTransportMessage,\n acceptedProtocolVersions,\n PartialTransportMessage,\n TransportClientId,\n handshakeResponseMessage,\n currentProtocolVersion,\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 { SessionState } from './sessionStateMachine/common';\nimport {\n ServerSession,\n ServerSessionStateGraph,\n} 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\n sessions = new Map<TransportClientId, ServerSession<ConnType>>();\n pendingSessions = new Set<SessionWaitingForHandshake<ConnType>>();\n\n constructor(\n clientId: TransportClientId,\n providedOptions?: ProvidedServerTransportOptions,\n ) {\n super(clientId, providedOptions);\n this.sessions = new Map();\n this.options = {\n ...defaultServerTransportOptions,\n ...providedOptions,\n };\n this.log?.info(`initiated server transport`, {\n clientId: this.clientId,\n protocolVersion: currentProtocolVersion,\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: ServerSession<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 = ServerSessionStateGraph.entrypoint(\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, code) => {\n this.log?.error(\n `invalid handshake: ${reason}`,\n pendingSession.loggingMetadata,\n );\n this.deletePendingSession(pendingSession);\n this.protocolError({\n type: ProtocolError.HandshakeFailed,\n code,\n message: reason,\n });\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({\n type: ProtocolError.HandshakeFailed,\n code,\n message: reason,\n });\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 (!acceptedProtocolVersions.includes(gotVersion)) {\n this.rejectHandshakeRequest(\n session,\n msg.from,\n `expected protocol version oneof [${acceptedProtocolVersions.toString()}], 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 let parsedMetadata: ParsedMetadata = {};\n if (this.handshakeExtensions) {\n if (!Value.Check(this.handshakeExtensions.schema, msg.payload.metadata)) {\n this.rejectHandshakeRequest(\n session,\n msg.from,\n 'received malformed handshake metadata',\n 'MALFORMED_HANDSHAKE_META',\n {\n ...session.loggingMetadata,\n connectedTo: msg.from,\n validationErrors: [\n ...Value.Errors(\n this.handshakeExtensions.schema,\n msg.payload.metadata,\n ),\n ],\n },\n );\n\n return;\n }\n\n const previousParsedMetadata = oldSession\n ? this.sessionHandshakeMetadata.get(oldSession.to)\n : undefined;\n\n const parsedMetadataOrFailureCode =\n await this.handshakeExtensions.validate(\n msg.payload.metadata,\n previousParsedMetadata,\n );\n\n // double-check to make sure we haven't transitioned the session yet\n if (session._isConsumed) {\n // bail out, don't need to do anything\n return;\n }\n\n // handler rejected the connection\n if (\n Value.Check(\n HandshakeErrorCustomHandlerFatalResponseCodes,\n parsedMetadataOrFailureCode,\n )\n ) {\n this.rejectHandshakeRequest(\n session,\n msg.from,\n 'rejected by handshake handler',\n parsedMetadataOrFailureCode,\n {\n ...session.loggingMetadata,\n connectedTo: msg.from,\n clientId: this.clientId,\n },\n );\n\n return;\n }\n\n // success!\n parsedMetadata = parsedMetadataOrFailureCode;\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 const clientNextExpectedSeq =\n msg.payload.expectedSessionState.nextExpectedSeq;\n const clientNextSentSeq = msg.payload.expectedSessionState.nextSentSeq ?? 0;\n\n if (\n this.options.enableTransparentSessionReconnects &&\n oldSession &&\n oldSession.id === msg.payload.sessionId\n ) {\n connectCase = 'transparent reconnection';\n\n // invariant: ordering must be correct\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.NoConnection) {\n const noConnectionSession =\n ServerSessionStateGraph.transition.ConnectedToNoConnection(\n oldSession,\n {\n onSessionGracePeriodElapsed: () => {\n this.onSessionGracePeriodElapsed(noConnectionSession);\n },\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.log?.info(\n `client is reconnecting to a new session (${msg.payload.sessionId}) with an old session (${oldSession.id}) already existing, closing old session`,\n {\n ...session.loggingMetadata,\n connectedTo: msg.from,\n sessionId: msg.payload.sessionId,\n },\n );\n this.deleteSession(oldSession);\n oldSession = undefined;\n }\n\n if (!oldSession && (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 connectCase = 'unknown session';\n\n const rejectionMessage = this.options.enableTransparentSessionReconnects\n ? `client is trying to reconnect to a session the server don't know about: ${msg.payload.sessionId}`\n : `client is attempting a transparent reconnect to a session but the server does not support it: ${msg.payload.sessionId}`;\n\n this.rejectHandshakeRequest(\n session,\n msg.from,\n rejectionMessage,\n 'SESSION_STATE_MISMATCH',\n {\n ...session.loggingMetadata,\n connectedTo: msg.from,\n transportMessage: msg,\n },\n );\n return;\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\n const responseMsg = handshakeResponseMessage({\n from: this.clientId,\n to: msg.from,\n status: {\n ok: true,\n sessionId,\n },\n });\n\n session.sendHandshake(responseMsg);\n\n // transition\n const connectedSession =\n ServerSessionStateGraph.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({\n type: ProtocolError.MessageOrderingViolated,\n message: reason,\n });\n this.deleteSession(connectedSession);\n },\n },\n gotVersion,\n );\n\n this.sessionHandshakeMetadata.set(connectedSession.to, parsedMetadata);\n this.updateSession(connectedSession);\n this.pendingSessions.delete(session);\n connectedSession.startActiveHeartbeat();\n }\n}\n"],"mappings":"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","names":["msg"]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
createSessionTelemetryInfo,
|
|
4
4
|
generateId,
|
|
5
5
|
isAck
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-3ROTSXAO.js";
|
|
7
7
|
import {
|
|
8
8
|
NaiveJsonCodec
|
|
9
9
|
} from "./chunk-4PVU7J25.js";
|
|
@@ -15,6 +15,7 @@ var defaultTransportOptions = {
|
|
|
15
15
|
sessionDisconnectGraceMs: 5e3,
|
|
16
16
|
connectionTimeoutMs: 2e3,
|
|
17
17
|
handshakeTimeoutMs: 1e3,
|
|
18
|
+
enableTransparentSessionReconnects: true,
|
|
18
19
|
codec: NaiveJsonCodec
|
|
19
20
|
};
|
|
20
21
|
var defaultConnectionRetryOptions = {
|
|
@@ -68,6 +69,7 @@ var StateMachineState = class {
|
|
|
68
69
|
}
|
|
69
70
|
if (prop === "_handleClose") {
|
|
70
71
|
return () => {
|
|
72
|
+
target._isConsumed = true;
|
|
71
73
|
target._handleStateExit();
|
|
72
74
|
target._handleClose();
|
|
73
75
|
};
|
|
@@ -150,15 +152,18 @@ var IdentifiedSession = class extends CommonSession {
|
|
|
150
152
|
}
|
|
151
153
|
get loggingMetadata() {
|
|
152
154
|
const spanContext = this.telemetry.span.spanContext();
|
|
153
|
-
|
|
155
|
+
const metadata = {
|
|
154
156
|
clientId: this.from,
|
|
155
157
|
connectedTo: this.to,
|
|
156
|
-
sessionId: this.id
|
|
157
|
-
|
|
158
|
+
sessionId: this.id
|
|
159
|
+
};
|
|
160
|
+
if (this.telemetry.span.isRecording()) {
|
|
161
|
+
metadata.telemetry = {
|
|
158
162
|
traceId: spanContext.traceId,
|
|
159
163
|
spanId: spanContext.spanId
|
|
160
|
-
}
|
|
161
|
-
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
return metadata;
|
|
162
167
|
}
|
|
163
168
|
constructMsg(partialMsg) {
|
|
164
169
|
const msg = {
|
|
@@ -187,9 +192,32 @@ var IdentifiedSession = class extends CommonSession {
|
|
|
187
192
|
this.telemetry.span.end();
|
|
188
193
|
}
|
|
189
194
|
};
|
|
195
|
+
var IdentifiedSessionWithGracePeriod = class extends IdentifiedSession {
|
|
196
|
+
graceExpiryTime;
|
|
197
|
+
gracePeriodTimeout;
|
|
198
|
+
listeners;
|
|
199
|
+
constructor(props) {
|
|
200
|
+
super(props);
|
|
201
|
+
this.listeners = props.listeners;
|
|
202
|
+
this.graceExpiryTime = props.graceExpiryTime;
|
|
203
|
+
this.gracePeriodTimeout = setTimeout(() => {
|
|
204
|
+
this.listeners.onSessionGracePeriodElapsed();
|
|
205
|
+
}, this.graceExpiryTime - Date.now());
|
|
206
|
+
}
|
|
207
|
+
_handleStateExit() {
|
|
208
|
+
super._handleStateExit();
|
|
209
|
+
if (this.gracePeriodTimeout) {
|
|
210
|
+
clearTimeout(this.gracePeriodTimeout);
|
|
211
|
+
this.gracePeriodTimeout = void 0;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
_handleClose() {
|
|
215
|
+
super._handleClose();
|
|
216
|
+
}
|
|
217
|
+
};
|
|
190
218
|
|
|
191
219
|
// transport/sessionStateMachine/SessionConnecting.ts
|
|
192
|
-
var SessionConnecting = class extends
|
|
220
|
+
var SessionConnecting = class extends IdentifiedSessionWithGracePeriod {
|
|
193
221
|
state = "Connecting" /* Connecting */;
|
|
194
222
|
connPromise;
|
|
195
223
|
listeners;
|
|
@@ -198,9 +226,6 @@ var SessionConnecting = class extends IdentifiedSession {
|
|
|
198
226
|
super(props);
|
|
199
227
|
this.connPromise = props.connPromise;
|
|
200
228
|
this.listeners = props.listeners;
|
|
201
|
-
this.connectionTimeout = setTimeout(() => {
|
|
202
|
-
this.listeners.onConnectionTimeout();
|
|
203
|
-
}, this.options.connectionTimeoutMs);
|
|
204
229
|
this.connPromise.then(
|
|
205
230
|
(conn) => {
|
|
206
231
|
if (this._isConsumed)
|
|
@@ -213,17 +238,33 @@ var SessionConnecting = class extends IdentifiedSession {
|
|
|
213
238
|
this.listeners.onConnectionFailed(err);
|
|
214
239
|
}
|
|
215
240
|
);
|
|
241
|
+
this.connectionTimeout = setTimeout(() => {
|
|
242
|
+
this.listeners.onConnectionTimeout();
|
|
243
|
+
}, this.options.connectionTimeoutMs);
|
|
216
244
|
}
|
|
217
245
|
// close a pending connection if it resolves, ignore errors if the promise
|
|
218
246
|
// ends up rejected anyways
|
|
219
247
|
bestEffortClose() {
|
|
220
|
-
|
|
248
|
+
const logger = this.log;
|
|
249
|
+
const metadata = this.loggingMetadata;
|
|
250
|
+
this.connPromise.then((conn) => {
|
|
251
|
+
conn.close();
|
|
252
|
+
logger?.info(
|
|
253
|
+
"connection eventually resolved but session has transitioned, closed connection",
|
|
254
|
+
{
|
|
255
|
+
...metadata,
|
|
256
|
+
...conn.loggingMetadata
|
|
257
|
+
}
|
|
258
|
+
);
|
|
259
|
+
}).catch(() => {
|
|
221
260
|
});
|
|
222
261
|
}
|
|
223
262
|
_handleStateExit() {
|
|
224
263
|
super._handleStateExit();
|
|
225
|
-
|
|
226
|
-
|
|
264
|
+
if (this.connectionTimeout) {
|
|
265
|
+
clearTimeout(this.connectionTimeout);
|
|
266
|
+
this.connectionTimeout = void 0;
|
|
267
|
+
}
|
|
227
268
|
}
|
|
228
269
|
_handleClose() {
|
|
229
270
|
this.bestEffortClose();
|
|
@@ -232,26 +273,13 @@ var SessionConnecting = class extends IdentifiedSession {
|
|
|
232
273
|
};
|
|
233
274
|
|
|
234
275
|
// transport/sessionStateMachine/SessionNoConnection.ts
|
|
235
|
-
var SessionNoConnection = class extends
|
|
276
|
+
var SessionNoConnection = class extends IdentifiedSessionWithGracePeriod {
|
|
236
277
|
state = "NoConnection" /* NoConnection */;
|
|
237
|
-
listeners;
|
|
238
|
-
gracePeriodTimeout;
|
|
239
|
-
constructor(props) {
|
|
240
|
-
super(props);
|
|
241
|
-
this.listeners = props.listeners;
|
|
242
|
-
this.gracePeriodTimeout = setTimeout(() => {
|
|
243
|
-
this.listeners.onSessionGracePeriodElapsed();
|
|
244
|
-
}, this.options.sessionDisconnectGraceMs);
|
|
245
|
-
}
|
|
246
278
|
_handleClose() {
|
|
247
279
|
super._handleClose();
|
|
248
280
|
}
|
|
249
281
|
_handleStateExit() {
|
|
250
282
|
super._handleStateExit();
|
|
251
|
-
if (this.gracePeriodTimeout) {
|
|
252
|
-
clearTimeout(this.gracePeriodTimeout);
|
|
253
|
-
this.gracePeriodTimeout = void 0;
|
|
254
|
-
}
|
|
255
283
|
}
|
|
256
284
|
};
|
|
257
285
|
|
|
@@ -272,20 +300,24 @@ var SessionWaitingForHandshake = class extends CommonSession {
|
|
|
272
300
|
this.conn.addErrorListener(this.listeners.onConnectionErrored);
|
|
273
301
|
this.conn.addCloseListener(this.listeners.onConnectionClosed);
|
|
274
302
|
}
|
|
303
|
+
get loggingMetadata() {
|
|
304
|
+
return {
|
|
305
|
+
clientId: this.from,
|
|
306
|
+
connId: this.conn.id,
|
|
307
|
+
...this.conn.loggingMetadata
|
|
308
|
+
};
|
|
309
|
+
}
|
|
275
310
|
onHandshakeData = (msg) => {
|
|
276
311
|
const parsedMsg = this.parseMsg(msg);
|
|
277
312
|
if (parsedMsg === null) {
|
|
278
|
-
this.listeners.onInvalidHandshake(
|
|
313
|
+
this.listeners.onInvalidHandshake(
|
|
314
|
+
"could not parse message",
|
|
315
|
+
"MALFORMED_HANDSHAKE"
|
|
316
|
+
);
|
|
279
317
|
return;
|
|
280
318
|
}
|
|
281
319
|
this.listeners.onHandshake(parsedMsg);
|
|
282
320
|
};
|
|
283
|
-
get loggingMetadata() {
|
|
284
|
-
return {
|
|
285
|
-
clientId: this.from,
|
|
286
|
-
connId: this.conn.id
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
321
|
sendHandshake(msg) {
|
|
290
322
|
return this.conn.send(this.options.codec.toBuffer(msg));
|
|
291
323
|
}
|
|
@@ -302,7 +334,7 @@ var SessionWaitingForHandshake = class extends CommonSession {
|
|
|
302
334
|
};
|
|
303
335
|
|
|
304
336
|
// transport/sessionStateMachine/SessionHandshaking.ts
|
|
305
|
-
var SessionHandshaking = class extends
|
|
337
|
+
var SessionHandshaking = class extends IdentifiedSessionWithGracePeriod {
|
|
306
338
|
state = "Handshaking" /* Handshaking */;
|
|
307
339
|
conn;
|
|
308
340
|
listeners;
|
|
@@ -318,10 +350,19 @@ var SessionHandshaking = class extends IdentifiedSession {
|
|
|
318
350
|
this.conn.addErrorListener(this.listeners.onConnectionErrored);
|
|
319
351
|
this.conn.addCloseListener(this.listeners.onConnectionClosed);
|
|
320
352
|
}
|
|
353
|
+
get loggingMetadata() {
|
|
354
|
+
return {
|
|
355
|
+
...super.loggingMetadata,
|
|
356
|
+
...this.conn.loggingMetadata
|
|
357
|
+
};
|
|
358
|
+
}
|
|
321
359
|
onHandshakeData = (msg) => {
|
|
322
360
|
const parsedMsg = this.parseMsg(msg);
|
|
323
361
|
if (parsedMsg === null) {
|
|
324
|
-
this.listeners.onInvalidHandshake(
|
|
362
|
+
this.listeners.onInvalidHandshake(
|
|
363
|
+
"could not parse message",
|
|
364
|
+
"MALFORMED_HANDSHAKE"
|
|
365
|
+
);
|
|
325
366
|
return;
|
|
326
367
|
}
|
|
327
368
|
this.listeners.onHandshake(parsedMsg);
|
|
@@ -334,7 +375,10 @@ var SessionHandshaking = class extends IdentifiedSession {
|
|
|
334
375
|
this.conn.removeDataListener(this.onHandshakeData);
|
|
335
376
|
this.conn.removeErrorListener(this.listeners.onConnectionErrored);
|
|
336
377
|
this.conn.removeCloseListener(this.listeners.onConnectionClosed);
|
|
337
|
-
|
|
378
|
+
if (this.handshakeTimeout) {
|
|
379
|
+
clearTimeout(this.handshakeTimeout);
|
|
380
|
+
this.handshakeTimeout = void 0;
|
|
381
|
+
}
|
|
338
382
|
}
|
|
339
383
|
_handleClose() {
|
|
340
384
|
super._handleClose();
|
|
@@ -399,6 +443,12 @@ var SessionConnected = class extends IdentifiedSession {
|
|
|
399
443
|
this.heartbeatMisses++;
|
|
400
444
|
}, this.options.heartbeatIntervalMs);
|
|
401
445
|
}
|
|
446
|
+
get loggingMetadata() {
|
|
447
|
+
return {
|
|
448
|
+
...super.loggingMetadata,
|
|
449
|
+
...this.conn.loggingMetadata
|
|
450
|
+
};
|
|
451
|
+
}
|
|
402
452
|
startActiveHeartbeat() {
|
|
403
453
|
this.isActivelyHeartbeating = true;
|
|
404
454
|
}
|
|
@@ -414,8 +464,10 @@ var SessionConnected = class extends IdentifiedSession {
|
|
|
414
464
|
}
|
|
415
465
|
onMessageData = (msg) => {
|
|
416
466
|
const parsedMsg = this.parseMsg(msg);
|
|
417
|
-
if (parsedMsg === null)
|
|
467
|
+
if (parsedMsg === null) {
|
|
468
|
+
this.listeners.onInvalidMessage("could not parse message");
|
|
418
469
|
return;
|
|
470
|
+
}
|
|
419
471
|
if (parsedMsg.seq !== this.ack) {
|
|
420
472
|
if (parsedMsg.seq < this.ack) {
|
|
421
473
|
this.log?.debug(
|
|
@@ -472,7 +524,7 @@ var SessionConnected = class extends IdentifiedSession {
|
|
|
472
524
|
};
|
|
473
525
|
|
|
474
526
|
// transport/sessionStateMachine/SessionBackingOff.ts
|
|
475
|
-
var SessionBackingOff = class extends
|
|
527
|
+
var SessionBackingOff = class extends IdentifiedSessionWithGracePeriod {
|
|
476
528
|
state = "BackingOff" /* BackingOff */;
|
|
477
529
|
listeners;
|
|
478
530
|
backoffTimeout;
|
|
@@ -510,6 +562,12 @@ function inheritSharedSession(session) {
|
|
|
510
562
|
protocolVersion: session.protocolVersion
|
|
511
563
|
};
|
|
512
564
|
}
|
|
565
|
+
function inheritSharedSessionWithGrace(session) {
|
|
566
|
+
return {
|
|
567
|
+
...inheritSharedSession(session),
|
|
568
|
+
graceExpiryTime: session.graceExpiryTime
|
|
569
|
+
};
|
|
570
|
+
}
|
|
513
571
|
var SessionStateGraph = {
|
|
514
572
|
entrypoints: {
|
|
515
573
|
NoConnection: (to, from, listeners, options, protocolVersion, log) => {
|
|
@@ -523,6 +581,7 @@ var SessionStateGraph = {
|
|
|
523
581
|
to,
|
|
524
582
|
seq: 0,
|
|
525
583
|
ack: 0,
|
|
584
|
+
graceExpiryTime: Date.now() + options.sessionDisconnectGraceMs,
|
|
526
585
|
sendBuffer,
|
|
527
586
|
telemetry,
|
|
528
587
|
options,
|
|
@@ -555,7 +614,7 @@ var SessionStateGraph = {
|
|
|
555
614
|
transition: {
|
|
556
615
|
// happy path transitions
|
|
557
616
|
NoConnectionToBackingOff: (oldSession, backoffMs, listeners) => {
|
|
558
|
-
const carriedState =
|
|
617
|
+
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
559
618
|
oldSession._handleStateExit();
|
|
560
619
|
const session = new SessionBackingOff({
|
|
561
620
|
backoffMs,
|
|
@@ -572,7 +631,7 @@ var SessionStateGraph = {
|
|
|
572
631
|
return session;
|
|
573
632
|
},
|
|
574
633
|
BackingOffToConnecting: (oldSession, connPromise, listeners) => {
|
|
575
|
-
const carriedState =
|
|
634
|
+
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
576
635
|
oldSession._handleStateExit();
|
|
577
636
|
const session = new SessionConnecting({
|
|
578
637
|
connPromise,
|
|
@@ -589,7 +648,7 @@ var SessionStateGraph = {
|
|
|
589
648
|
return session;
|
|
590
649
|
},
|
|
591
650
|
ConnectingToHandshaking: (oldSession, conn, listeners) => {
|
|
592
|
-
const carriedState =
|
|
651
|
+
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
593
652
|
oldSession._handleStateExit();
|
|
594
653
|
const session = new SessionHandshaking({
|
|
595
654
|
conn,
|
|
@@ -667,9 +726,12 @@ var SessionStateGraph = {
|
|
|
667
726
|
},
|
|
668
727
|
// disconnect paths
|
|
669
728
|
BackingOffToNoConnection: (oldSession, listeners) => {
|
|
670
|
-
const carriedState =
|
|
729
|
+
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
671
730
|
oldSession._handleStateExit();
|
|
672
|
-
const session = new SessionNoConnection({
|
|
731
|
+
const session = new SessionNoConnection({
|
|
732
|
+
listeners,
|
|
733
|
+
...carriedState
|
|
734
|
+
});
|
|
673
735
|
session.log?.info(
|
|
674
736
|
`session ${session.id} transition from BackingOff to NoConnection`,
|
|
675
737
|
{
|
|
@@ -680,10 +742,13 @@ var SessionStateGraph = {
|
|
|
680
742
|
return session;
|
|
681
743
|
},
|
|
682
744
|
ConnectingToNoConnection: (oldSession, listeners) => {
|
|
683
|
-
const carriedState =
|
|
745
|
+
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
684
746
|
oldSession.bestEffortClose();
|
|
685
747
|
oldSession._handleStateExit();
|
|
686
|
-
const session = new SessionNoConnection({
|
|
748
|
+
const session = new SessionNoConnection({
|
|
749
|
+
listeners,
|
|
750
|
+
...carriedState
|
|
751
|
+
});
|
|
687
752
|
session.log?.info(
|
|
688
753
|
`session ${session.id} transition from Connecting to NoConnection`,
|
|
689
754
|
{
|
|
@@ -694,10 +759,13 @@ var SessionStateGraph = {
|
|
|
694
759
|
return session;
|
|
695
760
|
},
|
|
696
761
|
HandshakingToNoConnection: (oldSession, listeners) => {
|
|
697
|
-
const carriedState =
|
|
762
|
+
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
698
763
|
oldSession.conn.close();
|
|
699
764
|
oldSession._handleStateExit();
|
|
700
|
-
const session = new SessionNoConnection({
|
|
765
|
+
const session = new SessionNoConnection({
|
|
766
|
+
listeners,
|
|
767
|
+
...carriedState
|
|
768
|
+
});
|
|
701
769
|
session.log?.info(
|
|
702
770
|
`session ${session.id} transition from Handshaking to NoConnection`,
|
|
703
771
|
{
|
|
@@ -709,9 +777,14 @@ var SessionStateGraph = {
|
|
|
709
777
|
},
|
|
710
778
|
ConnectedToNoConnection: (oldSession, listeners) => {
|
|
711
779
|
const carriedState = inheritSharedSession(oldSession);
|
|
780
|
+
const graceExpiryTime = Date.now() + oldSession.options.sessionDisconnectGraceMs;
|
|
712
781
|
oldSession.conn.close();
|
|
713
782
|
oldSession._handleStateExit();
|
|
714
|
-
const session = new SessionNoConnection({
|
|
783
|
+
const session = new SessionNoConnection({
|
|
784
|
+
listeners,
|
|
785
|
+
graceExpiryTime,
|
|
786
|
+
...carriedState
|
|
787
|
+
});
|
|
715
788
|
session.log?.info(
|
|
716
789
|
`session ${session.id} transition from Connected to NoConnection`,
|
|
717
790
|
{
|
|
@@ -728,24 +801,42 @@ var ClientSessionStateGraph = {
|
|
|
728
801
|
entrypoint: SessionStateGraph.entrypoints.NoConnection,
|
|
729
802
|
transition: {
|
|
730
803
|
// happy paths
|
|
804
|
+
// NoConnection -> BackingOff: attempt to connect
|
|
731
805
|
NoConnectionToBackingOff: transitions.NoConnectionToBackingOff,
|
|
806
|
+
// BackingOff -> Connecting: backoff period elapsed, start connection
|
|
732
807
|
BackingOffToConnecting: transitions.BackingOffToConnecting,
|
|
808
|
+
// Connecting -> Handshaking: connection established, start handshake
|
|
733
809
|
ConnectingToHandshaking: transitions.ConnectingToHandshaking,
|
|
810
|
+
// Handshaking -> Connected: handshake complete, session ready
|
|
734
811
|
HandshakingToConnected: transitions.HandshakingToConnected,
|
|
735
812
|
// disconnect paths
|
|
813
|
+
// BackingOff -> NoConnection: unused
|
|
736
814
|
BackingOffToNoConnection: transitions.BackingOffToNoConnection,
|
|
815
|
+
// Connecting -> NoConnection: connection failed or connection timeout
|
|
737
816
|
ConnectingToNoConnection: transitions.ConnectingToNoConnection,
|
|
817
|
+
// Handshaking -> NoConnection: connection closed or handshake timeout
|
|
738
818
|
HandshakingToNoConnection: transitions.HandshakingToNoConnection,
|
|
819
|
+
// Connected -> NoConnection: connection closed
|
|
739
820
|
ConnectedToNoConnection: transitions.ConnectedToNoConnection
|
|
821
|
+
// destroy/close paths
|
|
822
|
+
// NoConnection -> x: grace period elapsed
|
|
823
|
+
// BackingOff -> x: grace period elapsed
|
|
824
|
+
// Connecting -> x: grace period elapsed
|
|
825
|
+
// Handshaking -> x: grace period elapsed or invalid handshake message or handshake rejection
|
|
826
|
+
// Connected -> x: grace period elapsed or invalid message
|
|
740
827
|
}
|
|
741
828
|
};
|
|
742
829
|
var ServerSessionStateGraph = {
|
|
743
830
|
entrypoint: SessionStateGraph.entrypoints.WaitingForHandshake,
|
|
744
831
|
transition: {
|
|
745
832
|
// happy paths
|
|
833
|
+
// WaitingForHandshake -> Connected: handshake complete, session ready
|
|
746
834
|
WaitingForHandshakeToConnected: transitions.WaitingForHandshakeToConnected,
|
|
747
835
|
// disconnect paths
|
|
836
|
+
// Connected -> NoConnection: connection closed
|
|
748
837
|
ConnectedToNoConnection: transitions.ConnectedToNoConnection
|
|
838
|
+
// destroy/close paths
|
|
839
|
+
// WaitingForHandshake -> x: handshake timeout elapsed or invalid handshake message or handshake rejection or connection closed
|
|
749
840
|
}
|
|
750
841
|
};
|
|
751
842
|
|
|
@@ -758,4 +849,4 @@ export {
|
|
|
758
849
|
ClientSessionStateGraph,
|
|
759
850
|
ServerSessionStateGraph
|
|
760
851
|
};
|
|
761
|
-
//# sourceMappingURL=chunk-
|
|
852
|
+
//# sourceMappingURL=chunk-Y3JHOIJ7.js.map
|