@replit/river 0.207.2 → 0.208.0

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 (65) hide show
  1. package/dist/adapter-ChksXKVN.d.ts +46 -0
  2. package/dist/adapter-Cuc4JtfV.d.cts +46 -0
  3. package/dist/chunk-2JNVDUMN.js +2238 -0
  4. package/dist/chunk-2JNVDUMN.js.map +1 -0
  5. package/dist/{chunk-4HE7UYRL.js → chunk-DKW3GC3M.js} +6 -5
  6. package/dist/{chunk-4HE7UYRL.js.map → chunk-DKW3GC3M.js.map} +1 -1
  7. package/dist/{chunk-46IVOKJU.js → chunk-ETZAHFGQ.js} +80 -61
  8. package/dist/chunk-ETZAHFGQ.js.map +1 -0
  9. package/dist/codec/index.cjs +157 -23
  10. package/dist/codec/index.cjs.map +1 -1
  11. package/dist/codec/index.d.cts +5 -1
  12. package/dist/codec/index.d.ts +5 -1
  13. package/dist/codec/index.js +6 -20
  14. package/dist/codec/index.js.map +1 -1
  15. package/dist/connection-BF4zg6Qv.d.cts +35 -0
  16. package/dist/{connection-a18e31d5.d.ts → connection-Donr3JRB.d.ts} +4 -3
  17. package/dist/index-C9tpZjBN.d.cts +37 -0
  18. package/dist/index-D8IOd3LG.d.ts +37 -0
  19. package/dist/logging/index.d.cts +2 -1
  20. package/dist/logging/index.d.ts +2 -1
  21. package/dist/{message-ffacb98a.d.ts → message-Di94OL80.d.cts} +1 -35
  22. package/dist/message-Di94OL80.d.ts +108 -0
  23. package/dist/router/index.cjs +62 -43
  24. package/dist/router/index.cjs.map +1 -1
  25. package/dist/router/index.d.cts +27 -7
  26. package/dist/router/index.d.ts +27 -7
  27. package/dist/router/index.js +1 -1
  28. package/dist/testUtil/index.cjs +828 -725
  29. package/dist/testUtil/index.cjs.map +1 -1
  30. package/dist/testUtil/index.d.cts +5 -4
  31. package/dist/testUtil/index.d.ts +5 -4
  32. package/dist/testUtil/index.js +23 -25
  33. package/dist/testUtil/index.js.map +1 -1
  34. package/dist/transport/impls/ws/client.cjs +293 -233
  35. package/dist/transport/impls/ws/client.cjs.map +1 -1
  36. package/dist/transport/impls/ws/client.d.cts +6 -5
  37. package/dist/transport/impls/ws/client.d.ts +6 -5
  38. package/dist/transport/impls/ws/client.js +5 -7
  39. package/dist/transport/impls/ws/client.js.map +1 -1
  40. package/dist/transport/impls/ws/server.cjs +269 -200
  41. package/dist/transport/impls/ws/server.cjs.map +1 -1
  42. package/dist/transport/impls/ws/server.d.cts +6 -5
  43. package/dist/transport/impls/ws/server.d.ts +6 -5
  44. package/dist/transport/impls/ws/server.js +5 -7
  45. package/dist/transport/impls/ws/server.js.map +1 -1
  46. package/dist/transport/index.cjs +438 -342
  47. package/dist/transport/index.cjs.map +1 -1
  48. package/dist/transport/index.d.cts +7 -6
  49. package/dist/transport/index.d.ts +7 -6
  50. package/dist/transport/index.js +5 -10
  51. package/dist/transport-CCaWx1Rb.d.cts +1566 -0
  52. package/dist/{services-43528f4b.d.ts → transport-CZb3vdB4.d.ts} +294 -293
  53. package/dist/{wslike-e0b32dd5.d.ts → wslike-Dng9H1C7.d.cts} +1 -1
  54. package/dist/wslike-Dng9H1C7.d.ts +40 -0
  55. package/package.json +3 -3
  56. package/dist/chunk-24EWYOGK.js +0 -1287
  57. package/dist/chunk-24EWYOGK.js.map +0 -1
  58. package/dist/chunk-46IVOKJU.js.map +0 -1
  59. package/dist/chunk-A7RGOVRV.js +0 -438
  60. package/dist/chunk-A7RGOVRV.js.map +0 -1
  61. package/dist/chunk-AJGIY2UB.js +0 -56
  62. package/dist/chunk-AJGIY2UB.js.map +0 -1
  63. package/dist/chunk-XV4RQ62N.js +0 -377
  64. package/dist/chunk-XV4RQ62N.js.map +0 -1
  65. package/dist/types-3e5768ec.d.ts +0 -20
@@ -1,438 +0,0 @@
1
- import {
2
- ClientSessionStateGraph,
3
- ProtocolError,
4
- Transport,
5
- defaultClientTransportOptions
6
- } from "./chunk-24EWYOGK.js";
7
- import {
8
- ControlMessageHandshakeResponseSchema,
9
- HandshakeErrorRetriableResponseCodes,
10
- coerceErrorString,
11
- currentProtocolVersion,
12
- getPropagationContext,
13
- handshakeRequestMessage
14
- } from "./chunk-46IVOKJU.js";
15
-
16
- // transport/client.ts
17
- import { SpanStatusCode } from "@opentelemetry/api";
18
-
19
- // transport/rateLimit.ts
20
- var LeakyBucketRateLimit = class {
21
- budgetConsumed;
22
- intervalHandle;
23
- options;
24
- constructor(options) {
25
- this.options = options;
26
- this.budgetConsumed = 0;
27
- }
28
- getBackoffMs() {
29
- if (this.getBudgetConsumed() === 0) {
30
- return 0;
31
- }
32
- const exponent = Math.max(0, this.getBudgetConsumed() - 1);
33
- const jitter = Math.floor(Math.random() * this.options.maxJitterMs);
34
- const backoffMs = Math.min(
35
- this.options.baseIntervalMs * 2 ** exponent,
36
- this.options.maxBackoffMs
37
- );
38
- return backoffMs + jitter;
39
- }
40
- get totalBudgetRestoreTime() {
41
- return this.options.budgetRestoreIntervalMs * this.options.attemptBudgetCapacity;
42
- }
43
- consumeBudget() {
44
- this.stopLeak();
45
- this.budgetConsumed = this.getBudgetConsumed() + 1;
46
- }
47
- getBudgetConsumed() {
48
- return this.budgetConsumed;
49
- }
50
- hasBudget() {
51
- return this.getBudgetConsumed() < this.options.attemptBudgetCapacity;
52
- }
53
- startRestoringBudget() {
54
- if (this.intervalHandle) {
55
- return;
56
- }
57
- const restoreBudgetForUser = () => {
58
- const currentBudget = this.budgetConsumed;
59
- if (!currentBudget) {
60
- this.stopLeak();
61
- return;
62
- }
63
- const newBudget = currentBudget - 1;
64
- if (newBudget === 0) {
65
- return;
66
- }
67
- this.budgetConsumed = newBudget;
68
- };
69
- this.intervalHandle = setInterval(
70
- restoreBudgetForUser,
71
- this.options.budgetRestoreIntervalMs
72
- );
73
- }
74
- stopLeak() {
75
- if (!this.intervalHandle) {
76
- return;
77
- }
78
- clearInterval(this.intervalHandle);
79
- this.intervalHandle = void 0;
80
- }
81
- close() {
82
- this.stopLeak();
83
- }
84
- };
85
-
86
- // transport/client.ts
87
- import { Value } from "@sinclair/typebox/value";
88
- var ClientTransport = class extends Transport {
89
- /**
90
- * The options for this transport.
91
- */
92
- options;
93
- retryBudget;
94
- /**
95
- * A flag indicating whether the transport should automatically reconnect
96
- * when a connection is dropped.
97
- * Realistically, this should always be true for clients unless you are writing
98
- * tests or a special case where you don't want to reconnect.
99
- */
100
- reconnectOnConnectionDrop = true;
101
- /**
102
- * Optional handshake options for this client.
103
- */
104
- handshakeExtensions;
105
- sessions;
106
- constructor(clientId, providedOptions) {
107
- super(clientId, providedOptions);
108
- this.sessions = /* @__PURE__ */ new Map();
109
- this.options = {
110
- ...defaultClientTransportOptions,
111
- ...providedOptions
112
- };
113
- this.retryBudget = new LeakyBucketRateLimit(this.options);
114
- }
115
- extendHandshake(options) {
116
- this.handshakeExtensions = options;
117
- }
118
- tryReconnecting(to) {
119
- const oldSession = this.sessions.get(to);
120
- if (!this.options.enableTransparentSessionReconnects && oldSession) {
121
- this.deleteSession(oldSession);
122
- }
123
- if (this.reconnectOnConnectionDrop && this.getStatus() === "open") {
124
- this.connect(to);
125
- }
126
- }
127
- /*
128
- * Creates a raw unconnected session object.
129
- * This is mostly a River internal, you shouldn't need to use this directly.
130
- */
131
- createUnconnectedSession(to) {
132
- const session = ClientSessionStateGraph.entrypoint(
133
- to,
134
- this.clientId,
135
- {
136
- onSessionGracePeriodElapsed: () => {
137
- this.onSessionGracePeriodElapsed(session);
138
- }
139
- },
140
- this.options,
141
- currentProtocolVersion,
142
- this.tracer,
143
- this.log
144
- );
145
- this.createSession(session);
146
- return session;
147
- }
148
- // listeners
149
- onConnectingFailed(session) {
150
- const noConnectionSession = super.onConnectingFailed(session);
151
- this.tryReconnecting(noConnectionSession.to);
152
- return noConnectionSession;
153
- }
154
- onConnClosed(session) {
155
- const noConnectionSession = super.onConnClosed(session);
156
- this.tryReconnecting(noConnectionSession.to);
157
- return noConnectionSession;
158
- }
159
- onConnectionEstablished(session, conn) {
160
- const handshakingSession = ClientSessionStateGraph.transition.ConnectingToHandshaking(
161
- session,
162
- conn,
163
- {
164
- onConnectionErrored: (err) => {
165
- const errStr = coerceErrorString(err);
166
- this.log?.error(
167
- `connection to ${handshakingSession.to} errored during handshake: ${errStr}`,
168
- handshakingSession.loggingMetadata
169
- );
170
- },
171
- onConnectionClosed: () => {
172
- this.log?.warn(
173
- `connection to ${handshakingSession.to} closed during handshake`,
174
- handshakingSession.loggingMetadata
175
- );
176
- this.onConnClosed(handshakingSession);
177
- },
178
- onHandshake: (msg) => {
179
- this.onHandshakeResponse(handshakingSession, msg);
180
- },
181
- onInvalidHandshake: (reason, code) => {
182
- this.log?.error(
183
- `invalid handshake: ${reason}`,
184
- handshakingSession.loggingMetadata
185
- );
186
- this.deleteSession(session, { unhealthy: true });
187
- this.protocolError({
188
- type: ProtocolError.HandshakeFailed,
189
- code,
190
- message: reason
191
- });
192
- },
193
- onHandshakeTimeout: () => {
194
- this.log?.error(
195
- `connection to ${handshakingSession.to} timed out during handshake`,
196
- handshakingSession.loggingMetadata
197
- );
198
- this.onConnClosed(handshakingSession);
199
- },
200
- onSessionGracePeriodElapsed: () => {
201
- this.onSessionGracePeriodElapsed(handshakingSession);
202
- }
203
- }
204
- );
205
- this.updateSession(handshakingSession);
206
- void this.sendHandshake(handshakingSession);
207
- return handshakingSession;
208
- }
209
- rejectHandshakeResponse(session, reason, metadata) {
210
- session.conn.telemetry?.span.setStatus({
211
- code: SpanStatusCode.ERROR,
212
- message: reason
213
- });
214
- this.log?.warn(reason, metadata);
215
- this.deleteSession(session, { unhealthy: true });
216
- }
217
- onHandshakeResponse(session, msg) {
218
- if (!Value.Check(ControlMessageHandshakeResponseSchema, msg.payload)) {
219
- const reason = `received invalid handshake response`;
220
- this.rejectHandshakeResponse(session, reason, {
221
- ...session.loggingMetadata,
222
- transportMessage: msg,
223
- validationErrors: [
224
- ...Value.Errors(ControlMessageHandshakeResponseSchema, msg.payload)
225
- ]
226
- });
227
- return;
228
- }
229
- if (!msg.payload.status.ok) {
230
- const retriable = Value.Check(
231
- HandshakeErrorRetriableResponseCodes,
232
- msg.payload.status.code
233
- );
234
- const reason = `handshake failed: ${msg.payload.status.reason}`;
235
- const to = session.to;
236
- this.rejectHandshakeResponse(session, reason, {
237
- ...session.loggingMetadata,
238
- transportMessage: msg
239
- });
240
- if (retriable) {
241
- this.tryReconnecting(to);
242
- } else {
243
- this.protocolError({
244
- type: ProtocolError.HandshakeFailed,
245
- code: msg.payload.status.code,
246
- message: reason
247
- });
248
- }
249
- return;
250
- }
251
- if (msg.payload.status.sessionId !== session.id) {
252
- const reason = `session id mismatch: expected ${session.id}, got ${msg.payload.status.sessionId}`;
253
- this.rejectHandshakeResponse(session, reason, {
254
- ...session.loggingMetadata,
255
- transportMessage: msg
256
- });
257
- return;
258
- }
259
- this.log?.info(`handshake from ${msg.from} ok`, {
260
- ...session.loggingMetadata,
261
- transportMessage: msg
262
- });
263
- const connectedSession = ClientSessionStateGraph.transition.HandshakingToConnected(session, {
264
- onConnectionErrored: (err) => {
265
- const errStr = coerceErrorString(err);
266
- this.log?.warn(
267
- `connection to ${connectedSession.to} errored: ${errStr}`,
268
- connectedSession.loggingMetadata
269
- );
270
- },
271
- onConnectionClosed: () => {
272
- this.log?.info(
273
- `connection to ${connectedSession.to} closed`,
274
- connectedSession.loggingMetadata
275
- );
276
- this.onConnClosed(connectedSession);
277
- },
278
- onMessage: (msg2) => {
279
- this.handleMsg(msg2);
280
- },
281
- onInvalidMessage: (reason) => {
282
- this.deleteSession(connectedSession, { unhealthy: true });
283
- this.protocolError({
284
- type: ProtocolError.InvalidMessage,
285
- message: reason
286
- });
287
- }
288
- });
289
- this.updateSession(connectedSession);
290
- this.retryBudget.startRestoringBudget();
291
- }
292
- /**
293
- * Manually attempts to connect to a client.
294
- * @param to The client ID of the node to connect to.
295
- */
296
- connect(to) {
297
- if (this.getStatus() !== "open") {
298
- this.log?.info(
299
- `transport state is no longer open, cancelling attempt to connect to ${to}`
300
- );
301
- return;
302
- }
303
- const session = this.sessions.get(to) ?? this.createUnconnectedSession(to);
304
- if (session.state !== "NoConnection" /* NoConnection */) {
305
- this.log?.debug(
306
- `session to ${to} has state ${session.state}, skipping connect attempt`,
307
- session.loggingMetadata
308
- );
309
- return;
310
- }
311
- if (!this.retryBudget.hasBudget()) {
312
- const budgetConsumed = this.retryBudget.getBudgetConsumed();
313
- const errMsg = `tried to connect to ${to} but retry budget exceeded (more than ${budgetConsumed} attempts in the last ${this.retryBudget.totalBudgetRestoreTime}ms)`;
314
- this.log?.error(errMsg, session.loggingMetadata);
315
- this.protocolError({
316
- type: ProtocolError.RetriesExceeded,
317
- message: errMsg
318
- });
319
- return;
320
- }
321
- const backoffMs = this.retryBudget.getBackoffMs();
322
- this.log?.info(
323
- `attempting connection to ${to} (${backoffMs}ms backoff)`,
324
- session.loggingMetadata
325
- );
326
- this.retryBudget.consumeBudget();
327
- const backingOffSession = ClientSessionStateGraph.transition.NoConnectionToBackingOff(
328
- session,
329
- backoffMs,
330
- {
331
- onBackoffFinished: () => {
332
- this.onBackoffFinished(backingOffSession);
333
- },
334
- onSessionGracePeriodElapsed: () => {
335
- this.onSessionGracePeriodElapsed(backingOffSession);
336
- }
337
- }
338
- );
339
- this.updateSession(backingOffSession);
340
- }
341
- /**
342
- * Manually kills all sessions to the server (including all pending state).
343
- * This is useful for when you want to close all connections to a server
344
- * and don't want to wait for the grace period to elapse.
345
- */
346
- hardDisconnect() {
347
- const sessions = Array.from(this.sessions.values());
348
- for (const session of sessions) {
349
- this.deleteSession(session);
350
- }
351
- }
352
- onBackoffFinished(session) {
353
- const connPromise = session.tracer.startActiveSpan(
354
- "connect",
355
- async (span) => {
356
- try {
357
- return await this.createNewOutgoingConnection(session.to);
358
- } catch (err) {
359
- const errStr = coerceErrorString(err);
360
- span.recordException(errStr);
361
- span.setStatus({ code: SpanStatusCode.ERROR });
362
- throw err;
363
- } finally {
364
- span.end();
365
- }
366
- }
367
- );
368
- const connectingSession = ClientSessionStateGraph.transition.BackingOffToConnecting(
369
- session,
370
- connPromise,
371
- {
372
- onConnectionEstablished: (conn) => {
373
- this.log?.debug(
374
- `connection to ${connectingSession.to} established`,
375
- {
376
- ...conn.loggingMetadata,
377
- ...connectingSession.loggingMetadata
378
- }
379
- );
380
- this.onConnectionEstablished(connectingSession, conn);
381
- },
382
- onConnectionFailed: (error) => {
383
- const errStr = coerceErrorString(error);
384
- this.log?.error(
385
- `error connecting to ${connectingSession.to}: ${errStr}`,
386
- connectingSession.loggingMetadata
387
- );
388
- this.onConnectingFailed(connectingSession);
389
- },
390
- onConnectionTimeout: () => {
391
- this.log?.error(
392
- `connection to ${connectingSession.to} timed out`,
393
- connectingSession.loggingMetadata
394
- );
395
- this.onConnectingFailed(connectingSession);
396
- },
397
- onSessionGracePeriodElapsed: () => {
398
- this.onSessionGracePeriodElapsed(connectingSession);
399
- }
400
- }
401
- );
402
- this.updateSession(connectingSession);
403
- }
404
- async sendHandshake(session) {
405
- let metadata = void 0;
406
- if (this.handshakeExtensions) {
407
- metadata = await this.handshakeExtensions.construct();
408
- }
409
- if (session._isConsumed) {
410
- return;
411
- }
412
- const requestMsg = handshakeRequestMessage({
413
- from: this.clientId,
414
- to: session.to,
415
- sessionId: session.id,
416
- expectedSessionState: {
417
- nextExpectedSeq: session.ack,
418
- nextSentSeq: session.nextSeq()
419
- },
420
- metadata,
421
- tracing: getPropagationContext(session.telemetry.ctx)
422
- });
423
- this.log?.debug(`sending handshake request to ${session.to}`, {
424
- ...session.loggingMetadata,
425
- transportMessage: requestMsg
426
- });
427
- session.sendHandshake(requestMsg);
428
- }
429
- close() {
430
- this.retryBudget.close();
431
- super.close();
432
- }
433
- };
434
-
435
- export {
436
- ClientTransport
437
- };
438
- //# sourceMappingURL=chunk-A7RGOVRV.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../transport/client.ts","../transport/rateLimit.ts"],"sourcesContent":["import { SpanStatusCode } from '@opentelemetry/api';\nimport { ClientHandshakeOptions } from '../router/handshake';\nimport {\n ControlMessageHandshakeResponseSchema,\n HandshakeErrorRetriableResponseCodes,\n OpaqueTransportMessage,\n TransportClientId,\n currentProtocolVersion,\n handshakeRequestMessage,\n} from './message';\nimport {\n ClientTransportOptions,\n ProvidedClientTransportOptions,\n defaultClientTransportOptions,\n} from './options';\nimport { LeakyBucketRateLimit } from './rateLimit';\nimport { Transport } from './transport';\nimport { coerceErrorString } from './stringifyError';\nimport { ProtocolError } from './events';\nimport { Value } from '@sinclair/typebox/value';\nimport { getPropagationContext } from '../tracing';\nimport { Connection } from './connection';\nimport { MessageMetadata } from '../logging';\nimport { SessionConnecting } from './sessionStateMachine/SessionConnecting';\nimport { SessionHandshaking } from './sessionStateMachine/SessionHandshaking';\nimport { SessionConnected } from './sessionStateMachine/SessionConnected';\nimport {\n ClientSession,\n ClientSessionStateGraph,\n} from './sessionStateMachine/transitions';\nimport { SessionState } from './sessionStateMachine/common';\nimport { SessionNoConnection } from './sessionStateMachine/SessionNoConnection';\nimport { SessionBackingOff } from './sessionStateMachine/SessionBackingOff';\n\nexport abstract class ClientTransport<\n ConnType extends Connection,\n> extends Transport<ConnType> {\n /**\n * The options for this transport.\n */\n protected options: ClientTransportOptions;\n\n retryBudget: LeakyBucketRateLimit;\n\n /**\n * A flag indicating whether the transport should automatically reconnect\n * when a connection is dropped.\n * Realistically, this should always be true for clients unless you are writing\n * tests or a special case where you don't want to reconnect.\n */\n reconnectOnConnectionDrop = true;\n\n /**\n * Optional handshake options for this client.\n */\n handshakeExtensions?: ClientHandshakeOptions;\n\n sessions: Map<TransportClientId, ClientSession<ConnType>>;\n\n constructor(\n clientId: TransportClientId,\n providedOptions?: ProvidedClientTransportOptions,\n ) {\n super(clientId, providedOptions);\n this.sessions = new Map();\n this.options = {\n ...defaultClientTransportOptions,\n ...providedOptions,\n };\n this.retryBudget = new LeakyBucketRateLimit(this.options);\n }\n\n extendHandshake(options: ClientHandshakeOptions) {\n this.handshakeExtensions = options;\n }\n\n /**\n * Abstract method that creates a new {@link Connection} object.\n *\n * @param to The client ID of the node to connect to.\n * @returns The new connection object.\n */\n protected abstract createNewOutgoingConnection(\n to: TransportClientId,\n ): Promise<ConnType>;\n\n private tryReconnecting(to: TransportClientId) {\n const oldSession = this.sessions.get(to);\n if (!this.options.enableTransparentSessionReconnects && oldSession) {\n this.deleteSession(oldSession);\n }\n\n if (this.reconnectOnConnectionDrop && this.getStatus() === 'open') {\n this.connect(to);\n }\n }\n\n /*\n * Creates a raw unconnected session object.\n * This is mostly a River internal, you shouldn't need to use this directly.\n */\n createUnconnectedSession(to: string): SessionNoConnection {\n const session = ClientSessionStateGraph.entrypoint(\n to,\n this.clientId,\n {\n onSessionGracePeriodElapsed: () => {\n this.onSessionGracePeriodElapsed(session);\n },\n },\n this.options,\n currentProtocolVersion,\n this.tracer,\n this.log,\n );\n\n this.createSession(session);\n\n return session;\n }\n\n // listeners\n protected onConnectingFailed(session: SessionConnecting<ConnType>) {\n const noConnectionSession = super.onConnectingFailed(session);\n this.tryReconnecting(noConnectionSession.to);\n\n return noConnectionSession;\n }\n\n protected onConnClosed(\n session: SessionHandshaking<ConnType> | SessionConnected<ConnType>,\n ) {\n const noConnectionSession = super.onConnClosed(session);\n this.tryReconnecting(noConnectionSession.to);\n\n return noConnectionSession;\n }\n\n protected onConnectionEstablished(\n session: SessionConnecting<ConnType>,\n conn: ConnType,\n ): SessionHandshaking<ConnType> {\n // transition to handshaking\n const handshakingSession =\n ClientSessionStateGraph.transition.ConnectingToHandshaking(\n session,\n conn,\n {\n onConnectionErrored: (err) => {\n // just log, when we error we also emit close\n const errStr = coerceErrorString(err);\n this.log?.error(\n `connection to ${handshakingSession.to} errored during handshake: ${errStr}`,\n handshakingSession.loggingMetadata,\n );\n },\n onConnectionClosed: () => {\n this.log?.warn(\n `connection to ${handshakingSession.to} closed during handshake`,\n handshakingSession.loggingMetadata,\n );\n this.onConnClosed(handshakingSession);\n },\n onHandshake: (msg) => {\n this.onHandshakeResponse(handshakingSession, msg);\n },\n onInvalidHandshake: (reason, code) => {\n this.log?.error(\n `invalid handshake: ${reason}`,\n handshakingSession.loggingMetadata,\n );\n this.deleteSession(session, { unhealthy: true });\n this.protocolError({\n type: ProtocolError.HandshakeFailed,\n code,\n message: reason,\n });\n },\n onHandshakeTimeout: () => {\n this.log?.error(\n `connection to ${handshakingSession.to} timed out during handshake`,\n handshakingSession.loggingMetadata,\n );\n this.onConnClosed(handshakingSession);\n },\n onSessionGracePeriodElapsed: () => {\n this.onSessionGracePeriodElapsed(handshakingSession);\n },\n },\n );\n\n this.updateSession(handshakingSession);\n void this.sendHandshake(handshakingSession);\n\n return handshakingSession;\n }\n\n private rejectHandshakeResponse(\n session: SessionHandshaking<ConnType>,\n reason: string,\n metadata: MessageMetadata,\n ) {\n session.conn.telemetry?.span.setStatus({\n code: SpanStatusCode.ERROR,\n message: reason,\n });\n\n this.log?.warn(reason, metadata);\n this.deleteSession(session, { unhealthy: true });\n }\n\n protected onHandshakeResponse(\n session: SessionHandshaking<ConnType>,\n msg: OpaqueTransportMessage,\n ) {\n // invariant: msg is a handshake response\n if (!Value.Check(ControlMessageHandshakeResponseSchema, msg.payload)) {\n const reason = `received invalid handshake response`;\n this.rejectHandshakeResponse(session, reason, {\n ...session.loggingMetadata,\n transportMessage: msg,\n validationErrors: [\n ...Value.Errors(ControlMessageHandshakeResponseSchema, msg.payload),\n ],\n });\n\n return;\n }\n\n // invariant: handshake response should be ok\n if (!msg.payload.status.ok) {\n const retriable = Value.Check(\n HandshakeErrorRetriableResponseCodes,\n msg.payload.status.code,\n );\n\n const reason = `handshake failed: ${msg.payload.status.reason}`;\n const to = session.to;\n this.rejectHandshakeResponse(session, reason, {\n ...session.loggingMetadata,\n transportMessage: msg,\n });\n\n if (retriable) {\n this.tryReconnecting(to);\n } else {\n this.protocolError({\n type: ProtocolError.HandshakeFailed,\n code: msg.payload.status.code,\n message: reason,\n });\n }\n\n return;\n }\n\n // invariant: session id should match between client + server\n if (msg.payload.status.sessionId !== session.id) {\n const reason = `session id mismatch: expected ${session.id}, got ${msg.payload.status.sessionId}`;\n this.rejectHandshakeResponse(session, reason, {\n ...session.loggingMetadata,\n transportMessage: msg,\n });\n\n return;\n }\n\n // transition to connected!\n this.log?.info(`handshake from ${msg.from} ok`, {\n ...session.loggingMetadata,\n transportMessage: msg,\n });\n\n const connectedSession =\n ClientSessionStateGraph.transition.HandshakingToConnected(session, {\n onConnectionErrored: (err) => {\n // just log, when we error we also emit close\n const errStr = coerceErrorString(err);\n this.log?.warn(\n `connection to ${connectedSession.to} errored: ${errStr}`,\n connectedSession.loggingMetadata,\n );\n },\n onConnectionClosed: () => {\n this.log?.info(\n `connection to ${connectedSession.to} closed`,\n connectedSession.loggingMetadata,\n );\n this.onConnClosed(connectedSession);\n },\n onMessage: (msg) => {\n this.handleMsg(msg);\n },\n onInvalidMessage: (reason) => {\n this.deleteSession(connectedSession, { unhealthy: true });\n this.protocolError({\n type: ProtocolError.InvalidMessage,\n message: reason,\n });\n },\n });\n\n this.updateSession(connectedSession);\n this.retryBudget.startRestoringBudget();\n }\n\n /**\n * Manually attempts to connect to a client.\n * @param to The client ID of the node to connect to.\n */\n connect(to: TransportClientId) {\n if (this.getStatus() !== 'open') {\n this.log?.info(\n `transport state is no longer open, cancelling attempt to connect to ${to}`,\n );\n\n return;\n }\n\n const session = this.sessions.get(to) ?? this.createUnconnectedSession(to);\n if (session.state !== SessionState.NoConnection) {\n // already trying to connect\n this.log?.debug(\n `session to ${to} has state ${session.state}, skipping connect attempt`,\n session.loggingMetadata,\n );\n\n return;\n }\n\n // check budget\n if (!this.retryBudget.hasBudget()) {\n const budgetConsumed = this.retryBudget.getBudgetConsumed();\n const errMsg = `tried to connect to ${to} but retry budget exceeded (more than ${budgetConsumed} attempts in the last ${this.retryBudget.totalBudgetRestoreTime}ms)`;\n this.log?.error(errMsg, session.loggingMetadata);\n this.protocolError({\n type: ProtocolError.RetriesExceeded,\n message: errMsg,\n });\n\n return;\n }\n\n const backoffMs = this.retryBudget.getBackoffMs();\n\n this.log?.info(\n `attempting connection to ${to} (${backoffMs}ms backoff)`,\n session.loggingMetadata,\n );\n\n this.retryBudget.consumeBudget();\n const backingOffSession =\n ClientSessionStateGraph.transition.NoConnectionToBackingOff(\n session,\n backoffMs,\n {\n onBackoffFinished: () => {\n this.onBackoffFinished(backingOffSession);\n },\n onSessionGracePeriodElapsed: () => {\n this.onSessionGracePeriodElapsed(backingOffSession);\n },\n },\n );\n\n this.updateSession(backingOffSession);\n }\n\n /**\n * Manually kills all sessions to the server (including all pending state).\n * This is useful for when you want to close all connections to a server\n * and don't want to wait for the grace period to elapse.\n */\n hardDisconnect() {\n // create a copy of the sessions to avoid modifying the map while iterating\n const sessions = Array.from(this.sessions.values());\n for (const session of sessions) {\n this.deleteSession(session);\n }\n }\n\n protected onBackoffFinished(session: SessionBackingOff) {\n const connPromise = session.tracer.startActiveSpan(\n 'connect',\n async (span) => {\n try {\n return await this.createNewOutgoingConnection(session.to);\n } catch (err) {\n // rethrow the error so that the promise is rejected\n // as it was before we wrapped it in a span\n const errStr = coerceErrorString(err);\n span.recordException(errStr);\n span.setStatus({ code: SpanStatusCode.ERROR });\n throw err;\n } finally {\n span.end();\n }\n },\n );\n\n // transition to connecting\n const connectingSession =\n ClientSessionStateGraph.transition.BackingOffToConnecting(\n session,\n connPromise,\n {\n onConnectionEstablished: (conn) => {\n this.log?.debug(\n `connection to ${connectingSession.to} established`,\n {\n ...conn.loggingMetadata,\n ...connectingSession.loggingMetadata,\n },\n );\n\n // cast here because conn can't be narrowed to ConnType\n // in the callback due to variance rules\n this.onConnectionEstablished(connectingSession, conn as ConnType);\n },\n onConnectionFailed: (error: unknown) => {\n const errStr = coerceErrorString(error);\n this.log?.error(\n `error connecting to ${connectingSession.to}: ${errStr}`,\n connectingSession.loggingMetadata,\n );\n this.onConnectingFailed(connectingSession);\n },\n onConnectionTimeout: () => {\n this.log?.error(\n `connection to ${connectingSession.to} timed out`,\n connectingSession.loggingMetadata,\n );\n this.onConnectingFailed(connectingSession);\n },\n onSessionGracePeriodElapsed: () => {\n this.onSessionGracePeriodElapsed(connectingSession);\n },\n },\n );\n\n this.updateSession(connectingSession);\n }\n\n private async sendHandshake(session: SessionHandshaking<ConnType>) {\n let metadata: unknown = undefined;\n\n if (this.handshakeExtensions) {\n metadata = await this.handshakeExtensions.construct();\n }\n\n // double-check to make sure we haven't transitioned the session yet\n if (session._isConsumed) {\n // bail out, don't need to do anything\n return;\n }\n\n const requestMsg = handshakeRequestMessage({\n from: this.clientId,\n to: session.to,\n sessionId: session.id,\n expectedSessionState: {\n nextExpectedSeq: session.ack,\n nextSentSeq: session.nextSeq(),\n },\n metadata,\n tracing: getPropagationContext(session.telemetry.ctx),\n });\n\n this.log?.debug(`sending handshake request to ${session.to}`, {\n ...session.loggingMetadata,\n transportMessage: requestMsg,\n });\n\n session.sendHandshake(requestMsg);\n }\n\n close() {\n this.retryBudget.close();\n super.close();\n }\n}\n","/**\n * Options to control the backoff and retry behavior of the client transport's connection behaviour.\n *\n * River implements exponential backoff with jitter to prevent flooding the server\n * when there's an issue with connection establishment.\n *\n * The backoff is calculated via the following:\n * backOff = min(jitter + {@link baseIntervalMs} * 2 ^ budget_consumed, {@link maxBackoffMs})\n *\n * We use a leaky bucket rate limit with a budget of {@link attemptBudgetCapacity} reconnection attempts.\n * Budget only starts to restore after a successful handshake at a rate of one budget per {@link budgetRestoreIntervalMs}.\n */\nexport interface ConnectionRetryOptions {\n /**\n * The base interval to wait before retrying a connection.\n */\n baseIntervalMs: number;\n\n /**\n * The maximum random jitter to add to the total backoff time.\n */\n maxJitterMs: number;\n\n /**\n * The maximum amount of time to wait before retrying a connection.\n * This does not include the jitter.\n */\n maxBackoffMs: number;\n\n /**\n * The max number of times to attempt a connection before a successful handshake.\n * This persists across connections but starts restoring budget after a successful handshake.\n * The restoration interval depends on {@link budgetRestoreIntervalMs}\n */\n attemptBudgetCapacity: number;\n\n /**\n * After a successful connection attempt, how long to wait before we restore a single budget.\n */\n budgetRestoreIntervalMs: number;\n}\n\nexport class LeakyBucketRateLimit {\n private budgetConsumed: number;\n private intervalHandle?: ReturnType<typeof setInterval>;\n private readonly options: ConnectionRetryOptions;\n\n constructor(options: ConnectionRetryOptions) {\n this.options = options;\n this.budgetConsumed = 0;\n }\n\n getBackoffMs() {\n if (this.getBudgetConsumed() === 0) {\n return 0;\n }\n\n const exponent = Math.max(0, this.getBudgetConsumed() - 1);\n const jitter = Math.floor(Math.random() * this.options.maxJitterMs);\n const backoffMs = Math.min(\n this.options.baseIntervalMs * 2 ** exponent,\n this.options.maxBackoffMs,\n );\n\n return backoffMs + jitter;\n }\n\n get totalBudgetRestoreTime() {\n return (\n this.options.budgetRestoreIntervalMs * this.options.attemptBudgetCapacity\n );\n }\n\n consumeBudget() {\n // If we're consuming again, let's ensure that we're not leaking\n this.stopLeak();\n this.budgetConsumed = this.getBudgetConsumed() + 1;\n }\n\n getBudgetConsumed() {\n return this.budgetConsumed;\n }\n\n hasBudget() {\n return this.getBudgetConsumed() < this.options.attemptBudgetCapacity;\n }\n\n startRestoringBudget() {\n if (this.intervalHandle) {\n return;\n }\n\n const restoreBudgetForUser = () => {\n const currentBudget = this.budgetConsumed;\n if (!currentBudget) {\n this.stopLeak();\n\n return;\n }\n\n const newBudget = currentBudget - 1;\n if (newBudget === 0) {\n return;\n }\n\n this.budgetConsumed = newBudget;\n };\n\n this.intervalHandle = setInterval(\n restoreBudgetForUser,\n this.options.budgetRestoreIntervalMs,\n );\n }\n\n private stopLeak() {\n if (!this.intervalHandle) {\n return;\n }\n\n clearInterval(this.intervalHandle);\n this.intervalHandle = undefined;\n }\n\n close() {\n this.stopLeak();\n }\n}\n"],"mappings":"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","names":["msg"]}
@@ -1,56 +0,0 @@
1
- // codec/json.ts
2
- var encoder = new TextEncoder();
3
- var decoder = new TextDecoder();
4
- function uint8ArrayToBase64(uint8Array) {
5
- let binary = "";
6
- uint8Array.forEach((byte) => {
7
- binary += String.fromCharCode(byte);
8
- });
9
- return btoa(binary);
10
- }
11
- function base64ToUint8Array(base64) {
12
- const binaryString = atob(base64);
13
- const uint8Array = new Uint8Array(binaryString.length);
14
- for (let i = 0; i < binaryString.length; i++) {
15
- uint8Array[i] = binaryString.charCodeAt(i);
16
- }
17
- return uint8Array;
18
- }
19
- var NaiveJsonCodec = {
20
- toBuffer: (obj) => {
21
- return encoder.encode(
22
- JSON.stringify(obj, function replacer(key) {
23
- const val = this[key];
24
- if (val instanceof Uint8Array) {
25
- return { $t: uint8ArrayToBase64(val) };
26
- } else {
27
- return val;
28
- }
29
- })
30
- );
31
- },
32
- fromBuffer: (buff) => {
33
- try {
34
- const parsed = JSON.parse(
35
- decoder.decode(buff),
36
- function reviver(_key, val) {
37
- if (val?.$t) {
38
- return base64ToUint8Array(val.$t);
39
- } else {
40
- return val;
41
- }
42
- }
43
- );
44
- if (typeof parsed === "object")
45
- return parsed;
46
- return null;
47
- } catch {
48
- return null;
49
- }
50
- }
51
- };
52
-
53
- export {
54
- NaiveJsonCodec
55
- };
56
- //# sourceMappingURL=chunk-AJGIY2UB.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../codec/json.ts"],"sourcesContent":["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":";AAEA,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":[]}