@replit/river 0.24.1 → 0.24.3
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-IYYQ7BII.js → chunk-DZNP3EI5.js} +2 -2
- package/dist/{chunk-IYYQ7BII.js.map → chunk-DZNP3EI5.js.map} +1 -1
- package/dist/{chunk-BGJDNLTJ.js → chunk-EHXKU4TW.js} +2 -2
- package/dist/{chunk-6YFPHVNO.js → chunk-FKBXIWWN.js} +3 -3
- package/dist/{chunk-227EQHH5.js → chunk-KVLCQ24J.js} +2 -2
- package/dist/{chunk-M7E6LQO2.js → chunk-LSHUPI6U.js} +32 -16
- package/dist/{chunk-M7E6LQO2.js.map → chunk-LSHUPI6U.js.map} +1 -1
- package/dist/{chunk-L664A3WA.js → chunk-TDFWZIXR.js} +4 -10
- package/dist/chunk-TDFWZIXR.js.map +1 -0
- package/dist/{chunk-HXOQQXL4.js → chunk-W3CY6PNC.js} +4 -4
- package/dist/{chunk-XOFF3UPL.js → chunk-XKHLA5MP.js} +4 -4
- package/dist/router/index.cjs +31 -15
- package/dist/router/index.cjs.map +1 -1
- package/dist/router/index.d.cts +1 -1
- package/dist/router/index.d.ts +1 -1
- package/dist/router/index.js +2 -2
- package/dist/transport/impls/uds/client.cjs +3 -9
- package/dist/transport/impls/uds/client.cjs.map +1 -1
- package/dist/transport/impls/uds/client.js +5 -5
- package/dist/transport/impls/uds/server.cjs +3 -9
- package/dist/transport/impls/uds/server.cjs.map +1 -1
- package/dist/transport/impls/uds/server.js +5 -5
- package/dist/transport/impls/ws/client.cjs +1 -1
- package/dist/transport/impls/ws/client.cjs.map +1 -1
- package/dist/transport/impls/ws/client.js +5 -5
- package/dist/transport/impls/ws/server.cjs +1 -1
- package/dist/transport/impls/ws/server.cjs.map +1 -1
- package/dist/transport/impls/ws/server.js +5 -5
- package/dist/transport/index.cjs +1 -1
- package/dist/transport/index.cjs.map +1 -1
- package/dist/transport/index.js +5 -5
- package/dist/util/testHelpers.cjs +1 -1
- package/dist/util/testHelpers.cjs.map +1 -1
- package/dist/util/testHelpers.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-L664A3WA.js.map +0 -1
- /package/dist/{chunk-BGJDNLTJ.js.map → chunk-EHXKU4TW.js.map} +0 -0
- /package/dist/{chunk-6YFPHVNO.js.map → chunk-FKBXIWWN.js.map} +0 -0
- /package/dist/{chunk-227EQHH5.js.map → chunk-KVLCQ24J.js.map} +0 -0
- /package/dist/{chunk-HXOQQXL4.js.map → chunk-W3CY6PNC.js.map} +0 -0
- /package/dist/{chunk-XOFF3UPL.js.map → chunk-XKHLA5MP.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../transport/impls/ws/server.ts","../../../../transport/id.ts","../../../../transport/connection.ts","../../../../transport/impls/ws/connection.ts","../../../../transport/server.ts","../../../../transport/message.ts","../../../../codec/json.ts","../../../../transport/options.ts","../../../../logging/log.ts","../../../../transport/events.ts","../../../../transport/sessionStateMachine/common.ts","../../../../transport/sessionStateMachine/SessionConnecting.ts","../../../../transport/sessionStateMachine/SessionNoConnection.ts","../../../../tracing/index.ts","../../../../package.json","../../../../transport/sessionStateMachine/SessionWaitingForHandshake.ts","../../../../transport/sessionStateMachine/SessionHandshaking.ts","../../../../transport/sessionStateMachine/SessionConnected.ts","../../../../transport/sessionStateMachine/transitions.ts","../../../../transport/transport.ts","../../../../util/stringify.ts"],"sourcesContent":["import { TransportClientId } from '../../message';\nimport { WebSocketServer } from 'ws';\nimport { WebSocketConnection } from './connection';\nimport { WsLike } from './wslike';\nimport { ServerTransport } from '../../server';\nimport { ProvidedServerTransportOptions } from '../../options';\n\nexport class WebSocketServerTransport extends ServerTransport<WebSocketConnection> {\n wss: WebSocketServer;\n\n constructor(\n wss: WebSocketServer,\n clientId: TransportClientId,\n providedOptions?: ProvidedServerTransportOptions,\n ) {\n super(clientId, providedOptions);\n this.wss = wss;\n this.wss.on('connection', this.connectionHandler);\n }\n\n connectionHandler = (ws: WsLike) => {\n const conn = new WebSocketConnection(ws);\n this.handleConnection(conn);\n };\n\n close() {\n super.close();\n this.wss.off('connection', this.connectionHandler);\n }\n}\n","import { customAlphabet } from 'nanoid';\n\nconst alphabet = customAlphabet(\n '1234567890abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ',\n);\nexport const generateId = () => alphabet(12);\n","import { TelemetryInfo } from '../tracing';\nimport { MessageMetadata } from '../logging';\nimport { generateId } from './id';\n\n/**\n * A connection is the actual raw underlying transport connection.\n * It’s responsible for dispatching to/from the actual connection itself\n * This should be instantiated as soon as the client/server has a connection\n * It’s tied to the lifecycle of the underlying transport connection (i.e. if the WS drops, this connection should be deleted)\n */\nexport abstract class Connection {\n id: string;\n telemetry?: TelemetryInfo;\n constructor() {\n this.id = `conn-${generateId()}`; // for debugging, no collision safety needed\n }\n\n get loggingMetadata(): MessageMetadata {\n const metadata: MessageMetadata = { connId: this.id };\n const spanContext = this.telemetry?.span.spanContext();\n\n if (this.telemetry?.span.isRecording() && spanContext) {\n metadata.telemetry = {\n traceId: spanContext.traceId,\n spanId: spanContext.spanId,\n };\n }\n\n return metadata;\n }\n\n // can't use event emitter because we need this to work in both node + browser\n private _dataListeners = new Set<(msg: Uint8Array) => void>();\n private _closeListeners = new Set<() => void>();\n private _errorListeners = new Set<(err: Error) => void>();\n\n get dataListeners() {\n return [...this._dataListeners];\n }\n\n get closeListeners() {\n return [...this._closeListeners];\n }\n\n get errorListeners() {\n return [...this._errorListeners];\n }\n\n /**\n * Handle adding a callback for when a message is received.\n * @param msg The message that was received.\n */\n addDataListener(cb: (msg: Uint8Array) => void) {\n this._dataListeners.add(cb);\n }\n\n removeDataListener(cb: (msg: Uint8Array) => void): void {\n this._dataListeners.delete(cb);\n }\n\n /**\n * Handle adding a callback for when the connection is closed.\n * This should also be called if an error happens and after notifying all the error listeners.\n * @param cb The callback to call when the connection is closed.\n */\n addCloseListener(cb: () => void): void {\n this._closeListeners.add(cb);\n }\n\n removeCloseListener(cb: () => void): void {\n this._closeListeners.delete(cb);\n }\n\n /**\n * Handle adding a callback for when an error is received.\n * This should only be used for this.logging errors, all cleanup\n * should be delegated to addCloseListener.\n *\n * The implementer should take care such that the implemented\n * connection will call both the close and error callbacks\n * on an error.\n *\n * @param cb The callback to call when an error is received.\n */\n addErrorListener(cb: (err: Error) => void): void {\n this._errorListeners.add(cb);\n }\n\n removeErrorListener(cb: (err: Error) => void): void {\n this._errorListeners.delete(cb);\n }\n\n /**\n * Sends a message over the connection.\n * @param msg The message to send.\n * @returns true if the message was sent, false otherwise.\n */\n abstract send(msg: Uint8Array): boolean;\n\n /**\n * Closes the connection.\n */\n abstract close(): void;\n}\n","import { Connection } from '../../connection';\nimport { WsLike } from './wslike';\n\nexport class WebSocketConnection extends Connection {\n ws: WsLike;\n\n constructor(ws: WsLike) {\n super();\n this.ws = ws;\n this.ws.binaryType = 'arraybuffer';\n\n // Websockets are kinda shitty, they emit error events with no\n // information other than it errored, so we have to do some extra\n // work to figure out what happened.\n let didError = false;\n this.ws.onerror = () => {\n didError = true;\n };\n\n this.ws.onclose = ({ code, reason }) => {\n if (didError) {\n const err = new Error(\n `websocket closed with code and reason: ${code} - ${reason}`,\n );\n\n for (const cb of this.errorListeners) {\n cb(err);\n }\n }\n\n for (const cb of this.closeListeners) {\n cb();\n }\n };\n\n this.ws.onmessage = (msg) => {\n for (const cb of this.dataListeners) {\n cb(msg.data as Uint8Array);\n }\n };\n }\n\n send(payload: Uint8Array) {\n if (this.ws.readyState !== this.ws.OPEN) {\n return false;\n }\n this.ws.send(payload);\n return true;\n }\n\n close() {\n this.ws.close();\n }\n}\n","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","import { Type, TSchema, Static } from '@sinclair/typebox';\nimport { PropagationContext } from '../tracing';\nimport { generateId } from './id';\n\n/**\n * Control flags for transport messages.\n * An RPC message is coded with StreamOpenBit | StreamClosedBit.\n * Streams are expected to start with StreamOpenBit sent and the client SHOULD send an empty\n * message with StreamClosedBit to close the stream handler on the server, indicating that\n * it will not be using the stream anymore.\n */\nexport const enum ControlFlags {\n AckBit = 0b0001,\n StreamOpenBit = 0b0010,\n StreamClosedBit = 0b0100,\n}\n\n/**\n * Generic Typebox schema for a transport message.\n * @template T The type of the payload.\n * @param {T} t The payload schema.\n * @returns The transport message schema.\n */\nexport const TransportMessageSchema = <T extends TSchema>(t: T) =>\n Type.Object({\n id: Type.String(),\n from: Type.String(),\n to: Type.String(),\n seq: Type.Integer(),\n ack: Type.Integer(),\n serviceName: Type.Optional(Type.String()),\n procedureName: Type.Optional(Type.String()),\n streamId: Type.String(),\n controlFlags: Type.Integer(),\n tracing: Type.Optional(\n Type.Object({\n traceparent: Type.String(),\n tracestate: Type.String(),\n }),\n ),\n payload: t,\n });\n\n/**\n * Defines the schema for a transport acknowledgement message. This is never constructed manually\n * and is only used internally by the library for tracking inflight messages.\n * @returns The transport message schema.\n */\nexport const ControlMessageAckSchema = Type.Object({\n type: Type.Literal('ACK'),\n});\n\n/**\n * Defines the schema for a transport close message. This is never constructed manually and is only\n * used internally by the library for closing and cleaning up streams.\n */\nexport const ControlMessageCloseSchema = Type.Object({\n type: Type.Literal('CLOSE'),\n});\n\nexport const PROTOCOL_VERSION = 'v1.1';\nexport const ControlMessageHandshakeRequestSchema = Type.Object({\n type: Type.Literal('HANDSHAKE_REQ'),\n protocolVersion: Type.String(),\n sessionId: Type.String(),\n /**\n * Specifies what the server's expected session state (from the pov of the client). This can be\n * used by the server to know whether this is a new or a reestablished connection, and whether it\n * is compatible with what it already has.\n */\n expectedSessionState: Type.Object({\n // what the client expects the server to send next\n nextExpectedSeq: Type.Integer(),\n // TODO: remove optional once we know all servers\n // are nextSentSeq here\n // what the server expects the client to send next\n nextSentSeq: Type.Optional(Type.Integer()),\n }),\n\n metadata: Type.Optional(Type.Unknown()),\n});\n\nexport const HandshakeErrorRetriableResponseCodes = Type.Union([\n Type.Literal('SESSION_STATE_MISMATCH'),\n]);\n\nexport const HandshakeErrorFatalResponseCodes = Type.Union([\n Type.Literal('MALFORMED_HANDSHAKE_META'),\n Type.Literal('MALFORMED_HANDSHAKE'),\n Type.Literal('PROTOCOL_VERSION_MISMATCH'),\n Type.Literal('REJECTED_BY_CUSTOM_HANDLER'),\n]);\n\nexport const HandshakeErrorResponseCodes = Type.Union([\n HandshakeErrorRetriableResponseCodes,\n HandshakeErrorFatalResponseCodes,\n]);\n\nexport const ControlMessageHandshakeResponseSchema = Type.Object({\n type: Type.Literal('HANDSHAKE_RESP'),\n status: Type.Union([\n Type.Object({\n ok: Type.Literal(true),\n sessionId: Type.String(),\n }),\n Type.Object({\n ok: Type.Literal(false),\n reason: Type.String(),\n // TODO: remove optional once we know all servers\n // are sending code here\n code: Type.Optional(HandshakeErrorResponseCodes),\n }),\n ]),\n});\n\nexport const ControlMessagePayloadSchema = Type.Union([\n ControlMessageCloseSchema,\n ControlMessageAckSchema,\n ControlMessageHandshakeRequestSchema,\n ControlMessageHandshakeResponseSchema,\n]);\n\n/**\n * Defines the schema for an opaque transport message that is agnostic to any\n * procedure/service.\n * @returns The transport message schema.\n */\nexport const OpaqueTransportMessageSchema = TransportMessageSchema(\n Type.Unknown(),\n);\n\n/**\n * Represents a transport message. This is the same type as {@link TransportMessageSchema} but\n * we can't statically infer generics from generic Typebox schemas so we have to define it again here.\n *\n * TypeScript can't enforce types when a bitmask is involved, so these are the semantics of\n * `controlFlags`:\n * * If `controlFlags & StreamOpenBit == StreamOpenBit`, `streamId` must be set to a unique value\n * (suggestion: use `nanoid`).\n * * If `controlFlags & StreamOpenBit == StreamOpenBit`, `serviceName` and `procedureName` must be set.\n * * If `controlFlags & StreamClosedBit == StreamClosedBit` and the kind is `stream` or `subscription`,\n * `payload` should be discarded (usually contains a control message).\n * * If `controlFlags & AckBit == AckBit`, the message is an explicit acknowledgement message and doesn't\n * contain any payload that is relevant to the application so should not be delivered.\n * @template Payload The type of the payload.\n */\nexport interface TransportMessage<Payload = unknown> {\n id: string;\n from: string;\n to: string;\n seq: number;\n ack: number;\n serviceName?: string;\n procedureName?: string;\n streamId: string;\n controlFlags: number;\n tracing?: PropagationContext;\n payload: Payload;\n}\n\nexport type PartialTransportMessage<Payload = unknown> = Omit<\n TransportMessage<Payload>,\n 'id' | 'from' | 'to' | 'seq' | 'ack'\n>;\n\nexport function handshakeRequestMessage({\n from,\n to,\n sessionId,\n expectedSessionState,\n metadata,\n tracing,\n}: {\n from: TransportClientId;\n to: TransportClientId;\n sessionId: string;\n expectedSessionState: Static<\n typeof ControlMessageHandshakeRequestSchema\n >['expectedSessionState'];\n metadata?: unknown;\n tracing?: PropagationContext;\n}): TransportMessage<Static<typeof ControlMessageHandshakeRequestSchema>> {\n return {\n id: generateId(),\n from,\n to,\n seq: 0,\n ack: 0,\n streamId: generateId(),\n controlFlags: 0,\n tracing,\n payload: {\n type: 'HANDSHAKE_REQ',\n protocolVersion: PROTOCOL_VERSION,\n sessionId,\n expectedSessionState,\n metadata,\n } satisfies Static<typeof ControlMessageHandshakeRequestSchema>,\n };\n}\n\n/**\n * This is a reason that can be given during the handshake to indicate that the peer has the wrong\n * session state.\n */\nexport const SESSION_STATE_MISMATCH = 'session state mismatch';\n\nexport function handshakeResponseMessage({\n from,\n to,\n status,\n}: {\n from: TransportClientId;\n to: TransportClientId;\n status: Static<typeof ControlMessageHandshakeResponseSchema>['status'];\n}): TransportMessage<Static<typeof ControlMessageHandshakeResponseSchema>> {\n return {\n id: generateId(),\n from,\n to,\n seq: 0,\n ack: 0,\n streamId: generateId(),\n controlFlags: 0,\n payload: {\n type: 'HANDSHAKE_RESP',\n status,\n } satisfies Static<typeof ControlMessageHandshakeResponseSchema>,\n };\n}\n\nexport function closeStreamMessage(streamId: string): PartialTransportMessage {\n return {\n streamId,\n controlFlags: ControlFlags.StreamClosedBit,\n payload: {\n type: 'CLOSE' as const,\n } satisfies Static<typeof ControlMessagePayloadSchema>,\n };\n}\n\n/**\n * A type alias for a transport message with an opaque payload.\n * @template T - The type of the opaque payload.\n */\nexport type OpaqueTransportMessage = TransportMessage;\nexport type TransportClientId = string;\n\n/**\n * Checks if the given control flag (usually found in msg.controlFlag) is an ack message.\n * @param controlFlag - The control flag to check.\n * @returns True if the control flag contains the AckBit, false otherwise.\n */\nexport function isAck(controlFlag: number): boolean {\n /* eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison */\n return (controlFlag & ControlFlags.AckBit) === ControlFlags.AckBit;\n}\n\n/**\n * Checks if the given control flag (usually found in msg.controlFlag) is a stream open message.\n * @param controlFlag - The control flag to check.\n * @returns True if the control flag contains the StreamOpenBit, false otherwise.\n */\nexport function isStreamOpen(controlFlag: number): boolean {\n return (\n /* eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison */\n (controlFlag & ControlFlags.StreamOpenBit) === ControlFlags.StreamOpenBit\n );\n}\n\n/**\n * Checks if the given control flag (usually found in msg.controlFlag) is a stream close message.\n * @param controlFlag - The control flag to check.\n * @returns True if the control flag contains the StreamCloseBit, false otherwise.\n */\nexport function isStreamClose(controlFlag: number): boolean {\n return (\n /* eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison */\n (controlFlag & ControlFlags.StreamClosedBit) ===\n ControlFlags.StreamClosedBit\n );\n}\n","import { Codec } from './types';\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n// Convert Uint8Array to base64\nfunction uint8ArrayToBase64(uint8Array: Uint8Array) {\n let binary = '';\n uint8Array.forEach((byte) => {\n binary += String.fromCharCode(byte);\n });\n return btoa(binary);\n}\n\n// Convert base64 to Uint8Array\nfunction base64ToUint8Array(base64: string) {\n const binaryString = atob(base64);\n const uint8Array = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n uint8Array[i] = binaryString.charCodeAt(i);\n }\n return uint8Array;\n}\n\ninterface Base64EncodedValue {\n $t: string;\n}\n\n/**\n * Naive JSON codec implementation using JSON.stringify and JSON.parse.\n * @type {Codec}\n */\nexport const NaiveJsonCodec: Codec = {\n toBuffer: (obj: object) => {\n return encoder.encode(\n JSON.stringify(obj, function replacer<\n T extends object,\n >(this: T, key: keyof T) {\n const val = this[key];\n if (val instanceof Uint8Array) {\n return { $t: uint8ArrayToBase64(val) } satisfies Base64EncodedValue;\n } else {\n return val;\n }\n }),\n );\n },\n fromBuffer: (buff: Uint8Array) => {\n try {\n const parsed = JSON.parse(\n decoder.decode(buff),\n function reviver(_key, val: unknown) {\n if ((val as Base64EncodedValue | undefined)?.$t) {\n return base64ToUint8Array((val as Base64EncodedValue).$t);\n } else {\n return val;\n }\n },\n ) as unknown;\n\n if (typeof parsed === 'object') return parsed;\n return null;\n } catch {\n return null;\n }\n },\n};\n","import { NaiveJsonCodec } from '../codec/json';\nimport { ConnectionRetryOptions } from './rateLimit';\nimport { SessionOptions } from './sessionStateMachine/common';\n\nexport type TransportOptions = SessionOptions;\n\nexport type ProvidedTransportOptions = Partial<TransportOptions>;\n\nexport const defaultTransportOptions: TransportOptions = {\n heartbeatIntervalMs: 1_000,\n heartbeatsUntilDead: 2,\n sessionDisconnectGraceMs: 5_000,\n connectionTimeoutMs: 2_000,\n handshakeTimeoutMs: 1_000,\n codec: NaiveJsonCodec,\n};\n\nexport type ClientTransportOptions = TransportOptions & ConnectionRetryOptions;\n\nexport type ProvidedClientTransportOptions = Partial<ClientTransportOptions>;\n\nconst defaultConnectionRetryOptions: ConnectionRetryOptions = {\n baseIntervalMs: 250,\n maxJitterMs: 200,\n maxBackoffMs: 32_000,\n attemptBudgetCapacity: 5,\n budgetRestoreIntervalMs: 200,\n};\n\nexport const defaultClientTransportOptions: ClientTransportOptions = {\n ...defaultTransportOptions,\n ...defaultConnectionRetryOptions,\n};\n\nexport type ServerTransportOptions = TransportOptions;\n\nexport type ProvidedServerTransportOptions = Partial<ServerTransportOptions>;\n\nexport const defaultServerTransportOptions: ServerTransportOptions = {\n ...defaultTransportOptions,\n};\n","import { ValueError } from '@sinclair/typebox/value';\nimport { OpaqueTransportMessage } from '../transport/message';\n\nconst LoggingLevels = {\n debug: -1,\n info: 0,\n warn: 1,\n error: 2,\n} as const;\nexport type LoggingLevel = keyof typeof LoggingLevels;\n\nexport type LogFn = (\n msg: string,\n ctx?: MessageMetadata,\n level?: LoggingLevel,\n) => void;\nexport type Logger = {\n [key in LoggingLevel]: (msg: string, metadata?: MessageMetadata) => void;\n};\n\nexport type Tags = 'invariant-violation' | 'state-transition';\n\nconst cleanedLogFn = (log: LogFn) => {\n return (msg: string, metadata?: MessageMetadata) => {\n // skip cloning object if metadata has no transportMessage\n if (!metadata?.transportMessage) {\n log(msg, metadata);\n return;\n }\n\n // clone metadata and clean transportMessage\n const { payload, ...rest } = metadata.transportMessage;\n metadata.transportMessage = rest;\n log(msg, metadata);\n };\n};\n\nexport type MessageMetadata = Partial<{\n protocolVersion: string;\n clientId: string;\n connectedTo: string;\n sessionId: string;\n connId: string;\n transportMessage: Partial<OpaqueTransportMessage>;\n validationErrors: Array<ValueError>;\n tags: Array<Tags>;\n telemetry: {\n traceId: string;\n spanId: string;\n };\n}>;\n\nexport class BaseLogger implements Logger {\n minLevel: LoggingLevel;\n private output: LogFn;\n\n constructor(output: LogFn, minLevel: LoggingLevel = 'info') {\n this.minLevel = minLevel;\n this.output = output;\n }\n\n debug(msg: string, metadata?: MessageMetadata) {\n if (LoggingLevels[this.minLevel] <= LoggingLevels.debug) {\n this.output(msg, metadata ?? {}, 'debug');\n }\n }\n\n info(msg: string, metadata?: MessageMetadata) {\n if (LoggingLevels[this.minLevel] <= LoggingLevels.info) {\n this.output(msg, metadata ?? {}, 'info');\n }\n }\n\n warn(msg: string, metadata?: MessageMetadata) {\n if (LoggingLevels[this.minLevel] <= LoggingLevels.warn) {\n this.output(msg, metadata ?? {}, 'warn');\n }\n }\n\n error(msg: string, metadata?: MessageMetadata) {\n if (LoggingLevels[this.minLevel] <= LoggingLevels.error) {\n this.output(msg, metadata ?? {}, 'error');\n }\n }\n}\n\nexport const stringLogger: LogFn = (msg, ctx, level = 'info') => {\n const from = ctx?.clientId ? `${ctx.clientId} -- ` : '';\n console.log(`[river:${level}] ${from}${msg}`);\n};\n\nconst colorMap = {\n debug: '\\u001b[34m',\n info: '\\u001b[32m',\n warn: '\\u001b[33m',\n error: '\\u001b[31m',\n};\n\nexport const coloredStringLogger: LogFn = (msg, ctx, level = 'info') => {\n const color = colorMap[level];\n const from = ctx?.clientId ? `${ctx.clientId} -- ` : '';\n console.log(`[river:${color}${level}\\u001b[0m] ${from}${msg}`);\n};\n\nexport const jsonLogger: LogFn = (msg, ctx, level) => {\n console.log(JSON.stringify({ msg, ctx, level }));\n};\n\nexport const createLogProxy = (log: Logger) => ({\n debug: cleanedLogFn(log.debug.bind(log)),\n info: cleanedLogFn(log.info.bind(log)),\n warn: cleanedLogFn(log.warn.bind(log)),\n error: cleanedLogFn(log.error.bind(log)),\n});\n","import { Connection } from './connection';\nimport { OpaqueTransportMessage } from './message';\nimport { Session, SessionState } from './sessionStateMachine';\nimport { TransportStatus } from './transport';\n\nexport const ProtocolError = {\n RetriesExceeded: 'conn_retry_exceeded',\n HandshakeFailed: 'handshake_failed',\n MessageOrderingViolated: 'message_ordering_violated',\n} as const;\n\nexport type ProtocolErrorType =\n (typeof ProtocolError)[keyof typeof ProtocolError];\n\nexport interface EventMap {\n message: OpaqueTransportMessage;\n sessionStatus: {\n status: 'connect' | 'disconnect';\n session: Session<Connection>;\n };\n sessionTransition:\n | { state: SessionState.Connected }\n | { state: SessionState.Handshaking }\n | { state: SessionState.Connecting }\n | { state: SessionState.NoConnection };\n protocolError: {\n type: ProtocolErrorType;\n message: string;\n };\n transportStatus: {\n status: TransportStatus;\n };\n}\n\nexport type EventTypes = keyof EventMap;\nexport type EventHandler<K extends EventTypes> = (\n event: EventMap[K],\n) => unknown;\n\nexport class EventDispatcher<T extends EventTypes> {\n private eventListeners: { [K in T]?: Set<EventHandler<K>> } = {};\n\n removeAllListeners() {\n this.eventListeners = {};\n }\n\n numberOfListeners<K extends T>(eventType: K) {\n return this.eventListeners[eventType]?.size ?? 0;\n }\n\n addEventListener<K extends T>(eventType: K, handler: EventHandler<K>) {\n if (!this.eventListeners[eventType]) {\n this.eventListeners[eventType] = new Set();\n }\n\n this.eventListeners[eventType]?.add(handler);\n }\n\n removeEventListener<K extends T>(eventType: K, handler: EventHandler<K>) {\n const handlers = this.eventListeners[eventType];\n if (handlers) {\n this.eventListeners[eventType]?.delete(handler);\n }\n }\n\n dispatchEvent<K extends T>(eventType: K, event: EventMap[K]) {\n const handlers = this.eventListeners[eventType];\n if (handlers) {\n // copying ensures that adding more listeners in a handler doesn't\n // affect the current dispatch.\n const copy = [...handlers];\n for (const handler of copy) {\n handler(event);\n }\n }\n }\n}\n","import { Logger, MessageMetadata } from '../../logging';\nimport { TelemetryInfo } from '../../tracing';\nimport {\n OpaqueTransportMessage,\n OpaqueTransportMessageSchema,\n PartialTransportMessage,\n TransportClientId,\n TransportMessage,\n} from '../message';\nimport { Value } from '@sinclair/typebox/value';\nimport { SessionNoConnection } from './SessionNoConnection';\nimport { SessionConnecting } from './SessionConnecting';\nimport { SessionHandshaking } from './SessionHandshaking';\nimport { SessionConnected } from './SessionConnected';\nimport { Codec } from '../../codec';\nimport { Connection } from '../connection';\nimport { generateId } from '../id';\n\nexport const enum SessionState {\n NoConnection = 'NoConnection',\n Connecting = 'Connecting',\n Handshaking = 'Handshaking',\n Connected = 'Connected',\n WaitingForHandshake = 'WaitingForHandshake',\n}\n\nexport type Session<ConnType extends Connection> =\n | SessionNoConnection\n | SessionConnecting<ConnType>\n | SessionHandshaking<ConnType>\n | SessionConnected<ConnType>;\n\nexport const ERR_CONSUMED = `session state has been consumed and is no longer valid`;\n\nabstract class StateMachineState {\n abstract readonly state: SessionState;\n\n /*\n * Whether this state has been consumed\n * and we've moved on to another state\n */\n _isConsumed: boolean;\n\n // called when we're transitioning to another state\n // note that this is internal and should not be called directly\n // by consumers, the proxy will call this when the state is consumed\n // and we're transitioning to another state\n abstract _handleStateExit(): void;\n\n // called when we exit the state machine entirely\n // note that this is internal and should not be called directly\n // by consumers, the proxy will call this when .close is closed\n abstract _handleClose(): void;\n\n close(): void {\n this._handleClose();\n }\n\n constructor() {\n this._isConsumed = false;\n\n // proxy helps us prevent access to properties after the state has been consumed\n // e.g. if we hold a reference to a state and try to access it after it's been consumed\n // we intercept the access and throw an error to help catch bugs\n return new Proxy(this, {\n get(target, prop) {\n // always allow access to _isConsumed, id, and state\n if (prop === '_isConsumed' || prop === 'id' || prop === 'state') {\n return Reflect.get(target, prop);\n }\n\n // modify _handleStateExit\n if (prop === '_handleStateExit') {\n return () => {\n target._isConsumed = true;\n target._handleStateExit();\n };\n }\n\n // modify _handleClose\n if (prop === '_handleClose') {\n return () => {\n target._handleStateExit();\n target._handleClose();\n };\n }\n\n if (target._isConsumed) {\n throw new Error(\n `${ERR_CONSUMED}: getting ${prop.toString()} on consumed state`,\n );\n }\n\n return Reflect.get(target, prop);\n },\n set(target, prop, value) {\n if (target._isConsumed) {\n throw new Error(\n `${ERR_CONSUMED}: setting ${prop.toString()} on consumed state`,\n );\n }\n\n return Reflect.set(target, prop, value);\n },\n });\n }\n}\n\nexport interface SessionOptions {\n /**\n * Frequency at which to send heartbeat acknowledgements\n */\n heartbeatIntervalMs: number;\n /**\n * Number of elapsed heartbeats without a response message before we consider\n * the connection dead.\n */\n heartbeatsUntilDead: number;\n /**\n * Duration to wait between connection disconnect and actual session disconnect\n */\n sessionDisconnectGraceMs: number;\n /**\n * Connection timeout in milliseconds\n */\n connectionTimeoutMs: number;\n /**\n * Handshake timeout in milliseconds\n */\n handshakeTimeoutMs: number;\n /**\n * The codec to use for encoding/decoding messages over the wire\n */\n codec: Codec;\n}\n\n// all session states have a from and options\nexport abstract class CommonSession extends StateMachineState {\n readonly from: TransportClientId;\n readonly options: SessionOptions;\n\n log?: Logger;\n abstract get loggingMetadata(): MessageMetadata;\n\n constructor(\n from: TransportClientId,\n options: SessionOptions,\n log: Logger | undefined,\n ) {\n super();\n this.from = from;\n this.options = options;\n this.log = log;\n }\n\n parseMsg(msg: Uint8Array): OpaqueTransportMessage | null {\n const parsedMsg = this.options.codec.fromBuffer(msg);\n\n if (parsedMsg === null) {\n const decodedBuffer = new TextDecoder().decode(Buffer.from(msg));\n this.log?.error(\n `received malformed msg: ${decodedBuffer}`,\n this.loggingMetadata,\n );\n return null;\n }\n\n if (!Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {\n this.log?.error(`received invalid msg: ${JSON.stringify(parsedMsg)}`, {\n ...this.loggingMetadata,\n validationErrors: [\n ...Value.Errors(OpaqueTransportMessageSchema, parsedMsg),\n ],\n });\n\n return null;\n }\n\n return parsedMsg;\n }\n}\n\nexport type InheritedProperties = Pick<\n IdentifiedSession,\n 'id' | 'from' | 'to' | 'seq' | 'ack' | 'sendBuffer' | 'telemetry' | 'options'\n>;\n\nexport type SessionId = string;\n\n// all sessions where we know the other side's client id\nexport abstract class IdentifiedSession extends CommonSession {\n readonly id: SessionId;\n readonly telemetry: TelemetryInfo;\n readonly to: TransportClientId;\n\n /**\n * Index of the message we will send next (excluding handshake)\n */\n seq: number;\n\n /**\n * Number of unique messages we've received this session (excluding handshake)\n */\n ack: number;\n sendBuffer: Array<OpaqueTransportMessage>;\n\n constructor(\n id: SessionId,\n from: TransportClientId,\n to: TransportClientId,\n seq: number,\n ack: number,\n sendBuffer: Array<OpaqueTransportMessage>,\n telemetry: TelemetryInfo,\n options: SessionOptions,\n log: Logger | undefined,\n ) {\n super(from, options, log);\n this.id = id;\n this.to = to;\n this.seq = seq;\n this.ack = ack;\n this.sendBuffer = sendBuffer;\n this.telemetry = telemetry;\n this.log = log;\n }\n\n get loggingMetadata(): MessageMetadata {\n const spanContext = this.telemetry.span.spanContext();\n\n return {\n clientId: this.from,\n connectedTo: this.to,\n sessionId: this.id,\n telemetry: {\n traceId: spanContext.traceId,\n spanId: spanContext.spanId,\n },\n };\n }\n\n constructMsg<Payload>(\n partialMsg: PartialTransportMessage<Payload>,\n ): TransportMessage<Payload> {\n const msg = {\n ...partialMsg,\n id: generateId(),\n to: this.to,\n from: this.from,\n seq: this.seq,\n ack: this.ack,\n };\n\n this.seq++;\n return msg;\n }\n\n nextSeq(): number {\n return this.sendBuffer.length > 0 ? this.sendBuffer[0].seq : this.seq;\n }\n\n send(msg: PartialTransportMessage): string {\n const constructedMsg = this.constructMsg(msg);\n this.sendBuffer.push(constructedMsg);\n return constructedMsg.id;\n }\n\n _handleStateExit(): void {\n // noop\n }\n\n _handleClose(): void {\n // zero out the buffer\n this.sendBuffer.length = 0;\n this.telemetry.span.end();\n }\n}\n","import { Connection } from '../connection';\nimport { IdentifiedSession, SessionState } from './common';\n\nexport interface SessionConnectingListeners {\n onConnectionEstablished: (conn: Connection) => void;\n onConnectionFailed: (err: unknown) => void;\n\n // timeout related\n onConnectionTimeout: () => void;\n}\n\n/*\n * A session that is connecting but we don't have access to the raw connection\n * yet.\n *\n * Valid transitions:\n * - Connecting -> NoConnection (timeout)\n * - Connecting -> Handshaking (on connection established)\n */\nexport class SessionConnecting<\n ConnType extends Connection,\n> extends IdentifiedSession {\n readonly state = SessionState.Connecting as const;\n connPromise: Promise<ConnType>;\n listeners: SessionConnectingListeners;\n\n connectionTimeout?: ReturnType<typeof setTimeout>;\n\n constructor(\n connPromise: Promise<ConnType>,\n listeners: SessionConnectingListeners,\n ...args: ConstructorParameters<typeof IdentifiedSession>\n ) {\n super(...args);\n this.connPromise = connPromise;\n this.listeners = listeners;\n\n this.connectionTimeout = setTimeout(() => {\n listeners.onConnectionTimeout();\n }, this.options.connectionTimeoutMs);\n\n connPromise.then(\n (conn) => {\n if (this._isConsumed) return;\n listeners.onConnectionEstablished(conn);\n },\n (err) => {\n if (this._isConsumed) return;\n listeners.onConnectionFailed(err);\n },\n );\n }\n\n // close a pending connection if it resolves, ignore errors if the promise\n // ends up rejected anyways\n bestEffortClose() {\n void this.connPromise\n .then((conn) => conn.close())\n .catch(() => {\n // ignore errors\n });\n }\n\n _handleStateExit(): void {\n super._handleStateExit();\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = undefined;\n }\n\n _handleClose(): void {\n // close the pending connection if it resolves\n this.bestEffortClose();\n super._handleClose();\n }\n}\n","import { IdentifiedSession, SessionState } from './common';\n\nexport interface SessionNoConnectionListeners {\n // timeout related\n onSessionGracePeriodElapsed: () => void;\n}\n\n/*\n * A session that is not connected and cannot send or receive messages.\n *\n * Valid transitions:\n * - NoConnection -> Connecting (on connect)\n */\nexport class SessionNoConnection extends IdentifiedSession {\n readonly state = SessionState.NoConnection as const;\n listeners: SessionNoConnectionListeners;\n\n gracePeriodTimeout?: ReturnType<typeof setTimeout>;\n\n constructor(\n listeners: SessionNoConnectionListeners,\n ...args: ConstructorParameters<typeof IdentifiedSession>\n ) {\n super(...args);\n this.listeners = listeners;\n\n this.gracePeriodTimeout = setTimeout(() => {\n this.listeners.onSessionGracePeriodElapsed();\n }, this.options.sessionDisconnectGraceMs);\n }\n\n _handleClose(): void {\n super._handleClose();\n }\n\n _handleStateExit(): void {\n super._handleStateExit();\n\n if (this.gracePeriodTimeout) {\n clearTimeout(this.gracePeriodTimeout);\n this.gracePeriodTimeout = undefined;\n }\n }\n}\n","import {\n Context,\n Span,\n SpanKind,\n context,\n propagation,\n trace,\n} from '@opentelemetry/api';\nimport { version as RIVER_VERSION } from '../package.json';\nimport { ValidProcType } from '../router';\nimport {\n ClientTransport,\n Connection,\n OpaqueTransportMessage,\n} from '../transport';\n\nexport interface PropagationContext {\n traceparent: string;\n tracestate: string;\n}\n\nexport interface TelemetryInfo {\n span: Span;\n ctx: Context;\n}\n\nexport function getPropagationContext(\n ctx: Context,\n): PropagationContext | undefined {\n const tracing = {\n traceparent: '',\n tracestate: '',\n };\n propagation.inject(ctx, tracing);\n return tracing;\n}\n\nexport function createSessionTelemetryInfo(\n sessionId: string,\n to: string,\n from: string,\n propagationCtx?: PropagationContext,\n): TelemetryInfo {\n const parentCtx = propagationCtx\n ? propagation.extract(context.active(), propagationCtx)\n : context.active();\n\n const span = tracer.startSpan(\n `session ${sessionId}`,\n {\n attributes: {\n component: 'river',\n 'river.session.id': sessionId,\n 'river.session.to': to,\n 'river.session.from': from,\n },\n },\n parentCtx,\n );\n\n const ctx = trace.setSpan(parentCtx, span);\n\n return { span, ctx };\n}\n\nexport function createConnectionTelemetryInfo(\n connection: Connection,\n info: TelemetryInfo,\n): TelemetryInfo {\n const span = tracer.startSpan(\n `connection ${connection.id}`,\n {\n attributes: {\n component: 'river',\n 'river.connection.id': connection.id,\n },\n links: [{ context: info.span.spanContext() }],\n },\n info.ctx,\n );\n\n const ctx = trace.setSpan(info.ctx, span);\n\n return { span, ctx };\n}\n\nexport function createProcTelemetryInfo(\n transport: ClientTransport<Connection>,\n kind: ValidProcType,\n serviceName: string,\n procedureName: string,\n streamId: string,\n): TelemetryInfo {\n const baseCtx = context.active();\n const span = tracer.startSpan(\n `procedure call ${serviceName}.${procedureName}`,\n {\n attributes: {\n component: 'river',\n 'river.method.kind': kind,\n 'river.method.service': serviceName,\n 'river.method.name': procedureName,\n 'river.streamId': streamId,\n 'span.kind': 'client',\n },\n kind: SpanKind.CLIENT,\n },\n baseCtx,\n );\n\n const ctx = trace.setSpan(baseCtx, span);\n\n transport.log?.info(`invoked ${serviceName}.${procedureName}`, {\n clientId: transport.clientId,\n transportMessage: {\n procedureName,\n serviceName,\n },\n telemetry: {\n traceId: span.spanContext().traceId,\n spanId: span.spanContext().spanId,\n },\n });\n return { span, ctx };\n}\n\nexport function createHandlerSpan(\n kind: ValidProcType,\n message: OpaqueTransportMessage,\n fn: (span: Span) => Promise<unknown>,\n) {\n const ctx = message.tracing\n ? propagation.extract(context.active(), message.tracing)\n : context.active();\n\n return tracer.startActiveSpan(\n `procedure handler ${message.serviceName}.${message.procedureName}`,\n {\n attributes: {\n component: 'river',\n 'river.method.kind': kind,\n 'river.method.service': message.serviceName,\n 'river.method.name': message.procedureName,\n 'river.streamId': message.streamId,\n 'span.kind': 'server',\n },\n kind: SpanKind.SERVER,\n },\n ctx,\n fn,\n );\n}\n\nconst tracer = trace.getTracer('river', RIVER_VERSION);\nexport default tracer;\n","{\n \"name\": \"@replit/river\",\n \"description\": \"It's like tRPC but... with JSON Schema Support, duplex streaming and support for service multiplexing. Transport agnostic!\",\n \"version\": \"0.24.1\",\n \"type\": \"module\",\n \"exports\": {\n \".\": {\n \"import\": \"./dist/router/index.js\",\n \"require\": \"./dist/router/index.cjs\"\n },\n \"./logging\": {\n \"import\": \"./dist/logging/index.js\",\n \"require\": \"./dist/logging/index.cjs\"\n },\n \"./codec\": {\n \"import\": \"./dist/codec/index.js\",\n \"require\": \"./dist/codec/index.cjs\"\n },\n \"./transport\": {\n \"import\": \"./dist/transport/index.js\",\n \"require\": \"./dist/transport/index.cjs\"\n },\n \"./transport/ws/client\": {\n \"import\": \"./dist/transport/impls/ws/client.js\",\n \"require\": \"./dist/transport/impls/ws/client.cjs\"\n },\n \"./transport/ws/server\": {\n \"import\": \"./dist/transport/impls/ws/server.js\",\n \"require\": \"./dist/transport/impls/ws/server.cjs\"\n },\n \"./transport/uds/client\": {\n \"import\": \"./dist/transport/impls/uds/client.js\",\n \"require\": \"./dist/transport/impls/uds/client.cjs\"\n },\n \"./transport/uds/server\": {\n \"import\": \"./dist/transport/impls/uds/server.js\",\n \"require\": \"./dist/transport/impls/uds/server.cjs\"\n },\n \"./test-util\": {\n \"import\": \"./dist/util/testHelpers.js\",\n \"require\": \"./dist/util/testHelpers.cjs\"\n }\n },\n \"sideEffects\": [\n \"./dist/logging/index.js\"\n ],\n \"files\": [\n \"dist\"\n ],\n \"dependencies\": {\n \"@msgpack/msgpack\": \"^3.0.0-beta2\",\n \"it-pushable\": \"^3.2.3\",\n \"nanoid\": \"^4.0.2\",\n \"ws\": \"^8.17.0\"\n },\n \"peerDependencies\": {\n \"@opentelemetry/api\": \"^1.7.0\",\n \"@sinclair/typebox\": \"~0.32.8\"\n },\n \"devDependencies\": {\n \"@opentelemetry/sdk-trace-base\": \"^1.24.1\",\n \"@opentelemetry/sdk-trace-web\": \"^1.24.1\",\n \"@opentelemetry/core\": \"^1.7.0\",\n \"@types/ws\": \"^8.5.5\",\n \"@typescript-eslint/eslint-plugin\": \"^7.8.0\",\n \"@typescript-eslint/parser\": \"^7.8.0\",\n \"@vitest/ui\": \"^1.3.1\",\n \"eslint\": \"^8.57.0\",\n \"eslint-config-prettier\": \"^9.1.0\",\n \"eslint-plugin-prettier\": \"^5.1.3\",\n \"prettier\": \"^3.0.0\",\n \"tsup\": \"^7.2.0\",\n \"typescript\": \"^5.4.5\",\n \"vitest\": \"^1.3.1\"\n },\n \"scripts\": {\n \"check\": \"tsc --noEmit && npm run format && npm run lint\",\n \"format\": \"npx prettier . --check\",\n \"format:fix\": \"npx prettier . --write\",\n \"lint\": \"eslint .\",\n \"lint:fix\": \"eslint . --fix\",\n \"fix\": \"npm run format:fix && npm run lint:fix\",\n \"build\": \"rm -rf dist && tsup && du -sh dist\",\n \"prepack\": \"npm run build\",\n \"release\": \"npm publish --access public\",\n \"test:ui\": \"echo \\\"remember to go to /__vitest__ in the webview\\\" && vitest --ui --api.host 0.0.0.0 --api.port 3000\",\n \"test\": \"vitest\",\n \"test:single\": \"vitest run --reporter=dot\",\n \"test:flake\": \"./flake.sh\",\n \"bench\": \"vitest bench\"\n },\n \"engines\": {\n \"node\": \">=16\"\n },\n \"keywords\": [\n \"rpc\",\n \"websockets\",\n \"jsonschema\"\n ],\n \"author\": \"Jacky Zhao\",\n \"license\": \"MIT\"\n}\n","import { MessageMetadata } from '../../logging';\nimport { Connection } from '../connection';\nimport { TransportMessage } from '../message';\nimport { SessionHandshakingListeners } from './SessionHandshaking';\nimport { CommonSession, SessionState } from './common';\n\n/*\n * Server-side session that has a connection but is waiting for the client to identify itself.\n *\n * Valid transitions:\n * - WaitingForHandshake -> NoConnection (on close)\n * - WaitingForHandshake -> Connected (on handshake)\n */\nexport class SessionWaitingForHandshake<\n ConnType extends Connection,\n> extends CommonSession {\n readonly state = SessionState.WaitingForHandshake as const;\n conn: ConnType;\n listeners: SessionHandshakingListeners;\n\n handshakeTimeout?: ReturnType<typeof setTimeout>;\n\n constructor(\n conn: ConnType,\n listeners: SessionHandshakingListeners,\n ...args: ConstructorParameters<typeof CommonSession>\n ) {\n super(...args);\n this.conn = conn;\n this.listeners = listeners;\n\n this.handshakeTimeout = setTimeout(() => {\n listeners.onHandshakeTimeout();\n }, this.options.handshakeTimeoutMs);\n\n this.conn.addDataListener(this.onHandshakeData);\n this.conn.addErrorListener(listeners.onConnectionErrored);\n this.conn.addCloseListener(listeners.onConnectionClosed);\n }\n\n onHandshakeData = (msg: Uint8Array) => {\n const parsedMsg = this.parseMsg(msg);\n if (parsedMsg === null) {\n this.listeners.onInvalidHandshake('could not parse message');\n return;\n }\n\n // after this fires, the listener is responsible for transitioning the session\n // and thus removing the handshake timeout\n this.listeners.onHandshake(parsedMsg);\n };\n\n get loggingMetadata(): MessageMetadata {\n return {\n clientId: this.from,\n connId: this.conn.id,\n };\n }\n\n sendHandshake(msg: TransportMessage): boolean {\n return this.conn.send(this.options.codec.toBuffer(msg));\n }\n\n _handleStateExit(): void {\n this.conn.removeDataListener(this.onHandshakeData);\n this.conn.removeErrorListener(this.listeners.onConnectionErrored);\n this.conn.removeCloseListener(this.listeners.onConnectionClosed);\n clearTimeout(this.handshakeTimeout);\n this.handshakeTimeout = undefined;\n }\n\n _handleClose(): void {\n this.conn.close();\n }\n}\n","import { Connection } from '../connection';\nimport { OpaqueTransportMessage, TransportMessage } from '../message';\nimport { IdentifiedSession, SessionState } from './common';\n\nexport interface SessionHandshakingListeners {\n onConnectionErrored: (err: unknown) => void;\n onConnectionClosed: () => void;\n onHandshake: (msg: OpaqueTransportMessage) => void;\n onInvalidHandshake: (reason: string) => void;\n\n // timeout related\n onHandshakeTimeout: () => void;\n}\n\n/*\n * A session that is handshaking and waiting for the other side to identify itself.\n *\n * Valid transitions:\n * - Handshaking -> NoConnection (on close)\n * - Handshaking -> Connected (on handshake)\n */\nexport class SessionHandshaking<\n ConnType extends Connection,\n> extends IdentifiedSession {\n readonly state = SessionState.Handshaking as const;\n conn: ConnType;\n listeners: SessionHandshakingListeners;\n\n handshakeTimeout: ReturnType<typeof setTimeout>;\n\n constructor(\n conn: ConnType,\n listeners: SessionHandshakingListeners,\n ...args: ConstructorParameters<typeof IdentifiedSession>\n ) {\n super(...args);\n this.conn = conn;\n this.listeners = listeners;\n\n this.handshakeTimeout = setTimeout(() => {\n listeners.onHandshakeTimeout();\n }, this.options.handshakeTimeoutMs);\n\n this.conn.addDataListener(this.onHandshakeData);\n this.conn.addErrorListener(listeners.onConnectionErrored);\n this.conn.addCloseListener(listeners.onConnectionClosed);\n }\n\n onHandshakeData = (msg: Uint8Array) => {\n const parsedMsg = this.parseMsg(msg);\n if (parsedMsg === null) {\n this.listeners.onInvalidHandshake('could not parse message');\n return;\n }\n\n this.listeners.onHandshake(parsedMsg);\n };\n\n sendHandshake(msg: TransportMessage): boolean {\n return this.conn.send(this.options.codec.toBuffer(msg));\n }\n\n _handleStateExit(): void {\n super._handleStateExit();\n this.conn.removeDataListener(this.onHandshakeData);\n this.conn.removeErrorListener(this.listeners.onConnectionErrored);\n this.conn.removeCloseListener(this.listeners.onConnectionClosed);\n clearTimeout(this.handshakeTimeout);\n }\n\n _handleClose(): void {\n super._handleClose();\n this.conn.close();\n }\n}\n","import { Static } from '@sinclair/typebox';\nimport {\n ControlFlags,\n ControlMessageAckSchema,\n OpaqueTransportMessage,\n PartialTransportMessage,\n isAck,\n} from '../message';\nimport { IdentifiedSession, SessionState } from './common';\nimport { Connection } from '../connection';\nimport { SpanStatusCode } from '@opentelemetry/api';\n\nexport interface SessionConnectedListeners {\n onConnectionErrored: (err: unknown) => void;\n onConnectionClosed: () => void;\n onMessage: (msg: OpaqueTransportMessage) => void;\n onInvalidMessage: (reason: string) => void;\n}\n\n/*\n * A session that is connected and can send and receive messages.\n *\n * Valid transitions:\n * - Connected -> NoConnection (on close)\n */\nexport class SessionConnected<\n ConnType extends Connection,\n> extends IdentifiedSession {\n readonly state = SessionState.Connected as const;\n conn: ConnType;\n listeners: SessionConnectedListeners;\n\n heartbeatHandle?: ReturnType<typeof setInterval> | undefined;\n heartbeatMisses = 0;\n\n get isActivelyHeartbeating() {\n return this.heartbeatHandle !== undefined;\n }\n\n updateBookkeeping(ack: number, seq: number) {\n this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq >= ack);\n this.ack = seq + 1;\n this.heartbeatMisses = 0;\n }\n\n send(msg: PartialTransportMessage): string {\n const constructedMsg = this.constructMsg(msg);\n this.sendBuffer.push(constructedMsg);\n this.conn.send(this.options.codec.toBuffer(constructedMsg));\n return constructedMsg.id;\n }\n\n constructor(\n conn: ConnType,\n listeners: SessionConnectedListeners,\n ...args: ConstructorParameters<typeof IdentifiedSession>\n ) {\n super(...args);\n this.conn = conn;\n this.listeners = listeners;\n\n this.conn.addDataListener(this.onMessageData);\n this.conn.addCloseListener(listeners.onConnectionClosed);\n this.conn.addErrorListener(listeners.onConnectionErrored);\n\n // send any buffered messages\n if (this.sendBuffer.length > 0) {\n this.log?.debug(\n `sending ${this.sendBuffer.length} buffered messages`,\n this.loggingMetadata,\n );\n }\n\n for (const msg of this.sendBuffer) {\n conn.send(this.options.codec.toBuffer(msg));\n }\n\n // dont explicity clear the buffer, we'll just filter out old messages\n // when we receive an ack\n }\n\n startActiveHeartbeat() {\n this.heartbeatHandle = setInterval(() => {\n const misses = this.heartbeatMisses;\n const missDuration = misses * this.options.heartbeatIntervalMs;\n if (misses >= this.options.heartbeatsUntilDead) {\n this.log?.info(\n `closing connection to ${this.to} due to inactivity (missed ${misses} heartbeats which is ${missDuration}ms)`,\n this.loggingMetadata,\n );\n this.telemetry.span.addEvent('closing connection due to inactivity');\n this.conn.close();\n clearInterval(this.heartbeatHandle);\n this.heartbeatHandle = undefined;\n return;\n }\n\n this.sendHeartbeat();\n this.heartbeatMisses++;\n }, this.options.heartbeatIntervalMs);\n }\n\n private sendHeartbeat() {\n this.send({\n streamId: 'heartbeat',\n controlFlags: ControlFlags.AckBit,\n payload: {\n type: 'ACK',\n } satisfies Static<typeof ControlMessageAckSchema>,\n });\n }\n\n onMessageData = (msg: Uint8Array) => {\n const parsedMsg = this.parseMsg(msg);\n if (parsedMsg === null) return;\n\n // check message ordering here\n if (parsedMsg.seq !== this.ack) {\n if (parsedMsg.seq < this.ack) {\n this.log?.debug(\n `received duplicate msg (got seq: ${parsedMsg.seq}, wanted seq: ${this.ack}), discarding`,\n {\n ...this.loggingMetadata,\n transportMessage: parsedMsg,\n },\n );\n } else {\n const reason = `received out-of-order msg (got seq: ${parsedMsg.seq}, wanted seq: ${this.ack})`;\n this.log?.error(reason, {\n ...this.loggingMetadata,\n transportMessage: parsedMsg,\n tags: ['invariant-violation'],\n });\n this.telemetry.span.setStatus({\n code: SpanStatusCode.ERROR,\n message: reason,\n });\n\n this.listeners.onInvalidMessage(reason);\n }\n\n return;\n }\n\n // message is ok to update bookkeeping with\n this.log?.debug(`received msg`, {\n ...this.loggingMetadata,\n transportMessage: parsedMsg,\n });\n\n this.updateBookkeeping(parsedMsg.ack, parsedMsg.seq);\n\n // dispatch directly if its not an explicit ack\n if (!isAck(parsedMsg.controlFlags)) {\n this.listeners.onMessage(parsedMsg);\n return;\n }\n\n // discard acks (unless we aren't heartbeating in which case just respond)\n this.log?.debug(`discarding msg (ack bit set)`, {\n ...this.loggingMetadata,\n transportMessage: parsedMsg,\n });\n\n // if we are not actively heartbeating, we are in passive\n // heartbeat mode and should send a response to the ack\n if (!this.isActivelyHeartbeating) {\n this.sendHeartbeat();\n }\n };\n\n _handleStateExit(): void {\n super._handleStateExit();\n this.conn.removeDataListener(this.onMessageData);\n this.conn.removeCloseListener(this.listeners.onConnectionClosed);\n this.conn.removeErrorListener(this.listeners.onConnectionErrored);\n clearInterval(this.heartbeatHandle);\n this.heartbeatHandle = undefined;\n }\n\n _handleClose(): void {\n super._handleClose();\n this.conn.close();\n }\n}\n","import { OpaqueTransportMessage, TransportClientId } from '..';\nimport {\n SessionConnecting,\n SessionConnectingListeners,\n} from './SessionConnecting';\nimport {\n SessionNoConnection,\n SessionNoConnectionListeners,\n} from './SessionNoConnection';\nimport { IdentifiedSession, SessionOptions } from './common';\nimport { PropagationContext, createSessionTelemetryInfo } from '../../tracing';\nimport { SessionWaitingForHandshake } from './SessionWaitingForHandshake';\nimport {\n SessionHandshaking,\n SessionHandshakingListeners,\n} from './SessionHandshaking';\nimport {\n SessionConnected,\n SessionConnectedListeners,\n} from './SessionConnected';\nimport { generateId } from '../id';\nimport { Connection } from '../connection';\nimport { Logger } from '../../logging';\n\nfunction inheritSharedSession(\n session: IdentifiedSession,\n): ConstructorParameters<typeof IdentifiedSession> {\n return [\n session.id,\n session.from,\n session.to,\n session.seq,\n session.ack,\n session.sendBuffer,\n session.telemetry,\n session.options,\n session.log,\n ];\n}\n\n/*\n * Session state machine:\n * 1. SessionNoConnection is the client entrypoint as\n * we know who the other side is already, we just need to connect\n * 5. SessionWaitingForHandshake is the server entrypoint\n * as we have a connection but don't know who the other side is yet\n *\n * 1. SessionNoConnection ◄──┐\n * │ reconnect / connect attempt │\n * ▼ │\n * 2. SessionConnecting │\n * │ connect success ──────────────┤ connect failure\n * ▼ │\n * 3. SessionHandshaking │\n * │ handshake success ┌──────┤ connection drop\n * 5. WaitingForHandshake │ handshake failure ─────┤ │\n * │ handshake success ▼ │ │ connection drop\n * ├───────────────────────► 4. SessionConnected │ │ heartbeat misses\n * │ │ invalid message ───────┼──────┘\n * │ ▼ │\n * └───────────────────────► x. Destroy Session ◄─────┘\n * handshake failure\n */\nexport const SessionStateGraph = {\n entrypoints: {\n NoConnection(\n to: TransportClientId,\n from: TransportClientId,\n listeners: SessionNoConnectionListeners,\n options: SessionOptions,\n log?: Logger,\n ) {\n const id = `session-${generateId()}`;\n const telemetry = createSessionTelemetryInfo(id, to, from);\n const sendBuffer: Array<OpaqueTransportMessage> = [];\n\n const session = new SessionNoConnection(\n listeners,\n id,\n from,\n to,\n 0,\n 0,\n sendBuffer,\n telemetry,\n options,\n log,\n );\n\n session.log?.info(`session ${session.id} created in NoConnection state`, {\n ...session.loggingMetadata,\n tags: ['state-transition'],\n });\n\n return session;\n },\n WaitingForHandshake<ConnType extends Connection>(\n from: TransportClientId,\n conn: ConnType,\n listeners: SessionHandshakingListeners,\n options: SessionOptions,\n log?: Logger,\n ): SessionWaitingForHandshake<ConnType> {\n const session = new SessionWaitingForHandshake(\n conn,\n listeners,\n from,\n options,\n log,\n );\n\n session.log?.info(`session created in WaitingForHandshake state`, {\n ...session.loggingMetadata,\n tags: ['state-transition'],\n });\n\n return session;\n },\n },\n // All of the transitions 'move'/'consume' the old session and return a new one.\n // After a session is transitioned, any usage of the old session will throw.\n transition: {\n // happy path transitions\n NoConnectionToConnecting<ConnType extends Connection>(\n oldSession: SessionNoConnection,\n connPromise: Promise<ConnType>,\n listeners: SessionConnectingListeners,\n ): SessionConnecting<ConnType> {\n const carriedState = inheritSharedSession(oldSession);\n oldSession._handleStateExit();\n\n const session = new SessionConnecting(\n connPromise,\n listeners,\n ...carriedState,\n );\n session.log?.info(\n `session ${session.id} transition from NoConnection to Connecting`,\n {\n ...session.loggingMetadata,\n tags: ['state-transition'],\n },\n );\n return session;\n },\n ConnectingToHandshaking<ConnType extends Connection>(\n oldSession: SessionConnecting<ConnType>,\n conn: ConnType,\n listeners: SessionHandshakingListeners,\n ): SessionHandshaking<ConnType> {\n const carriedState = inheritSharedSession(oldSession);\n oldSession._handleStateExit();\n\n const session = new SessionHandshaking(conn, listeners, ...carriedState);\n session.log?.info(\n `session ${session.id} transition from Connecting to Handshaking`,\n {\n ...session.loggingMetadata,\n tags: ['state-transition'],\n },\n );\n\n return session;\n },\n HandshakingToConnected<ConnType extends Connection>(\n oldSession: SessionHandshaking<ConnType>,\n listeners: SessionConnectedListeners,\n ): SessionConnected<ConnType> {\n const carriedState = inheritSharedSession(oldSession);\n const conn = oldSession.conn;\n oldSession._handleStateExit();\n\n const session = new SessionConnected(conn, listeners, ...carriedState);\n session.log?.info(\n `session ${session.id} transition from Handshaking to Connected`,\n {\n ...session.loggingMetadata,\n tags: ['state-transition'],\n },\n );\n\n return session;\n },\n WaitingForHandshakeToConnected<ConnType extends Connection>(\n pendingSession: SessionWaitingForHandshake<ConnType>,\n oldSession: SessionNoConnection | undefined,\n sessionId: string,\n to: TransportClientId,\n propagationCtx: PropagationContext | undefined,\n listeners: SessionConnectedListeners,\n ): SessionConnected<ConnType> {\n const conn = pendingSession.conn;\n const { from, options } = pendingSession;\n const carriedState: ConstructorParameters<typeof IdentifiedSession> =\n oldSession\n ? // old session exists, inherit state\n inheritSharedSession(oldSession)\n : // old session does not exist, create new state\n [\n sessionId,\n from,\n to,\n 0,\n 0,\n [],\n createSessionTelemetryInfo(sessionId, to, from, propagationCtx),\n options,\n pendingSession.log,\n ];\n\n pendingSession._handleStateExit();\n oldSession?._handleStateExit();\n\n const session = new SessionConnected(conn, listeners, ...carriedState);\n session.log?.info(\n `session ${session.id} transition from WaitingForHandshake to Connected`,\n {\n ...session.loggingMetadata,\n tags: ['state-transition'],\n },\n );\n\n return session;\n },\n // disconnect paths\n ConnectingToNoConnection<ConnType extends Connection>(\n oldSession: SessionConnecting<ConnType>,\n listeners: SessionNoConnectionListeners,\n ): SessionNoConnection {\n const carriedState = inheritSharedSession(oldSession);\n oldSession.bestEffortClose();\n oldSession._handleStateExit();\n\n const session = new SessionNoConnection(listeners, ...carriedState);\n session.log?.info(\n `session ${session.id} transition from Connecting to NoConnection`,\n {\n ...session.loggingMetadata,\n tags: ['state-transition'],\n },\n );\n\n return session;\n },\n HandshakingToNoConnection<ConnType extends Connection>(\n oldSession: SessionHandshaking<ConnType>,\n listeners: SessionNoConnectionListeners,\n ): SessionNoConnection {\n const carriedState = inheritSharedSession(oldSession);\n oldSession.conn.close();\n oldSession._handleStateExit();\n\n const session = new SessionNoConnection(listeners, ...carriedState);\n session.log?.info(\n `session ${session.id} transition from Handshaking to NoConnection`,\n {\n ...session.loggingMetadata,\n tags: ['state-transition'],\n },\n );\n\n return session;\n },\n ConnectedToNoConnection<ConnType extends Connection>(\n oldSession: SessionConnected<ConnType>,\n listeners: SessionNoConnectionListeners,\n ): SessionNoConnection {\n const carriedState = inheritSharedSession(oldSession);\n oldSession.conn.close();\n oldSession._handleStateExit();\n\n const session = new SessionNoConnection(listeners, ...carriedState);\n session.log?.info(\n `session ${session.id} transition from Connected to NoConnection`,\n {\n ...session.loggingMetadata,\n tags: ['state-transition'],\n },\n );\n\n return session;\n },\n },\n} as const;\n","import {\n OpaqueTransportMessage,\n TransportClientId,\n PartialTransportMessage,\n} from './message';\nimport {\n BaseLogger,\n LogFn,\n Logger,\n LoggingLevel,\n createLogProxy,\n} from '../logging/log';\nimport {\n EventDispatcher,\n EventHandler,\n EventMap,\n EventTypes,\n ProtocolErrorType,\n} from './events';\nimport {\n ProvidedTransportOptions,\n TransportOptions,\n defaultTransportOptions,\n} from './options';\nimport {\n Session,\n SessionConnected,\n SessionConnecting,\n SessionHandshaking,\n SessionNoConnection,\n SessionState,\n SessionStateGraph,\n} from './sessionStateMachine';\nimport { Connection } from './connection';\n\n/**\n * Represents the possible states of a transport.\n * @property {'open'} open - The transport is open and operational (note that this doesn't mean it is actively connected)\n * @property {'closed'} closed - The transport is permanently closed and cannot be reopened.\n */\nexport type TransportStatus = 'open' | 'closed';\n\n/**\n * Transports manage the lifecycle (creation/deletion) of sessions\n *\n * ```plaintext\n * ▲\n * incoming │\n * messages │\n * ▼\n * ┌─────────────┐ 1:N ┌───────────┐ 1:1* ┌────────────┐\n * │ Transport │ ◄─────► │ Session │ ◄─────► │ Connection │\n * └─────────────┘ └───────────┘ └────────────┘\n * ▲ * (may or may not be initialized yet)\n * │\n * ▼\n * ┌───────────┐\n * │ Message │\n * │ Listeners │\n * └───────────┘\n * ```\n * @abstract\n */\nexport abstract class Transport<ConnType extends Connection> {\n /**\n * The status of the transport.\n */\n private status: TransportStatus;\n\n /**\n * The client ID of this transport.\n */\n clientId: TransportClientId;\n\n /**\n * The event dispatcher for handling events of type EventTypes.\n */\n eventDispatcher: EventDispatcher<EventTypes>;\n\n /**\n * The options for this transport.\n */\n protected options: TransportOptions;\n log?: Logger;\n\n sessions: Map<TransportClientId, Session<ConnType>>;\n\n /**\n * Creates a new Transport instance.\n * @param codec The codec used to encode and decode messages.\n * @param clientId The client ID of this transport.\n */\n constructor(\n clientId: TransportClientId,\n providedOptions?: ProvidedTransportOptions,\n ) {\n this.options = { ...defaultTransportOptions, ...providedOptions };\n this.eventDispatcher = new EventDispatcher();\n this.clientId = clientId;\n this.status = 'open';\n this.sessions = new Map();\n }\n\n bindLogger(fn: LogFn | Logger, level?: LoggingLevel) {\n // construct logger from fn\n if (typeof fn === 'function') {\n this.log = createLogProxy(new BaseLogger(fn, level));\n return;\n }\n\n // object case, just assign\n this.log = createLogProxy(fn);\n }\n\n /**\n * Called when a message is received by this transport.\n * You generally shouldn't need to override this in downstream transport implementations.\n * @param msg The received message.\n */\n protected handleMsg(msg: OpaqueTransportMessage) {\n if (this.getStatus() !== 'open') return;\n this.eventDispatcher.dispatchEvent('message', msg);\n }\n\n /**\n * Adds a listener to this transport.\n * @param the type of event to listen for\n * @param handler The message handler to add.\n */\n addEventListener<K extends EventTypes, T extends EventHandler<K>>(\n type: K,\n handler: T,\n ): void {\n this.eventDispatcher.addEventListener(type, handler);\n }\n\n /**\n * Removes a listener from this transport.\n * @param the type of event to un-listen on\n * @param handler The message handler to remove.\n */\n removeEventListener<K extends EventTypes, T extends EventHandler<K>>(\n type: K,\n handler: T,\n ): void {\n this.eventDispatcher.removeEventListener(type, handler);\n }\n\n /**\n * Sends a message over this transport, delegating to the appropriate connection to actually\n * send the message.\n * @param msg The message to send.\n * @returns The ID of the sent message or undefined if it wasn't sent\n */\n abstract send(to: TransportClientId, msg: PartialTransportMessage): string;\n\n protected protocolError(type: ProtocolErrorType, message: string) {\n this.eventDispatcher.dispatchEvent('protocolError', { type, message });\n }\n\n /**\n * Default close implementation for transports. You should override this in the downstream\n * implementation if you need to do any additional cleanup and call super.close() at the end.\n * Closes the transport. Any messages sent while the transport is closed will be silently discarded.\n */\n close() {\n this.status = 'closed';\n\n for (const session of this.sessions.values()) {\n this.deleteSession(session);\n }\n\n this.eventDispatcher.dispatchEvent('transportStatus', {\n status: this.status,\n });\n\n this.eventDispatcher.removeAllListeners();\n\n this.log?.info(`manually closed transport`, { clientId: this.clientId });\n }\n\n getStatus(): TransportStatus {\n return this.status;\n }\n\n protected updateSession<S extends Session<ConnType>>(session: S): S {\n const activeSession = this.sessions.get(session.to);\n if (activeSession && activeSession.id !== session.id) {\n const msg = `attempt to transition active session for ${session.to} but active session (${activeSession.id}) is different from handle (${session.id})`;\n throw new Error(msg);\n }\n\n this.sessions.set(session.to, session);\n\n if (!activeSession) {\n this.eventDispatcher.dispatchEvent('sessionStatus', {\n status: 'connect',\n session: session,\n });\n }\n\n this.eventDispatcher.dispatchEvent('sessionTransition', {\n state: session.state,\n session: session,\n } as EventMap['sessionTransition']);\n\n return session;\n }\n\n // state transitions\n protected deleteSession(session: Session<ConnType>) {\n session.log?.info(`closing session ${session.id}`, session.loggingMetadata);\n\n this.eventDispatcher.dispatchEvent('sessionStatus', {\n status: 'disconnect',\n session: session,\n });\n\n session.close();\n this.sessions.delete(session.to);\n }\n\n // common listeners\n protected onSessionGracePeriodElapsed(session: SessionNoConnection) {\n this.log?.warn(\n `session to ${session.to} grace period elapsed, closing`,\n session.loggingMetadata,\n );\n\n this.deleteSession(session);\n }\n\n protected onConnectingFailed(\n session: SessionConnecting<ConnType>,\n ): SessionNoConnection {\n // transition to no connection\n const noConnectionSession =\n SessionStateGraph.transition.ConnectingToNoConnection(session, {\n onSessionGracePeriodElapsed: () => {\n this.onSessionGracePeriodElapsed(noConnectionSession);\n },\n });\n\n return this.updateSession(noConnectionSession);\n }\n\n protected onConnClosed(\n session: SessionHandshaking<ConnType> | SessionConnected<ConnType>,\n ): SessionNoConnection {\n // transition to no connection\n let noConnectionSession: SessionNoConnection;\n if (session.state === SessionState.Handshaking) {\n noConnectionSession =\n SessionStateGraph.transition.HandshakingToNoConnection(session, {\n onSessionGracePeriodElapsed: () => {\n this.onSessionGracePeriodElapsed(noConnectionSession);\n },\n });\n } else {\n noConnectionSession =\n SessionStateGraph.transition.ConnectedToNoConnection(session, {\n onSessionGracePeriodElapsed: () => {\n this.onSessionGracePeriodElapsed(noConnectionSession);\n },\n });\n }\n\n return this.updateSession(noConnectionSession);\n }\n}\n","export function coerceErrorString(err: unknown): string {\n if (err instanceof Error) {\n return err.message || 'unknown reason';\n }\n\n return `[coerced to error] ${String(err)}`;\n}\n"],"mappings":"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","names":["import_api","import_api","import_value","msg"]}
|
|
1
|
+
{"version":3,"sources":["../../../../transport/impls/ws/server.ts","../../../../transport/id.ts","../../../../transport/connection.ts","../../../../transport/impls/ws/connection.ts","../../../../transport/server.ts","../../../../transport/message.ts","../../../../codec/json.ts","../../../../transport/options.ts","../../../../logging/log.ts","../../../../transport/events.ts","../../../../transport/sessionStateMachine/common.ts","../../../../transport/sessionStateMachine/SessionConnecting.ts","../../../../transport/sessionStateMachine/SessionNoConnection.ts","../../../../tracing/index.ts","../../../../package.json","../../../../transport/sessionStateMachine/SessionWaitingForHandshake.ts","../../../../transport/sessionStateMachine/SessionHandshaking.ts","../../../../transport/sessionStateMachine/SessionConnected.ts","../../../../transport/sessionStateMachine/transitions.ts","../../../../transport/transport.ts","../../../../util/stringify.ts"],"sourcesContent":["import { TransportClientId } from '../../message';\nimport { WebSocketServer } from 'ws';\nimport { WebSocketConnection } from './connection';\nimport { WsLike } from './wslike';\nimport { ServerTransport } from '../../server';\nimport { ProvidedServerTransportOptions } from '../../options';\n\nexport class WebSocketServerTransport extends ServerTransport<WebSocketConnection> {\n wss: WebSocketServer;\n\n constructor(\n wss: WebSocketServer,\n clientId: TransportClientId,\n providedOptions?: ProvidedServerTransportOptions,\n ) {\n super(clientId, providedOptions);\n this.wss = wss;\n this.wss.on('connection', this.connectionHandler);\n }\n\n connectionHandler = (ws: WsLike) => {\n const conn = new WebSocketConnection(ws);\n this.handleConnection(conn);\n };\n\n close() {\n super.close();\n this.wss.off('connection', this.connectionHandler);\n }\n}\n","import { customAlphabet } from 'nanoid';\n\nconst alphabet = customAlphabet(\n '1234567890abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ',\n);\nexport const generateId = () => alphabet(12);\n","import { TelemetryInfo } from '../tracing';\nimport { MessageMetadata } from '../logging';\nimport { generateId } from './id';\n\n/**\n * A connection is the actual raw underlying transport connection.\n * It’s responsible for dispatching to/from the actual connection itself\n * This should be instantiated as soon as the client/server has a connection\n * It’s tied to the lifecycle of the underlying transport connection (i.e. if the WS drops, this connection should be deleted)\n */\nexport abstract class Connection {\n id: string;\n telemetry?: TelemetryInfo;\n constructor() {\n this.id = `conn-${generateId()}`; // for debugging, no collision safety needed\n }\n\n get loggingMetadata(): MessageMetadata {\n const metadata: MessageMetadata = { connId: this.id };\n const spanContext = this.telemetry?.span.spanContext();\n\n if (this.telemetry?.span.isRecording() && spanContext) {\n metadata.telemetry = {\n traceId: spanContext.traceId,\n spanId: spanContext.spanId,\n };\n }\n\n return metadata;\n }\n\n // can't use event emitter because we need this to work in both node + browser\n private _dataListeners = new Set<(msg: Uint8Array) => void>();\n private _closeListeners = new Set<() => void>();\n private _errorListeners = new Set<(err: Error) => void>();\n\n get dataListeners() {\n return [...this._dataListeners];\n }\n\n get closeListeners() {\n return [...this._closeListeners];\n }\n\n get errorListeners() {\n return [...this._errorListeners];\n }\n\n /**\n * Handle adding a callback for when a message is received.\n * @param msg The message that was received.\n */\n addDataListener(cb: (msg: Uint8Array) => void) {\n this._dataListeners.add(cb);\n }\n\n removeDataListener(cb: (msg: Uint8Array) => void): void {\n this._dataListeners.delete(cb);\n }\n\n /**\n * Handle adding a callback for when the connection is closed.\n * This should also be called if an error happens and after notifying all the error listeners.\n * @param cb The callback to call when the connection is closed.\n */\n addCloseListener(cb: () => void): void {\n this._closeListeners.add(cb);\n }\n\n removeCloseListener(cb: () => void): void {\n this._closeListeners.delete(cb);\n }\n\n /**\n * Handle adding a callback for when an error is received.\n * This should only be used for this.logging errors, all cleanup\n * should be delegated to addCloseListener.\n *\n * The implementer should take care such that the implemented\n * connection will call both the close and error callbacks\n * on an error.\n *\n * @param cb The callback to call when an error is received.\n */\n addErrorListener(cb: (err: Error) => void): void {\n this._errorListeners.add(cb);\n }\n\n removeErrorListener(cb: (err: Error) => void): void {\n this._errorListeners.delete(cb);\n }\n\n /**\n * Sends a message over the connection.\n * @param msg The message to send.\n * @returns true if the message was sent, false otherwise.\n */\n abstract send(msg: Uint8Array): boolean;\n\n /**\n * Closes the connection.\n */\n abstract close(): void;\n}\n","import { Connection } from '../../connection';\nimport { WsLike } from './wslike';\n\nexport class WebSocketConnection extends Connection {\n ws: WsLike;\n\n constructor(ws: WsLike) {\n super();\n this.ws = ws;\n this.ws.binaryType = 'arraybuffer';\n\n // Websockets are kinda shitty, they emit error events with no\n // information other than it errored, so we have to do some extra\n // work to figure out what happened.\n let didError = false;\n this.ws.onerror = () => {\n didError = true;\n };\n\n this.ws.onclose = ({ code, reason }) => {\n if (didError) {\n const err = new Error(\n `websocket closed with code and reason: ${code} - ${reason}`,\n );\n\n for (const cb of this.errorListeners) {\n cb(err);\n }\n }\n\n for (const cb of this.closeListeners) {\n cb();\n }\n };\n\n this.ws.onmessage = (msg) => {\n for (const cb of this.dataListeners) {\n cb(msg.data as Uint8Array);\n }\n };\n }\n\n send(payload: Uint8Array) {\n if (this.ws.readyState !== this.ws.OPEN) {\n return false;\n }\n this.ws.send(payload);\n return true;\n }\n\n close() {\n this.ws.close();\n }\n}\n","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","import { Type, TSchema, Static } from '@sinclair/typebox';\nimport { PropagationContext } from '../tracing';\nimport { generateId } from './id';\n\n/**\n * Control flags for transport messages.\n * An RPC message is coded with StreamOpenBit | StreamClosedBit.\n * Streams are expected to start with StreamOpenBit sent and the client SHOULD send an empty\n * message with StreamClosedBit to close the stream handler on the server, indicating that\n * it will not be using the stream anymore.\n */\nexport const enum ControlFlags {\n AckBit = 0b0001,\n StreamOpenBit = 0b0010,\n StreamClosedBit = 0b0100,\n}\n\n/**\n * Generic Typebox schema for a transport message.\n * @template T The type of the payload.\n * @param {T} t The payload schema.\n * @returns The transport message schema.\n */\nexport const TransportMessageSchema = <T extends TSchema>(t: T) =>\n Type.Object({\n id: Type.String(),\n from: Type.String(),\n to: Type.String(),\n seq: Type.Integer(),\n ack: Type.Integer(),\n serviceName: Type.Optional(Type.String()),\n procedureName: Type.Optional(Type.String()),\n streamId: Type.String(),\n controlFlags: Type.Integer(),\n tracing: Type.Optional(\n Type.Object({\n traceparent: Type.String(),\n tracestate: Type.String(),\n }),\n ),\n payload: t,\n });\n\n/**\n * Defines the schema for a transport acknowledgement message. This is never constructed manually\n * and is only used internally by the library for tracking inflight messages.\n * @returns The transport message schema.\n */\nexport const ControlMessageAckSchema = Type.Object({\n type: Type.Literal('ACK'),\n});\n\n/**\n * Defines the schema for a transport close message. This is never constructed manually and is only\n * used internally by the library for closing and cleaning up streams.\n */\nexport const ControlMessageCloseSchema = Type.Object({\n type: Type.Literal('CLOSE'),\n});\n\nexport const PROTOCOL_VERSION = 'v1.1';\nexport const ControlMessageHandshakeRequestSchema = Type.Object({\n type: Type.Literal('HANDSHAKE_REQ'),\n protocolVersion: Type.String(),\n sessionId: Type.String(),\n /**\n * Specifies what the server's expected session state (from the pov of the client). This can be\n * used by the server to know whether this is a new or a reestablished connection, and whether it\n * is compatible with what it already has.\n */\n expectedSessionState: Type.Object({\n // what the client expects the server to send next\n nextExpectedSeq: Type.Integer(),\n // TODO: remove optional once we know all servers\n // are nextSentSeq here\n // what the server expects the client to send next\n nextSentSeq: Type.Optional(Type.Integer()),\n }),\n\n metadata: Type.Optional(Type.Unknown()),\n});\n\nexport const HandshakeErrorRetriableResponseCodes = Type.Union([\n Type.Literal('SESSION_STATE_MISMATCH'),\n]);\n\nexport const HandshakeErrorFatalResponseCodes = Type.Union([\n Type.Literal('MALFORMED_HANDSHAKE_META'),\n Type.Literal('MALFORMED_HANDSHAKE'),\n Type.Literal('PROTOCOL_VERSION_MISMATCH'),\n Type.Literal('REJECTED_BY_CUSTOM_HANDLER'),\n]);\n\nexport const HandshakeErrorResponseCodes = Type.Union([\n HandshakeErrorRetriableResponseCodes,\n HandshakeErrorFatalResponseCodes,\n]);\n\nexport const ControlMessageHandshakeResponseSchema = Type.Object({\n type: Type.Literal('HANDSHAKE_RESP'),\n status: Type.Union([\n Type.Object({\n ok: Type.Literal(true),\n sessionId: Type.String(),\n }),\n Type.Object({\n ok: Type.Literal(false),\n reason: Type.String(),\n // TODO: remove optional once we know all servers\n // are sending code here\n code: Type.Optional(HandshakeErrorResponseCodes),\n }),\n ]),\n});\n\nexport const ControlMessagePayloadSchema = Type.Union([\n ControlMessageCloseSchema,\n ControlMessageAckSchema,\n ControlMessageHandshakeRequestSchema,\n ControlMessageHandshakeResponseSchema,\n]);\n\n/**\n * Defines the schema for an opaque transport message that is agnostic to any\n * procedure/service.\n * @returns The transport message schema.\n */\nexport const OpaqueTransportMessageSchema = TransportMessageSchema(\n Type.Unknown(),\n);\n\n/**\n * Represents a transport message. This is the same type as {@link TransportMessageSchema} but\n * we can't statically infer generics from generic Typebox schemas so we have to define it again here.\n *\n * TypeScript can't enforce types when a bitmask is involved, so these are the semantics of\n * `controlFlags`:\n * * If `controlFlags & StreamOpenBit == StreamOpenBit`, `streamId` must be set to a unique value\n * (suggestion: use `nanoid`).\n * * If `controlFlags & StreamOpenBit == StreamOpenBit`, `serviceName` and `procedureName` must be set.\n * * If `controlFlags & StreamClosedBit == StreamClosedBit` and the kind is `stream` or `subscription`,\n * `payload` should be discarded (usually contains a control message).\n * * If `controlFlags & AckBit == AckBit`, the message is an explicit acknowledgement message and doesn't\n * contain any payload that is relevant to the application so should not be delivered.\n * @template Payload The type of the payload.\n */\nexport interface TransportMessage<Payload = unknown> {\n id: string;\n from: string;\n to: string;\n seq: number;\n ack: number;\n serviceName?: string;\n procedureName?: string;\n streamId: string;\n controlFlags: number;\n tracing?: PropagationContext;\n payload: Payload;\n}\n\nexport type PartialTransportMessage<Payload = unknown> = Omit<\n TransportMessage<Payload>,\n 'id' | 'from' | 'to' | 'seq' | 'ack'\n>;\n\nexport function handshakeRequestMessage({\n from,\n to,\n sessionId,\n expectedSessionState,\n metadata,\n tracing,\n}: {\n from: TransportClientId;\n to: TransportClientId;\n sessionId: string;\n expectedSessionState: Static<\n typeof ControlMessageHandshakeRequestSchema\n >['expectedSessionState'];\n metadata?: unknown;\n tracing?: PropagationContext;\n}): TransportMessage<Static<typeof ControlMessageHandshakeRequestSchema>> {\n return {\n id: generateId(),\n from,\n to,\n seq: 0,\n ack: 0,\n streamId: generateId(),\n controlFlags: 0,\n tracing,\n payload: {\n type: 'HANDSHAKE_REQ',\n protocolVersion: PROTOCOL_VERSION,\n sessionId,\n expectedSessionState,\n metadata,\n } satisfies Static<typeof ControlMessageHandshakeRequestSchema>,\n };\n}\n\n/**\n * This is a reason that can be given during the handshake to indicate that the peer has the wrong\n * session state.\n */\nexport const SESSION_STATE_MISMATCH = 'session state mismatch';\n\nexport function handshakeResponseMessage({\n from,\n to,\n status,\n}: {\n from: TransportClientId;\n to: TransportClientId;\n status: Static<typeof ControlMessageHandshakeResponseSchema>['status'];\n}): TransportMessage<Static<typeof ControlMessageHandshakeResponseSchema>> {\n return {\n id: generateId(),\n from,\n to,\n seq: 0,\n ack: 0,\n streamId: generateId(),\n controlFlags: 0,\n payload: {\n type: 'HANDSHAKE_RESP',\n status,\n } satisfies Static<typeof ControlMessageHandshakeResponseSchema>,\n };\n}\n\nexport function closeStreamMessage(streamId: string): PartialTransportMessage {\n return {\n streamId,\n controlFlags: ControlFlags.StreamClosedBit,\n payload: {\n type: 'CLOSE' as const,\n } satisfies Static<typeof ControlMessagePayloadSchema>,\n };\n}\n\n/**\n * A type alias for a transport message with an opaque payload.\n * @template T - The type of the opaque payload.\n */\nexport type OpaqueTransportMessage = TransportMessage;\nexport type TransportClientId = string;\n\n/**\n * Checks if the given control flag (usually found in msg.controlFlag) is an ack message.\n * @param controlFlag - The control flag to check.\n * @returns True if the control flag contains the AckBit, false otherwise.\n */\nexport function isAck(controlFlag: number): boolean {\n /* eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison */\n return (controlFlag & ControlFlags.AckBit) === ControlFlags.AckBit;\n}\n\n/**\n * Checks if the given control flag (usually found in msg.controlFlag) is a stream open message.\n * @param controlFlag - The control flag to check.\n * @returns True if the control flag contains the StreamOpenBit, false otherwise.\n */\nexport function isStreamOpen(controlFlag: number): boolean {\n return (\n /* eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison */\n (controlFlag & ControlFlags.StreamOpenBit) === ControlFlags.StreamOpenBit\n );\n}\n\n/**\n * Checks if the given control flag (usually found in msg.controlFlag) is a stream close message.\n * @param controlFlag - The control flag to check.\n * @returns True if the control flag contains the StreamCloseBit, false otherwise.\n */\nexport function isStreamClose(controlFlag: number): boolean {\n return (\n /* eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison */\n (controlFlag & ControlFlags.StreamClosedBit) ===\n ControlFlags.StreamClosedBit\n );\n}\n","import { Codec } from './types';\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n// Convert Uint8Array to base64\nfunction uint8ArrayToBase64(uint8Array: Uint8Array) {\n let binary = '';\n uint8Array.forEach((byte) => {\n binary += String.fromCharCode(byte);\n });\n return btoa(binary);\n}\n\n// Convert base64 to Uint8Array\nfunction base64ToUint8Array(base64: string) {\n const binaryString = atob(base64);\n const uint8Array = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n uint8Array[i] = binaryString.charCodeAt(i);\n }\n return uint8Array;\n}\n\ninterface Base64EncodedValue {\n $t: string;\n}\n\n/**\n * Naive JSON codec implementation using JSON.stringify and JSON.parse.\n * @type {Codec}\n */\nexport const NaiveJsonCodec: Codec = {\n toBuffer: (obj: object) => {\n return encoder.encode(\n JSON.stringify(obj, function replacer<\n T extends object,\n >(this: T, key: keyof T) {\n const val = this[key];\n if (val instanceof Uint8Array) {\n return { $t: uint8ArrayToBase64(val) } satisfies Base64EncodedValue;\n } else {\n return val;\n }\n }),\n );\n },\n fromBuffer: (buff: Uint8Array) => {\n try {\n const parsed = JSON.parse(\n decoder.decode(buff),\n function reviver(_key, val: unknown) {\n if ((val as Base64EncodedValue | undefined)?.$t) {\n return base64ToUint8Array((val as Base64EncodedValue).$t);\n } else {\n return val;\n }\n },\n ) as unknown;\n\n if (typeof parsed === 'object') return parsed;\n return null;\n } catch {\n return null;\n }\n },\n};\n","import { NaiveJsonCodec } from '../codec/json';\nimport { ConnectionRetryOptions } from './rateLimit';\nimport { SessionOptions } from './sessionStateMachine/common';\n\nexport type TransportOptions = SessionOptions;\n\nexport type ProvidedTransportOptions = Partial<TransportOptions>;\n\nexport const defaultTransportOptions: TransportOptions = {\n heartbeatIntervalMs: 1_000,\n heartbeatsUntilDead: 2,\n sessionDisconnectGraceMs: 5_000,\n connectionTimeoutMs: 2_000,\n handshakeTimeoutMs: 1_000,\n codec: NaiveJsonCodec,\n};\n\nexport type ClientTransportOptions = TransportOptions & ConnectionRetryOptions;\n\nexport type ProvidedClientTransportOptions = Partial<ClientTransportOptions>;\n\nconst defaultConnectionRetryOptions: ConnectionRetryOptions = {\n baseIntervalMs: 250,\n maxJitterMs: 200,\n maxBackoffMs: 32_000,\n attemptBudgetCapacity: 5,\n budgetRestoreIntervalMs: 200,\n};\n\nexport const defaultClientTransportOptions: ClientTransportOptions = {\n ...defaultTransportOptions,\n ...defaultConnectionRetryOptions,\n};\n\nexport type ServerTransportOptions = TransportOptions;\n\nexport type ProvidedServerTransportOptions = Partial<ServerTransportOptions>;\n\nexport const defaultServerTransportOptions: ServerTransportOptions = {\n ...defaultTransportOptions,\n};\n","import { ValueError } from '@sinclair/typebox/value';\nimport { OpaqueTransportMessage } from '../transport/message';\n\nconst LoggingLevels = {\n debug: -1,\n info: 0,\n warn: 1,\n error: 2,\n} as const;\nexport type LoggingLevel = keyof typeof LoggingLevels;\n\nexport type LogFn = (\n msg: string,\n ctx?: MessageMetadata,\n level?: LoggingLevel,\n) => void;\nexport type Logger = {\n [key in LoggingLevel]: (msg: string, metadata?: MessageMetadata) => void;\n};\n\nexport type Tags = 'invariant-violation' | 'state-transition';\n\nconst cleanedLogFn = (log: LogFn) => {\n return (msg: string, metadata?: MessageMetadata) => {\n // skip cloning object if metadata has no transportMessage\n if (!metadata?.transportMessage) {\n log(msg, metadata);\n return;\n }\n\n // clone metadata and clean transportMessage\n const { payload, ...rest } = metadata.transportMessage;\n metadata.transportMessage = rest;\n log(msg, metadata);\n };\n};\n\nexport type MessageMetadata = Partial<{\n protocolVersion: string;\n clientId: string;\n connectedTo: string;\n sessionId: string;\n connId: string;\n transportMessage: Partial<OpaqueTransportMessage>;\n validationErrors: Array<ValueError>;\n tags: Array<Tags>;\n telemetry: {\n traceId: string;\n spanId: string;\n };\n}>;\n\nexport class BaseLogger implements Logger {\n minLevel: LoggingLevel;\n private output: LogFn;\n\n constructor(output: LogFn, minLevel: LoggingLevel = 'info') {\n this.minLevel = minLevel;\n this.output = output;\n }\n\n debug(msg: string, metadata?: MessageMetadata) {\n if (LoggingLevels[this.minLevel] <= LoggingLevels.debug) {\n this.output(msg, metadata ?? {}, 'debug');\n }\n }\n\n info(msg: string, metadata?: MessageMetadata) {\n if (LoggingLevels[this.minLevel] <= LoggingLevels.info) {\n this.output(msg, metadata ?? {}, 'info');\n }\n }\n\n warn(msg: string, metadata?: MessageMetadata) {\n if (LoggingLevels[this.minLevel] <= LoggingLevels.warn) {\n this.output(msg, metadata ?? {}, 'warn');\n }\n }\n\n error(msg: string, metadata?: MessageMetadata) {\n if (LoggingLevels[this.minLevel] <= LoggingLevels.error) {\n this.output(msg, metadata ?? {}, 'error');\n }\n }\n}\n\nexport const stringLogger: LogFn = (msg, ctx, level = 'info') => {\n const from = ctx?.clientId ? `${ctx.clientId} -- ` : '';\n console.log(`[river:${level}] ${from}${msg}`);\n};\n\nconst colorMap = {\n debug: '\\u001b[34m',\n info: '\\u001b[32m',\n warn: '\\u001b[33m',\n error: '\\u001b[31m',\n};\n\nexport const coloredStringLogger: LogFn = (msg, ctx, level = 'info') => {\n const color = colorMap[level];\n const from = ctx?.clientId ? `${ctx.clientId} -- ` : '';\n console.log(`[river:${color}${level}\\u001b[0m] ${from}${msg}`);\n};\n\nexport const jsonLogger: LogFn = (msg, ctx, level) => {\n console.log(JSON.stringify({ msg, ctx, level }));\n};\n\nexport const createLogProxy = (log: Logger) => ({\n debug: cleanedLogFn(log.debug.bind(log)),\n info: cleanedLogFn(log.info.bind(log)),\n warn: cleanedLogFn(log.warn.bind(log)),\n error: cleanedLogFn(log.error.bind(log)),\n});\n","import { Connection } from './connection';\nimport { OpaqueTransportMessage } from './message';\nimport { Session, SessionState } from './sessionStateMachine';\nimport { TransportStatus } from './transport';\n\nexport const ProtocolError = {\n RetriesExceeded: 'conn_retry_exceeded',\n HandshakeFailed: 'handshake_failed',\n MessageOrderingViolated: 'message_ordering_violated',\n} as const;\n\nexport type ProtocolErrorType =\n (typeof ProtocolError)[keyof typeof ProtocolError];\n\nexport interface EventMap {\n message: OpaqueTransportMessage;\n sessionStatus: {\n status: 'connect' | 'disconnect';\n session: Session<Connection>;\n };\n sessionTransition:\n | { state: SessionState.Connected }\n | { state: SessionState.Handshaking }\n | { state: SessionState.Connecting }\n | { state: SessionState.NoConnection };\n protocolError: {\n type: ProtocolErrorType;\n message: string;\n };\n transportStatus: {\n status: TransportStatus;\n };\n}\n\nexport type EventTypes = keyof EventMap;\nexport type EventHandler<K extends EventTypes> = (\n event: EventMap[K],\n) => unknown;\n\nexport class EventDispatcher<T extends EventTypes> {\n private eventListeners: { [K in T]?: Set<EventHandler<K>> } = {};\n\n removeAllListeners() {\n this.eventListeners = {};\n }\n\n numberOfListeners<K extends T>(eventType: K) {\n return this.eventListeners[eventType]?.size ?? 0;\n }\n\n addEventListener<K extends T>(eventType: K, handler: EventHandler<K>) {\n if (!this.eventListeners[eventType]) {\n this.eventListeners[eventType] = new Set();\n }\n\n this.eventListeners[eventType]?.add(handler);\n }\n\n removeEventListener<K extends T>(eventType: K, handler: EventHandler<K>) {\n const handlers = this.eventListeners[eventType];\n if (handlers) {\n this.eventListeners[eventType]?.delete(handler);\n }\n }\n\n dispatchEvent<K extends T>(eventType: K, event: EventMap[K]) {\n const handlers = this.eventListeners[eventType];\n if (handlers) {\n // copying ensures that adding more listeners in a handler doesn't\n // affect the current dispatch.\n const copy = [...handlers];\n for (const handler of copy) {\n handler(event);\n }\n }\n }\n}\n","import { Logger, MessageMetadata } from '../../logging';\nimport { TelemetryInfo } from '../../tracing';\nimport {\n OpaqueTransportMessage,\n OpaqueTransportMessageSchema,\n PartialTransportMessage,\n TransportClientId,\n TransportMessage,\n} from '../message';\nimport { Value } from '@sinclair/typebox/value';\nimport { SessionNoConnection } from './SessionNoConnection';\nimport { SessionConnecting } from './SessionConnecting';\nimport { SessionHandshaking } from './SessionHandshaking';\nimport { SessionConnected } from './SessionConnected';\nimport { Codec } from '../../codec';\nimport { Connection } from '../connection';\nimport { generateId } from '../id';\n\nexport const enum SessionState {\n NoConnection = 'NoConnection',\n Connecting = 'Connecting',\n Handshaking = 'Handshaking',\n Connected = 'Connected',\n WaitingForHandshake = 'WaitingForHandshake',\n}\n\nexport type Session<ConnType extends Connection> =\n | SessionNoConnection\n | SessionConnecting<ConnType>\n | SessionHandshaking<ConnType>\n | SessionConnected<ConnType>;\n\nexport const ERR_CONSUMED = `session state has been consumed and is no longer valid`;\n\nabstract class StateMachineState {\n abstract readonly state: SessionState;\n\n /*\n * Whether this state has been consumed\n * and we've moved on to another state\n */\n _isConsumed: boolean;\n\n // called when we're transitioning to another state\n // note that this is internal and should not be called directly\n // by consumers, the proxy will call this when the state is consumed\n // and we're transitioning to another state\n abstract _handleStateExit(): void;\n\n // called when we exit the state machine entirely\n // note that this is internal and should not be called directly\n // by consumers, the proxy will call this when .close is closed\n abstract _handleClose(): void;\n\n close(): void {\n this._handleClose();\n }\n\n constructor() {\n this._isConsumed = false;\n\n // proxy helps us prevent access to properties after the state has been consumed\n // e.g. if we hold a reference to a state and try to access it after it's been consumed\n // we intercept the access and throw an error to help catch bugs\n return new Proxy(this, {\n get(target, prop) {\n // always allow access to _isConsumed, id, and state\n if (prop === '_isConsumed' || prop === 'id' || prop === 'state') {\n return Reflect.get(target, prop);\n }\n\n // modify _handleStateExit\n if (prop === '_handleStateExit') {\n return () => {\n target._isConsumed = true;\n target._handleStateExit();\n };\n }\n\n // modify _handleClose\n if (prop === '_handleClose') {\n return () => {\n target._handleStateExit();\n target._handleClose();\n };\n }\n\n if (target._isConsumed) {\n throw new Error(\n `${ERR_CONSUMED}: getting ${prop.toString()} on consumed state`,\n );\n }\n\n return Reflect.get(target, prop);\n },\n set(target, prop, value) {\n if (target._isConsumed) {\n throw new Error(\n `${ERR_CONSUMED}: setting ${prop.toString()} on consumed state`,\n );\n }\n\n return Reflect.set(target, prop, value);\n },\n });\n }\n}\n\nexport interface SessionOptions {\n /**\n * Frequency at which to send heartbeat acknowledgements\n */\n heartbeatIntervalMs: number;\n /**\n * Number of elapsed heartbeats without a response message before we consider\n * the connection dead.\n */\n heartbeatsUntilDead: number;\n /**\n * Duration to wait between connection disconnect and actual session disconnect\n */\n sessionDisconnectGraceMs: number;\n /**\n * Connection timeout in milliseconds\n */\n connectionTimeoutMs: number;\n /**\n * Handshake timeout in milliseconds\n */\n handshakeTimeoutMs: number;\n /**\n * The codec to use for encoding/decoding messages over the wire\n */\n codec: Codec;\n}\n\n// all session states have a from and options\nexport abstract class CommonSession extends StateMachineState {\n readonly from: TransportClientId;\n readonly options: SessionOptions;\n\n log?: Logger;\n abstract get loggingMetadata(): MessageMetadata;\n\n constructor(\n from: TransportClientId,\n options: SessionOptions,\n log: Logger | undefined,\n ) {\n super();\n this.from = from;\n this.options = options;\n this.log = log;\n }\n\n parseMsg(msg: Uint8Array): OpaqueTransportMessage | null {\n const parsedMsg = this.options.codec.fromBuffer(msg);\n\n if (parsedMsg === null) {\n const decodedBuffer = new TextDecoder().decode(Buffer.from(msg));\n this.log?.error(\n `received malformed msg: ${decodedBuffer}`,\n this.loggingMetadata,\n );\n return null;\n }\n\n if (!Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {\n this.log?.error(`received invalid msg: ${JSON.stringify(parsedMsg)}`, {\n ...this.loggingMetadata,\n validationErrors: [\n ...Value.Errors(OpaqueTransportMessageSchema, parsedMsg),\n ],\n });\n\n return null;\n }\n\n return parsedMsg;\n }\n}\n\nexport type InheritedProperties = Pick<\n IdentifiedSession,\n 'id' | 'from' | 'to' | 'seq' | 'ack' | 'sendBuffer' | 'telemetry' | 'options'\n>;\n\nexport type SessionId = string;\n\n// all sessions where we know the other side's client id\nexport abstract class IdentifiedSession extends CommonSession {\n readonly id: SessionId;\n readonly telemetry: TelemetryInfo;\n readonly to: TransportClientId;\n\n /**\n * Index of the message we will send next (excluding handshake)\n */\n seq: number;\n\n /**\n * Number of unique messages we've received this session (excluding handshake)\n */\n ack: number;\n sendBuffer: Array<OpaqueTransportMessage>;\n\n constructor(\n id: SessionId,\n from: TransportClientId,\n to: TransportClientId,\n seq: number,\n ack: number,\n sendBuffer: Array<OpaqueTransportMessage>,\n telemetry: TelemetryInfo,\n options: SessionOptions,\n log: Logger | undefined,\n ) {\n super(from, options, log);\n this.id = id;\n this.to = to;\n this.seq = seq;\n this.ack = ack;\n this.sendBuffer = sendBuffer;\n this.telemetry = telemetry;\n this.log = log;\n }\n\n get loggingMetadata(): MessageMetadata {\n const spanContext = this.telemetry.span.spanContext();\n\n return {\n clientId: this.from,\n connectedTo: this.to,\n sessionId: this.id,\n telemetry: {\n traceId: spanContext.traceId,\n spanId: spanContext.spanId,\n },\n };\n }\n\n constructMsg<Payload>(\n partialMsg: PartialTransportMessage<Payload>,\n ): TransportMessage<Payload> {\n const msg = {\n ...partialMsg,\n id: generateId(),\n to: this.to,\n from: this.from,\n seq: this.seq,\n ack: this.ack,\n };\n\n this.seq++;\n return msg;\n }\n\n nextSeq(): number {\n return this.sendBuffer.length > 0 ? this.sendBuffer[0].seq : this.seq;\n }\n\n send(msg: PartialTransportMessage): string {\n const constructedMsg = this.constructMsg(msg);\n this.sendBuffer.push(constructedMsg);\n return constructedMsg.id;\n }\n\n _handleStateExit(): void {\n // noop\n }\n\n _handleClose(): void {\n // zero out the buffer\n this.sendBuffer.length = 0;\n this.telemetry.span.end();\n }\n}\n","import { Connection } from '../connection';\nimport { IdentifiedSession, SessionState } from './common';\n\nexport interface SessionConnectingListeners {\n onConnectionEstablished: (conn: Connection) => void;\n onConnectionFailed: (err: unknown) => void;\n\n // timeout related\n onConnectionTimeout: () => void;\n}\n\n/*\n * A session that is connecting but we don't have access to the raw connection\n * yet.\n *\n * Valid transitions:\n * - Connecting -> NoConnection (timeout)\n * - Connecting -> Handshaking (on connection established)\n */\nexport class SessionConnecting<\n ConnType extends Connection,\n> extends IdentifiedSession {\n readonly state = SessionState.Connecting as const;\n connPromise: Promise<ConnType>;\n listeners: SessionConnectingListeners;\n\n connectionTimeout?: ReturnType<typeof setTimeout>;\n\n constructor(\n connPromise: Promise<ConnType>,\n listeners: SessionConnectingListeners,\n ...args: ConstructorParameters<typeof IdentifiedSession>\n ) {\n super(...args);\n this.connPromise = connPromise;\n this.listeners = listeners;\n\n this.connectionTimeout = setTimeout(() => {\n listeners.onConnectionTimeout();\n }, this.options.connectionTimeoutMs);\n\n connPromise.then(\n (conn) => {\n if (this._isConsumed) return;\n listeners.onConnectionEstablished(conn);\n },\n (err) => {\n if (this._isConsumed) return;\n listeners.onConnectionFailed(err);\n },\n );\n }\n\n // close a pending connection if it resolves, ignore errors if the promise\n // ends up rejected anyways\n bestEffortClose() {\n void this.connPromise\n .then((conn) => conn.close())\n .catch(() => {\n // ignore errors\n });\n }\n\n _handleStateExit(): void {\n super._handleStateExit();\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = undefined;\n }\n\n _handleClose(): void {\n // close the pending connection if it resolves\n this.bestEffortClose();\n super._handleClose();\n }\n}\n","import { IdentifiedSession, SessionState } from './common';\n\nexport interface SessionNoConnectionListeners {\n // timeout related\n onSessionGracePeriodElapsed: () => void;\n}\n\n/*\n * A session that is not connected and cannot send or receive messages.\n *\n * Valid transitions:\n * - NoConnection -> Connecting (on connect)\n */\nexport class SessionNoConnection extends IdentifiedSession {\n readonly state = SessionState.NoConnection as const;\n listeners: SessionNoConnectionListeners;\n\n gracePeriodTimeout?: ReturnType<typeof setTimeout>;\n\n constructor(\n listeners: SessionNoConnectionListeners,\n ...args: ConstructorParameters<typeof IdentifiedSession>\n ) {\n super(...args);\n this.listeners = listeners;\n\n this.gracePeriodTimeout = setTimeout(() => {\n this.listeners.onSessionGracePeriodElapsed();\n }, this.options.sessionDisconnectGraceMs);\n }\n\n _handleClose(): void {\n super._handleClose();\n }\n\n _handleStateExit(): void {\n super._handleStateExit();\n\n if (this.gracePeriodTimeout) {\n clearTimeout(this.gracePeriodTimeout);\n this.gracePeriodTimeout = undefined;\n }\n }\n}\n","import {\n Context,\n Span,\n SpanKind,\n context,\n propagation,\n trace,\n} from '@opentelemetry/api';\nimport { version as RIVER_VERSION } from '../package.json';\nimport { ValidProcType } from '../router';\nimport {\n ClientTransport,\n Connection,\n OpaqueTransportMessage,\n} from '../transport';\n\nexport interface PropagationContext {\n traceparent: string;\n tracestate: string;\n}\n\nexport interface TelemetryInfo {\n span: Span;\n ctx: Context;\n}\n\nexport function getPropagationContext(\n ctx: Context,\n): PropagationContext | undefined {\n const tracing = {\n traceparent: '',\n tracestate: '',\n };\n propagation.inject(ctx, tracing);\n return tracing;\n}\n\nexport function createSessionTelemetryInfo(\n sessionId: string,\n to: string,\n from: string,\n propagationCtx?: PropagationContext,\n): TelemetryInfo {\n const parentCtx = propagationCtx\n ? propagation.extract(context.active(), propagationCtx)\n : context.active();\n\n const span = tracer.startSpan(\n `session ${sessionId}`,\n {\n attributes: {\n component: 'river',\n 'river.session.id': sessionId,\n 'river.session.to': to,\n 'river.session.from': from,\n },\n },\n parentCtx,\n );\n\n const ctx = trace.setSpan(parentCtx, span);\n\n return { span, ctx };\n}\n\nexport function createConnectionTelemetryInfo(\n connection: Connection,\n info: TelemetryInfo,\n): TelemetryInfo {\n const span = tracer.startSpan(\n `connection ${connection.id}`,\n {\n attributes: {\n component: 'river',\n 'river.connection.id': connection.id,\n },\n links: [{ context: info.span.spanContext() }],\n },\n info.ctx,\n );\n\n const ctx = trace.setSpan(info.ctx, span);\n\n return { span, ctx };\n}\n\nexport function createProcTelemetryInfo(\n transport: ClientTransport<Connection>,\n kind: ValidProcType,\n serviceName: string,\n procedureName: string,\n streamId: string,\n): TelemetryInfo {\n const baseCtx = context.active();\n const span = tracer.startSpan(\n `procedure call ${serviceName}.${procedureName}`,\n {\n attributes: {\n component: 'river',\n 'river.method.kind': kind,\n 'river.method.service': serviceName,\n 'river.method.name': procedureName,\n 'river.streamId': streamId,\n 'span.kind': 'client',\n },\n kind: SpanKind.CLIENT,\n },\n baseCtx,\n );\n\n const ctx = trace.setSpan(baseCtx, span);\n\n transport.log?.info(`invoked ${serviceName}.${procedureName}`, {\n clientId: transport.clientId,\n transportMessage: {\n procedureName,\n serviceName,\n },\n telemetry: {\n traceId: span.spanContext().traceId,\n spanId: span.spanContext().spanId,\n },\n });\n return { span, ctx };\n}\n\nexport function createHandlerSpan(\n kind: ValidProcType,\n message: OpaqueTransportMessage,\n fn: (span: Span) => Promise<unknown>,\n) {\n const ctx = message.tracing\n ? propagation.extract(context.active(), message.tracing)\n : context.active();\n\n return tracer.startActiveSpan(\n `procedure handler ${message.serviceName}.${message.procedureName}`,\n {\n attributes: {\n component: 'river',\n 'river.method.kind': kind,\n 'river.method.service': message.serviceName,\n 'river.method.name': message.procedureName,\n 'river.streamId': message.streamId,\n 'span.kind': 'server',\n },\n kind: SpanKind.SERVER,\n },\n ctx,\n fn,\n );\n}\n\nconst tracer = trace.getTracer('river', RIVER_VERSION);\nexport default tracer;\n","{\n \"name\": \"@replit/river\",\n \"description\": \"It's like tRPC but... with JSON Schema Support, duplex streaming and support for service multiplexing. Transport agnostic!\",\n \"version\": \"0.24.3\",\n \"type\": \"module\",\n \"exports\": {\n \".\": {\n \"import\": \"./dist/router/index.js\",\n \"require\": \"./dist/router/index.cjs\"\n },\n \"./logging\": {\n \"import\": \"./dist/logging/index.js\",\n \"require\": \"./dist/logging/index.cjs\"\n },\n \"./codec\": {\n \"import\": \"./dist/codec/index.js\",\n \"require\": \"./dist/codec/index.cjs\"\n },\n \"./transport\": {\n \"import\": \"./dist/transport/index.js\",\n \"require\": \"./dist/transport/index.cjs\"\n },\n \"./transport/ws/client\": {\n \"import\": \"./dist/transport/impls/ws/client.js\",\n \"require\": \"./dist/transport/impls/ws/client.cjs\"\n },\n \"./transport/ws/server\": {\n \"import\": \"./dist/transport/impls/ws/server.js\",\n \"require\": \"./dist/transport/impls/ws/server.cjs\"\n },\n \"./transport/uds/client\": {\n \"import\": \"./dist/transport/impls/uds/client.js\",\n \"require\": \"./dist/transport/impls/uds/client.cjs\"\n },\n \"./transport/uds/server\": {\n \"import\": \"./dist/transport/impls/uds/server.js\",\n \"require\": \"./dist/transport/impls/uds/server.cjs\"\n },\n \"./test-util\": {\n \"import\": \"./dist/util/testHelpers.js\",\n \"require\": \"./dist/util/testHelpers.cjs\"\n }\n },\n \"sideEffects\": [\n \"./dist/logging/index.js\"\n ],\n \"files\": [\n \"dist\"\n ],\n \"dependencies\": {\n \"@msgpack/msgpack\": \"^3.0.0-beta2\",\n \"it-pushable\": \"^3.2.3\",\n \"nanoid\": \"^4.0.2\",\n \"ws\": \"^8.17.0\"\n },\n \"peerDependencies\": {\n \"@opentelemetry/api\": \"^1.7.0\",\n \"@sinclair/typebox\": \"~0.32.8\"\n },\n \"devDependencies\": {\n \"@opentelemetry/sdk-trace-base\": \"^1.24.1\",\n \"@opentelemetry/sdk-trace-web\": \"^1.24.1\",\n \"@opentelemetry/core\": \"^1.7.0\",\n \"@types/ws\": \"^8.5.5\",\n \"@typescript-eslint/eslint-plugin\": \"^7.8.0\",\n \"@typescript-eslint/parser\": \"^7.8.0\",\n \"@vitest/ui\": \"^1.3.1\",\n \"eslint\": \"^8.57.0\",\n \"eslint-config-prettier\": \"^9.1.0\",\n \"eslint-plugin-prettier\": \"^5.1.3\",\n \"prettier\": \"^3.0.0\",\n \"tsup\": \"^7.2.0\",\n \"typescript\": \"^5.4.5\",\n \"vitest\": \"^1.3.1\"\n },\n \"scripts\": {\n \"check\": \"tsc --noEmit && npm run format && npm run lint\",\n \"format\": \"npx prettier . --check\",\n \"format:fix\": \"npx prettier . --write\",\n \"lint\": \"eslint .\",\n \"lint:fix\": \"eslint . --fix\",\n \"fix\": \"npm run format:fix && npm run lint:fix\",\n \"build\": \"rm -rf dist && tsup && du -sh dist\",\n \"prepack\": \"npm run build\",\n \"release\": \"npm publish --access public\",\n \"test:ui\": \"echo \\\"remember to go to /__vitest__ in the webview\\\" && vitest --ui --api.host 0.0.0.0 --api.port 3000\",\n \"test\": \"vitest\",\n \"test:single\": \"vitest run --reporter=dot\",\n \"test:flake\": \"./flake.sh\",\n \"bench\": \"vitest bench\"\n },\n \"engines\": {\n \"node\": \">=16\"\n },\n \"keywords\": [\n \"rpc\",\n \"websockets\",\n \"jsonschema\"\n ],\n \"author\": \"Jacky Zhao\",\n \"license\": \"MIT\"\n}\n","import { MessageMetadata } from '../../logging';\nimport { Connection } from '../connection';\nimport { TransportMessage } from '../message';\nimport { SessionHandshakingListeners } from './SessionHandshaking';\nimport { CommonSession, SessionState } from './common';\n\n/*\n * Server-side session that has a connection but is waiting for the client to identify itself.\n *\n * Valid transitions:\n * - WaitingForHandshake -> NoConnection (on close)\n * - WaitingForHandshake -> Connected (on handshake)\n */\nexport class SessionWaitingForHandshake<\n ConnType extends Connection,\n> extends CommonSession {\n readonly state = SessionState.WaitingForHandshake as const;\n conn: ConnType;\n listeners: SessionHandshakingListeners;\n\n handshakeTimeout?: ReturnType<typeof setTimeout>;\n\n constructor(\n conn: ConnType,\n listeners: SessionHandshakingListeners,\n ...args: ConstructorParameters<typeof CommonSession>\n ) {\n super(...args);\n this.conn = conn;\n this.listeners = listeners;\n\n this.handshakeTimeout = setTimeout(() => {\n listeners.onHandshakeTimeout();\n }, this.options.handshakeTimeoutMs);\n\n this.conn.addDataListener(this.onHandshakeData);\n this.conn.addErrorListener(listeners.onConnectionErrored);\n this.conn.addCloseListener(listeners.onConnectionClosed);\n }\n\n onHandshakeData = (msg: Uint8Array) => {\n const parsedMsg = this.parseMsg(msg);\n if (parsedMsg === null) {\n this.listeners.onInvalidHandshake('could not parse message');\n return;\n }\n\n // after this fires, the listener is responsible for transitioning the session\n // and thus removing the handshake timeout\n this.listeners.onHandshake(parsedMsg);\n };\n\n get loggingMetadata(): MessageMetadata {\n return {\n clientId: this.from,\n connId: this.conn.id,\n };\n }\n\n sendHandshake(msg: TransportMessage): boolean {\n return this.conn.send(this.options.codec.toBuffer(msg));\n }\n\n _handleStateExit(): void {\n this.conn.removeDataListener(this.onHandshakeData);\n this.conn.removeErrorListener(this.listeners.onConnectionErrored);\n this.conn.removeCloseListener(this.listeners.onConnectionClosed);\n clearTimeout(this.handshakeTimeout);\n this.handshakeTimeout = undefined;\n }\n\n _handleClose(): void {\n this.conn.close();\n }\n}\n","import { Connection } from '../connection';\nimport { OpaqueTransportMessage, TransportMessage } from '../message';\nimport { IdentifiedSession, SessionState } from './common';\n\nexport interface SessionHandshakingListeners {\n onConnectionErrored: (err: unknown) => void;\n onConnectionClosed: () => void;\n onHandshake: (msg: OpaqueTransportMessage) => void;\n onInvalidHandshake: (reason: string) => void;\n\n // timeout related\n onHandshakeTimeout: () => void;\n}\n\n/*\n * A session that is handshaking and waiting for the other side to identify itself.\n *\n * Valid transitions:\n * - Handshaking -> NoConnection (on close)\n * - Handshaking -> Connected (on handshake)\n */\nexport class SessionHandshaking<\n ConnType extends Connection,\n> extends IdentifiedSession {\n readonly state = SessionState.Handshaking as const;\n conn: ConnType;\n listeners: SessionHandshakingListeners;\n\n handshakeTimeout: ReturnType<typeof setTimeout>;\n\n constructor(\n conn: ConnType,\n listeners: SessionHandshakingListeners,\n ...args: ConstructorParameters<typeof IdentifiedSession>\n ) {\n super(...args);\n this.conn = conn;\n this.listeners = listeners;\n\n this.handshakeTimeout = setTimeout(() => {\n listeners.onHandshakeTimeout();\n }, this.options.handshakeTimeoutMs);\n\n this.conn.addDataListener(this.onHandshakeData);\n this.conn.addErrorListener(listeners.onConnectionErrored);\n this.conn.addCloseListener(listeners.onConnectionClosed);\n }\n\n onHandshakeData = (msg: Uint8Array) => {\n const parsedMsg = this.parseMsg(msg);\n if (parsedMsg === null) {\n this.listeners.onInvalidHandshake('could not parse message');\n return;\n }\n\n this.listeners.onHandshake(parsedMsg);\n };\n\n sendHandshake(msg: TransportMessage): boolean {\n return this.conn.send(this.options.codec.toBuffer(msg));\n }\n\n _handleStateExit(): void {\n super._handleStateExit();\n this.conn.removeDataListener(this.onHandshakeData);\n this.conn.removeErrorListener(this.listeners.onConnectionErrored);\n this.conn.removeCloseListener(this.listeners.onConnectionClosed);\n clearTimeout(this.handshakeTimeout);\n }\n\n _handleClose(): void {\n super._handleClose();\n this.conn.close();\n }\n}\n","import { Static } from '@sinclair/typebox';\nimport {\n ControlFlags,\n ControlMessageAckSchema,\n OpaqueTransportMessage,\n PartialTransportMessage,\n isAck,\n} from '../message';\nimport { IdentifiedSession, SessionState } from './common';\nimport { Connection } from '../connection';\nimport { SpanStatusCode } from '@opentelemetry/api';\n\nexport interface SessionConnectedListeners {\n onConnectionErrored: (err: unknown) => void;\n onConnectionClosed: () => void;\n onMessage: (msg: OpaqueTransportMessage) => void;\n onInvalidMessage: (reason: string) => void;\n}\n\n/*\n * A session that is connected and can send and receive messages.\n *\n * Valid transitions:\n * - Connected -> NoConnection (on close)\n */\nexport class SessionConnected<\n ConnType extends Connection,\n> extends IdentifiedSession {\n readonly state = SessionState.Connected as const;\n conn: ConnType;\n listeners: SessionConnectedListeners;\n\n heartbeatHandle?: ReturnType<typeof setInterval> | undefined;\n heartbeatMisses = 0;\n\n get isActivelyHeartbeating() {\n return this.heartbeatHandle !== undefined;\n }\n\n updateBookkeeping(ack: number, seq: number) {\n this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq >= ack);\n this.ack = seq + 1;\n this.heartbeatMisses = 0;\n }\n\n send(msg: PartialTransportMessage): string {\n const constructedMsg = this.constructMsg(msg);\n this.sendBuffer.push(constructedMsg);\n this.conn.send(this.options.codec.toBuffer(constructedMsg));\n return constructedMsg.id;\n }\n\n constructor(\n conn: ConnType,\n listeners: SessionConnectedListeners,\n ...args: ConstructorParameters<typeof IdentifiedSession>\n ) {\n super(...args);\n this.conn = conn;\n this.listeners = listeners;\n\n this.conn.addDataListener(this.onMessageData);\n this.conn.addCloseListener(listeners.onConnectionClosed);\n this.conn.addErrorListener(listeners.onConnectionErrored);\n\n // send any buffered messages\n if (this.sendBuffer.length > 0) {\n this.log?.debug(\n `sending ${this.sendBuffer.length} buffered messages`,\n this.loggingMetadata,\n );\n }\n\n for (const msg of this.sendBuffer) {\n conn.send(this.options.codec.toBuffer(msg));\n }\n\n // dont explicity clear the buffer, we'll just filter out old messages\n // when we receive an ack\n }\n\n startActiveHeartbeat() {\n this.heartbeatHandle = setInterval(() => {\n const misses = this.heartbeatMisses;\n const missDuration = misses * this.options.heartbeatIntervalMs;\n if (misses >= this.options.heartbeatsUntilDead) {\n this.log?.info(\n `closing connection to ${this.to} due to inactivity (missed ${misses} heartbeats which is ${missDuration}ms)`,\n this.loggingMetadata,\n );\n this.telemetry.span.addEvent('closing connection due to inactivity');\n this.conn.close();\n clearInterval(this.heartbeatHandle);\n this.heartbeatHandle = undefined;\n return;\n }\n\n this.sendHeartbeat();\n this.heartbeatMisses++;\n }, this.options.heartbeatIntervalMs);\n }\n\n private sendHeartbeat() {\n this.send({\n streamId: 'heartbeat',\n controlFlags: ControlFlags.AckBit,\n payload: {\n type: 'ACK',\n } satisfies Static<typeof ControlMessageAckSchema>,\n });\n }\n\n onMessageData = (msg: Uint8Array) => {\n const parsedMsg = this.parseMsg(msg);\n if (parsedMsg === null) return;\n\n // check message ordering here\n if (parsedMsg.seq !== this.ack) {\n if (parsedMsg.seq < this.ack) {\n this.log?.debug(\n `received duplicate msg (got seq: ${parsedMsg.seq}, wanted seq: ${this.ack}), discarding`,\n {\n ...this.loggingMetadata,\n transportMessage: parsedMsg,\n },\n );\n } else {\n const reason = `received out-of-order msg (got seq: ${parsedMsg.seq}, wanted seq: ${this.ack})`;\n this.log?.error(reason, {\n ...this.loggingMetadata,\n transportMessage: parsedMsg,\n tags: ['invariant-violation'],\n });\n this.telemetry.span.setStatus({\n code: SpanStatusCode.ERROR,\n message: reason,\n });\n\n this.listeners.onInvalidMessage(reason);\n }\n\n return;\n }\n\n // message is ok to update bookkeeping with\n this.log?.debug(`received msg`, {\n ...this.loggingMetadata,\n transportMessage: parsedMsg,\n });\n\n this.updateBookkeeping(parsedMsg.ack, parsedMsg.seq);\n\n // dispatch directly if its not an explicit ack\n if (!isAck(parsedMsg.controlFlags)) {\n this.listeners.onMessage(parsedMsg);\n return;\n }\n\n // discard acks (unless we aren't heartbeating in which case just respond)\n this.log?.debug(`discarding msg (ack bit set)`, {\n ...this.loggingMetadata,\n transportMessage: parsedMsg,\n });\n\n // if we are not actively heartbeating, we are in passive\n // heartbeat mode and should send a response to the ack\n if (!this.isActivelyHeartbeating) {\n this.sendHeartbeat();\n }\n };\n\n _handleStateExit(): void {\n super._handleStateExit();\n this.conn.removeDataListener(this.onMessageData);\n this.conn.removeCloseListener(this.listeners.onConnectionClosed);\n this.conn.removeErrorListener(this.listeners.onConnectionErrored);\n clearInterval(this.heartbeatHandle);\n this.heartbeatHandle = undefined;\n }\n\n _handleClose(): void {\n super._handleClose();\n this.conn.close();\n }\n}\n","import { OpaqueTransportMessage, TransportClientId } from '..';\nimport {\n SessionConnecting,\n SessionConnectingListeners,\n} from './SessionConnecting';\nimport {\n SessionNoConnection,\n SessionNoConnectionListeners,\n} from './SessionNoConnection';\nimport { IdentifiedSession, SessionOptions } from './common';\nimport { PropagationContext, createSessionTelemetryInfo } from '../../tracing';\nimport { SessionWaitingForHandshake } from './SessionWaitingForHandshake';\nimport {\n SessionHandshaking,\n SessionHandshakingListeners,\n} from './SessionHandshaking';\nimport {\n SessionConnected,\n SessionConnectedListeners,\n} from './SessionConnected';\nimport { generateId } from '../id';\nimport { Connection } from '../connection';\nimport { Logger } from '../../logging';\n\nfunction inheritSharedSession(\n session: IdentifiedSession,\n): ConstructorParameters<typeof IdentifiedSession> {\n return [\n session.id,\n session.from,\n session.to,\n session.seq,\n session.ack,\n session.sendBuffer,\n session.telemetry,\n session.options,\n session.log,\n ];\n}\n\n/*\n * Session state machine:\n * 1. SessionNoConnection is the client entrypoint as\n * we know who the other side is already, we just need to connect\n * 5. SessionWaitingForHandshake is the server entrypoint\n * as we have a connection but don't know who the other side is yet\n *\n * 1. SessionNoConnection ◄──┐\n * │ reconnect / connect attempt │\n * ▼ │\n * 2. SessionConnecting │\n * │ connect success ──────────────┤ connect failure\n * ▼ │\n * 3. SessionHandshaking │\n * │ handshake success ┌──────┤ connection drop\n * 5. WaitingForHandshake │ handshake failure ─────┤ │\n * │ handshake success ▼ │ │ connection drop\n * ├───────────────────────► 4. SessionConnected │ │ heartbeat misses\n * │ │ invalid message ───────┼──────┘\n * │ ▼ │\n * └───────────────────────► x. Destroy Session ◄─────┘\n * handshake failure\n */\nexport const SessionStateGraph = {\n entrypoints: {\n NoConnection(\n to: TransportClientId,\n from: TransportClientId,\n listeners: SessionNoConnectionListeners,\n options: SessionOptions,\n log?: Logger,\n ) {\n const id = `session-${generateId()}`;\n const telemetry = createSessionTelemetryInfo(id, to, from);\n const sendBuffer: Array<OpaqueTransportMessage> = [];\n\n const session = new SessionNoConnection(\n listeners,\n id,\n from,\n to,\n 0,\n 0,\n sendBuffer,\n telemetry,\n options,\n log,\n );\n\n session.log?.info(`session ${session.id} created in NoConnection state`, {\n ...session.loggingMetadata,\n tags: ['state-transition'],\n });\n\n return session;\n },\n WaitingForHandshake<ConnType extends Connection>(\n from: TransportClientId,\n conn: ConnType,\n listeners: SessionHandshakingListeners,\n options: SessionOptions,\n log?: Logger,\n ): SessionWaitingForHandshake<ConnType> {\n const session = new SessionWaitingForHandshake(\n conn,\n listeners,\n from,\n options,\n log,\n );\n\n session.log?.info(`session created in WaitingForHandshake state`, {\n ...session.loggingMetadata,\n tags: ['state-transition'],\n });\n\n return session;\n },\n },\n // All of the transitions 'move'/'consume' the old session and return a new one.\n // After a session is transitioned, any usage of the old session will throw.\n transition: {\n // happy path transitions\n NoConnectionToConnecting<ConnType extends Connection>(\n oldSession: SessionNoConnection,\n connPromise: Promise<ConnType>,\n listeners: SessionConnectingListeners,\n ): SessionConnecting<ConnType> {\n const carriedState = inheritSharedSession(oldSession);\n oldSession._handleStateExit();\n\n const session = new SessionConnecting(\n connPromise,\n listeners,\n ...carriedState,\n );\n session.log?.info(\n `session ${session.id} transition from NoConnection to Connecting`,\n {\n ...session.loggingMetadata,\n tags: ['state-transition'],\n },\n );\n return session;\n },\n ConnectingToHandshaking<ConnType extends Connection>(\n oldSession: SessionConnecting<ConnType>,\n conn: ConnType,\n listeners: SessionHandshakingListeners,\n ): SessionHandshaking<ConnType> {\n const carriedState = inheritSharedSession(oldSession);\n oldSession._handleStateExit();\n\n const session = new SessionHandshaking(conn, listeners, ...carriedState);\n session.log?.info(\n `session ${session.id} transition from Connecting to Handshaking`,\n {\n ...session.loggingMetadata,\n tags: ['state-transition'],\n },\n );\n\n return session;\n },\n HandshakingToConnected<ConnType extends Connection>(\n oldSession: SessionHandshaking<ConnType>,\n listeners: SessionConnectedListeners,\n ): SessionConnected<ConnType> {\n const carriedState = inheritSharedSession(oldSession);\n const conn = oldSession.conn;\n oldSession._handleStateExit();\n\n const session = new SessionConnected(conn, listeners, ...carriedState);\n session.log?.info(\n `session ${session.id} transition from Handshaking to Connected`,\n {\n ...session.loggingMetadata,\n tags: ['state-transition'],\n },\n );\n\n return session;\n },\n WaitingForHandshakeToConnected<ConnType extends Connection>(\n pendingSession: SessionWaitingForHandshake<ConnType>,\n oldSession: SessionNoConnection | undefined,\n sessionId: string,\n to: TransportClientId,\n propagationCtx: PropagationContext | undefined,\n listeners: SessionConnectedListeners,\n ): SessionConnected<ConnType> {\n const conn = pendingSession.conn;\n const { from, options } = pendingSession;\n const carriedState: ConstructorParameters<typeof IdentifiedSession> =\n oldSession\n ? // old session exists, inherit state\n inheritSharedSession(oldSession)\n : // old session does not exist, create new state\n [\n sessionId,\n from,\n to,\n 0,\n 0,\n [],\n createSessionTelemetryInfo(sessionId, to, from, propagationCtx),\n options,\n pendingSession.log,\n ];\n\n pendingSession._handleStateExit();\n oldSession?._handleStateExit();\n\n const session = new SessionConnected(conn, listeners, ...carriedState);\n session.log?.info(\n `session ${session.id} transition from WaitingForHandshake to Connected`,\n {\n ...session.loggingMetadata,\n tags: ['state-transition'],\n },\n );\n\n return session;\n },\n // disconnect paths\n ConnectingToNoConnection<ConnType extends Connection>(\n oldSession: SessionConnecting<ConnType>,\n listeners: SessionNoConnectionListeners,\n ): SessionNoConnection {\n const carriedState = inheritSharedSession(oldSession);\n oldSession.bestEffortClose();\n oldSession._handleStateExit();\n\n const session = new SessionNoConnection(listeners, ...carriedState);\n session.log?.info(\n `session ${session.id} transition from Connecting to NoConnection`,\n {\n ...session.loggingMetadata,\n tags: ['state-transition'],\n },\n );\n\n return session;\n },\n HandshakingToNoConnection<ConnType extends Connection>(\n oldSession: SessionHandshaking<ConnType>,\n listeners: SessionNoConnectionListeners,\n ): SessionNoConnection {\n const carriedState = inheritSharedSession(oldSession);\n oldSession.conn.close();\n oldSession._handleStateExit();\n\n const session = new SessionNoConnection(listeners, ...carriedState);\n session.log?.info(\n `session ${session.id} transition from Handshaking to NoConnection`,\n {\n ...session.loggingMetadata,\n tags: ['state-transition'],\n },\n );\n\n return session;\n },\n ConnectedToNoConnection<ConnType extends Connection>(\n oldSession: SessionConnected<ConnType>,\n listeners: SessionNoConnectionListeners,\n ): SessionNoConnection {\n const carriedState = inheritSharedSession(oldSession);\n oldSession.conn.close();\n oldSession._handleStateExit();\n\n const session = new SessionNoConnection(listeners, ...carriedState);\n session.log?.info(\n `session ${session.id} transition from Connected to NoConnection`,\n {\n ...session.loggingMetadata,\n tags: ['state-transition'],\n },\n );\n\n return session;\n },\n },\n} as const;\n","import {\n OpaqueTransportMessage,\n TransportClientId,\n PartialTransportMessage,\n} from './message';\nimport {\n BaseLogger,\n LogFn,\n Logger,\n LoggingLevel,\n createLogProxy,\n} from '../logging/log';\nimport {\n EventDispatcher,\n EventHandler,\n EventMap,\n EventTypes,\n ProtocolErrorType,\n} from './events';\nimport {\n ProvidedTransportOptions,\n TransportOptions,\n defaultTransportOptions,\n} from './options';\nimport {\n Session,\n SessionConnected,\n SessionConnecting,\n SessionHandshaking,\n SessionNoConnection,\n SessionState,\n SessionStateGraph,\n} from './sessionStateMachine';\nimport { Connection } from './connection';\n\n/**\n * Represents the possible states of a transport.\n * @property {'open'} open - The transport is open and operational (note that this doesn't mean it is actively connected)\n * @property {'closed'} closed - The transport is permanently closed and cannot be reopened.\n */\nexport type TransportStatus = 'open' | 'closed';\n\n/**\n * Transports manage the lifecycle (creation/deletion) of sessions\n *\n * ```plaintext\n * ▲\n * incoming │\n * messages │\n * ▼\n * ┌─────────────┐ 1:N ┌───────────┐ 1:1* ┌────────────┐\n * │ Transport │ ◄─────► │ Session │ ◄─────► │ Connection │\n * └─────────────┘ └───────────┘ └────────────┘\n * ▲ * (may or may not be initialized yet)\n * │\n * ▼\n * ┌───────────┐\n * │ Message │\n * │ Listeners │\n * └───────────┘\n * ```\n * @abstract\n */\nexport abstract class Transport<ConnType extends Connection> {\n /**\n * The status of the transport.\n */\n private status: TransportStatus;\n\n /**\n * The client ID of this transport.\n */\n clientId: TransportClientId;\n\n /**\n * The event dispatcher for handling events of type EventTypes.\n */\n eventDispatcher: EventDispatcher<EventTypes>;\n\n /**\n * The options for this transport.\n */\n protected options: TransportOptions;\n log?: Logger;\n\n sessions: Map<TransportClientId, Session<ConnType>>;\n\n /**\n * Creates a new Transport instance.\n * @param codec The codec used to encode and decode messages.\n * @param clientId The client ID of this transport.\n */\n constructor(\n clientId: TransportClientId,\n providedOptions?: ProvidedTransportOptions,\n ) {\n this.options = { ...defaultTransportOptions, ...providedOptions };\n this.eventDispatcher = new EventDispatcher();\n this.clientId = clientId;\n this.status = 'open';\n this.sessions = new Map();\n }\n\n bindLogger(fn: LogFn | Logger, level?: LoggingLevel) {\n // construct logger from fn\n if (typeof fn === 'function') {\n this.log = createLogProxy(new BaseLogger(fn, level));\n return;\n }\n\n // object case, just assign\n this.log = createLogProxy(fn);\n }\n\n /**\n * Called when a message is received by this transport.\n * You generally shouldn't need to override this in downstream transport implementations.\n * @param msg The received message.\n */\n protected handleMsg(msg: OpaqueTransportMessage) {\n if (this.getStatus() !== 'open') return;\n this.eventDispatcher.dispatchEvent('message', msg);\n }\n\n /**\n * Adds a listener to this transport.\n * @param the type of event to listen for\n * @param handler The message handler to add.\n */\n addEventListener<K extends EventTypes, T extends EventHandler<K>>(\n type: K,\n handler: T,\n ): void {\n this.eventDispatcher.addEventListener(type, handler);\n }\n\n /**\n * Removes a listener from this transport.\n * @param the type of event to un-listen on\n * @param handler The message handler to remove.\n */\n removeEventListener<K extends EventTypes, T extends EventHandler<K>>(\n type: K,\n handler: T,\n ): void {\n this.eventDispatcher.removeEventListener(type, handler);\n }\n\n /**\n * Sends a message over this transport, delegating to the appropriate connection to actually\n * send the message.\n * @param msg The message to send.\n * @returns The ID of the sent message or undefined if it wasn't sent\n */\n abstract send(to: TransportClientId, msg: PartialTransportMessage): string;\n\n protected protocolError(type: ProtocolErrorType, message: string) {\n this.eventDispatcher.dispatchEvent('protocolError', { type, message });\n }\n\n /**\n * Default close implementation for transports. You should override this in the downstream\n * implementation if you need to do any additional cleanup and call super.close() at the end.\n * Closes the transport. Any messages sent while the transport is closed will be silently discarded.\n */\n close() {\n this.status = 'closed';\n\n for (const session of this.sessions.values()) {\n this.deleteSession(session);\n }\n\n this.eventDispatcher.dispatchEvent('transportStatus', {\n status: this.status,\n });\n\n this.eventDispatcher.removeAllListeners();\n\n this.log?.info(`manually closed transport`, { clientId: this.clientId });\n }\n\n getStatus(): TransportStatus {\n return this.status;\n }\n\n protected updateSession<S extends Session<ConnType>>(session: S): S {\n const activeSession = this.sessions.get(session.to);\n if (activeSession && activeSession.id !== session.id) {\n const msg = `attempt to transition active session for ${session.to} but active session (${activeSession.id}) is different from handle (${session.id})`;\n throw new Error(msg);\n }\n\n this.sessions.set(session.to, session);\n\n if (!activeSession) {\n this.eventDispatcher.dispatchEvent('sessionStatus', {\n status: 'connect',\n session: session,\n });\n }\n\n this.eventDispatcher.dispatchEvent('sessionTransition', {\n state: session.state,\n session: session,\n } as EventMap['sessionTransition']);\n\n return session;\n }\n\n // state transitions\n protected deleteSession(session: Session<ConnType>) {\n session.log?.info(`closing session ${session.id}`, session.loggingMetadata);\n\n this.eventDispatcher.dispatchEvent('sessionStatus', {\n status: 'disconnect',\n session: session,\n });\n\n session.close();\n this.sessions.delete(session.to);\n }\n\n // common listeners\n protected onSessionGracePeriodElapsed(session: SessionNoConnection) {\n this.log?.warn(\n `session to ${session.to} grace period elapsed, closing`,\n session.loggingMetadata,\n );\n\n this.deleteSession(session);\n }\n\n protected onConnectingFailed(\n session: SessionConnecting<ConnType>,\n ): SessionNoConnection {\n // transition to no connection\n const noConnectionSession =\n SessionStateGraph.transition.ConnectingToNoConnection(session, {\n onSessionGracePeriodElapsed: () => {\n this.onSessionGracePeriodElapsed(noConnectionSession);\n },\n });\n\n return this.updateSession(noConnectionSession);\n }\n\n protected onConnClosed(\n session: SessionHandshaking<ConnType> | SessionConnected<ConnType>,\n ): SessionNoConnection {\n // transition to no connection\n let noConnectionSession: SessionNoConnection;\n if (session.state === SessionState.Handshaking) {\n noConnectionSession =\n SessionStateGraph.transition.HandshakingToNoConnection(session, {\n onSessionGracePeriodElapsed: () => {\n this.onSessionGracePeriodElapsed(noConnectionSession);\n },\n });\n } else {\n noConnectionSession =\n SessionStateGraph.transition.ConnectedToNoConnection(session, {\n onSessionGracePeriodElapsed: () => {\n this.onSessionGracePeriodElapsed(noConnectionSession);\n },\n });\n }\n\n return this.updateSession(noConnectionSession);\n }\n}\n","export function coerceErrorString(err: unknown): string {\n if (err instanceof Error) {\n return err.message || 'unknown reason';\n }\n\n return `[coerced to error] ${String(err)}`;\n}\n"],"mappings":"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","names":["import_api","import_api","import_value","msg"]}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ServerTransport
|
|
3
|
-
} from "../../../chunk-
|
|
3
|
+
} from "../../../chunk-W3CY6PNC.js";
|
|
4
4
|
import {
|
|
5
5
|
WebSocketConnection
|
|
6
|
-
} from "../../../chunk-
|
|
7
|
-
import "../../../chunk-
|
|
6
|
+
} from "../../../chunk-EHXKU4TW.js";
|
|
7
|
+
import "../../../chunk-FKBXIWWN.js";
|
|
8
8
|
import "../../../chunk-TAH2GVTJ.js";
|
|
9
|
-
import "../../../chunk-
|
|
10
|
-
import "../../../chunk-
|
|
9
|
+
import "../../../chunk-KVLCQ24J.js";
|
|
10
|
+
import "../../../chunk-DZNP3EI5.js";
|
|
11
11
|
import "../../../chunk-4PVU7J25.js";
|
|
12
12
|
|
|
13
13
|
// transport/impls/ws/server.ts
|