@replit/river 0.200.0-rc.9 → 0.200.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.
Files changed (72) hide show
  1. package/README.md +8 -8
  2. package/dist/{chunk-42Z2FQIU.js → chunk-6VA5DW7N.js} +21 -13
  3. package/dist/chunk-6VA5DW7N.js.map +1 -0
  4. package/dist/{chunk-4PVU7J25.js → chunk-AJGIY2UB.js} +1 -1
  5. package/dist/chunk-AJGIY2UB.js.map +1 -0
  6. package/dist/chunk-MADS7AI5.js +298 -0
  7. package/dist/chunk-MADS7AI5.js.map +1 -0
  8. package/dist/{chunk-4HT6P2ZG.js → chunk-SONGYR7A.js} +22 -30
  9. package/dist/chunk-SONGYR7A.js.map +1 -0
  10. package/dist/{chunk-EETL2L77.js → chunk-UQHYJZTP.js} +14 -32
  11. package/dist/chunk-UQHYJZTP.js.map +1 -0
  12. package/dist/{chunk-ZXZE253M.js → chunk-YQPJ3HZK.js} +24 -37
  13. package/dist/chunk-YQPJ3HZK.js.map +1 -0
  14. package/dist/{chunk-VXYHC666.js → chunk-YTMS7OP6.js} +1 -1
  15. package/dist/chunk-YTMS7OP6.js.map +1 -0
  16. package/dist/{chunk-I75XYO5W.js → chunk-ZDYZ2FCN.js} +82 -20
  17. package/dist/chunk-ZDYZ2FCN.js.map +1 -0
  18. package/dist/{chunk-GR3AQKHL.js → chunk-ZNJM2HIE.js} +14 -4
  19. package/dist/chunk-ZNJM2HIE.js.map +1 -0
  20. package/dist/{client-22a47343.d.ts → client-095a929e.d.ts} +3 -4
  21. package/dist/codec/index.cjs.map +1 -1
  22. package/dist/codec/index.js +1 -1
  23. package/dist/connection-623d75e9.d.ts +32 -0
  24. package/dist/{context-b4aff18f.d.ts → context-85b8690e.d.ts} +43 -43
  25. package/dist/logging/index.cjs.map +1 -1
  26. package/dist/logging/index.d.cts +1 -1
  27. package/dist/logging/index.d.ts +1 -1
  28. package/dist/logging/index.js +1 -1
  29. package/dist/{message-7d135e38.d.ts → message-57bb8187.d.ts} +5 -3
  30. package/dist/router/index.cjs +600 -681
  31. package/dist/router/index.cjs.map +1 -1
  32. package/dist/router/index.d.cts +22 -12
  33. package/dist/router/index.d.ts +22 -12
  34. package/dist/router/index.js +477 -389
  35. package/dist/router/index.js.map +1 -1
  36. package/dist/{server-dd6a9853.d.ts → server-456bf6cb.d.ts} +5 -5
  37. package/dist/{services-1b5ac5bc.d.ts → services-e4f28470.d.ts} +182 -194
  38. package/dist/transport/impls/ws/client.cjs +129 -62
  39. package/dist/transport/impls/ws/client.cjs.map +1 -1
  40. package/dist/transport/impls/ws/client.d.cts +4 -4
  41. package/dist/transport/impls/ws/client.d.ts +4 -4
  42. package/dist/transport/impls/ws/client.js +7 -7
  43. package/dist/transport/impls/ws/client.js.map +1 -1
  44. package/dist/transport/impls/ws/server.cjs +146 -70
  45. package/dist/transport/impls/ws/server.cjs.map +1 -1
  46. package/dist/transport/impls/ws/server.d.cts +6 -5
  47. package/dist/transport/impls/ws/server.d.ts +6 -5
  48. package/dist/transport/impls/ws/server.js +21 -9
  49. package/dist/transport/impls/ws/server.js.map +1 -1
  50. package/dist/transport/index.cjs +138 -92
  51. package/dist/transport/index.cjs.map +1 -1
  52. package/dist/transport/index.d.cts +4 -4
  53. package/dist/transport/index.d.ts +4 -4
  54. package/dist/transport/index.js +7 -7
  55. package/dist/util/testHelpers.cjs +256 -327
  56. package/dist/util/testHelpers.cjs.map +1 -1
  57. package/dist/util/testHelpers.d.cts +36 -31
  58. package/dist/util/testHelpers.d.ts +36 -31
  59. package/dist/util/testHelpers.js +82 -52
  60. package/dist/util/testHelpers.js.map +1 -1
  61. package/package.json +4 -3
  62. package/dist/chunk-42Z2FQIU.js.map +0 -1
  63. package/dist/chunk-4HT6P2ZG.js.map +0 -1
  64. package/dist/chunk-4PVU7J25.js.map +0 -1
  65. package/dist/chunk-EETL2L77.js.map +0 -1
  66. package/dist/chunk-GR3AQKHL.js.map +0 -1
  67. package/dist/chunk-I75XYO5W.js.map +0 -1
  68. package/dist/chunk-MQ6ANR3H.js +0 -451
  69. package/dist/chunk-MQ6ANR3H.js.map +0 -1
  70. package/dist/chunk-VXYHC666.js.map +0 -1
  71. package/dist/chunk-ZXZE253M.js.map +0 -1
  72. package/dist/connection-260e45a8.d.ts +0 -11
@@ -1,20 +1,21 @@
1
1
  import {
2
2
  BaseLogger,
3
3
  createLogProxy
4
- } from "./chunk-VXYHC666.js";
4
+ } from "./chunk-YTMS7OP6.js";
5
5
  import {
6
6
  SessionStateGraph,
7
7
  defaultTransportOptions
8
- } from "./chunk-42Z2FQIU.js";
8
+ } from "./chunk-6VA5DW7N.js";
9
9
  import {
10
10
  generateId
11
- } from "./chunk-EETL2L77.js";
11
+ } from "./chunk-UQHYJZTP.js";
12
12
 
13
13
  // transport/events.ts
14
14
  var ProtocolError = {
15
15
  RetriesExceeded: "conn_retry_exceeded",
16
16
  HandshakeFailed: "handshake_failed",
17
- MessageOrderingViolated: "message_ordering_violated"
17
+ MessageOrderingViolated: "message_ordering_violated",
18
+ InvalidMessage: "invalid_message"
18
19
  };
19
20
  var EventDispatcher = class {
20
21
  eventListeners = {};
@@ -89,12 +90,12 @@ var Transport = class {
89
90
  /**
90
91
  * Called when a message is received by this transport.
91
92
  * You generally shouldn't need to override this in downstream transport implementations.
92
- * @param msg The received message.
93
+ * @param message The received message.
93
94
  */
94
- handleMsg(msg) {
95
+ handleMsg(message) {
95
96
  if (this.getStatus() !== "open")
96
97
  return;
97
- this.eventDispatcher.dispatchEvent("message", msg);
98
+ this.eventDispatcher.dispatchEvent("message", message);
98
99
  }
99
100
  /**
100
101
  * Adds a listener to this transport.
@@ -134,28 +135,59 @@ var Transport = class {
134
135
  getStatus() {
135
136
  return this.status;
136
137
  }
137
- updateSession(session) {
138
+ // state transitions
139
+ createSession(session) {
138
140
  const activeSession = this.sessions.get(session.to);
139
- if (activeSession && activeSession.id !== session.id) {
140
- const msg = `attempt to transition active session for ${session.to} but active session (${activeSession.id}) is different from handle (${session.id})`;
141
+ if (activeSession) {
142
+ const msg = `attempt to create session for ${session.to} but active session (${activeSession.id}) already exists`;
143
+ this.log?.error(msg, {
144
+ ...session.loggingMetadata,
145
+ tags: ["invariant-violation"]
146
+ });
141
147
  throw new Error(msg);
142
148
  }
143
149
  this.sessions.set(session.to, session);
150
+ this.eventDispatcher.dispatchEvent("sessionStatus", {
151
+ status: "connect",
152
+ session
153
+ });
154
+ this.eventDispatcher.dispatchEvent("sessionTransition", {
155
+ state: session.state,
156
+ session
157
+ });
158
+ }
159
+ updateSession(session) {
160
+ const activeSession = this.sessions.get(session.to);
144
161
  if (!activeSession) {
145
- this.eventDispatcher.dispatchEvent("sessionStatus", {
146
- status: "connect",
147
- session
162
+ const msg = `attempt to transition session for ${session.to} but no active session exists`;
163
+ this.log?.error(msg, {
164
+ ...session.loggingMetadata,
165
+ tags: ["invariant-violation"]
166
+ });
167
+ throw new Error(msg);
168
+ }
169
+ if (activeSession.id !== session.id) {
170
+ const msg = `attempt to transition active session for ${session.to} but active session (${activeSession.id}) is different from handle (${session.id})`;
171
+ this.log?.error(msg, {
172
+ ...session.loggingMetadata,
173
+ tags: ["invariant-violation"]
148
174
  });
175
+ throw new Error(msg);
149
176
  }
177
+ this.sessions.set(session.to, session);
150
178
  this.eventDispatcher.dispatchEvent("sessionTransition", {
151
179
  state: session.state,
152
180
  session
153
181
  });
154
- return session;
155
182
  }
156
- // state transitions
157
- deleteSession(session) {
158
- session.log?.info(`closing session ${session.id}`, session.loggingMetadata);
183
+ deleteSession(session, options) {
184
+ if (session._isConsumed)
185
+ return;
186
+ const loggingMetadata = session.loggingMetadata;
187
+ if (loggingMetadata.tags && options?.unhealthy) {
188
+ loggingMetadata.tags.push("unhealthy-session");
189
+ }
190
+ session.log?.info(`closing session ${session.id}`, loggingMetadata);
159
191
  this.eventDispatcher.dispatchEvent("sessionStatus", {
160
192
  status: "disconnect",
161
193
  session
@@ -178,7 +210,8 @@ var Transport = class {
178
210
  this.onSessionGracePeriodElapsed(noConnectionSession);
179
211
  }
180
212
  });
181
- return this.updateSession(noConnectionSession);
213
+ this.updateSession(noConnectionSession);
214
+ return noConnectionSession;
182
215
  }
183
216
  onConnClosed(session) {
184
217
  let noConnectionSession;
@@ -195,7 +228,36 @@ var Transport = class {
195
228
  }
196
229
  });
197
230
  }
198
- return this.updateSession(noConnectionSession);
231
+ this.updateSession(noConnectionSession);
232
+ return noConnectionSession;
233
+ }
234
+ /**
235
+ * Gets a send closure scoped to a specific session. Sending using the returned
236
+ * closure after the session has transitioned to a different state will be a noop.
237
+ *
238
+ * Session objects themselves can become stale as they transition between
239
+ * states. As stale sessions cannot be used again (and will throw), holding
240
+ * onto a session object is not recommended.
241
+ */
242
+ getSessionBoundSendFn(to, sessionId) {
243
+ if (this.getStatus() !== "open") {
244
+ throw new Error("cannot get a bound send function on a closed transport");
245
+ }
246
+ return (msg) => {
247
+ const session = this.sessions.get(to);
248
+ if (!session) {
249
+ throw new Error(
250
+ `session scope for ${sessionId} has ended (close), can't send`
251
+ );
252
+ }
253
+ const sameSession = session.id === sessionId;
254
+ if (!sameSession) {
255
+ throw new Error(
256
+ `session scope for ${sessionId} has ended (transition), can't send`
257
+ );
258
+ }
259
+ return session.send(msg);
260
+ };
199
261
  }
200
262
  };
201
263
 
@@ -275,4 +337,4 @@ export {
275
337
  Transport,
276
338
  Connection
277
339
  };
278
- //# sourceMappingURL=chunk-I75XYO5W.js.map
340
+ //# sourceMappingURL=chunk-ZDYZ2FCN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../transport/events.ts","../transport/transport.ts","../transport/connection.ts"],"sourcesContent":["import { type Static } from '@sinclair/typebox';\nimport { Connection } from './connection';\nimport { OpaqueTransportMessage, HandshakeErrorResponseCodes } 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 InvalidMessage: 'invalid_message',\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.BackingOff }\n | { state: SessionState.NoConnection };\n protocolError:\n | {\n type: (typeof ProtocolError)['HandshakeFailed'];\n code: Static<typeof HandshakeErrorResponseCodes>;\n message: string;\n }\n | {\n type: Omit<\n ProtocolErrorType,\n (typeof ProtocolError)['HandshakeFailed']\n >;\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 {\n OpaqueTransportMessage,\n PartialTransportMessage,\n TransportClientId,\n} from './message';\nimport {\n BaseLogger,\n LogFn,\n Logger,\n LoggingLevel,\n createLogProxy,\n} from '../logging/log';\nimport { EventDispatcher, EventHandler, EventMap, EventTypes } from './events';\nimport {\n ProvidedTransportOptions,\n TransportOptions,\n defaultTransportOptions,\n} from './options';\nimport {\n SessionConnected,\n SessionConnecting,\n SessionHandshaking,\n SessionNoConnection,\n SessionState,\n} from './sessionStateMachine';\nimport { Connection } from './connection';\nimport { Session, SessionStateGraph } from './sessionStateMachine/transitions';\nimport { SessionId } from './sessionStateMachine/common';\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\nexport interface DeleteSessionOptions {\n unhealthy: boolean;\n}\n\nexport type SessionBoundSendFn = (\n msg: PartialTransportMessage,\n) => string | undefined;\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\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 message The received message.\n */\n protected handleMsg(message: OpaqueTransportMessage) {\n if (this.getStatus() !== 'open') return;\n this.eventDispatcher.dispatchEvent('message', message);\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 protected protocolError(message: EventMap['protocolError']) {\n this.eventDispatcher.dispatchEvent('protocolError', 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 this.log?.info(`manually closed transport`, { clientId: this.clientId });\n }\n\n getStatus(): TransportStatus {\n return this.status;\n }\n\n // state transitions\n protected createSession<S extends Session<ConnType>>(session: S): void {\n const activeSession = this.sessions.get(session.to);\n if (activeSession) {\n const msg = `attempt to create session for ${session.to} but active session (${activeSession.id}) already exists`;\n this.log?.error(msg, {\n ...session.loggingMetadata,\n tags: ['invariant-violation'],\n });\n throw new Error(msg);\n }\n\n this.sessions.set(session.to, session);\n this.eventDispatcher.dispatchEvent('sessionStatus', {\n status: 'connect',\n session: session,\n });\n\n this.eventDispatcher.dispatchEvent('sessionTransition', {\n state: session.state,\n session: session,\n } as EventMap['sessionTransition']);\n }\n\n protected updateSession<S extends Session<ConnType>>(session: S): void {\n const activeSession = this.sessions.get(session.to);\n if (!activeSession) {\n const msg = `attempt to transition session for ${session.to} but no active session exists`;\n this.log?.error(msg, {\n ...session.loggingMetadata,\n tags: ['invariant-violation'],\n });\n throw new Error(msg);\n }\n\n if (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 this.log?.error(msg, {\n ...session.loggingMetadata,\n tags: ['invariant-violation'],\n });\n throw new Error(msg);\n }\n\n this.sessions.set(session.to, session);\n this.eventDispatcher.dispatchEvent('sessionTransition', {\n state: session.state,\n session: session,\n } as EventMap['sessionTransition']);\n }\n\n protected deleteSession(\n session: Session<ConnType>,\n options?: DeleteSessionOptions,\n ) {\n // ensure idempotency esp re: dispatching events\n if (session._isConsumed) return;\n\n const loggingMetadata = session.loggingMetadata;\n if (loggingMetadata.tags && options?.unhealthy) {\n loggingMetadata.tags.push('unhealthy-session');\n }\n\n session.log?.info(`closing session ${session.id}`, loggingMetadata);\n this.eventDispatcher.dispatchEvent('sessionStatus', {\n status: 'disconnect',\n session: session,\n });\n\n const to = session.to;\n session.close();\n this.sessions.delete(to);\n }\n\n // common listeners\n protected onSessionGracePeriodElapsed(session: Session<ConnType>) {\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 this.updateSession(noConnectionSession);\n\n return 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 this.updateSession(noConnectionSession);\n\n return noConnectionSession;\n }\n\n /**\n * Gets a send closure scoped to a specific session. Sending using the returned\n * closure after the session has transitioned to a different state will be a noop.\n *\n * Session objects themselves can become stale as they transition between\n * states. As stale sessions cannot be used again (and will throw), holding\n * onto a session object is not recommended.\n */\n getSessionBoundSendFn(\n to: TransportClientId,\n sessionId: SessionId,\n ): SessionBoundSendFn {\n if (this.getStatus() !== 'open') {\n throw new Error('cannot get a bound send function on a closed transport');\n }\n\n return (msg: PartialTransportMessage) => {\n const session = this.sessions.get(to);\n if (!session) {\n throw new Error(\n `session scope for ${sessionId} has ended (close), can't send`,\n );\n }\n\n const sameSession = session.id === sessionId;\n if (!sameSession) {\n throw new Error(\n `session scope for ${sessionId} has ended (transition), can't send`,\n );\n }\n\n return session.send(msg);\n };\n }\n}\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\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"],"mappings":"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","names":[]}
@@ -1,13 +1,23 @@
1
1
  import {
2
2
  Connection
3
- } from "./chunk-I75XYO5W.js";
3
+ } from "./chunk-ZDYZ2FCN.js";
4
4
 
5
5
  // transport/impls/ws/connection.ts
6
+ var WS_HEALTHY_CLOSE_CODE = 1e3;
6
7
  var WebSocketConnection = class extends Connection {
7
8
  ws;
8
- constructor(ws) {
9
+ extras;
10
+ get loggingMetadata() {
11
+ const metadata = super.loggingMetadata;
12
+ if (this.extras) {
13
+ metadata.extras = this.extras;
14
+ }
15
+ return metadata;
16
+ }
17
+ constructor(ws, extras) {
9
18
  super();
10
19
  this.ws = ws;
20
+ this.extras = extras;
11
21
  this.ws.binaryType = "arraybuffer";
12
22
  let didError = false;
13
23
  this.ws.onerror = () => {
@@ -40,11 +50,11 @@ var WebSocketConnection = class extends Connection {
40
50
  return true;
41
51
  }
42
52
  close() {
43
- this.ws.close();
53
+ this.ws.close(WS_HEALTHY_CLOSE_CODE);
44
54
  }
45
55
  };
46
56
 
47
57
  export {
48
58
  WebSocketConnection
49
59
  };
50
- //# sourceMappingURL=chunk-GR3AQKHL.js.map
60
+ //# sourceMappingURL=chunk-ZNJM2HIE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../transport/impls/ws/connection.ts"],"sourcesContent":["import { Connection } from '../../connection';\nimport { WsLike } from './wslike';\n\ninterface ConnectionInfoExtras {\n headers: Record<string, string>;\n}\n\nconst WS_HEALTHY_CLOSE_CODE = 1000;\n\nexport class WebSocketConnection extends Connection {\n ws: WsLike;\n extras?: ConnectionInfoExtras;\n\n get loggingMetadata() {\n const metadata = super.loggingMetadata;\n if (this.extras) {\n metadata.extras = this.extras;\n }\n\n return metadata;\n }\n\n constructor(ws: WsLike, extras?: ConnectionInfoExtras) {\n super();\n this.ws = ws;\n this.extras = extras;\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\n this.ws.send(payload);\n\n return true;\n }\n\n close() {\n // we close with 1000 normal even if its not really healthy at the river level\n // if we don't specify this, it defaults to 1005 which\n // some proxies/loggers detect as an error\n this.ws.close(WS_HEALTHY_CLOSE_CODE);\n }\n}\n"],"mappings":";;;;;AAOA,IAAM,wBAAwB;AAEvB,IAAM,sBAAN,cAAkC,WAAW;AAAA,EAClD;AAAA,EACA;AAAA,EAEA,IAAI,kBAAkB;AACpB,UAAM,WAAW,MAAM;AACvB,QAAI,KAAK,QAAQ;AACf,eAAS,SAAS,KAAK;AAAA,IACzB;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,YAAY,IAAY,QAA+B;AACrD,UAAM;AACN,SAAK,KAAK;AACV,SAAK,SAAS;AACd,SAAK,GAAG,aAAa;AAKrB,QAAI,WAAW;AACf,SAAK,GAAG,UAAU,MAAM;AACtB,iBAAW;AAAA,IACb;AAEA,SAAK,GAAG,UAAU,CAAC,EAAE,MAAM,OAAO,MAAM;AACtC,UAAI,UAAU;AACZ,cAAM,MAAM,IAAI;AAAA,UACd,0CAA0C,IAAI,MAAM,MAAM;AAAA,QAC5D;AAEA,mBAAW,MAAM,KAAK,gBAAgB;AACpC,aAAG,GAAG;AAAA,QACR;AAAA,MACF;AAEA,iBAAW,MAAM,KAAK,gBAAgB;AACpC,WAAG;AAAA,MACL;AAAA,IACF;AAEA,SAAK,GAAG,YAAY,CAAC,QAAQ;AAC3B,iBAAW,MAAM,KAAK,eAAe;AACnC,WAAG,IAAI,IAAkB;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAAA,EAEA,KAAK,SAAqB;AACxB,QAAI,KAAK,GAAG,eAAe,KAAK,GAAG,MAAM;AACvC,aAAO;AAAA,IACT;AAEA,SAAK,GAAG,KAAK,OAAO;AAEpB,WAAO;AAAA,EACT;AAAA,EAEA,QAAQ;AAIN,SAAK,GAAG,MAAM,qBAAqB;AAAA,EACrC;AACF;","names":[]}
@@ -1,5 +1,5 @@
1
- import { C as Connection, T as Transport, n as ClientTransportOptions, L as LeakyBucketRateLimit, p as ClientHandshakeOptions, q as ClientSession, b as ProvidedClientTransportOptions, f as SessionConnecting, e as SessionNoConnection, g as SessionHandshaking, h as SessionConnected, r as SessionBackingOff } from './context-b4aff18f.js';
2
- import { c as TransportClientId, P as PartialTransportMessage, b as OpaqueTransportMessage } from './message-7d135e38.js';
1
+ import { C as Connection, T as Transport, n as ClientTransportOptions, L as LeakyBucketRateLimit, q as ClientHandshakeOptions, r as ClientSession, b as ProvidedClientTransportOptions, e as SessionNoConnection, f as SessionConnecting, g as SessionHandshaking, h as SessionConnected, s as SessionBackingOff } from './context-85b8690e.js';
2
+ import { c as TransportClientId, b as OpaqueTransportMessage } from './message-57bb8187.js';
3
3
 
4
4
  declare abstract class ClientTransport<ConnType extends Connection> extends Transport<ConnType> {
5
5
  /**
@@ -29,8 +29,7 @@ declare abstract class ClientTransport<ConnType extends Connection> extends Tran
29
29
  */
30
30
  protected abstract createNewOutgoingConnection(to: TransportClientId): Promise<ConnType>;
31
31
  private tryReconnecting;
32
- send(to: string, msg: PartialTransportMessage): string;
33
- private createUnconnectedSession;
32
+ createUnconnectedSession(to: string): SessionNoConnection;
34
33
  protected onConnectingFailed(session: SessionConnecting<ConnType>): SessionNoConnection;
35
34
  protected onConnClosed(session: SessionHandshaking<ConnType> | SessionConnected<ConnType>): SessionNoConnection;
36
35
  protected onConnectionEstablished(session: SessionConnecting<ConnType>, conn: ConnType): SessionHandshaking<ConnType>;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../codec/index.ts","../../codec/binary.ts","../../codec/json.ts"],"sourcesContent":["export { BinaryCodec } from './binary';\nexport { NaiveJsonCodec } from './json';\nexport type { Codec } from './types';\n","import { decode, encode } from '@msgpack/msgpack';\nimport { Codec } from './types';\n\n/**\n * Binary codec, uses [msgpack](https://www.npmjs.com/package/@msgpack/msgpack) under the hood\n * @type {Codec}\n */\nexport const BinaryCodec: Codec = {\n toBuffer(obj) {\n return encode(obj, { ignoreUndefined: true });\n },\n fromBuffer: (buff: Uint8Array) => {\n try {\n const res = decode(buff);\n if (typeof res !== 'object') {\n return null;\n }\n\n return res;\n } catch {\n return null;\n }\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"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,qBAA+B;AAOxB,IAAM,cAAqB;AAAA,EAChC,SAAS,KAAK;AACZ,eAAO,uBAAO,KAAK,EAAE,iBAAiB,KAAK,CAAC;AAAA,EAC9C;AAAA,EACA,YAAY,CAAC,SAAqB;AAChC,QAAI;AACF,YAAM,UAAM,uBAAO,IAAI;AACvB,UAAI,OAAO,QAAQ,UAAU;AAC3B,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;ACrBA,IAAM,UAAU,IAAI,YAAY;AAChC,IAAM,UAAU,IAAI,YAAY;AAGhC,SAAS,mBAAmB,YAAwB;AAClD,MAAI,SAAS;AACb,aAAW,QAAQ,CAAC,SAAS;AAC3B,cAAU,OAAO,aAAa,IAAI;AAAA,EACpC,CAAC;AACD,SAAO,KAAK,MAAM;AACpB;AAGA,SAAS,mBAAmB,QAAgB;AAC1C,QAAM,eAAe,KAAK,MAAM;AAChC,QAAM,aAAa,IAAI,WAAW,aAAa,MAAM;AACrD,WAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,eAAW,CAAC,IAAI,aAAa,WAAW,CAAC;AAAA,EAC3C;AACA,SAAO;AACT;AAUO,IAAM,iBAAwB;AAAA,EACnC,UAAU,CAAC,QAAgB;AACzB,WAAO,QAAQ;AAAA,MACb,KAAK,UAAU,KAAK,SAAS,SAElB,KAAc;AACvB,cAAM,MAAM,KAAK,GAAG;AACpB,YAAI,eAAe,YAAY;AAC7B,iBAAO,EAAE,IAAI,mBAAmB,GAAG,EAAE;AAAA,QACvC,OAAO;AACL,iBAAO;AAAA,QACT;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EACA,YAAY,CAAC,SAAqB;AAChC,QAAI;AACF,YAAM,SAAS,KAAK;AAAA,QAClB,QAAQ,OAAO,IAAI;AAAA,QACnB,SAAS,QAAQ,MAAM,KAAc;AACnC,cAAK,KAAwC,IAAI;AAC/C,mBAAO,mBAAoB,IAA2B,EAAE;AAAA,UAC1D,OAAO;AACL,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAEA,UAAI,OAAO,WAAW;AAAU,eAAO;AACvC,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../codec/index.ts","../../codec/binary.ts","../../codec/json.ts"],"sourcesContent":["export { BinaryCodec } from './binary';\nexport { NaiveJsonCodec } from './json';\nexport type { Codec } from './types';\n","import { decode, encode } from '@msgpack/msgpack';\nimport { Codec } from './types';\n\n/**\n * Binary codec, uses [msgpack](https://www.npmjs.com/package/@msgpack/msgpack) under the hood\n * @type {Codec}\n */\nexport const BinaryCodec: Codec = {\n toBuffer(obj) {\n return encode(obj, { ignoreUndefined: true });\n },\n fromBuffer: (buff: Uint8Array) => {\n try {\n const res = decode(buff);\n if (typeof res !== 'object') {\n return null;\n }\n\n return res;\n } catch {\n return null;\n }\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\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\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\n return null;\n } catch {\n return null;\n }\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,qBAA+B;AAOxB,IAAM,cAAqB;AAAA,EAChC,SAAS,KAAK;AACZ,eAAO,uBAAO,KAAK,EAAE,iBAAiB,KAAK,CAAC;AAAA,EAC9C;AAAA,EACA,YAAY,CAAC,SAAqB;AAChC,QAAI;AACF,YAAM,UAAM,uBAAO,IAAI;AACvB,UAAI,OAAO,QAAQ,UAAU;AAC3B,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;ACrBA,IAAM,UAAU,IAAI,YAAY;AAChC,IAAM,UAAU,IAAI,YAAY;AAGhC,SAAS,mBAAmB,YAAwB;AAClD,MAAI,SAAS;AACb,aAAW,QAAQ,CAAC,SAAS;AAC3B,cAAU,OAAO,aAAa,IAAI;AAAA,EACpC,CAAC;AAED,SAAO,KAAK,MAAM;AACpB;AAGA,SAAS,mBAAmB,QAAgB;AAC1C,QAAM,eAAe,KAAK,MAAM;AAChC,QAAM,aAAa,IAAI,WAAW,aAAa,MAAM;AACrD,WAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,eAAW,CAAC,IAAI,aAAa,WAAW,CAAC;AAAA,EAC3C;AAEA,SAAO;AACT;AAUO,IAAM,iBAAwB;AAAA,EACnC,UAAU,CAAC,QAAgB;AACzB,WAAO,QAAQ;AAAA,MACb,KAAK,UAAU,KAAK,SAAS,SAElB,KAAc;AACvB,cAAM,MAAM,KAAK,GAAG;AACpB,YAAI,eAAe,YAAY;AAC7B,iBAAO,EAAE,IAAI,mBAAmB,GAAG,EAAE;AAAA,QACvC,OAAO;AACL,iBAAO;AAAA,QACT;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EACA,YAAY,CAAC,SAAqB;AAChC,QAAI;AACF,YAAM,SAAS,KAAK;AAAA,QAClB,QAAQ,OAAO,IAAI;AAAA,QACnB,SAAS,QAAQ,MAAM,KAAc;AACnC,cAAK,KAAwC,IAAI;AAC/C,mBAAO,mBAAoB,IAA2B,EAAE;AAAA,UAC1D,OAAO;AACL,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAEA,UAAI,OAAO,WAAW;AAAU,eAAO;AAEvC,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  NaiveJsonCodec
3
- } from "../chunk-4PVU7J25.js";
3
+ } from "../chunk-AJGIY2UB.js";
4
4
 
5
5
  // codec/binary.ts
6
6
  import { decode, encode } from "@msgpack/msgpack";
@@ -0,0 +1,32 @@
1
+ import { e as ProtocolVersion, b as OpaqueTransportMessage, f as Tags } from './message-57bb8187.js';
2
+ import * as _sinclair_typebox_errors from '@sinclair/typebox/errors';
3
+ import { C as Connection } from './context-85b8690e.js';
4
+ import { W as WsLike } from './wslike-e0b32dd5.js';
5
+
6
+ interface ConnectionInfoExtras {
7
+ headers: Record<string, string>;
8
+ }
9
+ declare class WebSocketConnection extends Connection {
10
+ ws: WsLike;
11
+ extras?: ConnectionInfoExtras;
12
+ get loggingMetadata(): Partial<{
13
+ protocolVersion: ProtocolVersion;
14
+ clientId: string;
15
+ connectedTo: string;
16
+ sessionId: string;
17
+ connId: string;
18
+ transportMessage: Partial<OpaqueTransportMessage>;
19
+ validationErrors: _sinclair_typebox_errors.ValueError[];
20
+ tags: Tags[];
21
+ telemetry: {
22
+ traceId: string;
23
+ spanId: string;
24
+ };
25
+ extras: unknown;
26
+ }>;
27
+ constructor(ws: WsLike, extras?: ConnectionInfoExtras);
28
+ send(payload: Uint8Array): boolean;
29
+ close(): void;
30
+ }
31
+
32
+ export { WebSocketConnection as W };
@@ -1,4 +1,4 @@
1
- import { f as TelemetryInfo, M as MessageMetadata, c as TransportClientId, L as Logger, b as OpaqueTransportMessage, P as PartialTransportMessage, a as TransportMessage, e as Tags, H as HandshakeErrorResponseCodes, g as LogFn, h as LoggingLevel, j as HandshakeErrorCustomHandlerFatalResponseCodes } from './message-7d135e38.js';
1
+ import { g as TelemetryInfo, M as MessageMetadata, c as TransportClientId, L as Logger, b as OpaqueTransportMessage, e as ProtocolVersion, P as PartialTransportMessage, a as TransportMessage, f as Tags, H as HandshakeErrorResponseCodes, h as LogFn, j as LoggingLevel, k as HandshakeErrorCustomHandlerFatalResponseCodes } from './message-57bb8187.js';
2
2
  import { Static, TSchema } from '@sinclair/typebox';
3
3
  import * as _sinclair_typebox_errors from '@sinclair/typebox/errors';
4
4
  import { C as Codec } from './types-3e5768ec.js';
@@ -130,13 +130,13 @@ interface IdentifiedSessionProps extends CommonSessionProps {
130
130
  ack: number;
131
131
  sendBuffer: Array<OpaqueTransportMessage>;
132
132
  telemetry: TelemetryInfo;
133
- protocolVersion: string;
133
+ protocolVersion: ProtocolVersion;
134
134
  }
135
135
  declare abstract class IdentifiedSession extends CommonSession {
136
136
  readonly id: SessionId;
137
137
  readonly telemetry: TelemetryInfo;
138
138
  readonly to: TransportClientId;
139
- readonly protocolVersion: string;
139
+ readonly protocolVersion: ProtocolVersion;
140
140
  /**
141
141
  * Index of the message we will send next (excluding handshake)
142
142
  */
@@ -214,7 +214,7 @@ declare class SessionHandshaking<ConnType extends Connection> extends Identified
214
214
  handshakeTimeout?: ReturnType<typeof setTimeout>;
215
215
  constructor(props: SessionHandshakingProps<ConnType>);
216
216
  get loggingMetadata(): {
217
- protocolVersion?: string | undefined;
217
+ protocolVersion?: ProtocolVersion | undefined;
218
218
  clientId?: string | undefined;
219
219
  connectedTo?: string | undefined;
220
220
  sessionId?: string | undefined;
@@ -226,6 +226,7 @@ declare class SessionHandshaking<ConnType extends Connection> extends Identified
226
226
  traceId: string;
227
227
  spanId: string;
228
228
  } | undefined;
229
+ extras?: unknown;
229
230
  };
230
231
  onHandshakeData: (msg: Uint8Array) => void;
231
232
  sendHandshake(msg: TransportMessage): boolean;
@@ -254,7 +255,7 @@ declare class SessionConnected<ConnType extends Connection> extends IdentifiedSe
254
255
  send(msg: PartialTransportMessage): string;
255
256
  constructor(props: SessionConnectedProps<ConnType>);
256
257
  get loggingMetadata(): {
257
- protocolVersion?: string | undefined;
258
+ protocolVersion?: ProtocolVersion | undefined;
258
259
  clientId?: string | undefined;
259
260
  connectedTo?: string | undefined;
260
261
  sessionId?: string | undefined;
@@ -266,9 +267,11 @@ declare class SessionConnected<ConnType extends Connection> extends IdentifiedSe
266
267
  traceId: string;
267
268
  spanId: string;
268
269
  } | undefined;
270
+ extras?: unknown;
269
271
  };
270
272
  startActiveHeartbeat(): void;
271
273
  private sendHeartbeat;
274
+ closeConnection(): void;
272
275
  onMessageData: (msg: Uint8Array) => void;
273
276
  _handleStateExit(): void;
274
277
  _handleClose(): void;
@@ -298,6 +301,7 @@ declare const ProtocolError: {
298
301
  readonly RetriesExceeded: "conn_retry_exceeded";
299
302
  readonly HandshakeFailed: "handshake_failed";
300
303
  readonly MessageOrderingViolated: "message_ordering_violated";
304
+ readonly InvalidMessage: "invalid_message";
301
305
  };
302
306
  type ProtocolErrorType = (typeof ProtocolError)[keyof typeof ProtocolError];
303
307
  interface EventMap {
@@ -405,6 +409,10 @@ type ProvidedServerTransportOptions = Partial<ServerTransportOptions>;
405
409
  * @property {'closed'} closed - The transport is permanently closed and cannot be reopened.
406
410
  */
407
411
  type TransportStatus = 'open' | 'closed';
412
+ interface DeleteSessionOptions {
413
+ unhealthy: boolean;
414
+ }
415
+ type SessionBoundSendFn = (msg: PartialTransportMessage) => string | undefined;
408
416
  /**
409
417
  * Transports manage the lifecycle (creation/deletion) of sessions
410
418
  *
@@ -455,9 +463,9 @@ declare abstract class Transport<ConnType extends Connection> {
455
463
  /**
456
464
  * Called when a message is received by this transport.
457
465
  * You generally shouldn't need to override this in downstream transport implementations.
458
- * @param msg The received message.
466
+ * @param message The received message.
459
467
  */
460
- protected handleMsg(msg: OpaqueTransportMessage): void;
468
+ protected handleMsg(message: OpaqueTransportMessage): void;
461
469
  /**
462
470
  * Adds a listener to this transport.
463
471
  * @param the type of event to listen for
@@ -470,13 +478,6 @@ declare abstract class Transport<ConnType extends Connection> {
470
478
  * @param handler The message handler to remove.
471
479
  */
472
480
  removeEventListener<K extends EventTypes, T extends EventHandler<K>>(type: K, handler: T): void;
473
- /**
474
- * Sends a message over this transport, delegating to the appropriate connection to actually
475
- * send the message.
476
- * @param msg The message to send.
477
- * @returns The ID of the sent message or undefined if it wasn't sent
478
- */
479
- abstract send(to: TransportClientId, msg: PartialTransportMessage): string;
480
481
  protected protocolError(message: EventMap['protocolError']): void;
481
482
  /**
482
483
  * Default close implementation for transports. You should override this in the downstream
@@ -485,11 +486,21 @@ declare abstract class Transport<ConnType extends Connection> {
485
486
  */
486
487
  close(): void;
487
488
  getStatus(): TransportStatus;
488
- protected updateSession<S extends Session<ConnType>>(session: S): S;
489
- protected deleteSession(session: Session<ConnType>): void;
489
+ protected createSession<S extends Session<ConnType>>(session: S): void;
490
+ protected updateSession<S extends Session<ConnType>>(session: S): void;
491
+ protected deleteSession(session: Session<ConnType>, options?: DeleteSessionOptions): void;
490
492
  protected onSessionGracePeriodElapsed(session: Session<ConnType>): void;
491
493
  protected onConnectingFailed(session: SessionConnecting<ConnType>): SessionNoConnection;
492
494
  protected onConnClosed(session: SessionHandshaking<ConnType> | SessionConnected<ConnType>): SessionNoConnection;
495
+ /**
496
+ * Gets a send closure scoped to a specific session. Sending using the returned
497
+ * closure after the session has transitioned to a different state will be a noop.
498
+ *
499
+ * Session objects themselves can become stale as they transition between
500
+ * states. As stale sessions cannot be used again (and will throw), holding
501
+ * onto a session object is not recommended.
502
+ */
503
+ getSessionBoundSendFn(to: TransportClientId, sessionId: SessionId): SessionBoundSendFn;
493
504
  }
494
505
 
495
506
  type ConstructHandshake<T extends TSchema> = () => Static<T> | Promise<Static<T>>;
@@ -587,40 +598,29 @@ type ProcedureHandlerContext<State> = ServiceContext & {
587
598
  */
588
599
  from: TransportClientId;
589
600
  /**
590
- * An AbortController for this stream. This is used to abort the stream from the
591
- * handler and notify the client that the stream was aborted.
592
- *
593
- * Important to note that this controller is owned by the handler, if you
594
- * want to listen to aborts coming from the client, you should use the
595
- * {@link clientAbortSignal}.
601
+ * This is used to cancel the procedure call from the handler and notify the client that the
602
+ * call was cancelled.
596
603
  *
597
- * Aborts are not the same as closing streams gracefully, please refer to
604
+ * Cancelling is not the same as closing procedure calls gracefully, please refer to
598
605
  * the river documentation to understand the difference between the two concepts.
599
606
  */
600
- abortController: AbortController;
607
+ cancel: () => void;
601
608
  /**
602
- * You can listen to clientAbortSignal this to check if the client aborted the request,
603
- * or if the request was aborted due to an unexpected disconnect from the calling
604
- * session.
609
+ * This signal is a standard [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)
610
+ * triggered when the procedure invocation is done. This signal tracks the invocation/request finishing
611
+ * for _any_ reason including the procedure invocation.
605
612
  *
606
- * If the procedure has a read stream (e.g. upload or stream), the procedure will
607
- * notified of aborts as part of the stream, but you may still want to use
608
- * this signal as it is triggered immediately after an abort comes in,
609
- * in readStreams some data may be buffered before the abort result shows up.
613
+ * You can use this to pass it on to asynchronous operations (such as fetch).
610
614
  *
611
- * Important to note that this signal is owned by the client, you have a separate
612
- * signal inside {@link abortController} for aborts triggered within the handler.
615
+ * You may also want to explicitly register callbacks on the
616
+ * ['abort' event](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/abort_event)
617
+ * as a way to cleanup after the request is finished.
613
618
  *
614
- * Aborts are not the same as closing streams gracefully, please refer to
615
- * the river documentation to understand the difference between the two concepts.
616
- */
617
- clientAbortSignal: AbortSignal;
618
- /**
619
- * Lets you add a function that will run when the request is done, this can be
620
- * due to an abort (from either side), error, or success. If the callback is
621
- * added after the stream ended, it will run immediately.
619
+ * Note that (per standard AbortSignals) callbacks registered _after_ the procedure invocation
620
+ * is done are not triggered. In such cases, you can check the "aborted" property and cleanup
621
+ * immediately if needed.
622
622
  */
623
- onRequestFinished: (callback: () => void) => void;
623
+ signal: AbortSignal;
624
624
  };
625
625
 
626
- export { ServerSession as A, Connection as C, EventMap as E, LeakyBucketRateLimit as L, ProvidedTransportOptions as P, Session as S, Transport as T, TransportStatus as a, ProvidedClientTransportOptions as b, ProvidedServerTransportOptions as c, SessionState as d, SessionNoConnection as e, SessionConnecting as f, SessionHandshaking as g, SessionConnected as h, EventTypes as i, EventHandler as j, ProtocolError as k, ProtocolErrorType as l, SessionOptions as m, ClientTransportOptions as n, ServiceContext as o, ClientHandshakeOptions as p, ClientSession as q, SessionBackingOff as r, ServerHandshakeOptions as s, ParsedMetadata as t, ProcedureHandlerContext as u, createClientHandshakeOptions as v, createServerHandshakeOptions as w, CommonSession as x, CommonSessionProps as y, ServerTransportOptions as z };
626
+ export { ServerTransportOptions as A, ServerSession as B, Connection as C, DeleteSessionOptions as D, EventMap as E, LeakyBucketRateLimit as L, ProvidedTransportOptions as P, Session as S, Transport as T, TransportStatus as a, ProvidedClientTransportOptions as b, ProvidedServerTransportOptions as c, SessionState as d, SessionNoConnection as e, SessionConnecting as f, SessionHandshaking as g, SessionConnected as h, EventTypes as i, EventHandler as j, ProtocolError as k, ProtocolErrorType as l, SessionOptions as m, ClientTransportOptions as n, SessionBoundSendFn as o, ServiceContext as p, ClientHandshakeOptions as q, ClientSession as r, SessionBackingOff as s, ParsedMetadata as t, ServerHandshakeOptions as u, ProcedureHandlerContext as v, createClientHandshakeOptions as w, createServerHandshakeOptions as x, CommonSession as y, CommonSessionProps as z };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../logging/index.ts","../../logging/log.ts"],"sourcesContent":["export { stringLogger, coloredStringLogger, jsonLogger } from './log';\nexport type { Logger, LogFn, MessageMetadata } from './log';\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 =\n | 'invariant-violation'\n | 'state-transition'\n | 'invalid-request';\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"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACyFO,IAAM,eAAsB,CAAC,KAAK,KAAK,QAAQ,WAAW;AAC/D,QAAM,OAAO,KAAK,WAAW,GAAG,IAAI,QAAQ,SAAS;AACrD,UAAQ,IAAI,UAAU,KAAK,KAAK,IAAI,GAAG,GAAG,EAAE;AAC9C;AAEA,IAAM,WAAW;AAAA,EACf,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT;AAEO,IAAM,sBAA6B,CAAC,KAAK,KAAK,QAAQ,WAAW;AACtE,QAAM,QAAQ,SAAS,KAAK;AAC5B,QAAM,OAAO,KAAK,WAAW,GAAG,IAAI,QAAQ,SAAS;AACrD,UAAQ,IAAI,UAAU,KAAK,GAAG,KAAK,YAAc,IAAI,GAAG,GAAG,EAAE;AAC/D;AAEO,IAAM,aAAoB,CAAC,KAAK,KAAK,UAAU;AACpD,UAAQ,IAAI,KAAK,UAAU,EAAE,KAAK,KAAK,MAAM,CAAC,CAAC;AACjD;","names":[]}
1
+ {"version":3,"sources":["../../logging/index.ts","../../logging/log.ts"],"sourcesContent":["export { stringLogger, coloredStringLogger, jsonLogger } from './log';\nexport type { Logger, LogFn, MessageMetadata } from './log';\n","import { ValueError } from '@sinclair/typebox/value';\nimport { OpaqueTransportMessage, ProtocolVersion } 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 =\n | 'invariant-violation'\n | 'state-transition'\n | 'invalid-request'\n | 'unhealthy-session';\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\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: ProtocolVersion;\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 extras: unknown;\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"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC4FO,IAAM,eAAsB,CAAC,KAAK,KAAK,QAAQ,WAAW;AAC/D,QAAM,OAAO,KAAK,WAAW,GAAG,IAAI,QAAQ,SAAS;AACrD,UAAQ,IAAI,UAAU,KAAK,KAAK,IAAI,GAAG,GAAG,EAAE;AAC9C;AAEA,IAAM,WAAW;AAAA,EACf,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT;AAEO,IAAM,sBAA6B,CAAC,KAAK,KAAK,QAAQ,WAAW;AACtE,QAAM,QAAQ,SAAS,KAAK;AAC5B,QAAM,OAAO,KAAK,WAAW,GAAG,IAAI,QAAQ,SAAS;AACrD,UAAQ,IAAI,UAAU,KAAK,GAAG,KAAK,YAAc,IAAI,GAAG,GAAG,EAAE;AAC/D;AAEO,IAAM,aAAoB,CAAC,KAAK,KAAK,UAAU;AACpD,UAAQ,IAAI,KAAK,UAAU,EAAE,KAAK,KAAK,MAAM,CAAC,CAAC;AACjD;","names":[]}
@@ -1,4 +1,4 @@
1
- export { g as LogFn, L as Logger, M as MessageMetadata, k as coloredStringLogger, l as jsonLogger, s as stringLogger } from '../message-7d135e38.js';
1
+ export { h as LogFn, L as Logger, M as MessageMetadata, l as coloredStringLogger, m as jsonLogger, s as stringLogger } from '../message-57bb8187.js';
2
2
  import '@sinclair/typebox/value';
3
3
  import '@sinclair/typebox';
4
4
  import '@opentelemetry/api';
@@ -1,4 +1,4 @@
1
- export { g as LogFn, L as Logger, M as MessageMetadata, k as coloredStringLogger, l as jsonLogger, s as stringLogger } from '../message-7d135e38.js';
1
+ export { h as LogFn, L as Logger, M as MessageMetadata, l as coloredStringLogger, m as jsonLogger, s as stringLogger } from '../message-57bb8187.js';
2
2
  import '@sinclair/typebox/value';
3
3
  import '@sinclair/typebox';
4
4
  import '@opentelemetry/api';
@@ -2,7 +2,7 @@ import {
2
2
  coloredStringLogger,
3
3
  jsonLogger,
4
4
  stringLogger
5
- } from "../chunk-VXYHC666.js";
5
+ } from "../chunk-YTMS7OP6.js";
6
6
  export {
7
7
  coloredStringLogger,
8
8
  jsonLogger,
@@ -14,9 +14,9 @@ type LogFn = (msg: string, ctx?: MessageMetadata, level?: LoggingLevel) => void;
14
14
  type Logger = {
15
15
  [key in LoggingLevel]: (msg: string, metadata?: MessageMetadata) => void;
16
16
  };
17
- type Tags = 'invariant-violation' | 'state-transition' | 'invalid-request';
17
+ type Tags = 'invariant-violation' | 'state-transition' | 'invalid-request' | 'unhealthy-session';
18
18
  type MessageMetadata = Partial<{
19
- protocolVersion: string;
19
+ protocolVersion: ProtocolVersion;
20
20
  clientId: string;
21
21
  connectedTo: string;
22
22
  sessionId: string;
@@ -28,6 +28,7 @@ type MessageMetadata = Partial<{
28
28
  traceId: string;
29
29
  spanId: string;
30
30
  };
31
+ extras: unknown;
31
32
  }>;
32
33
  declare const stringLogger: LogFn;
33
34
  declare const coloredStringLogger: LogFn;
@@ -64,6 +65,7 @@ declare const TransportMessageSchema: <T extends TSchema>(t: T) => _sinclair_typ
64
65
  }>>;
65
66
  payload: T;
66
67
  }>;
68
+ type ProtocolVersion = 'v1.1' | 'v2.0';
67
69
  declare const HandshakeErrorCustomHandlerFatalResponseCodes: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"REJECTED_UNSUPPORTED_CLIENT">, _sinclair_typebox.TLiteral<"REJECTED_BY_CUSTOM_HANDLER">]>;
68
70
  declare const HandshakeErrorResponseCodes: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"SESSION_STATE_MISMATCH">, _sinclair_typebox.TUnion<[_sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"REJECTED_UNSUPPORTED_CLIENT">, _sinclair_typebox.TLiteral<"REJECTED_BY_CUSTOM_HANDLER">]>, _sinclair_typebox.TLiteral<"MALFORMED_HANDSHAKE_META">, _sinclair_typebox.TLiteral<"MALFORMED_HANDSHAKE">, _sinclair_typebox.TLiteral<"PROTOCOL_VERSION_MISMATCH">]>]>;
69
71
  /**
@@ -135,4 +137,4 @@ declare function isStreamOpen(controlFlag: number): boolean;
135
137
  */
136
138
  declare function isStreamClose(controlFlag: number): boolean;
137
139
 
138
- export { HandshakeErrorResponseCodes as H, Logger as L, MessageMetadata as M, OpaqueTransportMessageSchema as O, PartialTransportMessage as P, TransportMessageSchema as T, TransportMessage as a, OpaqueTransportMessage as b, TransportClientId as c, isStreamClose as d, Tags as e, TelemetryInfo as f, LogFn as g, LoggingLevel as h, isStreamOpen as i, HandshakeErrorCustomHandlerFatalResponseCodes as j, coloredStringLogger as k, jsonLogger as l, stringLogger as s };
140
+ export { HandshakeErrorResponseCodes as H, Logger as L, MessageMetadata as M, OpaqueTransportMessageSchema as O, PartialTransportMessage as P, TransportMessageSchema as T, TransportMessage as a, OpaqueTransportMessage as b, TransportClientId as c, isStreamClose as d, ProtocolVersion as e, Tags as f, TelemetryInfo as g, LogFn as h, isStreamOpen as i, LoggingLevel as j, HandshakeErrorCustomHandlerFatalResponseCodes as k, coloredStringLogger as l, jsonLogger as m, stringLogger as s };