@replit/river 0.214.0 → 0.215.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{adapter-DjiEwOYi.d.cts → adapter-CjgmjtUJ.d.cts} +3 -2
- package/dist/{adapter-Cp7_gIVA.d.ts → adapter-Dtt4bYL-.d.ts} +3 -2
- package/dist/{chunk-DRYCLL6N.js → chunk-3DDZCLJM.js} +182 -54
- package/dist/chunk-3DDZCLJM.js.map +1 -0
- package/dist/{chunk-LECVFB2G.js → chunk-NUGV5QWU.js} +15 -10
- package/dist/chunk-NUGV5QWU.js.map +1 -0
- package/dist/{client-DXJRow2s.d.cts → client-B9aKi9Li.d.cts} +2 -2
- package/dist/{client-Dw0JBBs3.d.ts → client-BOc8blGj.d.ts} +2 -2
- package/dist/codec/index.cjs.map +1 -1
- package/dist/codec/index.d.cts +3 -3
- package/dist/codec/index.d.ts +3 -3
- package/dist/codec/index.js +2 -2
- package/dist/{connection-Dzkqj18h.d.cts → connection-1hFoyxuX.d.cts} +3 -3
- package/dist/{connection-C2lYgRh0.d.ts → connection-DnMYvolf.d.ts} +3 -3
- package/dist/{index-D9R6UTMl.d.cts → index-Bf9PGbS4.d.cts} +1 -1
- package/dist/{index-CSM8soK7.d.ts → index-DiAq34gk.d.ts} +1 -1
- package/dist/logging/index.d.cts +2 -2
- package/dist/logging/index.d.ts +2 -2
- package/dist/{message-Dlsh5WDF.d.cts → message-DL74OqsX.d.cts} +12 -1
- package/dist/{message-Dlsh5WDF.d.ts → message-DL74OqsX.d.ts} +12 -1
- package/dist/router/index.cjs +14 -9
- package/dist/router/index.cjs.map +1 -1
- package/dist/router/index.d.cts +11 -11
- package/dist/router/index.d.ts +11 -11
- package/dist/router/index.js +1 -1
- package/dist/{server-BDSYa-CO.d.cts → server-BkEzDYIv.d.cts} +4 -4
- package/dist/{server-DFOzjvLh.d.ts → server-_bfE7LYc.d.ts} +4 -4
- package/dist/{services-D47_GPCH.d.ts → services-KdKBWdJr.d.ts} +4 -4
- package/dist/{services-DqYQvm_L.d.cts → services-zaansuuR.d.cts} +4 -4
- package/dist/testUtil/index.cjs +183 -53
- package/dist/testUtil/index.cjs.map +1 -1
- package/dist/testUtil/index.d.cts +7 -7
- package/dist/testUtil/index.d.ts +7 -7
- package/dist/testUtil/index.js +4 -2
- package/dist/testUtil/index.js.map +1 -1
- package/dist/transport/impls/ws/client.cjs +170 -53
- package/dist/transport/impls/ws/client.cjs.map +1 -1
- package/dist/transport/impls/ws/client.d.cts +6 -6
- package/dist/transport/impls/ws/client.d.ts +6 -6
- package/dist/transport/impls/ws/client.js +2 -2
- package/dist/transport/impls/ws/server.cjs +133 -53
- package/dist/transport/impls/ws/server.cjs.map +1 -1
- package/dist/transport/impls/ws/server.d.cts +6 -6
- package/dist/transport/impls/ws/server.d.ts +6 -6
- package/dist/transport/impls/ws/server.js +2 -2
- package/dist/transport/index.cjs +181 -53
- package/dist/transport/index.cjs.map +1 -1
- package/dist/transport/index.d.cts +7 -7
- package/dist/transport/index.d.ts +7 -7
- package/dist/transport/index.js +2 -2
- package/dist/{transport-pdbkDzmJ.d.ts → transport-CCBNESLA.d.cts} +72 -65
- package/dist/{transport-CxT7y8Qk.d.cts → transport-kW92H6x-.d.ts} +72 -65
- package/package.json +1 -1
- package/dist/chunk-DRYCLL6N.js.map +0 -1
- package/dist/chunk-LECVFB2G.js.map +0 -1
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { C as ClientTransport } from '../client-
|
|
3
|
-
import { S as ServerTransport } from '../server-
|
|
4
|
-
import {
|
|
1
|
+
import { P as ProvidedClientTransportOptions, e as ProvidedServerTransportOptions, n as ClientHandshakeOptions, C as Connection, q as ServerHandshakeOptions, T as Transport, i as SessionNoConnection, x as SessionBoundSendFn, m as ClientTransportOptions, y as SessionOptions } from '../transport-CCBNESLA.cjs';
|
|
2
|
+
import { C as ClientTransport } from '../client-B9aKi9Li.cjs';
|
|
3
|
+
import { S as ServerTransport } from '../server-BkEzDYIv.cjs';
|
|
4
|
+
import { T as TransportClientId, e as PartialTransportMessage, O as OpaqueTransportMessage } from '../message-DL74OqsX.cjs';
|
|
5
5
|
import { TSchema, Static } from '@sinclair/typebox';
|
|
6
|
-
import {
|
|
6
|
+
import { B as BaseErrorSchemaType, q as Readable, $ as ReadableIterator, s as ReadableResult } from '../services-zaansuuR.cjs';
|
|
7
7
|
import { W as WsLike } from '../wslike-Dng9H1C7.cjs';
|
|
8
8
|
import NodeWs from 'ws';
|
|
9
9
|
import http from 'node:http';
|
|
10
10
|
import { Duplex } from 'node:stream';
|
|
11
|
-
import '../index-
|
|
12
|
-
import '../adapter-
|
|
11
|
+
import '../index-Bf9PGbS4.cjs';
|
|
12
|
+
import '../adapter-CjgmjtUJ.cjs';
|
|
13
13
|
import '@opentelemetry/api';
|
|
14
14
|
|
|
15
15
|
interface TestTransportOptions {
|
package/dist/testUtil/index.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { C as ClientTransport } from '../client-
|
|
3
|
-
import { S as ServerTransport } from '../server-
|
|
4
|
-
import {
|
|
1
|
+
import { P as ProvidedClientTransportOptions, e as ProvidedServerTransportOptions, n as ClientHandshakeOptions, C as Connection, q as ServerHandshakeOptions, T as Transport, i as SessionNoConnection, x as SessionBoundSendFn, m as ClientTransportOptions, y as SessionOptions } from '../transport-kW92H6x-.js';
|
|
2
|
+
import { C as ClientTransport } from '../client-BOc8blGj.js';
|
|
3
|
+
import { S as ServerTransport } from '../server-_bfE7LYc.js';
|
|
4
|
+
import { T as TransportClientId, e as PartialTransportMessage, O as OpaqueTransportMessage } from '../message-DL74OqsX.js';
|
|
5
5
|
import { TSchema, Static } from '@sinclair/typebox';
|
|
6
|
-
import {
|
|
6
|
+
import { B as BaseErrorSchemaType, q as Readable, $ as ReadableIterator, s as ReadableResult } from '../services-KdKBWdJr.js';
|
|
7
7
|
import { W as WsLike } from '../wslike-Dng9H1C7.js';
|
|
8
8
|
import NodeWs from 'ws';
|
|
9
9
|
import http from 'node:http';
|
|
10
10
|
import { Duplex } from 'node:stream';
|
|
11
|
-
import '../index-
|
|
12
|
-
import '../adapter-
|
|
11
|
+
import '../index-DiAq34gk.js';
|
|
12
|
+
import '../adapter-Dtt4bYL-.js';
|
|
13
13
|
import '@opentelemetry/api';
|
|
14
14
|
|
|
15
15
|
interface TestTransportOptions {
|
package/dist/testUtil/index.js
CHANGED
|
@@ -5,12 +5,12 @@ import {
|
|
|
5
5
|
SessionStateGraph,
|
|
6
6
|
defaultClientTransportOptions,
|
|
7
7
|
defaultTransportOptions
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-3DDZCLJM.js";
|
|
9
9
|
import "../chunk-CC7RN7GI.js";
|
|
10
10
|
import {
|
|
11
11
|
currentProtocolVersion,
|
|
12
12
|
getTracer
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-NUGV5QWU.js";
|
|
14
14
|
|
|
15
15
|
// testUtil/index.ts
|
|
16
16
|
import NodeWs, { WebSocketServer } from "ws";
|
|
@@ -308,6 +308,8 @@ function dummySession() {
|
|
|
308
308
|
"server",
|
|
309
309
|
{
|
|
310
310
|
onSessionGracePeriodElapsed: () => {
|
|
311
|
+
},
|
|
312
|
+
onMessageSendFailure: () => {
|
|
311
313
|
}
|
|
312
314
|
},
|
|
313
315
|
testingSessionOptions,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../testUtil/index.ts","../../testUtil/observable/observable.ts","../../testUtil/duplex/duplexPair.ts","../../testUtil/fixtures/mockTransport.ts"],"sourcesContent":["import NodeWs, { WebSocketServer } from 'ws';\nimport http from 'node:http';\nimport { Static } from '@sinclair/typebox';\nimport {\n OpaqueTransportMessage,\n PartialTransportMessage,\n currentProtocolVersion,\n} from '../transport/message';\nimport { Transport } from '../transport/transport';\nimport { Readable, ReadableResult, ReadableIterator } from '../router/streams';\nimport { WsLike } from '../transport/impls/ws/wslike';\nimport {\n defaultClientTransportOptions,\n defaultTransportOptions,\n} from '../transport/options';\nimport { Connection } from '../transport/connection';\nimport { SessionState } from '../transport/sessionStateMachine/common';\nimport { SessionStateGraph } from '../transport/sessionStateMachine/transitions';\nimport { BaseErrorSchemaType } from '../router/errors';\nimport { ClientTransport } from '../transport/client';\nimport { ServerTransport } from '../transport/server';\nimport { getTracer } from '../tracing';\n\nexport {\n createMockTransportNetwork,\n InMemoryConnection,\n} from './fixtures/mockTransport';\n\n/**\n * Creates a WebSocket client that connects to a local server at the specified port.\n * This should only be used for testing.\n * @param port - The port number to connect to.\n * @returns A Promise that resolves to a WebSocket instance.\n */\nexport function createLocalWebSocketClient(port: number): WsLike {\n const sock = new NodeWs(`ws://localhost:${port}`);\n sock.binaryType = 'arraybuffer';\n\n return sock;\n}\n\n/**\n * Creates a WebSocket server instance using the provided HTTP server.\n * Only used as helper for testing.\n * @param server - The HTTP server instance to use for the WebSocket server.\n * @returns A Promise that resolves to the created WebSocket server instance.\n */\nexport function createWebSocketServer(server: http.Server) {\n return new WebSocketServer({ server });\n}\n\n/**\n * Starts listening on the given server and returns the automatically allocated port number.\n * This should only be used for testing.\n * @param server - The http server to listen on.\n * @returns A promise that resolves with the allocated port number.\n * @throws An error if a port cannot be allocated.\n */\nexport function onWsServerReady(server: http.Server): Promise<number> {\n return new Promise((resolve, reject) => {\n server.listen(() => {\n const addr = server.address();\n if (typeof addr === 'object' && addr) {\n resolve(addr.port);\n } else {\n reject(new Error(\"couldn't find a port to allocate\"));\n }\n });\n });\n}\n\nconst readableIterators = new WeakMap<\n Readable<unknown, Static<BaseErrorSchemaType>>,\n ReadableIterator<unknown, Static<BaseErrorSchemaType>>\n>();\n\n/**\n * A safe way to access {@link Readble}'s iterator multiple times in test helpers.\n *\n * If there are other iteration attempts outside of the test helpers\n * (this function, {@link readNextResult}, and {@link isReadableDone})\n * it will throw an error.\n */\nexport function getReadableIterator<T, E extends Static<BaseErrorSchemaType>>(\n readable: Readable<T, E>,\n): ReadableIterator<T, E> {\n let iter = readableIterators.get(readable) as\n | ReadableIterator<T, E>\n | undefined;\n\n if (!iter) {\n iter = readable[Symbol.asyncIterator]();\n readableIterators.set(readable, iter);\n }\n\n return iter;\n}\n\n/**\n * Retrieves the next value from {@link Readable}, or throws an error if the Readable is done.\n *\n * Calling semantics are similar to {@link getReadableIterator}\n */\nexport async function readNextResult<T, E extends Static<BaseErrorSchemaType>>(\n readable: Readable<T, E>,\n): Promise<ReadableResult<T, E>> {\n const res = await getReadableIterator(readable).next();\n\n if (res.done) {\n throw new Error('readNext from a done Readable');\n }\n\n return res.value;\n}\n\n/**\n * Checks if the readable is done iterating, it consumes an iteration in the process.\n *\n * Calling semantics are similar to {@link getReadableIterator}\n */\nexport async function isReadableDone<T, E extends Static<BaseErrorSchemaType>>(\n readable: Readable<T, E>,\n) {\n const res = await getReadableIterator(readable).next();\n\n return res.done;\n}\n\nexport function payloadToTransportMessage<Payload>(\n payload: Payload,\n): PartialTransportMessage<Payload> {\n return {\n streamId: 'stream',\n controlFlags: 0,\n payload,\n };\n}\n\nexport function createDummyTransportMessage() {\n return payloadToTransportMessage({\n msg: 'cool',\n test: Math.random(),\n });\n}\n\n/**\n * Waits for a message on the transport.\n * @param {Transport} t - The transport to listen to.\n * @param filter - An optional filter function to apply to the received messages.\n * @returns A promise that resolves with the payload of the first message that passes the filter.\n */\nexport async function waitForMessage(\n t: Transport<Connection>,\n filter?: (msg: OpaqueTransportMessage) => boolean,\n rejectMismatch?: boolean,\n) {\n return new Promise((resolve, reject) => {\n function cleanup() {\n t.removeEventListener('message', onMessage);\n }\n\n function onMessage(msg: OpaqueTransportMessage) {\n if (!filter || filter(msg)) {\n cleanup();\n resolve(msg.payload);\n } else if (rejectMismatch) {\n cleanup();\n reject(new Error('message didnt match the filter'));\n }\n }\n\n t.addEventListener('message', onMessage);\n });\n}\n\nexport const testingSessionOptions = defaultTransportOptions;\nexport const testingClientSessionOptions = defaultClientTransportOptions;\n\nexport function dummySession() {\n return SessionStateGraph.entrypoints.NoConnection(\n 'client',\n 'server',\n {\n onSessionGracePeriodElapsed: () => {\n /* noop */\n },\n },\n testingSessionOptions,\n currentProtocolVersion,\n getTracer(),\n );\n}\n\nexport function getClientSendFn(\n clientTransport: ClientTransport<Connection>,\n serverTransport: ServerTransport<Connection>,\n) {\n const session =\n clientTransport.sessions.get(serverTransport.clientId) ??\n clientTransport.createUnconnectedSession(serverTransport.clientId);\n\n return clientTransport.getSessionBoundSendFn(\n serverTransport.clientId,\n session.id,\n );\n}\n\nexport function getServerSendFn(\n serverTransport: ServerTransport<Connection>,\n clientTransport: ClientTransport<Connection>,\n) {\n const session = serverTransport.sessions.get(clientTransport.clientId);\n if (!session) {\n throw new Error('session not found');\n }\n\n return serverTransport.getSessionBoundSendFn(\n clientTransport.clientId,\n session.id,\n );\n}\n\nexport function getTransportConnections<ConnType extends Connection>(\n transport: Transport<ConnType>,\n): Array<ConnType> {\n const connections = [];\n for (const session of transport.sessions.values()) {\n if (session.state === SessionState.Connected) {\n connections.push(session.conn);\n }\n }\n\n return connections;\n}\n\nexport function numberOfConnections<ConnType extends Connection>(\n transport: Transport<ConnType>,\n): number {\n return getTransportConnections(transport).length;\n}\n\nexport function closeAllConnections<ConnType extends Connection>(\n transport: Transport<ConnType>,\n) {\n for (const conn of getTransportConnections(transport)) {\n conn.close();\n }\n}\n\n/**\n * Wraps a partial context object in a proxy that throws when accessing\n * properties that weren't provided. This is useful for test contexts where\n * you only want to mock the dependencies a test actually uses.\n *\n * Symbols and `then` are allowed through without throwing — river checks\n * for `Symbol.asyncDispose` / `Symbol.dispose` on context values during\n * `server.close()`, and `then` is checked by the JS runtime when the\n * proxy is returned from an async function.\n *\n * @example\n * ```ts\n * const ctx = createPartialContext<MyContext>({\n * database: mockDb,\n * // accessing ctx.redis will throw\n * });\n *\n * const server = createServer(transport, services, {\n * extendedContext: ctx,\n * });\n * ```\n */\nexport function createPartialContext<T extends Record<string, unknown>>(\n partial: Partial<T>,\n): T {\n return new Proxy(partial as T, {\n get(target, prop, receiver) {\n if (prop in target) {\n return Reflect.get(target, prop, receiver);\n }\n\n if (typeof prop === 'string' && prop !== 'then') {\n throw new Error(\n `${prop} is not mocked in the test context. Provide it via createPartialContext if your test needs it.`,\n );\n }\n\n return undefined;\n },\n });\n}\n","/**\n * Represents an observable value that can be subscribed to for changes.\n * This should only be used in tests\n * @template T - The type of the value being observed.\n */\nexport class Observable<T> {\n value: T;\n private listeners: Set<(val: T) => void>;\n\n constructor(initialValue: T) {\n this.value = initialValue;\n this.listeners = new Set();\n }\n\n /**\n * Gets the current value of the observable.\n */\n get() {\n return this.value;\n }\n\n /**\n * Sets the current value of the observable. All listeners will get an update with this value.\n * @param newValue - The new value to set.\n */\n set(tx: (preValue: T) => T) {\n const newValue = tx(this.value);\n this.value = newValue;\n this.listeners.forEach((listener) => listener(newValue));\n }\n\n /**\n * Subscribes to changes in the observable value.\n * @param listener - A callback function that will be called when the value changes.\n * @returns A function that can be called to unsubscribe from further notifications.\n */\n observe(listener: (val: T) => void) {\n this.listeners.add(listener);\n listener(this.get());\n\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Returns the number of listeners currently observing the observable\n */\n get listenerCount(): number {\n return this.listeners.size;\n }\n}\n","import { Duplex } from 'node:stream';\nimport assert from 'assert';\n\nconst kCallback = Symbol('Callback');\nconst kInitOtherSide = Symbol('InitOtherSide');\n\n// yoinked from https://github.com/nodejs/node/blob/c3a7b29e56a5ada6327ebb622ba746d022685742/lib/internal/streams/duplexpair.js#L55\n// but with types\nclass DuplexSide extends Duplex {\n private otherSide: DuplexSide | null;\n private [kCallback]: (() => void) | null;\n\n constructor() {\n super();\n this[kCallback] = null;\n this.otherSide = null;\n }\n\n [kInitOtherSide](otherSide: DuplexSide) {\n if (this.otherSide === null) {\n this.otherSide = otherSide;\n }\n }\n\n _read() {\n const callback = this[kCallback];\n if (callback) {\n this[kCallback] = null;\n callback();\n }\n }\n\n _write(\n chunk: Uint8Array,\n _encoding: BufferEncoding,\n callback: (error?: Error | null) => void,\n ) {\n assert(this.otherSide !== null);\n assert(this.otherSide[kCallback] === null);\n if (chunk.length === 0) {\n process.nextTick(callback);\n } else {\n this.otherSide.push(chunk);\n this.otherSide[kCallback] = callback;\n }\n }\n\n _final(callback: (error?: Error | null) => void) {\n this.otherSide?.on('end', callback);\n this.otherSide?.push(null);\n }\n}\n\nexport function duplexPair(): [DuplexSide, DuplexSide] {\n const side0 = new DuplexSide();\n const side1 = new DuplexSide();\n side0[kInitOtherSide](side1);\n side1[kInitOtherSide](side0);\n side0.on('close', () => {\n setImmediate(() => {\n side1.destroy();\n });\n });\n\n side1.on('close', () => {\n setImmediate(() => {\n side0.destroy();\n });\n });\n\n return [side0, side1];\n}\n","import { Transport, TransportClientId } from '../../transport';\nimport { ClientTransport } from '../../transport/client';\nimport { Connection } from '../../transport/connection';\nimport { ServerTransport } from '../../transport/server';\nimport { Observable } from '../observable/observable';\nimport { ProvidedServerTransportOptions } from '../../transport/options';\nimport { TestSetupHelpers, TestTransportOptions } from './transports';\nimport { Duplex } from 'node:stream';\nimport { duplexPair } from '../duplex/duplexPair';\nimport { nanoid } from 'nanoid';\nimport { TSchema } from '@sinclair/typebox';\nimport { ServerHandshakeOptions } from '../../router/handshake';\n\nexport class InMemoryConnection extends Connection {\n conn: Duplex;\n\n constructor(pipe: Duplex) {\n super();\n this.conn = pipe;\n this.conn.allowHalfOpen = false;\n\n this.conn.on('data', (data: Uint8Array) => {\n this.dataListener?.(data);\n });\n\n this.conn.on('close', () => {\n this.closeListener?.();\n });\n\n this.conn.on('error', (err) => {\n this.errorListener?.(err);\n });\n }\n\n send(payload: Uint8Array): boolean {\n setImmediate(() => {\n this.conn.write(payload);\n });\n\n return true;\n }\n\n close(): void {\n setImmediate(() => {\n this.conn.end();\n this.conn.emit('close');\n });\n }\n}\n\ninterface BidiConnection {\n id: string;\n clientToServer: Duplex;\n serverToClient: Duplex;\n clientId: TransportClientId;\n serverId: TransportClientId;\n handled: boolean;\n}\n\n// we construct a network of transports connected by node streams here\n// so that we can test the transport layer without needing to actually\n// use real network/websocket connections\n// this is useful for testing the transport layer in isolation\n// and allows us to control network conditions in a way that would be\n// difficult with real network connections (e.g. simulating a phantom\n// disconnect, .pause() vs .removeAllListeners('data'), congestion,\n// latency, differences in ws implementations between node and browsers, etc.)\nexport function createMockTransportNetwork(\n opts?: TestTransportOptions,\n): TestSetupHelpers {\n // conn id -> [client->server, server->client]\n const connections = new Observable<Record<string, BidiConnection>>({});\n\n const transports: Array<Transport<InMemoryConnection>> = [];\n class MockClientTransport extends ClientTransport<InMemoryConnection> {\n async createNewOutgoingConnection(\n to: TransportClientId,\n ): Promise<InMemoryConnection> {\n const [clientToServer, serverToClient] = duplexPair();\n await new Promise((resolve) => setImmediate(resolve));\n\n const connId = nanoid();\n connections.set((prev) => ({\n ...prev,\n [connId]: {\n id: connId,\n clientToServer,\n serverToClient,\n clientId: this.clientId,\n serverId: to,\n handled: false,\n },\n }));\n\n return new InMemoryConnection(clientToServer);\n }\n }\n\n class MockServerTransport<\n MetadataSchema extends TSchema = TSchema,\n ParsedMetadata extends object = object,\n > extends ServerTransport<\n InMemoryConnection,\n MetadataSchema,\n ParsedMetadata\n > {\n subscribeCleanup: () => void;\n\n constructor(\n clientId: TransportClientId,\n options?: ProvidedServerTransportOptions,\n ) {\n super(clientId, options);\n\n this.subscribeCleanup = connections.observe((conns) => {\n // look for any unhandled connections\n for (const conn of Object.values(conns)) {\n // if we've already handled this connection, skip it\n // or if it's not for us, skip it\n if (conn.handled || conn.serverId !== this.clientId) {\n continue;\n }\n\n conn.handled = true;\n const connection = new InMemoryConnection(conn.serverToClient);\n this.handleConnection(connection);\n }\n });\n }\n\n close() {\n this.subscribeCleanup();\n super.close();\n }\n }\n\n return {\n getClientTransport: (id, handshakeOptions) => {\n const clientTransport = new MockClientTransport(id, opts?.client);\n if (handshakeOptions) {\n clientTransport.extendHandshake(handshakeOptions);\n }\n\n transports.push(clientTransport);\n\n return clientTransport;\n },\n getServerTransport: <\n MetadataSchema extends TSchema = TSchema,\n ParsedMetadata extends object = object,\n >(\n id = 'SERVER',\n handshakeOptions:\n | ServerHandshakeOptions<MetadataSchema, ParsedMetadata>\n | undefined,\n ) => {\n const serverTransport = new MockServerTransport<\n MetadataSchema,\n ParsedMetadata\n >(id, opts?.server);\n if (handshakeOptions) {\n serverTransport.extendHandshake(handshakeOptions);\n }\n\n transports.push(serverTransport);\n\n return serverTransport;\n },\n simulatePhantomDisconnect() {\n for (const conn of Object.values(connections.get())) {\n conn.serverToClient.pause();\n conn.clientToServer.pause();\n }\n },\n async restartServer() {\n for (const transport of transports) {\n if (transport.clientId !== 'SERVER') continue;\n transport.close();\n }\n\n // kill all connections while we're at it\n for (const conn of Object.values(connections.get())) {\n conn.serverToClient.destroy();\n conn.clientToServer.destroy();\n }\n },\n cleanup() {\n for (const conn of Object.values(connections.get())) {\n conn.serverToClient.destroy();\n conn.clientToServer.destroy();\n }\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;AAAA,OAAO,UAAU,uBAAuB;;;ACKjC,IAAM,aAAN,MAAoB;AAAA,EACzB;AAAA,EACQ;AAAA,EAER,YAAY,cAAiB;AAC3B,SAAK,QAAQ;AACb,SAAK,YAAY,oBAAI,IAAI;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM;AACJ,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,IAAwB;AAC1B,UAAM,WAAW,GAAG,KAAK,KAAK;AAC9B,SAAK,QAAQ;AACb,SAAK,UAAU,QAAQ,CAAC,aAAa,SAAS,QAAQ,CAAC;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,QAAQ,UAA4B;AAClC,SAAK,UAAU,IAAI,QAAQ;AAC3B,aAAS,KAAK,IAAI,CAAC;AAEnB,WAAO,MAAM,KAAK,UAAU,OAAO,QAAQ;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,gBAAwB;AAC1B,WAAO,KAAK,UAAU;AAAA,EACxB;AACF;;;ACjDA,SAAS,cAAc;AACvB,OAAO,YAAY;AAEnB,IAAM,YAAY,OAAO,UAAU;AACnC,IAAM,iBAAiB,OAAO,eAAe;AAI7C,IAAM,aAAN,cAAyB,OAAO;AAAA,EACtB;AAAA,EACR,CAAS,SAAS;AAAA,EAElB,cAAc;AACZ,UAAM;AACN,SAAK,SAAS,IAAI;AAClB,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,CAAC,cAAc,EAAE,WAAuB;AACtC,QAAI,KAAK,cAAc,MAAM;AAC3B,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,QAAQ;AACN,UAAM,WAAW,KAAK,SAAS;AAC/B,QAAI,UAAU;AACZ,WAAK,SAAS,IAAI;AAClB,eAAS;AAAA,IACX;AAAA,EACF;AAAA,EAEA,OACE,OACA,WACA,UACA;AACA,WAAO,KAAK,cAAc,IAAI;AAC9B,WAAO,KAAK,UAAU,SAAS,MAAM,IAAI;AACzC,QAAI,MAAM,WAAW,GAAG;AACtB,cAAQ,SAAS,QAAQ;AAAA,IAC3B,OAAO;AACL,WAAK,UAAU,KAAK,KAAK;AACzB,WAAK,UAAU,SAAS,IAAI;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,OAAO,UAA0C;AAC/C,SAAK,WAAW,GAAG,OAAO,QAAQ;AAClC,SAAK,WAAW,KAAK,IAAI;AAAA,EAC3B;AACF;AAEO,SAAS,aAAuC;AACrD,QAAM,QAAQ,IAAI,WAAW;AAC7B,QAAM,QAAQ,IAAI,WAAW;AAC7B,QAAM,cAAc,EAAE,KAAK;AAC3B,QAAM,cAAc,EAAE,KAAK;AAC3B,QAAM,GAAG,SAAS,MAAM;AACtB,iBAAa,MAAM;AACjB,YAAM,QAAQ;AAAA,IAChB,CAAC;AAAA,EACH,CAAC;AAED,QAAM,GAAG,SAAS,MAAM;AACtB,iBAAa,MAAM;AACjB,YAAM,QAAQ;AAAA,IAChB,CAAC;AAAA,EACH,CAAC;AAED,SAAO,CAAC,OAAO,KAAK;AACtB;;;AC9DA,SAAS,cAAc;AAIhB,IAAM,qBAAN,cAAiC,WAAW;AAAA,EACjD;AAAA,EAEA,YAAY,MAAc;AACxB,UAAM;AACN,SAAK,OAAO;AACZ,SAAK,KAAK,gBAAgB;AAE1B,SAAK,KAAK,GAAG,QAAQ,CAAC,SAAqB;AACzC,WAAK,eAAe,IAAI;AAAA,IAC1B,CAAC;AAED,SAAK,KAAK,GAAG,SAAS,MAAM;AAC1B,WAAK,gBAAgB;AAAA,IACvB,CAAC;AAED,SAAK,KAAK,GAAG,SAAS,CAAC,QAAQ;AAC7B,WAAK,gBAAgB,GAAG;AAAA,IAC1B,CAAC;AAAA,EACH;AAAA,EAEA,KAAK,SAA8B;AACjC,iBAAa,MAAM;AACjB,WAAK,KAAK,MAAM,OAAO;AAAA,IACzB,CAAC;AAED,WAAO;AAAA,EACT;AAAA,EAEA,QAAc;AACZ,iBAAa,MAAM;AACjB,WAAK,KAAK,IAAI;AACd,WAAK,KAAK,KAAK,OAAO;AAAA,IACxB,CAAC;AAAA,EACH;AACF;AAmBO,SAAS,2BACd,MACkB;AAElB,QAAM,cAAc,IAAI,WAA2C,CAAC,CAAC;AAErE,QAAM,aAAmD,CAAC;AAAA,EAC1D,MAAM,4BAA4B,gBAAoC;AAAA,IACpE,MAAM,4BACJ,IAC6B;AAC7B,YAAM,CAAC,gBAAgB,cAAc,IAAI,WAAW;AACpD,YAAM,IAAI,QAAQ,CAAC,YAAY,aAAa,OAAO,CAAC;AAEpD,YAAM,SAAS,OAAO;AACtB,kBAAY,IAAI,CAAC,UAAU;AAAA,QACzB,GAAG;AAAA,QACH,CAAC,MAAM,GAAG;AAAA,UACR,IAAI;AAAA,UACJ;AAAA,UACA;AAAA,UACA,UAAU,KAAK;AAAA,UACf,UAAU;AAAA,UACV,SAAS;AAAA,QACX;AAAA,MACF,EAAE;AAEF,aAAO,IAAI,mBAAmB,cAAc;AAAA,IAC9C;AAAA,EACF;AAAA,EAEA,MAAM,4BAGI,gBAIR;AAAA,IACA;AAAA,IAEA,YACE,UACA,SACA;AACA,YAAM,UAAU,OAAO;AAEvB,WAAK,mBAAmB,YAAY,QAAQ,CAAC,UAAU;AAErD,mBAAW,QAAQ,OAAO,OAAO,KAAK,GAAG;AAGvC,cAAI,KAAK,WAAW,KAAK,aAAa,KAAK,UAAU;AACnD;AAAA,UACF;AAEA,eAAK,UAAU;AACf,gBAAM,aAAa,IAAI,mBAAmB,KAAK,cAAc;AAC7D,eAAK,iBAAiB,UAAU;AAAA,QAClC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEA,QAAQ;AACN,WAAK,iBAAiB;AACtB,YAAM,MAAM;AAAA,IACd;AAAA,EACF;AAEA,SAAO;AAAA,IACL,oBAAoB,CAAC,IAAI,qBAAqB;AAC5C,YAAM,kBAAkB,IAAI,oBAAoB,IAAI,MAAM,MAAM;AAChE,UAAI,kBAAkB;AACpB,wBAAgB,gBAAgB,gBAAgB;AAAA,MAClD;AAEA,iBAAW,KAAK,eAAe;AAE/B,aAAO;AAAA,IACT;AAAA,IACA,oBAAoB,CAIlB,KAAK,UACL,qBAGG;AACH,YAAM,kBAAkB,IAAI,oBAG1B,IAAI,MAAM,MAAM;AAClB,UAAI,kBAAkB;AACpB,wBAAgB,gBAAgB,gBAAgB;AAAA,MAClD;AAEA,iBAAW,KAAK,eAAe;AAE/B,aAAO;AAAA,IACT;AAAA,IACA,4BAA4B;AAC1B,iBAAW,QAAQ,OAAO,OAAO,YAAY,IAAI,CAAC,GAAG;AACnD,aAAK,eAAe,MAAM;AAC1B,aAAK,eAAe,MAAM;AAAA,MAC5B;AAAA,IACF;AAAA,IACA,MAAM,gBAAgB;AACpB,iBAAW,aAAa,YAAY;AAClC,YAAI,UAAU,aAAa,SAAU;AACrC,kBAAU,MAAM;AAAA,MAClB;AAGA,iBAAW,QAAQ,OAAO,OAAO,YAAY,IAAI,CAAC,GAAG;AACnD,aAAK,eAAe,QAAQ;AAC5B,aAAK,eAAe,QAAQ;AAAA,MAC9B;AAAA,IACF;AAAA,IACA,UAAU;AACR,iBAAW,QAAQ,OAAO,OAAO,YAAY,IAAI,CAAC,GAAG;AACnD,aAAK,eAAe,QAAQ;AAC5B,aAAK,eAAe,QAAQ;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AACF;;;AH/JO,SAAS,2BAA2B,MAAsB;AAC/D,QAAM,OAAO,IAAI,OAAO,kBAAkB,IAAI,EAAE;AAChD,OAAK,aAAa;AAElB,SAAO;AACT;AAQO,SAAS,sBAAsB,QAAqB;AACzD,SAAO,IAAI,gBAAgB,EAAE,OAAO,CAAC;AACvC;AASO,SAAS,gBAAgB,QAAsC;AACpE,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAO,OAAO,MAAM;AAClB,YAAM,OAAO,OAAO,QAAQ;AAC5B,UAAI,OAAO,SAAS,YAAY,MAAM;AACpC,gBAAQ,KAAK,IAAI;AAAA,MACnB,OAAO;AACL,eAAO,IAAI,MAAM,kCAAkC,CAAC;AAAA,MACtD;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;AAEA,IAAM,oBAAoB,oBAAI,QAG5B;AASK,SAAS,oBACd,UACwB;AACxB,MAAI,OAAO,kBAAkB,IAAI,QAAQ;AAIzC,MAAI,CAAC,MAAM;AACT,WAAO,SAAS,OAAO,aAAa,EAAE;AACtC,sBAAkB,IAAI,UAAU,IAAI;AAAA,EACtC;AAEA,SAAO;AACT;AAOA,eAAsB,eACpB,UAC+B;AAC/B,QAAM,MAAM,MAAM,oBAAoB,QAAQ,EAAE,KAAK;AAErD,MAAI,IAAI,MAAM;AACZ,UAAM,IAAI,MAAM,+BAA+B;AAAA,EACjD;AAEA,SAAO,IAAI;AACb;AAOA,eAAsB,eACpB,UACA;AACA,QAAM,MAAM,MAAM,oBAAoB,QAAQ,EAAE,KAAK;AAErD,SAAO,IAAI;AACb;AAEO,SAAS,0BACd,SACkC;AAClC,SAAO;AAAA,IACL,UAAU;AAAA,IACV,cAAc;AAAA,IACd;AAAA,EACF;AACF;AAEO,SAAS,8BAA8B;AAC5C,SAAO,0BAA0B;AAAA,IAC/B,KAAK;AAAA,IACL,MAAM,KAAK,OAAO;AAAA,EACpB,CAAC;AACH;AAQA,eAAsB,eACpB,GACA,QACA,gBACA;AACA,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,aAAS,UAAU;AACjB,QAAE,oBAAoB,WAAW,SAAS;AAAA,IAC5C;AAEA,aAAS,UAAU,KAA6B;AAC9C,UAAI,CAAC,UAAU,OAAO,GAAG,GAAG;AAC1B,gBAAQ;AACR,gBAAQ,IAAI,OAAO;AAAA,MACrB,WAAW,gBAAgB;AACzB,gBAAQ;AACR,eAAO,IAAI,MAAM,gCAAgC,CAAC;AAAA,MACpD;AAAA,IACF;AAEA,MAAE,iBAAiB,WAAW,SAAS;AAAA,EACzC,CAAC;AACH;AAEO,IAAM,wBAAwB;AAC9B,IAAM,8BAA8B;AAEpC,SAAS,eAAe;AAC7B,SAAO,kBAAkB,YAAY;AAAA,IACnC;AAAA,IACA;AAAA,IACA;AAAA,MACE,6BAA6B,MAAM;AAAA,MAEnC;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,EACZ;AACF;AAEO,SAAS,gBACd,iBACA,iBACA;AACA,QAAM,UACJ,gBAAgB,SAAS,IAAI,gBAAgB,QAAQ,KACrD,gBAAgB,yBAAyB,gBAAgB,QAAQ;AAEnE,SAAO,gBAAgB;AAAA,IACrB,gBAAgB;AAAA,IAChB,QAAQ;AAAA,EACV;AACF;AAEO,SAAS,gBACd,iBACA,iBACA;AACA,QAAM,UAAU,gBAAgB,SAAS,IAAI,gBAAgB,QAAQ;AACrE,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,mBAAmB;AAAA,EACrC;AAEA,SAAO,gBAAgB;AAAA,IACrB,gBAAgB;AAAA,IAChB,QAAQ;AAAA,EACV;AACF;AAEO,SAAS,wBACd,WACiB;AACjB,QAAM,cAAc,CAAC;AACrB,aAAW,WAAW,UAAU,SAAS,OAAO,GAAG;AACjD,QAAI,QAAQ,uCAAkC;AAC5C,kBAAY,KAAK,QAAQ,IAAI;AAAA,IAC/B;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,oBACd,WACQ;AACR,SAAO,wBAAwB,SAAS,EAAE;AAC5C;AAEO,SAAS,oBACd,WACA;AACA,aAAW,QAAQ,wBAAwB,SAAS,GAAG;AACrD,SAAK,MAAM;AAAA,EACb;AACF;AAwBO,SAAS,qBACd,SACG;AACH,SAAO,IAAI,MAAM,SAAc;AAAA,IAC7B,IAAI,QAAQ,MAAM,UAAU;AAC1B,UAAI,QAAQ,QAAQ;AAClB,eAAO,QAAQ,IAAI,QAAQ,MAAM,QAAQ;AAAA,MAC3C;AAEA,UAAI,OAAO,SAAS,YAAY,SAAS,QAAQ;AAC/C,cAAM,IAAI;AAAA,UACR,GAAG,IAAI;AAAA,QACT;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AACH;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../testUtil/index.ts","../../testUtil/observable/observable.ts","../../testUtil/duplex/duplexPair.ts","../../testUtil/fixtures/mockTransport.ts"],"sourcesContent":["import NodeWs, { WebSocketServer } from 'ws';\nimport http from 'node:http';\nimport { Static } from '@sinclair/typebox';\nimport {\n OpaqueTransportMessage,\n PartialTransportMessage,\n currentProtocolVersion,\n} from '../transport/message';\nimport { Transport } from '../transport/transport';\nimport { Readable, ReadableResult, ReadableIterator } from '../router/streams';\nimport { WsLike } from '../transport/impls/ws/wslike';\nimport {\n defaultClientTransportOptions,\n defaultTransportOptions,\n} from '../transport/options';\nimport { Connection } from '../transport/connection';\nimport { SessionState } from '../transport/sessionStateMachine/common';\nimport { SessionStateGraph } from '../transport/sessionStateMachine/transitions';\nimport { BaseErrorSchemaType } from '../router/errors';\nimport { ClientTransport } from '../transport/client';\nimport { ServerTransport } from '../transport/server';\nimport { getTracer } from '../tracing';\n\nexport {\n createMockTransportNetwork,\n InMemoryConnection,\n} from './fixtures/mockTransport';\n\n/**\n * Creates a WebSocket client that connects to a local server at the specified port.\n * This should only be used for testing.\n * @param port - The port number to connect to.\n * @returns A Promise that resolves to a WebSocket instance.\n */\nexport function createLocalWebSocketClient(port: number): WsLike {\n const sock = new NodeWs(`ws://localhost:${port}`);\n sock.binaryType = 'arraybuffer';\n\n return sock;\n}\n\n/**\n * Creates a WebSocket server instance using the provided HTTP server.\n * Only used as helper for testing.\n * @param server - The HTTP server instance to use for the WebSocket server.\n * @returns A Promise that resolves to the created WebSocket server instance.\n */\nexport function createWebSocketServer(server: http.Server) {\n return new WebSocketServer({ server });\n}\n\n/**\n * Starts listening on the given server and returns the automatically allocated port number.\n * This should only be used for testing.\n * @param server - The http server to listen on.\n * @returns A promise that resolves with the allocated port number.\n * @throws An error if a port cannot be allocated.\n */\nexport function onWsServerReady(server: http.Server): Promise<number> {\n return new Promise((resolve, reject) => {\n server.listen(() => {\n const addr = server.address();\n if (typeof addr === 'object' && addr) {\n resolve(addr.port);\n } else {\n reject(new Error(\"couldn't find a port to allocate\"));\n }\n });\n });\n}\n\nconst readableIterators = new WeakMap<\n Readable<unknown, Static<BaseErrorSchemaType>>,\n ReadableIterator<unknown, Static<BaseErrorSchemaType>>\n>();\n\n/**\n * A safe way to access {@link Readble}'s iterator multiple times in test helpers.\n *\n * If there are other iteration attempts outside of the test helpers\n * (this function, {@link readNextResult}, and {@link isReadableDone})\n * it will throw an error.\n */\nexport function getReadableIterator<T, E extends Static<BaseErrorSchemaType>>(\n readable: Readable<T, E>,\n): ReadableIterator<T, E> {\n let iter = readableIterators.get(readable) as\n | ReadableIterator<T, E>\n | undefined;\n\n if (!iter) {\n iter = readable[Symbol.asyncIterator]();\n readableIterators.set(readable, iter);\n }\n\n return iter;\n}\n\n/**\n * Retrieves the next value from {@link Readable}, or throws an error if the Readable is done.\n *\n * Calling semantics are similar to {@link getReadableIterator}\n */\nexport async function readNextResult<T, E extends Static<BaseErrorSchemaType>>(\n readable: Readable<T, E>,\n): Promise<ReadableResult<T, E>> {\n const res = await getReadableIterator(readable).next();\n\n if (res.done) {\n throw new Error('readNext from a done Readable');\n }\n\n return res.value;\n}\n\n/**\n * Checks if the readable is done iterating, it consumes an iteration in the process.\n *\n * Calling semantics are similar to {@link getReadableIterator}\n */\nexport async function isReadableDone<T, E extends Static<BaseErrorSchemaType>>(\n readable: Readable<T, E>,\n) {\n const res = await getReadableIterator(readable).next();\n\n return res.done;\n}\n\nexport function payloadToTransportMessage<Payload>(\n payload: Payload,\n): PartialTransportMessage<Payload> {\n return {\n streamId: 'stream',\n controlFlags: 0,\n payload,\n };\n}\n\nexport function createDummyTransportMessage() {\n return payloadToTransportMessage({\n msg: 'cool',\n test: Math.random(),\n });\n}\n\n/**\n * Waits for a message on the transport.\n * @param {Transport} t - The transport to listen to.\n * @param filter - An optional filter function to apply to the received messages.\n * @returns A promise that resolves with the payload of the first message that passes the filter.\n */\nexport async function waitForMessage(\n t: Transport<Connection>,\n filter?: (msg: OpaqueTransportMessage) => boolean,\n rejectMismatch?: boolean,\n) {\n return new Promise((resolve, reject) => {\n function cleanup() {\n t.removeEventListener('message', onMessage);\n }\n\n function onMessage(msg: OpaqueTransportMessage) {\n if (!filter || filter(msg)) {\n cleanup();\n resolve(msg.payload);\n } else if (rejectMismatch) {\n cleanup();\n reject(new Error('message didnt match the filter'));\n }\n }\n\n t.addEventListener('message', onMessage);\n });\n}\n\nexport const testingSessionOptions = defaultTransportOptions;\nexport const testingClientSessionOptions = defaultClientTransportOptions;\n\nexport function dummySession() {\n return SessionStateGraph.entrypoints.NoConnection(\n 'client',\n 'server',\n {\n onSessionGracePeriodElapsed: () => {\n /* noop */\n },\n onMessageSendFailure: () => {\n /* noop */\n },\n },\n testingSessionOptions,\n currentProtocolVersion,\n getTracer(),\n );\n}\n\nexport function getClientSendFn(\n clientTransport: ClientTransport<Connection>,\n serverTransport: ServerTransport<Connection>,\n) {\n const session =\n clientTransport.sessions.get(serverTransport.clientId) ??\n clientTransport.createUnconnectedSession(serverTransport.clientId);\n\n return clientTransport.getSessionBoundSendFn(\n serverTransport.clientId,\n session.id,\n );\n}\n\nexport function getServerSendFn(\n serverTransport: ServerTransport<Connection>,\n clientTransport: ClientTransport<Connection>,\n) {\n const session = serverTransport.sessions.get(clientTransport.clientId);\n if (!session) {\n throw new Error('session not found');\n }\n\n return serverTransport.getSessionBoundSendFn(\n clientTransport.clientId,\n session.id,\n );\n}\n\nexport function getTransportConnections<ConnType extends Connection>(\n transport: Transport<ConnType>,\n): Array<ConnType> {\n const connections = [];\n for (const session of transport.sessions.values()) {\n if (session.state === SessionState.Connected) {\n connections.push(session.conn);\n }\n }\n\n return connections;\n}\n\nexport function numberOfConnections<ConnType extends Connection>(\n transport: Transport<ConnType>,\n): number {\n return getTransportConnections(transport).length;\n}\n\nexport function closeAllConnections<ConnType extends Connection>(\n transport: Transport<ConnType>,\n) {\n for (const conn of getTransportConnections(transport)) {\n conn.close();\n }\n}\n\n/**\n * Wraps a partial context object in a proxy that throws when accessing\n * properties that weren't provided. This is useful for test contexts where\n * you only want to mock the dependencies a test actually uses.\n *\n * Symbols and `then` are allowed through without throwing — river checks\n * for `Symbol.asyncDispose` / `Symbol.dispose` on context values during\n * `server.close()`, and `then` is checked by the JS runtime when the\n * proxy is returned from an async function.\n *\n * @example\n * ```ts\n * const ctx = createPartialContext<MyContext>({\n * database: mockDb,\n * // accessing ctx.redis will throw\n * });\n *\n * const server = createServer(transport, services, {\n * extendedContext: ctx,\n * });\n * ```\n */\nexport function createPartialContext<T extends Record<string, unknown>>(\n partial: Partial<T>,\n): T {\n return new Proxy(partial as T, {\n get(target, prop, receiver) {\n if (prop in target) {\n return Reflect.get(target, prop, receiver);\n }\n\n if (typeof prop === 'string' && prop !== 'then') {\n throw new Error(\n `${prop} is not mocked in the test context. Provide it via createPartialContext if your test needs it.`,\n );\n }\n\n return undefined;\n },\n });\n}\n","/**\n * Represents an observable value that can be subscribed to for changes.\n * This should only be used in tests\n * @template T - The type of the value being observed.\n */\nexport class Observable<T> {\n value: T;\n private listeners: Set<(val: T) => void>;\n\n constructor(initialValue: T) {\n this.value = initialValue;\n this.listeners = new Set();\n }\n\n /**\n * Gets the current value of the observable.\n */\n get() {\n return this.value;\n }\n\n /**\n * Sets the current value of the observable. All listeners will get an update with this value.\n * @param newValue - The new value to set.\n */\n set(tx: (preValue: T) => T) {\n const newValue = tx(this.value);\n this.value = newValue;\n this.listeners.forEach((listener) => listener(newValue));\n }\n\n /**\n * Subscribes to changes in the observable value.\n * @param listener - A callback function that will be called when the value changes.\n * @returns A function that can be called to unsubscribe from further notifications.\n */\n observe(listener: (val: T) => void) {\n this.listeners.add(listener);\n listener(this.get());\n\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Returns the number of listeners currently observing the observable\n */\n get listenerCount(): number {\n return this.listeners.size;\n }\n}\n","import { Duplex } from 'node:stream';\nimport assert from 'assert';\n\nconst kCallback = Symbol('Callback');\nconst kInitOtherSide = Symbol('InitOtherSide');\n\n// yoinked from https://github.com/nodejs/node/blob/c3a7b29e56a5ada6327ebb622ba746d022685742/lib/internal/streams/duplexpair.js#L55\n// but with types\nclass DuplexSide extends Duplex {\n private otherSide: DuplexSide | null;\n private [kCallback]: (() => void) | null;\n\n constructor() {\n super();\n this[kCallback] = null;\n this.otherSide = null;\n }\n\n [kInitOtherSide](otherSide: DuplexSide) {\n if (this.otherSide === null) {\n this.otherSide = otherSide;\n }\n }\n\n _read() {\n const callback = this[kCallback];\n if (callback) {\n this[kCallback] = null;\n callback();\n }\n }\n\n _write(\n chunk: Uint8Array,\n _encoding: BufferEncoding,\n callback: (error?: Error | null) => void,\n ) {\n assert(this.otherSide !== null);\n assert(this.otherSide[kCallback] === null);\n if (chunk.length === 0) {\n process.nextTick(callback);\n } else {\n this.otherSide.push(chunk);\n this.otherSide[kCallback] = callback;\n }\n }\n\n _final(callback: (error?: Error | null) => void) {\n this.otherSide?.on('end', callback);\n this.otherSide?.push(null);\n }\n}\n\nexport function duplexPair(): [DuplexSide, DuplexSide] {\n const side0 = new DuplexSide();\n const side1 = new DuplexSide();\n side0[kInitOtherSide](side1);\n side1[kInitOtherSide](side0);\n side0.on('close', () => {\n setImmediate(() => {\n side1.destroy();\n });\n });\n\n side1.on('close', () => {\n setImmediate(() => {\n side0.destroy();\n });\n });\n\n return [side0, side1];\n}\n","import { Transport, TransportClientId } from '../../transport';\nimport { ClientTransport } from '../../transport/client';\nimport { Connection } from '../../transport/connection';\nimport { ServerTransport } from '../../transport/server';\nimport { Observable } from '../observable/observable';\nimport { ProvidedServerTransportOptions } from '../../transport/options';\nimport { TestSetupHelpers, TestTransportOptions } from './transports';\nimport { Duplex } from 'node:stream';\nimport { duplexPair } from '../duplex/duplexPair';\nimport { nanoid } from 'nanoid';\nimport { TSchema } from '@sinclair/typebox';\nimport { ServerHandshakeOptions } from '../../router/handshake';\n\nexport class InMemoryConnection extends Connection {\n conn: Duplex;\n\n constructor(pipe: Duplex) {\n super();\n this.conn = pipe;\n this.conn.allowHalfOpen = false;\n\n this.conn.on('data', (data: Uint8Array) => {\n this.dataListener?.(data);\n });\n\n this.conn.on('close', () => {\n this.closeListener?.();\n });\n\n this.conn.on('error', (err) => {\n this.errorListener?.(err);\n });\n }\n\n send(payload: Uint8Array): boolean {\n setImmediate(() => {\n this.conn.write(payload);\n });\n\n return true;\n }\n\n close(): void {\n setImmediate(() => {\n this.conn.end();\n this.conn.emit('close');\n });\n }\n}\n\ninterface BidiConnection {\n id: string;\n clientToServer: Duplex;\n serverToClient: Duplex;\n clientId: TransportClientId;\n serverId: TransportClientId;\n handled: boolean;\n}\n\n// we construct a network of transports connected by node streams here\n// so that we can test the transport layer without needing to actually\n// use real network/websocket connections\n// this is useful for testing the transport layer in isolation\n// and allows us to control network conditions in a way that would be\n// difficult with real network connections (e.g. simulating a phantom\n// disconnect, .pause() vs .removeAllListeners('data'), congestion,\n// latency, differences in ws implementations between node and browsers, etc.)\nexport function createMockTransportNetwork(\n opts?: TestTransportOptions,\n): TestSetupHelpers {\n // conn id -> [client->server, server->client]\n const connections = new Observable<Record<string, BidiConnection>>({});\n\n const transports: Array<Transport<InMemoryConnection>> = [];\n class MockClientTransport extends ClientTransport<InMemoryConnection> {\n async createNewOutgoingConnection(\n to: TransportClientId,\n ): Promise<InMemoryConnection> {\n const [clientToServer, serverToClient] = duplexPair();\n await new Promise((resolve) => setImmediate(resolve));\n\n const connId = nanoid();\n connections.set((prev) => ({\n ...prev,\n [connId]: {\n id: connId,\n clientToServer,\n serverToClient,\n clientId: this.clientId,\n serverId: to,\n handled: false,\n },\n }));\n\n return new InMemoryConnection(clientToServer);\n }\n }\n\n class MockServerTransport<\n MetadataSchema extends TSchema = TSchema,\n ParsedMetadata extends object = object,\n > extends ServerTransport<\n InMemoryConnection,\n MetadataSchema,\n ParsedMetadata\n > {\n subscribeCleanup: () => void;\n\n constructor(\n clientId: TransportClientId,\n options?: ProvidedServerTransportOptions,\n ) {\n super(clientId, options);\n\n this.subscribeCleanup = connections.observe((conns) => {\n // look for any unhandled connections\n for (const conn of Object.values(conns)) {\n // if we've already handled this connection, skip it\n // or if it's not for us, skip it\n if (conn.handled || conn.serverId !== this.clientId) {\n continue;\n }\n\n conn.handled = true;\n const connection = new InMemoryConnection(conn.serverToClient);\n this.handleConnection(connection);\n }\n });\n }\n\n close() {\n this.subscribeCleanup();\n super.close();\n }\n }\n\n return {\n getClientTransport: (id, handshakeOptions) => {\n const clientTransport = new MockClientTransport(id, opts?.client);\n if (handshakeOptions) {\n clientTransport.extendHandshake(handshakeOptions);\n }\n\n transports.push(clientTransport);\n\n return clientTransport;\n },\n getServerTransport: <\n MetadataSchema extends TSchema = TSchema,\n ParsedMetadata extends object = object,\n >(\n id = 'SERVER',\n handshakeOptions:\n | ServerHandshakeOptions<MetadataSchema, ParsedMetadata>\n | undefined,\n ) => {\n const serverTransport = new MockServerTransport<\n MetadataSchema,\n ParsedMetadata\n >(id, opts?.server);\n if (handshakeOptions) {\n serverTransport.extendHandshake(handshakeOptions);\n }\n\n transports.push(serverTransport);\n\n return serverTransport;\n },\n simulatePhantomDisconnect() {\n for (const conn of Object.values(connections.get())) {\n conn.serverToClient.pause();\n conn.clientToServer.pause();\n }\n },\n async restartServer() {\n for (const transport of transports) {\n if (transport.clientId !== 'SERVER') continue;\n transport.close();\n }\n\n // kill all connections while we're at it\n for (const conn of Object.values(connections.get())) {\n conn.serverToClient.destroy();\n conn.clientToServer.destroy();\n }\n },\n cleanup() {\n for (const conn of Object.values(connections.get())) {\n conn.serverToClient.destroy();\n conn.clientToServer.destroy();\n }\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -295,6 +295,10 @@ var LeakyBucketRateLimit = class {
|
|
|
295
295
|
clearInterval(this.intervalHandle);
|
|
296
296
|
this.intervalHandle = void 0;
|
|
297
297
|
}
|
|
298
|
+
resetBudget() {
|
|
299
|
+
this.stopLeak();
|
|
300
|
+
this.budgetConsumed = 0;
|
|
301
|
+
}
|
|
298
302
|
close() {
|
|
299
303
|
this.stopLeak();
|
|
300
304
|
}
|
|
@@ -479,6 +483,7 @@ var IdentifiedSession = class extends CommonSession {
|
|
|
479
483
|
telemetry;
|
|
480
484
|
to;
|
|
481
485
|
protocolVersion;
|
|
486
|
+
listeners;
|
|
482
487
|
/**
|
|
483
488
|
* Index of the message we will send next (excluding handshake)
|
|
484
489
|
*/
|
|
@@ -502,7 +507,8 @@ var IdentifiedSession = class extends CommonSession {
|
|
|
502
507
|
telemetry,
|
|
503
508
|
log,
|
|
504
509
|
protocolVersion,
|
|
505
|
-
seqSent: messagesSent
|
|
510
|
+
seqSent: messagesSent,
|
|
511
|
+
listeners
|
|
506
512
|
} = props;
|
|
507
513
|
super(props);
|
|
508
514
|
this.id = id;
|
|
@@ -514,6 +520,7 @@ var IdentifiedSession = class extends CommonSession {
|
|
|
514
520
|
this.log = log;
|
|
515
521
|
this.protocolVersion = protocolVersion;
|
|
516
522
|
this.seqSent = messagesSent;
|
|
523
|
+
this.listeners = listeners;
|
|
517
524
|
}
|
|
518
525
|
get loggingMetadata() {
|
|
519
526
|
const metadata = {
|
|
@@ -530,7 +537,7 @@ var IdentifiedSession = class extends CommonSession {
|
|
|
530
537
|
}
|
|
531
538
|
return metadata;
|
|
532
539
|
}
|
|
533
|
-
|
|
540
|
+
encodeMsg(partialMsg) {
|
|
534
541
|
const msg = {
|
|
535
542
|
...partialMsg,
|
|
536
543
|
id: generateId(),
|
|
@@ -539,18 +546,37 @@ var IdentifiedSession = class extends CommonSession {
|
|
|
539
546
|
seq: this.seq,
|
|
540
547
|
ack: this.ack
|
|
541
548
|
};
|
|
549
|
+
const encoded = this.codec.toBuffer(msg);
|
|
550
|
+
if (!encoded.ok) {
|
|
551
|
+
this.listeners.onMessageSendFailure(
|
|
552
|
+
{ ...partialMsg, seq: this.seq },
|
|
553
|
+
encoded.reason
|
|
554
|
+
);
|
|
555
|
+
return encoded;
|
|
556
|
+
}
|
|
542
557
|
this.seq++;
|
|
543
|
-
return
|
|
558
|
+
return {
|
|
559
|
+
ok: true,
|
|
560
|
+
value: {
|
|
561
|
+
id: msg.id,
|
|
562
|
+
seq: msg.seq,
|
|
563
|
+
msg: partialMsg,
|
|
564
|
+
data: encoded.value
|
|
565
|
+
}
|
|
566
|
+
};
|
|
544
567
|
}
|
|
545
568
|
nextSeq() {
|
|
546
569
|
return this.sendBuffer.length > 0 ? this.sendBuffer[0].seq : this.seq;
|
|
547
570
|
}
|
|
548
571
|
send(msg) {
|
|
549
|
-
const
|
|
550
|
-
|
|
572
|
+
const encodeResult = this.encodeMsg(msg);
|
|
573
|
+
if (!encodeResult.ok) {
|
|
574
|
+
return encodeResult;
|
|
575
|
+
}
|
|
576
|
+
this.sendBuffer.push(encodeResult.value);
|
|
551
577
|
return {
|
|
552
578
|
ok: true,
|
|
553
|
-
value:
|
|
579
|
+
value: encodeResult.value.id
|
|
554
580
|
};
|
|
555
581
|
}
|
|
556
582
|
_handleStateExit() {
|
|
@@ -583,23 +609,6 @@ var IdentifiedSessionWithGracePeriod = class extends IdentifiedSession {
|
|
|
583
609
|
super._handleClose();
|
|
584
610
|
}
|
|
585
611
|
};
|
|
586
|
-
function sendMessage(conn, codec, msg) {
|
|
587
|
-
const buff = codec.toBuffer(msg);
|
|
588
|
-
if (!buff.ok) {
|
|
589
|
-
return buff;
|
|
590
|
-
}
|
|
591
|
-
const sent = conn.send(buff.value);
|
|
592
|
-
if (!sent) {
|
|
593
|
-
return {
|
|
594
|
-
ok: false,
|
|
595
|
-
reason: "failed to send message"
|
|
596
|
-
};
|
|
597
|
-
}
|
|
598
|
-
return {
|
|
599
|
-
ok: true,
|
|
600
|
-
value: msg.id
|
|
601
|
-
};
|
|
602
|
-
}
|
|
603
612
|
|
|
604
613
|
// transport/sessionStateMachine/SessionConnecting.ts
|
|
605
614
|
var SessionConnecting = class extends IdentifiedSessionWithGracePeriod {
|
|
@@ -678,7 +687,7 @@ function coerceErrorString(err) {
|
|
|
678
687
|
}
|
|
679
688
|
|
|
680
689
|
// package.json
|
|
681
|
-
var version = "0.
|
|
690
|
+
var version = "0.215.1";
|
|
682
691
|
|
|
683
692
|
// tracing/index.ts
|
|
684
693
|
function getPropagationContext(ctx) {
|
|
@@ -761,7 +770,21 @@ var SessionWaitingForHandshake = class extends CommonSession {
|
|
|
761
770
|
this.listeners.onHandshake(parsedMsgRes.value);
|
|
762
771
|
};
|
|
763
772
|
sendHandshake(msg) {
|
|
764
|
-
|
|
773
|
+
const buff = this.codec.toBuffer(msg);
|
|
774
|
+
if (!buff.ok) {
|
|
775
|
+
return buff;
|
|
776
|
+
}
|
|
777
|
+
const sent = this.conn.send(buff.value);
|
|
778
|
+
if (!sent) {
|
|
779
|
+
return {
|
|
780
|
+
ok: false,
|
|
781
|
+
reason: "failed to send handshake"
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
return {
|
|
785
|
+
ok: true,
|
|
786
|
+
value: msg.id
|
|
787
|
+
};
|
|
765
788
|
}
|
|
766
789
|
_handleStateExit() {
|
|
767
790
|
this.conn.removeDataListener();
|
|
@@ -810,7 +833,21 @@ var SessionHandshaking = class extends IdentifiedSessionWithGracePeriod {
|
|
|
810
833
|
this.listeners.onHandshake(parsedMsgRes.value);
|
|
811
834
|
};
|
|
812
835
|
sendHandshake(msg) {
|
|
813
|
-
|
|
836
|
+
const buff = this.codec.toBuffer(msg);
|
|
837
|
+
if (!buff.ok) {
|
|
838
|
+
return buff;
|
|
839
|
+
}
|
|
840
|
+
const sent = this.conn.send(buff.value);
|
|
841
|
+
if (!sent) {
|
|
842
|
+
return {
|
|
843
|
+
ok: false,
|
|
844
|
+
reason: "failed to send handshake"
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
return {
|
|
848
|
+
ok: true,
|
|
849
|
+
value: msg.id
|
|
850
|
+
};
|
|
814
851
|
}
|
|
815
852
|
_handleStateExit() {
|
|
816
853
|
super._handleStateExit();
|
|
@@ -845,28 +882,35 @@ var SessionConnected = class extends IdentifiedSession {
|
|
|
845
882
|
}
|
|
846
883
|
this.startMissingHeartbeatTimeout();
|
|
847
884
|
}
|
|
848
|
-
assertSendOrdering(
|
|
849
|
-
if (
|
|
850
|
-
const msg = `invariant violation: would have sent out of order msg (seq: ${
|
|
885
|
+
assertSendOrdering(encodedMsg) {
|
|
886
|
+
if (encodedMsg.seq > this.seqSent + 1) {
|
|
887
|
+
const msg = `invariant violation: would have sent out of order msg (seq: ${encodedMsg.seq}, expected: ${this.seqSent} + 1)`;
|
|
851
888
|
this.log?.error(msg, {
|
|
852
889
|
...this.loggingMetadata,
|
|
853
|
-
transportMessage: constructedMsg,
|
|
854
890
|
tags: ["invariant-violation"]
|
|
855
891
|
});
|
|
856
892
|
throw new Error(msg);
|
|
857
893
|
}
|
|
858
894
|
}
|
|
859
895
|
send(msg) {
|
|
860
|
-
const
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
896
|
+
const encodeResult = this.encodeMsg(msg);
|
|
897
|
+
if (!encodeResult.ok) {
|
|
898
|
+
return encodeResult;
|
|
899
|
+
}
|
|
900
|
+
const encodedMsg = encodeResult.value;
|
|
901
|
+
this.assertSendOrdering(encodedMsg);
|
|
902
|
+
this.sendBuffer.push(encodedMsg);
|
|
903
|
+
const sent = this.conn.send(encodedMsg.data);
|
|
904
|
+
if (!sent) {
|
|
905
|
+
const reason = "failed to send message";
|
|
906
|
+
this.listeners.onMessageSendFailure(
|
|
907
|
+
{ ...encodedMsg.msg, seq: encodedMsg.seq },
|
|
908
|
+
reason
|
|
909
|
+
);
|
|
910
|
+
return { ok: false, reason };
|
|
867
911
|
}
|
|
868
|
-
this.seqSent =
|
|
869
|
-
return
|
|
912
|
+
this.seqSent = encodedMsg.seq;
|
|
913
|
+
return { ok: true, value: encodedMsg.id };
|
|
870
914
|
}
|
|
871
915
|
constructor(props) {
|
|
872
916
|
super(props);
|
|
@@ -884,10 +928,14 @@ var SessionConnected = class extends IdentifiedSession {
|
|
|
884
928
|
);
|
|
885
929
|
for (const msg of this.sendBuffer) {
|
|
886
930
|
this.assertSendOrdering(msg);
|
|
887
|
-
const
|
|
888
|
-
if (!
|
|
889
|
-
|
|
890
|
-
|
|
931
|
+
const sent = this.conn.send(msg.data);
|
|
932
|
+
if (!sent) {
|
|
933
|
+
const reason = "failed to send buffered message";
|
|
934
|
+
this.listeners.onMessageSendFailure(
|
|
935
|
+
{ ...msg.msg, seq: msg.seq },
|
|
936
|
+
reason
|
|
937
|
+
);
|
|
938
|
+
return { ok: false, reason };
|
|
891
939
|
}
|
|
892
940
|
this.seqSent = msg.seq;
|
|
893
941
|
}
|
|
@@ -1675,6 +1723,17 @@ var Transport = class {
|
|
|
1675
1723
|
const noConnectionSession = SessionStateGraph.transition.ConnectingToNoConnection(session, {
|
|
1676
1724
|
onSessionGracePeriodElapsed: () => {
|
|
1677
1725
|
this.onSessionGracePeriodElapsed(noConnectionSession);
|
|
1726
|
+
},
|
|
1727
|
+
onMessageSendFailure: (msg, reason) => {
|
|
1728
|
+
this.log?.error(`failed to send message: ${reason}`, {
|
|
1729
|
+
...noConnectionSession.loggingMetadata,
|
|
1730
|
+
transportMessage: msg
|
|
1731
|
+
});
|
|
1732
|
+
this.protocolError({
|
|
1733
|
+
type: ProtocolError.MessageSendFailure,
|
|
1734
|
+
message: reason
|
|
1735
|
+
});
|
|
1736
|
+
this.deleteSession(noConnectionSession, { unhealthy: true });
|
|
1678
1737
|
}
|
|
1679
1738
|
});
|
|
1680
1739
|
this.updateSession(noConnectionSession);
|
|
@@ -1682,18 +1741,32 @@ var Transport = class {
|
|
|
1682
1741
|
}
|
|
1683
1742
|
onConnClosed(session) {
|
|
1684
1743
|
let noConnectionSession;
|
|
1744
|
+
const listeners = {
|
|
1745
|
+
onSessionGracePeriodElapsed: () => {
|
|
1746
|
+
this.onSessionGracePeriodElapsed(noConnectionSession);
|
|
1747
|
+
},
|
|
1748
|
+
onMessageSendFailure: (msg, reason) => {
|
|
1749
|
+
this.log?.error(`failed to send message: ${reason}`, {
|
|
1750
|
+
...noConnectionSession.loggingMetadata,
|
|
1751
|
+
transportMessage: msg
|
|
1752
|
+
});
|
|
1753
|
+
this.protocolError({
|
|
1754
|
+
type: ProtocolError.MessageSendFailure,
|
|
1755
|
+
message: reason
|
|
1756
|
+
});
|
|
1757
|
+
this.deleteSession(noConnectionSession, { unhealthy: true });
|
|
1758
|
+
}
|
|
1759
|
+
};
|
|
1685
1760
|
if (session.state === "Handshaking" /* Handshaking */) {
|
|
1686
|
-
noConnectionSession = SessionStateGraph.transition.HandshakingToNoConnection(
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
});
|
|
1761
|
+
noConnectionSession = SessionStateGraph.transition.HandshakingToNoConnection(
|
|
1762
|
+
session,
|
|
1763
|
+
listeners
|
|
1764
|
+
);
|
|
1691
1765
|
} else {
|
|
1692
|
-
noConnectionSession = SessionStateGraph.transition.ConnectedToNoConnection(
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
});
|
|
1766
|
+
noConnectionSession = SessionStateGraph.transition.ConnectedToNoConnection(
|
|
1767
|
+
session,
|
|
1768
|
+
listeners
|
|
1769
|
+
);
|
|
1697
1770
|
}
|
|
1698
1771
|
this.updateSession(noConnectionSession);
|
|
1699
1772
|
return noConnectionSession;
|
|
@@ -1784,6 +1857,17 @@ var ClientTransport = class extends Transport {
|
|
|
1784
1857
|
{
|
|
1785
1858
|
onSessionGracePeriodElapsed: () => {
|
|
1786
1859
|
this.onSessionGracePeriodElapsed(session);
|
|
1860
|
+
},
|
|
1861
|
+
onMessageSendFailure: (msg, reason) => {
|
|
1862
|
+
this.log?.error(`failed to send message: ${reason}`, {
|
|
1863
|
+
...session.loggingMetadata,
|
|
1864
|
+
transportMessage: msg
|
|
1865
|
+
});
|
|
1866
|
+
this.protocolError({
|
|
1867
|
+
type: ProtocolError.MessageSendFailure,
|
|
1868
|
+
message: reason
|
|
1869
|
+
});
|
|
1870
|
+
this.deleteSession(session, { unhealthy: true });
|
|
1787
1871
|
}
|
|
1788
1872
|
},
|
|
1789
1873
|
this.options,
|
|
@@ -1848,6 +1932,17 @@ var ClientTransport = class extends Transport {
|
|
|
1848
1932
|
},
|
|
1849
1933
|
onSessionGracePeriodElapsed: () => {
|
|
1850
1934
|
this.onSessionGracePeriodElapsed(handshakingSession);
|
|
1935
|
+
},
|
|
1936
|
+
onMessageSendFailure: (msg, reason) => {
|
|
1937
|
+
this.log?.error(`failed to send message: ${reason}`, {
|
|
1938
|
+
...handshakingSession.loggingMetadata,
|
|
1939
|
+
transportMessage: msg
|
|
1940
|
+
});
|
|
1941
|
+
this.protocolError({
|
|
1942
|
+
type: ProtocolError.MessageSendFailure,
|
|
1943
|
+
message: reason
|
|
1944
|
+
});
|
|
1945
|
+
this.deleteSession(handshakingSession, { unhealthy: true });
|
|
1851
1946
|
}
|
|
1852
1947
|
}
|
|
1853
1948
|
);
|
|
@@ -2009,6 +2104,17 @@ var ClientTransport = class extends Transport {
|
|
|
2009
2104
|
},
|
|
2010
2105
|
onSessionGracePeriodElapsed: () => {
|
|
2011
2106
|
this.onSessionGracePeriodElapsed(backingOffSession);
|
|
2107
|
+
},
|
|
2108
|
+
onMessageSendFailure: (msg, reason) => {
|
|
2109
|
+
this.log?.error(`failed to send message: ${reason}`, {
|
|
2110
|
+
...backingOffSession.loggingMetadata,
|
|
2111
|
+
transportMessage: msg
|
|
2112
|
+
});
|
|
2113
|
+
this.protocolError({
|
|
2114
|
+
type: ProtocolError.MessageSendFailure,
|
|
2115
|
+
message: reason
|
|
2116
|
+
});
|
|
2117
|
+
this.deleteSession(backingOffSession, { unhealthy: true });
|
|
2012
2118
|
}
|
|
2013
2119
|
}
|
|
2014
2120
|
);
|
|
@@ -2072,6 +2178,17 @@ var ClientTransport = class extends Transport {
|
|
|
2072
2178
|
},
|
|
2073
2179
|
onSessionGracePeriodElapsed: () => {
|
|
2074
2180
|
this.onSessionGracePeriodElapsed(connectingSession);
|
|
2181
|
+
},
|
|
2182
|
+
onMessageSendFailure: (msg, reason) => {
|
|
2183
|
+
this.log?.error(`failed to send message: ${reason}`, {
|
|
2184
|
+
...connectingSession.loggingMetadata,
|
|
2185
|
+
transportMessage: msg
|
|
2186
|
+
});
|
|
2187
|
+
this.protocolError({
|
|
2188
|
+
type: ProtocolError.MessageSendFailure,
|
|
2189
|
+
message: reason
|
|
2190
|
+
});
|
|
2191
|
+
this.deleteSession(connectingSession, { unhealthy: true });
|
|
2075
2192
|
}
|
|
2076
2193
|
}
|
|
2077
2194
|
);
|