@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.
- package/README.md +8 -8
- package/dist/{chunk-42Z2FQIU.js → chunk-6VA5DW7N.js} +21 -13
- package/dist/chunk-6VA5DW7N.js.map +1 -0
- package/dist/{chunk-4PVU7J25.js → chunk-AJGIY2UB.js} +1 -1
- package/dist/chunk-AJGIY2UB.js.map +1 -0
- package/dist/chunk-MADS7AI5.js +298 -0
- package/dist/chunk-MADS7AI5.js.map +1 -0
- package/dist/{chunk-4HT6P2ZG.js → chunk-SONGYR7A.js} +22 -30
- package/dist/chunk-SONGYR7A.js.map +1 -0
- package/dist/{chunk-EETL2L77.js → chunk-UQHYJZTP.js} +14 -32
- package/dist/chunk-UQHYJZTP.js.map +1 -0
- package/dist/{chunk-ZXZE253M.js → chunk-YQPJ3HZK.js} +24 -37
- package/dist/chunk-YQPJ3HZK.js.map +1 -0
- package/dist/{chunk-VXYHC666.js → chunk-YTMS7OP6.js} +1 -1
- package/dist/chunk-YTMS7OP6.js.map +1 -0
- package/dist/{chunk-I75XYO5W.js → chunk-ZDYZ2FCN.js} +82 -20
- package/dist/chunk-ZDYZ2FCN.js.map +1 -0
- package/dist/{chunk-GR3AQKHL.js → chunk-ZNJM2HIE.js} +14 -4
- package/dist/chunk-ZNJM2HIE.js.map +1 -0
- package/dist/{client-22a47343.d.ts → client-095a929e.d.ts} +3 -4
- package/dist/codec/index.cjs.map +1 -1
- package/dist/codec/index.js +1 -1
- package/dist/connection-623d75e9.d.ts +32 -0
- package/dist/{context-b4aff18f.d.ts → context-85b8690e.d.ts} +43 -43
- package/dist/logging/index.cjs.map +1 -1
- package/dist/logging/index.d.cts +1 -1
- package/dist/logging/index.d.ts +1 -1
- package/dist/logging/index.js +1 -1
- package/dist/{message-7d135e38.d.ts → message-57bb8187.d.ts} +5 -3
- package/dist/router/index.cjs +600 -681
- package/dist/router/index.cjs.map +1 -1
- package/dist/router/index.d.cts +22 -12
- package/dist/router/index.d.ts +22 -12
- package/dist/router/index.js +477 -389
- package/dist/router/index.js.map +1 -1
- package/dist/{server-dd6a9853.d.ts → server-456bf6cb.d.ts} +5 -5
- package/dist/{services-1b5ac5bc.d.ts → services-e4f28470.d.ts} +182 -194
- package/dist/transport/impls/ws/client.cjs +129 -62
- package/dist/transport/impls/ws/client.cjs.map +1 -1
- package/dist/transport/impls/ws/client.d.cts +4 -4
- package/dist/transport/impls/ws/client.d.ts +4 -4
- package/dist/transport/impls/ws/client.js +7 -7
- package/dist/transport/impls/ws/client.js.map +1 -1
- package/dist/transport/impls/ws/server.cjs +146 -70
- package/dist/transport/impls/ws/server.cjs.map +1 -1
- package/dist/transport/impls/ws/server.d.cts +6 -5
- package/dist/transport/impls/ws/server.d.ts +6 -5
- package/dist/transport/impls/ws/server.js +21 -9
- package/dist/transport/impls/ws/server.js.map +1 -1
- package/dist/transport/index.cjs +138 -92
- package/dist/transport/index.cjs.map +1 -1
- package/dist/transport/index.d.cts +4 -4
- package/dist/transport/index.d.ts +4 -4
- package/dist/transport/index.js +7 -7
- package/dist/util/testHelpers.cjs +256 -327
- package/dist/util/testHelpers.cjs.map +1 -1
- package/dist/util/testHelpers.d.cts +36 -31
- package/dist/util/testHelpers.d.ts +36 -31
- package/dist/util/testHelpers.js +82 -52
- package/dist/util/testHelpers.js.map +1 -1
- package/package.json +4 -3
- package/dist/chunk-42Z2FQIU.js.map +0 -1
- package/dist/chunk-4HT6P2ZG.js.map +0 -1
- package/dist/chunk-4PVU7J25.js.map +0 -1
- package/dist/chunk-EETL2L77.js.map +0 -1
- package/dist/chunk-GR3AQKHL.js.map +0 -1
- package/dist/chunk-I75XYO5W.js.map +0 -1
- package/dist/chunk-MQ6ANR3H.js +0 -451
- package/dist/chunk-MQ6ANR3H.js.map +0 -1
- package/dist/chunk-VXYHC666.js.map +0 -1
- package/dist/chunk-ZXZE253M.js.map +0 -1
- package/dist/connection-260e45a8.d.ts +0 -11
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BaseLogger,
|
|
3
3
|
createLogProxy
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-YTMS7OP6.js";
|
|
5
5
|
import {
|
|
6
6
|
SessionStateGraph,
|
|
7
7
|
defaultTransportOptions
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-6VA5DW7N.js";
|
|
9
9
|
import {
|
|
10
10
|
generateId
|
|
11
|
-
} from "./chunk-
|
|
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
|
|
93
|
+
* @param message The received message.
|
|
93
94
|
*/
|
|
94
|
-
handleMsg(
|
|
95
|
+
handleMsg(message) {
|
|
95
96
|
if (this.getStatus() !== "open")
|
|
96
97
|
return;
|
|
97
|
-
this.eventDispatcher.dispatchEvent("message",
|
|
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
|
-
|
|
138
|
+
// state transitions
|
|
139
|
+
createSession(session) {
|
|
138
140
|
const activeSession = this.sessions.get(session.to);
|
|
139
|
-
if (activeSession
|
|
140
|
-
const msg = `attempt to
|
|
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
|
-
|
|
146
|
-
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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-
|
|
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,
|
|
2
|
-
import { c as TransportClientId,
|
|
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
|
-
|
|
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>;
|
package/dist/codec/index.cjs.map
CHANGED
|
@@ -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;
|
|
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":[]}
|
package/dist/codec/index.js
CHANGED
|
@@ -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 {
|
|
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:
|
|
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:
|
|
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?:
|
|
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?:
|
|
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
|
|
466
|
+
* @param message The received message.
|
|
459
467
|
*/
|
|
460
|
-
protected handleMsg(
|
|
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
|
|
489
|
-
protected
|
|
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
|
-
*
|
|
591
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
607
|
+
cancel: () => void;
|
|
601
608
|
/**
|
|
602
|
-
*
|
|
603
|
-
*
|
|
604
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
612
|
-
*
|
|
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
|
-
*
|
|
615
|
-
*
|
|
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
|
-
|
|
623
|
+
signal: AbortSignal;
|
|
624
624
|
};
|
|
625
625
|
|
|
626
|
-
export {
|
|
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:
|
|
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":[]}
|
package/dist/logging/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
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';
|
package/dist/logging/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
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';
|
package/dist/logging/index.js
CHANGED
|
@@ -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:
|
|
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,
|
|
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 };
|