@replit/river 0.200.0-rc.9 → 0.200.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +8 -8
  2. package/dist/{chunk-42Z2FQIU.js → chunk-6BH2CXVE.js} +21 -13
  3. package/dist/chunk-6BH2CXVE.js.map +1 -0
  4. package/dist/{chunk-4HT6P2ZG.js → chunk-A4JKES5A.js} +22 -30
  5. package/dist/chunk-A4JKES5A.js.map +1 -0
  6. package/dist/{chunk-4PVU7J25.js → chunk-AJGIY2UB.js} +1 -1
  7. package/dist/chunk-AJGIY2UB.js.map +1 -0
  8. package/dist/{chunk-EETL2L77.js → chunk-GJUUVID2.js} +14 -32
  9. package/dist/chunk-GJUUVID2.js.map +1 -0
  10. package/dist/{chunk-GR3AQKHL.js → chunk-HRKM7BIE.js} +14 -4
  11. package/dist/chunk-HRKM7BIE.js.map +1 -0
  12. package/dist/{chunk-ZXZE253M.js → chunk-PJB2Y2AV.js} +24 -37
  13. package/dist/chunk-PJB2Y2AV.js.map +1 -0
  14. package/dist/{chunk-I75XYO5W.js → chunk-QIDEN5PP.js} +82 -20
  15. package/dist/chunk-QIDEN5PP.js.map +1 -0
  16. package/dist/{chunk-VXYHC666.js → chunk-YTMS7OP6.js} +1 -1
  17. package/dist/chunk-YTMS7OP6.js.map +1 -0
  18. package/dist/chunk-Z4PX66JO.js +307 -0
  19. package/dist/chunk-Z4PX66JO.js.map +1 -0
  20. package/dist/{client-22a47343.d.ts → client-9292552a.d.ts} +3 -4
  21. package/dist/codec/index.cjs.map +1 -1
  22. package/dist/codec/index.js +1 -1
  23. package/dist/connection-94dea547.d.ts +32 -0
  24. package/dist/{context-b4aff18f.d.ts → context-69f37ac1.d.ts} +48 -43
  25. package/dist/logging/index.cjs.map +1 -1
  26. package/dist/logging/index.d.cts +1 -1
  27. package/dist/logging/index.d.ts +1 -1
  28. package/dist/logging/index.js +1 -1
  29. package/dist/{message-7d135e38.d.ts → message-57bb8187.d.ts} +5 -3
  30. package/dist/router/index.cjs +649 -709
  31. package/dist/router/index.cjs.map +1 -1
  32. package/dist/router/index.d.cts +22 -12
  33. package/dist/router/index.d.ts +22 -12
  34. package/dist/router/index.js +502 -404
  35. package/dist/router/index.js.map +1 -1
  36. package/dist/{server-dd6a9853.d.ts → server-8fdd7fb2.d.ts} +5 -5
  37. package/dist/{services-1b5ac5bc.d.ts → services-259f39a3.d.ts} +191 -194
  38. package/dist/transport/impls/ws/client.cjs +129 -62
  39. package/dist/transport/impls/ws/client.cjs.map +1 -1
  40. package/dist/transport/impls/ws/client.d.cts +4 -4
  41. package/dist/transport/impls/ws/client.d.ts +4 -4
  42. package/dist/transport/impls/ws/client.js +7 -7
  43. package/dist/transport/impls/ws/client.js.map +1 -1
  44. package/dist/transport/impls/ws/server.cjs +146 -70
  45. package/dist/transport/impls/ws/server.cjs.map +1 -1
  46. package/dist/transport/impls/ws/server.d.cts +6 -5
  47. package/dist/transport/impls/ws/server.d.ts +6 -5
  48. package/dist/transport/impls/ws/server.js +21 -9
  49. package/dist/transport/impls/ws/server.js.map +1 -1
  50. package/dist/transport/index.cjs +138 -92
  51. package/dist/transport/index.cjs.map +1 -1
  52. package/dist/transport/index.d.cts +4 -4
  53. package/dist/transport/index.d.ts +4 -4
  54. package/dist/transport/index.js +7 -7
  55. package/dist/util/testHelpers.cjs +265 -327
  56. package/dist/util/testHelpers.cjs.map +1 -1
  57. package/dist/util/testHelpers.d.cts +36 -31
  58. package/dist/util/testHelpers.d.ts +36 -31
  59. package/dist/util/testHelpers.js +82 -52
  60. package/dist/util/testHelpers.js.map +1 -1
  61. package/package.json +4 -3
  62. package/dist/chunk-42Z2FQIU.js.map +0 -1
  63. package/dist/chunk-4HT6P2ZG.js.map +0 -1
  64. package/dist/chunk-4PVU7J25.js.map +0 -1
  65. package/dist/chunk-EETL2L77.js.map +0 -1
  66. package/dist/chunk-GR3AQKHL.js.map +0 -1
  67. package/dist/chunk-I75XYO5W.js.map +0 -1
  68. package/dist/chunk-MQ6ANR3H.js +0 -451
  69. package/dist/chunk-MQ6ANR3H.js.map +0 -1
  70. package/dist/chunk-VXYHC666.js.map +0 -1
  71. package/dist/chunk-ZXZE253M.js.map +0 -1
  72. package/dist/connection-260e45a8.d.ts +0 -11
@@ -20,15 +20,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // router/index.ts
21
21
  var router_exports = {};
22
22
  __export(router_exports, {
23
- ABORT_CODE: () => ABORT_CODE,
23
+ CANCEL_CODE: () => CANCEL_CODE,
24
24
  Err: () => Err,
25
- INTERNAL_RIVER_ERROR_CODE: () => INTERNAL_RIVER_ERROR_CODE,
26
25
  INVALID_REQUEST_CODE: () => INVALID_REQUEST_CODE,
27
26
  Ok: () => Ok,
28
27
  Procedure: () => Procedure,
29
28
  RIVER_VERSION: () => version,
30
- RequestReaderErrorSchema: () => RequestReaderErrorSchema,
31
- ResponseReaderErrorSchema: () => ResponseReaderErrorSchema,
29
+ ReaderErrorSchema: () => ReaderErrorSchema,
32
30
  ServiceSchema: () => ServiceSchema,
33
31
  UNCAUGHT_ERROR_CODE: () => UNCAUGHT_ERROR_CODE,
34
32
  UNEXPECTED_DISCONNECT_CODE: () => UNEXPECTED_DISCONNECT_CODE,
@@ -36,12 +34,79 @@ __export(router_exports, {
36
34
  createClientHandshakeOptions: () => createClientHandshakeOptions,
37
35
  createServer: () => createServer,
38
36
  createServerHandshakeOptions: () => createServerHandshakeOptions,
39
- serializeSchema: () => serializeSchema
37
+ flattenErrorType: () => flattenErrorType,
38
+ serializeSchema: () => serializeSchema,
39
+ serializeSchemaV1Compat: () => serializeSchemaV1Compat,
40
+ unwrapOrThrow: () => unwrapOrThrow
40
41
  });
41
42
  module.exports = __toCommonJS(router_exports);
42
43
 
43
44
  // router/services.ts
45
+ var import_typebox2 = require("@sinclair/typebox");
46
+
47
+ // router/errors.ts
44
48
  var import_typebox = require("@sinclair/typebox");
49
+ var UNCAUGHT_ERROR_CODE = "UNCAUGHT_ERROR";
50
+ var UNEXPECTED_DISCONNECT_CODE = "UNEXPECTED_DISCONNECT";
51
+ var INVALID_REQUEST_CODE = "INVALID_REQUEST";
52
+ var CANCEL_CODE = "CANCEL";
53
+ var ErrResultSchema = (t) => import_typebox.Type.Object({
54
+ ok: import_typebox.Type.Literal(false),
55
+ payload: t
56
+ });
57
+ var ReaderErrorSchema = import_typebox.Type.Union([
58
+ import_typebox.Type.Object({
59
+ code: import_typebox.Type.Literal(UNCAUGHT_ERROR_CODE),
60
+ message: import_typebox.Type.String()
61
+ }),
62
+ import_typebox.Type.Object({
63
+ code: import_typebox.Type.Literal(UNEXPECTED_DISCONNECT_CODE),
64
+ message: import_typebox.Type.String()
65
+ }),
66
+ import_typebox.Type.Object({
67
+ code: import_typebox.Type.Literal(INVALID_REQUEST_CODE),
68
+ message: import_typebox.Type.String()
69
+ }),
70
+ import_typebox.Type.Object({
71
+ code: import_typebox.Type.Literal(CANCEL_CODE),
72
+ message: import_typebox.Type.String()
73
+ })
74
+ ]);
75
+ function isUnion(schema) {
76
+ return schema[import_typebox.Kind] === "Union";
77
+ }
78
+ function flattenErrorType(errType) {
79
+ if (!isUnion(errType)) {
80
+ return errType;
81
+ }
82
+ const flattenedTypes = [];
83
+ function flatten(type) {
84
+ if (isUnion(type)) {
85
+ for (const t of type.anyOf) {
86
+ flatten(t);
87
+ }
88
+ } else {
89
+ flattenedTypes.push(type);
90
+ }
91
+ }
92
+ flatten(errType);
93
+ return import_typebox.Type.Union(flattenedTypes);
94
+ }
95
+
96
+ // router/services.ts
97
+ function serializeSchemaV1Compat(services, handshakeSchema) {
98
+ const serializedServiceObject = Object.entries(services).reduce((acc, [name, value]) => {
99
+ acc[name] = value.serializeV1Compat();
100
+ return acc;
101
+ }, {});
102
+ const schema = {
103
+ services: serializedServiceObject
104
+ };
105
+ if (handshakeSchema) {
106
+ schema.handshakeSchema = import_typebox2.Type.Strict(handshakeSchema);
107
+ }
108
+ return schema;
109
+ }
45
110
  function serializeSchema(services, handshakeSchema) {
46
111
  const serializedServiceObject = Object.entries(services).reduce((acc, [name, value]) => {
47
112
  acc[name] = value.serialize();
@@ -51,7 +116,7 @@ function serializeSchema(services, handshakeSchema) {
51
116
  services: serializedServiceObject
52
117
  };
53
118
  if (handshakeSchema) {
54
- schema.handshakeSchema = import_typebox.Type.Strict(handshakeSchema);
119
+ schema.handshakeSchema = import_typebox2.Type.Strict(handshakeSchema);
55
120
  }
56
121
  return schema;
57
122
  }
@@ -154,18 +219,15 @@ var ServiceSchema = class _ServiceSchema {
154
219
  Object.entries(this.procedures).map(([procName, procDef]) => [
155
220
  procName,
156
221
  {
157
- init: import_typebox.Type.Strict(procDef.requestInit),
158
- output: import_typebox.Type.Strict(procDef.responseData),
222
+ init: import_typebox2.Type.Strict(procDef.requestInit),
223
+ output: import_typebox2.Type.Strict(procDef.responseData),
224
+ errors: getSerializedProcErrors(procDef),
159
225
  // Only add `description` field if the type declares it.
160
226
  ..."description" in procDef ? { description: procDef.description } : {},
161
- // Only add the `errors` field if the type declares it.
162
- ..."responseError" in procDef ? {
163
- errors: import_typebox.Type.Strict(procDef.responseError)
164
- } : {},
165
227
  type: procDef.type,
166
228
  // Only add the `input` field if the type declares it.
167
229
  ..."requestData" in procDef ? {
168
- input: import_typebox.Type.Strict(procDef.requestData)
230
+ input: import_typebox2.Type.Strict(procDef.requestData)
169
231
  } : {}
170
232
  }
171
233
  ])
@@ -178,7 +240,7 @@ var ServiceSchema = class _ServiceSchema {
178
240
  * protocol v1. This is useful to be able to continue to generate schemas for older
179
241
  * clients as they are still supported.
180
242
  */
181
- serializeBackwardsCompatible() {
243
+ serializeV1Compat() {
182
244
  return {
183
245
  procedures: Object.fromEntries(
184
246
  Object.entries(this.procedures).map(
@@ -189,14 +251,11 @@ var ServiceSchema = class _ServiceSchema {
189
251
  {
190
252
  // BACKWARDS COMPAT: map init to input for protocolv1
191
253
  // this is the only change needed to make it compatible.
192
- input: import_typebox.Type.Strict(procDef.requestInit),
193
- output: import_typebox.Type.Strict(procDef.responseData),
254
+ input: import_typebox2.Type.Strict(procDef.requestInit),
255
+ output: import_typebox2.Type.Strict(procDef.responseData),
256
+ errors: getSerializedProcErrors(procDef),
194
257
  // Only add `description` field if the type declares it.
195
258
  ..."description" in procDef ? { description: procDef.description } : {},
196
- // Only add the `errors` field if the type declares it.
197
- ..."responseError" in procDef ? {
198
- errors: import_typebox.Type.Strict(procDef.responseError)
199
- } : {},
200
259
  type: procDef.type
201
260
  }
202
261
  ];
@@ -204,16 +263,13 @@ var ServiceSchema = class _ServiceSchema {
204
263
  return [
205
264
  procName,
206
265
  {
207
- init: import_typebox.Type.Strict(procDef.requestInit),
208
- output: import_typebox.Type.Strict(procDef.responseData),
266
+ init: import_typebox2.Type.Strict(procDef.requestInit),
267
+ output: import_typebox2.Type.Strict(procDef.responseData),
268
+ errors: getSerializedProcErrors(procDef),
209
269
  // Only add `description` field if the type declares it.
210
270
  ..."description" in procDef ? { description: procDef.description } : {},
211
- // Only add the `errors` field if the type declares it.
212
- ..."responseError" in procDef ? {
213
- errors: import_typebox.Type.Strict(procDef.responseError)
214
- } : {},
215
271
  type: procDef.type,
216
- input: import_typebox.Type.Strict(procDef.requestData)
272
+ input: import_typebox2.Type.Strict(procDef.requestData)
217
273
  }
218
274
  ];
219
275
  }
@@ -234,6 +290,15 @@ var ServiceSchema = class _ServiceSchema {
234
290
  });
235
291
  }
236
292
  };
293
+ function getSerializedProcErrors(procDef) {
294
+ if (!("responseError" in procDef) || procDef.responseError[import_typebox2.Kind] === "Never") {
295
+ return import_typebox2.Type.Strict(ReaderErrorSchema);
296
+ }
297
+ const withProtocolErrors = flattenErrorType(
298
+ import_typebox2.Type.Union([procDef.responseError, ReaderErrorSchema])
299
+ );
300
+ return import_typebox2.Type.Strict(withProtocolErrors);
301
+ }
237
302
  var ServiceScaffold = class {
238
303
  /**
239
304
  * The configuration for this service.
@@ -292,35 +357,11 @@ var ServiceScaffold = class {
292
357
  };
293
358
 
294
359
  // router/procedures.ts
295
- var import_typebox2 = require("@sinclair/typebox");
296
- var INTERNAL_RIVER_ERROR_CODE = "INTERNAL_RIVER_ERROR";
297
- var UNCAUGHT_ERROR_CODE = "UNCAUGHT_ERROR";
298
- var UNEXPECTED_DISCONNECT_CODE = "UNEXPECTED_DISCONNECT";
299
- var INVALID_REQUEST_CODE = "INVALID_REQUEST";
300
- var ABORT_CODE = "ABORT";
301
- var ResponseReaderErrorSchema = import_typebox2.Type.Object({
302
- code: import_typebox2.Type.Union([
303
- import_typebox2.Type.Literal(INTERNAL_RIVER_ERROR_CODE),
304
- import_typebox2.Type.Literal(UNCAUGHT_ERROR_CODE),
305
- import_typebox2.Type.Literal(UNEXPECTED_DISCONNECT_CODE),
306
- import_typebox2.Type.Literal(INVALID_REQUEST_CODE),
307
- import_typebox2.Type.Literal(ABORT_CODE)
308
- ]),
309
- message: import_typebox2.Type.String()
310
- });
311
- var RequestReaderErrorSchema = import_typebox2.Type.Object({
312
- code: import_typebox2.Type.Union([
313
- import_typebox2.Type.Literal(UNCAUGHT_ERROR_CODE),
314
- import_typebox2.Type.Literal(UNEXPECTED_DISCONNECT_CODE),
315
- import_typebox2.Type.Literal(INVALID_REQUEST_CODE),
316
- import_typebox2.Type.Literal(ABORT_CODE)
317
- ]),
318
- message: import_typebox2.Type.String()
319
- });
360
+ var import_typebox3 = require("@sinclair/typebox");
320
361
  function rpc({
321
362
  requestInit,
322
363
  responseData,
323
- responseError = import_typebox2.Type.Never(),
364
+ responseError = import_typebox3.Type.Never(),
324
365
  description,
325
366
  handler
326
367
  }) {
@@ -337,7 +378,7 @@ function upload({
337
378
  requestInit,
338
379
  requestData,
339
380
  responseData,
340
- responseError = import_typebox2.Type.Never(),
381
+ responseError = import_typebox3.Type.Never(),
341
382
  description,
342
383
  handler
343
384
  }) {
@@ -354,7 +395,7 @@ function upload({
354
395
  function subscription({
355
396
  requestInit,
356
397
  responseData,
357
- responseError = import_typebox2.Type.Never(),
398
+ responseError = import_typebox3.Type.Never(),
358
399
  description,
359
400
  handler
360
401
  }) {
@@ -371,7 +412,7 @@ function stream({
371
412
  requestInit,
372
413
  requestData,
373
414
  responseData,
374
- responseError = import_typebox2.Type.Never(),
415
+ responseError = import_typebox3.Type.Never(),
375
416
  description,
376
417
  handler
377
418
  }) {
@@ -393,7 +434,7 @@ var Procedure = {
393
434
  };
394
435
 
395
436
  // transport/message.ts
396
- var import_typebox3 = require("@sinclair/typebox");
437
+ var import_typebox4 = require("@sinclair/typebox");
397
438
 
398
439
  // transport/id.ts
399
440
  var import_nanoid = require("nanoid");
@@ -403,95 +444,90 @@ var alphabet = (0, import_nanoid.customAlphabet)(
403
444
  var generateId = () => alphabet(12);
404
445
 
405
446
  // transport/message.ts
406
- var TransportMessageSchema = (t) => import_typebox3.Type.Object({
407
- id: import_typebox3.Type.String(),
408
- from: import_typebox3.Type.String(),
409
- to: import_typebox3.Type.String(),
410
- seq: import_typebox3.Type.Integer(),
411
- ack: import_typebox3.Type.Integer(),
412
- serviceName: import_typebox3.Type.Optional(import_typebox3.Type.String()),
413
- procedureName: import_typebox3.Type.Optional(import_typebox3.Type.String()),
414
- streamId: import_typebox3.Type.String(),
415
- controlFlags: import_typebox3.Type.Integer(),
416
- tracing: import_typebox3.Type.Optional(
417
- import_typebox3.Type.Object({
418
- traceparent: import_typebox3.Type.String(),
419
- tracestate: import_typebox3.Type.String()
447
+ var TransportMessageSchema = (t) => import_typebox4.Type.Object({
448
+ id: import_typebox4.Type.String(),
449
+ from: import_typebox4.Type.String(),
450
+ to: import_typebox4.Type.String(),
451
+ seq: import_typebox4.Type.Integer(),
452
+ ack: import_typebox4.Type.Integer(),
453
+ serviceName: import_typebox4.Type.Optional(import_typebox4.Type.String()),
454
+ procedureName: import_typebox4.Type.Optional(import_typebox4.Type.String()),
455
+ streamId: import_typebox4.Type.String(),
456
+ controlFlags: import_typebox4.Type.Integer(),
457
+ tracing: import_typebox4.Type.Optional(
458
+ import_typebox4.Type.Object({
459
+ traceparent: import_typebox4.Type.String(),
460
+ tracestate: import_typebox4.Type.String()
420
461
  })
421
462
  ),
422
463
  payload: t
423
464
  });
424
- var ControlMessageAckSchema = import_typebox3.Type.Object({
425
- type: import_typebox3.Type.Literal("ACK")
465
+ var ControlMessageAckSchema = import_typebox4.Type.Object({
466
+ type: import_typebox4.Type.Literal("ACK")
426
467
  });
427
- var ControlMessageCloseSchema = import_typebox3.Type.Object({
428
- type: import_typebox3.Type.Literal("CLOSE")
468
+ var ControlMessageCloseSchema = import_typebox4.Type.Object({
469
+ type: import_typebox4.Type.Literal("CLOSE")
429
470
  });
430
- var ControlMessageHandshakeRequestSchema = import_typebox3.Type.Object({
431
- type: import_typebox3.Type.Literal("HANDSHAKE_REQ"),
432
- protocolVersion: import_typebox3.Type.String(),
433
- sessionId: import_typebox3.Type.String(),
471
+ var ControlMessageHandshakeRequestSchema = import_typebox4.Type.Object({
472
+ type: import_typebox4.Type.Literal("HANDSHAKE_REQ"),
473
+ protocolVersion: import_typebox4.Type.String(),
474
+ sessionId: import_typebox4.Type.String(),
434
475
  /**
435
476
  * Specifies what the server's expected session state (from the pov of the client). This can be
436
477
  * used by the server to know whether this is a new or a reestablished connection, and whether it
437
478
  * is compatible with what it already has.
438
479
  */
439
- expectedSessionState: import_typebox3.Type.Object({
480
+ expectedSessionState: import_typebox4.Type.Object({
440
481
  // what the client expects the server to send next
441
- nextExpectedSeq: import_typebox3.Type.Integer(),
442
- // TODO: remove optional once we know all servers
443
- // are nextSentSeq here
444
- // what the server expects the client to send next
445
- nextSentSeq: import_typebox3.Type.Optional(import_typebox3.Type.Integer())
482
+ nextExpectedSeq: import_typebox4.Type.Integer(),
483
+ nextSentSeq: import_typebox4.Type.Integer()
446
484
  }),
447
- metadata: import_typebox3.Type.Optional(import_typebox3.Type.Unknown())
485
+ metadata: import_typebox4.Type.Optional(import_typebox4.Type.Unknown())
448
486
  });
449
- var HandshakeErrorRetriableResponseCodes = import_typebox3.Type.Union([
450
- import_typebox3.Type.Literal("SESSION_STATE_MISMATCH")
487
+ var HandshakeErrorRetriableResponseCodes = import_typebox4.Type.Union([
488
+ import_typebox4.Type.Literal("SESSION_STATE_MISMATCH")
451
489
  ]);
452
- var HandshakeErrorCustomHandlerFatalResponseCodes = import_typebox3.Type.Union([
490
+ var HandshakeErrorCustomHandlerFatalResponseCodes = import_typebox4.Type.Union([
453
491
  // The custom validation handler rejected the handler because the client is unsupported.
454
- import_typebox3.Type.Literal("REJECTED_UNSUPPORTED_CLIENT"),
492
+ import_typebox4.Type.Literal("REJECTED_UNSUPPORTED_CLIENT"),
455
493
  // The custom validation handler rejected the handshake.
456
- import_typebox3.Type.Literal("REJECTED_BY_CUSTOM_HANDLER")
494
+ import_typebox4.Type.Literal("REJECTED_BY_CUSTOM_HANDLER")
457
495
  ]);
458
- var HandshakeErrorFatalResponseCodes = import_typebox3.Type.Union([
496
+ var HandshakeErrorFatalResponseCodes = import_typebox4.Type.Union([
459
497
  HandshakeErrorCustomHandlerFatalResponseCodes,
460
498
  // The ciient sent a handshake that doesn't comply with the extended handshake metadata.
461
- import_typebox3.Type.Literal("MALFORMED_HANDSHAKE_META"),
499
+ import_typebox4.Type.Literal("MALFORMED_HANDSHAKE_META"),
462
500
  // The ciient sent a handshake that doesn't comply with ControlMessageHandshakeRequestSchema.
463
- import_typebox3.Type.Literal("MALFORMED_HANDSHAKE"),
501
+ import_typebox4.Type.Literal("MALFORMED_HANDSHAKE"),
464
502
  // The client's protocol version does not match the server's.
465
- import_typebox3.Type.Literal("PROTOCOL_VERSION_MISMATCH")
503
+ import_typebox4.Type.Literal("PROTOCOL_VERSION_MISMATCH")
466
504
  ]);
467
- var HandshakeErrorResponseCodes = import_typebox3.Type.Union([
505
+ var HandshakeErrorResponseCodes = import_typebox4.Type.Union([
468
506
  HandshakeErrorRetriableResponseCodes,
469
507
  HandshakeErrorFatalResponseCodes
470
508
  ]);
471
- var ControlMessageHandshakeResponseSchema = import_typebox3.Type.Object({
472
- type: import_typebox3.Type.Literal("HANDSHAKE_RESP"),
473
- status: import_typebox3.Type.Union([
474
- import_typebox3.Type.Object({
475
- ok: import_typebox3.Type.Literal(true),
476
- sessionId: import_typebox3.Type.String()
509
+ var ControlMessageHandshakeResponseSchema = import_typebox4.Type.Object({
510
+ type: import_typebox4.Type.Literal("HANDSHAKE_RESP"),
511
+ status: import_typebox4.Type.Union([
512
+ import_typebox4.Type.Object({
513
+ ok: import_typebox4.Type.Literal(true),
514
+ sessionId: import_typebox4.Type.String()
477
515
  }),
478
- import_typebox3.Type.Object({
479
- ok: import_typebox3.Type.Literal(false),
480
- reason: import_typebox3.Type.String(),
481
- // TODO: remove optional once we know all servers
482
- // are sending code here
483
- code: import_typebox3.Type.Optional(HandshakeErrorResponseCodes)
516
+ import_typebox4.Type.Object({
517
+ ok: import_typebox4.Type.Literal(false),
518
+ reason: import_typebox4.Type.String(),
519
+ code: HandshakeErrorResponseCodes
484
520
  })
485
521
  ])
486
522
  });
487
- var ControlMessagePayloadSchema = import_typebox3.Type.Union([
523
+ var ControlMessagePayloadSchema = import_typebox4.Type.Union([
488
524
  ControlMessageCloseSchema,
489
525
  ControlMessageAckSchema,
490
526
  ControlMessageHandshakeRequestSchema,
491
527
  ControlMessageHandshakeResponseSchema
492
528
  ]);
493
529
  var OpaqueTransportMessageSchema = TransportMessageSchema(
494
- import_typebox3.Type.Unknown()
530
+ import_typebox4.Type.Unknown()
495
531
  );
496
532
  function closeStreamMessage(streamId) {
497
533
  return {
@@ -502,19 +538,10 @@ function closeStreamMessage(streamId) {
502
538
  }
503
539
  };
504
540
  }
505
- function requestCloseStreamMessage(streamId) {
541
+ function cancelMessage(streamId, payload) {
506
542
  return {
507
543
  streamId,
508
- controlFlags: 16 /* StreamCloseRequestBit */,
509
- payload: {
510
- type: "CLOSE"
511
- }
512
- };
513
- }
514
- function abortMessage(streamId, payload) {
515
- return {
516
- streamId,
517
- controlFlags: 4 /* StreamAbortBit */,
544
+ controlFlags: 4 /* StreamCancelBit */,
518
545
  payload
519
546
  };
520
547
  }
@@ -530,37 +557,27 @@ function isStreamClose(controlFlag) {
530
557
  (controlFlag & 8 /* StreamClosedBit */) === 8 /* StreamClosedBit */
531
558
  );
532
559
  }
533
- function isStreamCloseRequest(controlFlag) {
560
+ function isStreamCancel(controlFlag) {
534
561
  return (
535
562
  /* eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison */
536
- (controlFlag & 16 /* StreamCloseRequestBit */) === 16 /* StreamCloseRequestBit */
537
- );
538
- }
539
- function isStreamAbort(controlFlag) {
540
- return (
541
- /* eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison */
542
- (controlFlag & 4 /* StreamAbortBit */) === 4 /* StreamAbortBit */
563
+ (controlFlag & 4 /* StreamCancelBit */) === 4 /* StreamCancelBit */
543
564
  );
544
565
  }
545
566
 
546
567
  // router/result.ts
547
- var import_typebox4 = require("@sinclair/typebox");
548
- var ErrResultSchema = (t) => import_typebox4.Type.Object({
549
- ok: import_typebox4.Type.Literal(false),
550
- payload: t
551
- });
552
- var AnyResultSchema = import_typebox4.Type.Union([
553
- import_typebox4.Type.Object({
554
- ok: import_typebox4.Type.Literal(false),
555
- payload: import_typebox4.Type.Object({
556
- code: import_typebox4.Type.String(),
557
- message: import_typebox4.Type.String(),
558
- extras: import_typebox4.Type.Optional(import_typebox4.Type.Unknown())
568
+ var import_typebox5 = require("@sinclair/typebox");
569
+ var AnyResultSchema = import_typebox5.Type.Union([
570
+ import_typebox5.Type.Object({
571
+ ok: import_typebox5.Type.Literal(false),
572
+ payload: import_typebox5.Type.Object({
573
+ code: import_typebox5.Type.String(),
574
+ message: import_typebox5.Type.String(),
575
+ extras: import_typebox5.Type.Optional(import_typebox5.Type.Unknown())
559
576
  })
560
577
  }),
561
- import_typebox4.Type.Object({
562
- ok: import_typebox4.Type.Literal(true),
563
- payload: import_typebox4.Type.Unknown()
578
+ import_typebox5.Type.Object({
579
+ ok: import_typebox5.Type.Literal(true),
580
+ payload: import_typebox5.Type.Unknown()
564
581
  })
565
582
  ]);
566
583
  function Ok(payload) {
@@ -575,12 +592,20 @@ function Err(error) {
575
592
  payload: error
576
593
  };
577
594
  }
595
+ function unwrapOrThrow(result) {
596
+ if (result.ok) {
597
+ return result.payload;
598
+ }
599
+ throw new Error(
600
+ `Cannot non-ok result, got: ${result.payload.code} - ${result.payload.message}`
601
+ );
602
+ }
578
603
 
579
604
  // tracing/index.ts
580
605
  var import_api = require("@opentelemetry/api");
581
606
 
582
607
  // package.json
583
- var version = "0.200.0-rc.9";
608
+ var version = "0.200.2";
584
609
 
585
610
  // tracing/index.ts
586
611
  function getPropagationContext(ctx) {
@@ -644,306 +669,210 @@ function createHandlerSpan(kind, serviceName, procedureName, streamId, tracing,
644
669
  var tracer = import_api.trace.getTracer("river", version);
645
670
 
646
671
  // router/streams.ts
647
- var StreamDrainedError = {
648
- code: "STREAM_DRAINED",
649
- message: "Stream was drained"
672
+ var ReadableBrokenError = {
673
+ code: "READABLE_BROKEN",
674
+ message: "Readable was broken before it is fully consumed"
650
675
  };
651
- var ReadStreamImpl = class {
676
+ function createPromiseWithResolvers() {
677
+ let resolve;
678
+ let reject;
679
+ const promise = new Promise((res, rej) => {
680
+ resolve = res;
681
+ reject = rej;
682
+ });
683
+ return {
684
+ promise,
685
+ // @ts-expect-error promise callbacks are sync
686
+ resolve,
687
+ // @ts-expect-error promise callbacks are sync
688
+ reject
689
+ };
690
+ }
691
+ var ReadableImpl = class {
652
692
  /**
653
- * Whether the stream is closed.
693
+ * Whether the {@link Readable} is closed.
694
+ *
695
+ * Closed {@link Readable}s are done receiving values, but that doesn't affect
696
+ * any other aspect of the {@link Readable} such as it's consumability.
654
697
  */
655
698
  closed = false;
656
699
  /**
657
- * A list of listeners that will be called when the stream is closed.
658
- */
659
- onCloseListeners;
660
- /**
661
- * Whether the user has requested to close the stream.
662
- */
663
- closeRequested = false;
664
- /**
665
- * Used to signal to the outside world that the user has requested to close the stream.
666
- */
667
- closeRequestCallback;
668
- /**
669
- * Whether the stream is locked.
700
+ * Whether the {@link Readable} is locked.
701
+ *
702
+ * @see {@link Readable}'s typedoc to understand locking
670
703
  */
671
704
  locked = false;
672
705
  /**
673
- * Whether drain was called.
706
+ * Whether {@link break} was called.
707
+ *
708
+ * @see {@link break} for more information
674
709
  */
675
- drained = false;
710
+ broken = false;
676
711
  /**
677
- * This flag allows us to avoid cases where drain was called,
678
- * but the stream is fully consumed and closed. We don't need
679
- * to signal that drain was called.
712
+ * This flag allows us to avoid emitting a {@link ReadableBrokenError} after {@link break} was called
713
+ * in cases where the {@link queue} is fully consumed and {@link ReadableImpl} is {@link closed}. This is just an
714
+ * ergonomic feature to avoid emitting an error in our iteration when we don't have to.
680
715
  */
681
- didDrainDisposeValues = false;
716
+ brokenWithValuesLeftToRead = false;
682
717
  /**
683
- * A list of values that have been pushed to the stream but not yet emitted to the user.
718
+ * A list of values that have been pushed to the {@link ReadableImpl} but not yet emitted to the user.
684
719
  */
685
720
  queue = [];
686
721
  /**
687
722
  * Used by methods in the class to signal to the iterator that it
688
723
  * should check for the next value.
689
724
  */
690
- nextPromise = null;
691
- /**
692
- * Resolves nextPromise
693
- */
694
- resolveNextPromise = null;
695
- constructor(closeRequestCallback) {
696
- this.closeRequestCallback = closeRequestCallback;
697
- this.onCloseListeners = /* @__PURE__ */ new Set();
698
- }
725
+ next = null;
699
726
  [Symbol.asyncIterator]() {
700
- if (this.isLocked()) {
701
- throw new TypeError("ReadStream is already locked");
727
+ if (this.locked) {
728
+ throw new TypeError("Readable is already locked");
702
729
  }
703
- let didSignalDrain = false;
704
730
  this.locked = true;
731
+ let didSignalBreak = false;
705
732
  return {
706
733
  next: async () => {
707
- if (this.drained && didSignalDrain) {
734
+ if (didSignalBreak) {
708
735
  return {
709
736
  done: true,
710
737
  value: void 0
711
738
  };
712
739
  }
713
740
  while (this.queue.length === 0) {
714
- if (this.isClosed() && !this.didDrainDisposeValues) {
741
+ if (this.closed && !this.brokenWithValuesLeftToRead) {
715
742
  return {
716
743
  done: true,
717
744
  value: void 0
718
745
  };
719
746
  }
720
- if (this.drained) {
721
- didSignalDrain = true;
747
+ if (this.broken) {
748
+ didSignalBreak = true;
722
749
  return {
723
750
  done: false,
724
- value: Err(StreamDrainedError)
751
+ value: Err(ReadableBrokenError)
725
752
  };
726
753
  }
727
- if (!this.nextPromise) {
728
- this.nextPromise = new Promise((resolve) => {
729
- this.resolveNextPromise = resolve;
730
- });
754
+ if (!this.next) {
755
+ this.next = createPromiseWithResolvers();
731
756
  }
732
- await this.nextPromise;
733
- this.nextPromise = null;
734
- this.resolveNextPromise = null;
757
+ await this.next.promise;
758
+ this.next = null;
735
759
  }
736
760
  const value = this.queue.shift();
737
761
  return { done: false, value };
738
762
  },
739
763
  return: () => {
740
- this.drain();
764
+ this.break();
741
765
  return { done: true, value: void 0 };
742
766
  }
743
767
  };
744
768
  }
745
- unwrappedIter() {
746
- const iterator = this[Symbol.asyncIterator]();
747
- let unwrappedLock = false;
748
- return {
749
- [Symbol.asyncIterator]() {
750
- if (unwrappedLock) {
751
- throw new TypeError("ReadStream is already locked");
752
- }
753
- unwrappedLock = true;
754
- return {
755
- next: async () => {
756
- const next = await iterator.next();
757
- if (next.done) {
758
- return next;
759
- }
760
- if (next.value.ok) {
761
- return { done: false, value: next.value.payload };
762
- }
763
- iterator.return();
764
- throw new Error(
765
- `Got err result in unwrappedIter: ${next.value.payload.code} - ${next.value.payload.message}`
766
- );
767
- },
768
- return: () => iterator.return()
769
- };
770
- }
771
- };
772
- }
773
- async asArray() {
769
+ async collect() {
774
770
  const array = [];
775
771
  for await (const value of this) {
776
772
  array.push(value);
777
773
  }
778
774
  return array;
779
775
  }
780
- drain() {
781
- if (this.drained) {
776
+ break() {
777
+ if (this.broken) {
782
778
  return;
783
779
  }
784
780
  this.locked = true;
785
- this.drained = true;
786
- this.didDrainDisposeValues = this.queue.length > 0;
781
+ this.broken = true;
782
+ this.brokenWithValuesLeftToRead = this.queue.length > 0;
787
783
  this.queue.length = 0;
788
- this.resolveNextPromise?.();
784
+ this.next?.resolve();
789
785
  }
790
- isClosed() {
791
- return this.closed;
792
- }
793
- isLocked() {
794
- return this.locked;
795
- }
796
- onClose(cb) {
797
- if (this.isClosed()) {
798
- throw new Error("Stream is already closed");
799
- }
800
- this.onCloseListeners.add(cb);
801
- return () => {
802
- this.onCloseListeners.delete(cb);
803
- };
804
- }
805
- requestClose() {
806
- if (this.isClosed()) {
807
- throw new Error("Cannot request close after stream already closed");
808
- }
809
- if (!this.closeRequested) {
810
- this.closeRequested = true;
811
- this.closeRequestCallback();
812
- }
813
- return new Promise((resolve) => {
814
- this.onClose(() => {
815
- resolve(void 0);
816
- });
817
- });
818
- }
819
- isCloseRequested() {
820
- return this.closeRequested;
786
+ isReadable() {
787
+ return !this.locked && !this.broken;
821
788
  }
822
789
  /**
823
790
  * @internal meant for use within river, not exposed as a public API
824
791
  *
825
- * Pushes a value to the stream.
792
+ * Pushes a value to be read.
826
793
  */
827
- pushValue(value) {
828
- if (this.drained) {
794
+ _pushValue(value) {
795
+ if (this.broken) {
829
796
  return;
830
797
  }
831
798
  if (this.closed) {
832
- throw new Error("Cannot push to closed stream");
799
+ throw new Error("Cannot push to closed Readable");
833
800
  }
834
801
  this.queue.push(value);
835
- this.resolveNextPromise?.();
802
+ this.next?.resolve();
836
803
  }
837
804
  /**
838
805
  * @internal meant for use within river, not exposed as a public API
839
806
  *
840
- * Triggers the close of the stream. Make sure to push all remaining
807
+ * Triggers the close of the {@link Readable}. Make sure to push all remaining
841
808
  * values before calling this method.
842
809
  */
843
- triggerClose() {
844
- if (this.isClosed()) {
810
+ _triggerClose() {
811
+ if (this.closed) {
845
812
  throw new Error("Unexpected closing multiple times");
846
813
  }
847
814
  this.closed = true;
848
- this.resolveNextPromise?.();
849
- this.onCloseListeners.forEach((cb) => cb());
850
- this.onCloseListeners.clear();
815
+ this.next?.resolve();
851
816
  }
852
817
  /**
853
818
  * @internal meant for use within river, not exposed as a public API
854
819
  */
855
- hasValuesInQueue() {
820
+ _hasValuesInQueue() {
856
821
  return this.queue.length > 0;
857
822
  }
858
- };
859
- var WriteStreamImpl = class {
860
- /**
861
- * Passed via constructor to pass on write requests
862
- */
863
- writeCb;
864
823
  /**
865
- * Whether the stream is closed.
824
+ * @internal meant for use within river, not exposed as a public API
866
825
  */
867
- closed = false;
826
+ isClosed() {
827
+ return this.closed;
828
+ }
829
+ };
830
+ var WritableImpl = class {
868
831
  /**
869
- * A list of listeners that will be called when the stream is closed.
832
+ * Passed via constructor to pass on calls to {@link write}
870
833
  */
871
- onCloseListeners;
834
+ writeCb;
872
835
  /**
873
- * Whether the reader has requested to close the stream.
836
+ * Passed via constructor to pass on calls to {@link close}
874
837
  */
875
- closeRequested = false;
838
+ closeCb;
876
839
  /**
877
- * A list of listeners that will be called when a close request is triggered.
840
+ * Whether {@link close} was called, and {@link Writable} is not writable anymore.
878
841
  */
879
- onCloseRequestListeners;
880
- constructor(writeCb) {
881
- this.writeCb = writeCb;
882
- this.onCloseListeners = /* @__PURE__ */ new Set();
883
- this.onCloseRequestListeners = /* @__PURE__ */ new Set();
842
+ closed = false;
843
+ constructor(callbacks) {
844
+ this.writeCb = callbacks.writeCb;
845
+ this.closeCb = callbacks.closeCb;
884
846
  }
885
847
  write(value) {
886
- if (this.isClosed()) {
887
- throw new Error("Cannot write to closed stream");
848
+ if (this.closed) {
849
+ throw new Error("Cannot write to closed Writable");
888
850
  }
889
851
  this.writeCb(value);
890
852
  }
891
- isClosed() {
892
- return this.closed;
893
- }
894
- onClose(cb) {
895
- if (this.isClosed()) {
896
- cb();
897
- return () => void 0;
898
- }
899
- this.onCloseListeners.add(cb);
900
- return () => this.onCloseListeners.delete(cb);
853
+ isWritable() {
854
+ return !this.closed;
901
855
  }
902
856
  close() {
903
- if (this.isClosed()) {
857
+ if (this.closed) {
904
858
  return;
905
859
  }
906
860
  this.closed = true;
907
- this.onCloseListeners.forEach((cb) => cb());
908
- this.onCloseListeners.clear();
909
- this.onCloseRequestListeners.clear();
910
861
  this.writeCb = () => void 0;
911
- }
912
- isCloseRequested() {
913
- return this.closeRequested;
914
- }
915
- onCloseRequest(cb) {
916
- if (this.isClosed()) {
917
- throw new Error("Stream is already closed");
918
- }
919
- if (this.isCloseRequested()) {
920
- cb();
921
- return () => void 0;
922
- }
923
- this.onCloseRequestListeners.add(cb);
924
- return () => this.onCloseRequestListeners.delete(cb);
862
+ this.closeCb();
863
+ this.closeCb = () => void 0;
925
864
  }
926
865
  /**
927
866
  * @internal meant for use within river, not exposed as a public API
928
- *
929
- * Triggers a close request.
930
867
  */
931
- triggerCloseRequest() {
932
- if (this.isCloseRequested()) {
933
- throw new Error("Cannot trigger close request multiple times");
934
- }
935
- if (this.isClosed()) {
936
- throw new Error("Cannot trigger close request on closed stream");
937
- }
938
- this.closeRequested = true;
939
- this.onCloseRequestListeners.forEach((cb) => cb());
940
- this.onCloseRequestListeners.clear();
868
+ isClosed() {
869
+ return this.closed;
941
870
  }
942
871
  };
943
872
 
944
873
  // router/client.ts
945
874
  var import_value = require("@sinclair/typebox/value");
946
- var OutputErrResultSchema = ErrResultSchema(ResponseReaderErrorSchema);
875
+ var ReaderErrResultSchema = ErrResultSchema(ReaderErrorSchema);
947
876
  var noop = () => {
948
877
  };
949
878
  function _createRecursiveProxy(callback, path) {
@@ -1004,6 +933,11 @@ function createClient(transport, serverId, providedClientOptions = {}) {
1004
933
  }, []);
1005
934
  }
1006
935
  function handleProc(procType, transport, serverId, init, serviceName, procedureName, abortSignal) {
936
+ const session = transport.sessions.get(serverId) ?? transport.createUnconnectedSession(serverId);
937
+ const sessionScopedSend = transport.getSessionBoundSendFn(
938
+ serverId,
939
+ session.id
940
+ );
1007
941
  const procClosesWithInit = procType === "rpc" || procType === "subscription";
1008
942
  const streamId = generateId();
1009
943
  const { span, ctx } = createProcTelemetryInfo(
@@ -1014,61 +948,61 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
1014
948
  streamId
1015
949
  );
1016
950
  let cleanClose = true;
1017
- const reqWriter = new WriteStreamImpl((rawIn) => {
1018
- transport.send(serverId, {
1019
- streamId,
1020
- payload: rawIn,
1021
- controlFlags: 0,
1022
- tracing: getPropagationContext(ctx)
1023
- });
1024
- });
1025
- reqWriter.onClose(() => {
1026
- span.addEvent("reqWriter closed");
1027
- if (!procClosesWithInit && cleanClose) {
1028
- transport.send(serverId, closeStreamMessage(streamId));
1029
- }
1030
- if (resReader.isClosed()) {
1031
- cleanup();
951
+ const reqWritable = new WritableImpl({
952
+ writeCb: (rawIn) => {
953
+ sessionScopedSend({
954
+ streamId,
955
+ payload: rawIn,
956
+ controlFlags: 0
957
+ });
958
+ },
959
+ // close callback
960
+ closeCb: () => {
961
+ span.addEvent("reqWritable closed");
962
+ if (!procClosesWithInit && cleanClose) {
963
+ sessionScopedSend(closeStreamMessage(streamId));
964
+ }
965
+ if (resReadable.isClosed()) {
966
+ cleanup();
967
+ }
1032
968
  }
1033
969
  });
1034
- const resReader = new ReadStreamImpl(() => {
1035
- transport.send(serverId, requestCloseStreamMessage(streamId));
1036
- });
1037
- resReader.onClose(() => {
1038
- span.addEvent("resReader closed");
1039
- if (reqWriter.isClosed()) {
970
+ const resReadable = new ReadableImpl();
971
+ const closeReadable = () => {
972
+ resReadable._triggerClose();
973
+ span.addEvent("resReadable closed");
974
+ if (reqWritable.isClosed()) {
1040
975
  cleanup();
1041
976
  }
1042
- });
977
+ };
1043
978
  function cleanup() {
1044
979
  transport.removeEventListener("message", onMessage);
1045
980
  transport.removeEventListener("sessionStatus", onSessionStatus);
1046
- abortSignal?.removeEventListener("abort", onClientAbort);
981
+ abortSignal?.removeEventListener("abort", onClientCancel);
1047
982
  span.end();
1048
983
  }
1049
- function onClientAbort() {
1050
- if (resReader.isClosed() && reqWriter.isClosed()) {
984
+ function onClientCancel() {
985
+ if (resReadable.isClosed() && reqWritable.isClosed()) {
1051
986
  return;
1052
987
  }
1053
- span.addEvent("sending abort");
988
+ span.addEvent("sending cancel");
1054
989
  cleanClose = false;
1055
- if (!resReader.isClosed()) {
1056
- resReader.pushValue(
990
+ if (!resReadable.isClosed()) {
991
+ resReadable._pushValue(
1057
992
  Err({
1058
- code: ABORT_CODE,
1059
- message: "Aborted by client"
993
+ code: CANCEL_CODE,
994
+ message: "cancelled by client"
1060
995
  })
1061
996
  );
1062
- resReader.triggerClose();
997
+ closeReadable();
1063
998
  }
1064
- reqWriter.close();
1065
- transport.send(
1066
- serverId,
1067
- abortMessage(
999
+ reqWritable.close();
1000
+ sessionScopedSend(
1001
+ cancelMessage(
1068
1002
  streamId,
1069
1003
  Err({
1070
- code: ABORT_CODE,
1071
- message: "Aborted by client"
1004
+ code: CANCEL_CODE,
1005
+ message: "cancelled by client"
1072
1006
  })
1073
1007
  )
1074
1008
  );
@@ -1077,47 +1011,44 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
1077
1011
  if (msg.streamId !== streamId)
1078
1012
  return;
1079
1013
  if (msg.to !== transport.clientId) {
1080
- transport.log?.error("Got stream message from unexpected client", {
1014
+ transport.log?.error("got stream message from unexpected client", {
1081
1015
  clientId: transport.clientId,
1082
1016
  transportMessage: msg
1083
1017
  });
1084
1018
  return;
1085
1019
  }
1086
- if (isStreamCloseRequest(msg.controlFlags)) {
1087
- reqWriter.triggerCloseRequest();
1088
- }
1089
- if (isStreamAbort(msg.controlFlags)) {
1020
+ if (isStreamCancel(msg.controlFlags)) {
1090
1021
  cleanClose = false;
1091
- span.addEvent("received abort");
1092
- let abortResult;
1093
- if (import_value.Value.Check(OutputErrResultSchema, msg.payload)) {
1094
- abortResult = msg.payload;
1022
+ span.addEvent("received cancel");
1023
+ let cancelResult;
1024
+ if (import_value.Value.Check(ReaderErrResultSchema, msg.payload)) {
1025
+ cancelResult = msg.payload;
1095
1026
  } else {
1096
- abortResult = Err({
1097
- code: ABORT_CODE,
1098
- message: "Stream aborted with invalid payload"
1027
+ cancelResult = Err({
1028
+ code: CANCEL_CODE,
1029
+ message: "stream cancelled with invalid payload"
1099
1030
  });
1100
1031
  transport.log?.error(
1101
- "Got stream abort without a valid protocol error",
1032
+ "got stream cancel without a valid protocol error",
1102
1033
  {
1103
1034
  clientId: transport.clientId,
1104
1035
  transportMessage: msg,
1105
1036
  validationErrors: [
1106
- ...import_value.Value.Errors(OutputErrResultSchema, msg.payload)
1037
+ ...import_value.Value.Errors(ReaderErrResultSchema, msg.payload)
1107
1038
  ]
1108
1039
  }
1109
1040
  );
1110
1041
  }
1111
- if (!resReader.isClosed()) {
1112
- resReader.pushValue(abortResult);
1113
- resReader.triggerClose();
1042
+ if (!resReadable.isClosed()) {
1043
+ resReadable._pushValue(cancelResult);
1044
+ closeReadable();
1114
1045
  }
1115
- reqWriter.close();
1046
+ reqWritable.close();
1116
1047
  return;
1117
1048
  }
1118
- if (resReader.isClosed()) {
1119
- span.recordException("Received message after output stream is closed");
1120
- transport.log?.error("Received message after output stream is closed", {
1049
+ if (resReadable.isClosed()) {
1050
+ span.recordException("received message after response stream is closed");
1051
+ transport.log?.error("received message after response stream is closed", {
1121
1052
  clientId: transport.clientId,
1122
1053
  transportMessage: msg
1123
1054
  });
@@ -1125,7 +1056,7 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
1125
1056
  }
1126
1057
  if (!import_value.Value.Check(ControlMessageCloseSchema, msg.payload)) {
1127
1058
  if (import_value.Value.Check(AnyResultSchema, msg.payload)) {
1128
- resReader.pushValue(msg.payload);
1059
+ resReadable._pushValue(msg.payload);
1129
1060
  } else {
1130
1061
  transport.log?.error(
1131
1062
  "Got non-control payload, but was not a valid result",
@@ -1138,33 +1069,36 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
1138
1069
  }
1139
1070
  }
1140
1071
  if (isStreamClose(msg.controlFlags)) {
1141
- span.addEvent("received output close");
1142
- resReader.triggerClose();
1072
+ span.addEvent("received response close");
1073
+ if (resReadable.isClosed()) {
1074
+ transport.log?.error(
1075
+ "received stream close but readable was already closed"
1076
+ );
1077
+ } else {
1078
+ closeReadable();
1079
+ }
1143
1080
  }
1144
1081
  }
1145
1082
  function onSessionStatus(evt) {
1146
- if (evt.status !== "disconnect") {
1147
- return;
1148
- }
1149
- if (evt.session.to !== serverId) {
1083
+ if (evt.status !== "disconnect" || evt.session.to !== serverId || session.id !== evt.session.id) {
1150
1084
  return;
1151
1085
  }
1152
1086
  cleanClose = false;
1153
- if (!resReader.isClosed()) {
1154
- resReader.pushValue(
1087
+ if (!resReadable.isClosed()) {
1088
+ resReadable._pushValue(
1155
1089
  Err({
1156
1090
  code: UNEXPECTED_DISCONNECT_CODE,
1157
1091
  message: `${serverId} unexpectedly disconnected`
1158
1092
  })
1159
1093
  );
1094
+ closeReadable();
1160
1095
  }
1161
- reqWriter.close();
1162
- resReader.triggerClose();
1096
+ reqWritable.close();
1163
1097
  }
1164
- abortSignal?.addEventListener("abort", onClientAbort);
1098
+ abortSignal?.addEventListener("abort", onClientCancel);
1165
1099
  transport.addEventListener("message", onMessage);
1166
1100
  transport.addEventListener("sessionStatus", onSessionStatus);
1167
- transport.send(serverId, {
1101
+ sessionScopedSend({
1168
1102
  streamId,
1169
1103
  serviceName,
1170
1104
  procedureName,
@@ -1173,34 +1107,39 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
1173
1107
  controlFlags: procClosesWithInit ? 2 /* StreamOpenBit */ | 8 /* StreamClosedBit */ : 2 /* StreamOpenBit */
1174
1108
  });
1175
1109
  if (procClosesWithInit) {
1176
- reqWriter.close();
1110
+ reqWritable.close();
1177
1111
  }
1178
1112
  if (procType === "subscription") {
1179
- return { resReader };
1113
+ return {
1114
+ resReadable
1115
+ };
1180
1116
  }
1181
1117
  if (procType === "rpc") {
1182
- return getSingleMessage(resReader, transport.log);
1118
+ return getSingleMessage(resReadable, transport.log);
1183
1119
  }
1184
1120
  if (procType === "upload") {
1185
1121
  let didFinalize = false;
1186
1122
  return {
1187
- reqWriter,
1188
- async finalize() {
1123
+ reqWritable,
1124
+ finalize: () => {
1189
1125
  if (didFinalize) {
1190
1126
  throw new Error("upload stream already finalized");
1191
1127
  }
1192
1128
  didFinalize = true;
1193
- if (!reqWriter.isClosed()) {
1194
- reqWriter.close();
1129
+ if (!reqWritable.isClosed()) {
1130
+ reqWritable.close();
1195
1131
  }
1196
- return getSingleMessage(resReader, transport.log);
1132
+ return getSingleMessage(resReadable, transport.log);
1197
1133
  }
1198
1134
  };
1199
1135
  }
1200
- return { reqWriter, resReader };
1136
+ return {
1137
+ resReadable,
1138
+ reqWritable
1139
+ };
1201
1140
  }
1202
- async function getSingleMessage(resReader, log) {
1203
- const ret = await resReader.asArray();
1141
+ async function getSingleMessage(resReadable, log) {
1142
+ const ret = await resReadable.collect();
1204
1143
  if (ret.length > 1) {
1205
1144
  log?.error("Expected single message from server, got multiple");
1206
1145
  }
@@ -1208,6 +1147,7 @@ async function getSingleMessage(resReader, log) {
1208
1147
  }
1209
1148
 
1210
1149
  // router/server.ts
1150
+ var import_typebox6 = require("@sinclair/typebox");
1211
1151
  var import_value2 = require("@sinclair/typebox/value");
1212
1152
 
1213
1153
  // util/stringify.ts
@@ -1220,23 +1160,28 @@ function coerceErrorString(err) {
1220
1160
 
1221
1161
  // router/server.ts
1222
1162
  var import_api2 = require("@opentelemetry/api");
1223
- var InputErrResultSchema = ErrResultSchema(RequestReaderErrorSchema);
1163
+ var CancelResultSchema = ErrResultSchema(
1164
+ import_typebox6.Type.Object({
1165
+ code: import_typebox6.Type.Literal(CANCEL_CODE),
1166
+ message: import_typebox6.Type.String()
1167
+ })
1168
+ );
1224
1169
  var RiverServer = class {
1225
1170
  transport;
1226
1171
  contextMap;
1227
1172
  log;
1228
1173
  /**
1229
- * We create a tombstones for streams aborted by the server
1174
+ * We create a tombstones for streams cancelled by the server
1230
1175
  * so that we don't hit errors when the client has inflight
1231
- * requests it sent before it saw the abort.
1232
- * We track aborted streams for every session separately, so
1176
+ * requests it sent before it saw the cancel.
1177
+ * We track cancelled streams for every client separately, so
1233
1178
  * that bad clients don't affect good clients.
1234
1179
  */
1235
- serverAbortedStreams;
1236
- maxAbortedStreamTombstonesPerSession;
1237
- openStreams;
1180
+ serverCancelledStreams;
1181
+ maxCancelledStreamTombstonesPerSession;
1182
+ streams;
1238
1183
  services;
1239
- constructor(transport, services, handshakeOptions, extendedContext, maxAbortedStreamTombstonesPerSession = 200) {
1184
+ constructor(transport, services, handshakeOptions, extendedContext, maxCancelledStreamTombstonesPerSession = 200) {
1240
1185
  const instances = {};
1241
1186
  this.services = instances;
1242
1187
  this.contextMap = /* @__PURE__ */ new Map();
@@ -1252,34 +1197,40 @@ var RiverServer = class {
1252
1197
  transport.extendHandshake(handshakeOptions);
1253
1198
  }
1254
1199
  this.transport = transport;
1255
- this.openStreams = /* @__PURE__ */ new Set();
1256
- this.serverAbortedStreams = /* @__PURE__ */ new Map();
1257
- this.maxAbortedStreamTombstonesPerSession = maxAbortedStreamTombstonesPerSession;
1200
+ this.streams = /* @__PURE__ */ new Map();
1201
+ this.serverCancelledStreams = /* @__PURE__ */ new Map();
1202
+ this.maxCancelledStreamTombstonesPerSession = maxCancelledStreamTombstonesPerSession;
1258
1203
  this.log = transport.log;
1259
- const handleMessage = (msg) => {
1260
- if (msg.to !== this.transport.clientId) {
1204
+ const handleCreatingNewStreams = (message) => {
1205
+ if (message.to !== this.transport.clientId) {
1261
1206
  this.log?.info(
1262
1207
  `got msg with destination that isn't this server, ignoring`,
1263
1208
  {
1264
1209
  clientId: this.transport.clientId,
1265
- transportMessage: msg
1210
+ transportMessage: message
1266
1211
  }
1267
1212
  );
1268
1213
  return;
1269
1214
  }
1270
- if (this.openStreams.has(msg.streamId)) {
1215
+ const streamId = message.streamId;
1216
+ const stream2 = this.streams.get(streamId);
1217
+ if (stream2) {
1218
+ stream2.handleMsg(message);
1271
1219
  return;
1272
1220
  }
1273
- if (this.serverAbortedStreams.get(msg.from)?.has(msg.streamId)) {
1221
+ if (this.serverCancelledStreams.get(message.from)?.has(streamId)) {
1274
1222
  return;
1275
1223
  }
1276
- const validated = this.validateNewProcStream(msg);
1277
- if (!validated) {
1224
+ const newStreamProps = this.validateNewProcStream(message);
1225
+ if (!newStreamProps) {
1278
1226
  return;
1279
1227
  }
1280
- this.createNewProcStream(validated);
1228
+ const newStream = this.createNewProcStream({
1229
+ ...newStreamProps,
1230
+ ...message
1231
+ });
1232
+ this.streams.set(streamId, newStream);
1281
1233
  };
1282
- this.transport.addEventListener("message", handleMessage);
1283
1234
  const handleSessionStatus = (evt) => {
1284
1235
  if (evt.status !== "disconnect")
1285
1236
  return;
@@ -1288,256 +1239,258 @@ var RiverServer = class {
1288
1239
  `got session disconnect from ${disconnectedClientId}, cleaning up streams`,
1289
1240
  evt.session.loggingMetadata
1290
1241
  );
1291
- this.serverAbortedStreams.delete(disconnectedClientId);
1242
+ for (const stream2 of this.streams.values()) {
1243
+ if (stream2.from === disconnectedClientId) {
1244
+ stream2.handleSessionDisconnect();
1245
+ }
1246
+ }
1247
+ this.serverCancelledStreams.delete(disconnectedClientId);
1292
1248
  };
1293
- this.transport.addEventListener("sessionStatus", handleSessionStatus);
1294
- this.transport.addEventListener("transportStatus", (evt) => {
1249
+ const handleTransportStatus = (evt) => {
1295
1250
  if (evt.status !== "closed")
1296
1251
  return;
1297
- this.transport.removeEventListener("message", handleMessage);
1252
+ this.transport.removeEventListener("message", handleCreatingNewStreams);
1298
1253
  this.transport.removeEventListener("sessionStatus", handleSessionStatus);
1299
- });
1300
- }
1301
- createNewProcStream({
1302
- procedure,
1303
- procedureName,
1304
- service,
1305
- serviceName,
1306
- sessionMetadata,
1307
- loggingMetadata,
1308
- streamId,
1309
- controlFlags,
1310
- initPayload,
1311
- from,
1312
- sessionId,
1313
- tracingCtx,
1314
- protocolVersion,
1315
- passInitAsDataForBackwardsCompat
1316
- }) {
1317
- this.openStreams.add(streamId);
1318
- let cleanClose = true;
1319
- const onServerAbort = (errResult) => {
1320
- if (reqReader.isClosed() && resWriter.isClosed()) {
1321
- return;
1322
- }
1323
- cleanClose = false;
1324
- if (!reqReader.isClosed()) {
1325
- reqReader.pushValue(errResult);
1326
- reqReader.triggerClose();
1327
- }
1328
- resWriter.close();
1329
- this.abortStream(from, streamId, errResult);
1330
- };
1331
- const onHandlerAbort = () => {
1332
- onServerAbort(
1333
- Err({
1334
- code: ABORT_CODE,
1335
- message: "Aborted by server procedure handler"
1336
- })
1254
+ this.transport.removeEventListener(
1255
+ "transportStatus",
1256
+ handleTransportStatus
1337
1257
  );
1338
1258
  };
1339
- const handlerAbortController = new AbortController();
1340
- handlerAbortController.signal.addEventListener("abort", onHandlerAbort);
1341
- const clientAbortController = new AbortController();
1342
- const onSessionStatus = (evt) => {
1343
- if (evt.status !== "disconnect") {
1344
- return;
1345
- }
1346
- if (evt.session.to !== from) {
1347
- return;
1348
- }
1349
- cleanClose = false;
1350
- const errPayload = {
1351
- code: UNEXPECTED_DISCONNECT_CODE,
1352
- message: `client unexpectedly disconnected`
1353
- };
1354
- if (!reqReader.isClosed()) {
1355
- reqReader.pushValue(Err(errPayload));
1356
- reqReader.triggerClose();
1357
- }
1358
- clientAbortController.abort(errPayload);
1359
- resWriter.close();
1360
- };
1361
- this.transport.addEventListener("sessionStatus", onSessionStatus);
1259
+ this.transport.addEventListener("message", handleCreatingNewStreams);
1260
+ this.transport.addEventListener("sessionStatus", handleSessionStatus);
1261
+ this.transport.addEventListener("transportStatus", handleTransportStatus);
1262
+ }
1263
+ createNewProcStream(props) {
1264
+ const {
1265
+ streamId,
1266
+ initialSession,
1267
+ procedureName,
1268
+ serviceName,
1269
+ procedure,
1270
+ sessionMetadata,
1271
+ serviceContext,
1272
+ initPayload,
1273
+ tracingCtx,
1274
+ procClosesWithInit,
1275
+ passInitAsDataForBackwardsCompat
1276
+ } = props;
1277
+ const {
1278
+ to: from,
1279
+ loggingMetadata,
1280
+ protocolVersion,
1281
+ id: sessionId
1282
+ } = initialSession;
1283
+ let cleanClose = true;
1362
1284
  const onMessage = (msg) => {
1363
- if (streamId !== msg.streamId) {
1364
- return;
1365
- }
1366
1285
  if (msg.from !== from) {
1367
- this.log?.error("Got stream message from unexpected client", {
1286
+ this.log?.error("got stream message from unexpected client", {
1368
1287
  ...loggingMetadata,
1369
- clientId: this.transport.clientId,
1370
1288
  transportMessage: msg,
1371
1289
  tags: ["invariant-violation"]
1372
1290
  });
1373
1291
  return;
1374
1292
  }
1375
- if (isStreamCloseRequest(msg.controlFlags)) {
1376
- resWriter.triggerCloseRequest();
1377
- }
1378
- if (isStreamAbortBackwardsCompat(msg.controlFlags, protocolVersion)) {
1379
- let abortResult;
1380
- if (import_value2.Value.Check(InputErrResultSchema, msg.payload)) {
1381
- abortResult = msg.payload;
1293
+ if (isStreamCancelBackwardsCompat(msg.controlFlags, protocolVersion)) {
1294
+ let cancelResult;
1295
+ if (import_value2.Value.Check(CancelResultSchema, msg.payload)) {
1296
+ cancelResult = msg.payload;
1382
1297
  } else {
1383
- abortResult = Err({
1384
- code: ABORT_CODE,
1385
- message: "Stream aborted, client sent invalid payload"
1298
+ cancelResult = Err({
1299
+ code: CANCEL_CODE,
1300
+ message: "stream cancelled, client sent invalid payload"
1386
1301
  });
1387
- this.log?.warn("Got stream abort without a valid protocol error", {
1302
+ this.log?.warn("got stream cancel without a valid protocol error", {
1388
1303
  ...loggingMetadata,
1389
- clientId: this.transport.clientId,
1390
1304
  transportMessage: msg,
1391
1305
  validationErrors: [
1392
- ...import_value2.Value.Errors(InputErrResultSchema, msg.payload)
1306
+ ...import_value2.Value.Errors(CancelResultSchema, msg.payload)
1393
1307
  ],
1394
1308
  tags: ["invalid-request"]
1395
1309
  });
1396
1310
  }
1397
- if (!reqReader.isClosed()) {
1398
- reqReader.pushValue(abortResult);
1399
- reqReader.triggerClose();
1311
+ if (!reqReadable.isClosed()) {
1312
+ reqReadable._pushValue(cancelResult);
1313
+ closeReadable();
1400
1314
  }
1401
- resWriter.close();
1402
- clientAbortController.abort(abortResult.payload);
1315
+ resWritable.close();
1403
1316
  return;
1404
1317
  }
1405
- if (reqReader.isClosed()) {
1406
- this.log?.warn("Received message after input stream is closed", {
1318
+ if (reqReadable.isClosed()) {
1319
+ this.log?.warn("received message after request stream is closed", {
1407
1320
  ...loggingMetadata,
1408
- clientId: this.transport.clientId,
1409
1321
  transportMessage: msg,
1410
1322
  tags: ["invalid-request"]
1411
1323
  });
1412
- onServerAbort(
1413
- Err({
1414
- code: INVALID_REQUEST_CODE,
1415
- message: "Received message after input stream is closed"
1416
- })
1417
- );
1324
+ onServerCancel({
1325
+ code: INVALID_REQUEST_CODE,
1326
+ message: "received message after request stream is closed"
1327
+ });
1418
1328
  return;
1419
1329
  }
1420
1330
  if ("requestData" in procedure && import_value2.Value.Check(procedure.requestData, msg.payload)) {
1421
- reqReader.pushValue(Ok(msg.payload));
1422
- } else if (!import_value2.Value.Check(ControlMessagePayloadSchema, msg.payload)) {
1423
- const validationErrors = [
1331
+ reqReadable._pushValue(Ok(msg.payload));
1332
+ if (isStreamCloseBackwardsCompat(msg.controlFlags, protocolVersion)) {
1333
+ closeReadable();
1334
+ }
1335
+ return;
1336
+ }
1337
+ if (import_value2.Value.Check(ControlMessagePayloadSchema, msg.payload) && isStreamCloseBackwardsCompat(msg.controlFlags, protocolVersion)) {
1338
+ closeReadable();
1339
+ return;
1340
+ }
1341
+ let validationErrors;
1342
+ let errMessage;
1343
+ if ("requestData" in procedure) {
1344
+ errMessage = "expected requestData or control payload";
1345
+ validationErrors = [
1346
+ ...import_value2.Value.Errors(procedure.responseData, msg.payload)
1347
+ ];
1348
+ } else {
1349
+ validationErrors = [
1424
1350
  ...import_value2.Value.Errors(ControlMessagePayloadSchema, msg.payload)
1425
1351
  ];
1426
- let errMessage = "Expected control payload for procedure with no input";
1427
- if ("requestData" in procedure) {
1428
- errMessage = "Expected either control or input payload, validation failed for both";
1429
- validationErrors.push(
1430
- ...import_value2.Value.Errors(procedure.responseData, msg.payload)
1431
- );
1352
+ errMessage = "expected control payload";
1353
+ }
1354
+ this.log?.warn(errMessage, {
1355
+ ...loggingMetadata,
1356
+ transportMessage: msg,
1357
+ validationErrors,
1358
+ tags: ["invalid-request"]
1359
+ });
1360
+ onServerCancel({
1361
+ code: INVALID_REQUEST_CODE,
1362
+ message: errMessage
1363
+ });
1364
+ };
1365
+ const procStream = {
1366
+ from,
1367
+ streamId,
1368
+ procedureName,
1369
+ serviceName,
1370
+ sessionMetadata,
1371
+ procedure,
1372
+ handleMsg: onMessage,
1373
+ handleSessionDisconnect: () => {
1374
+ cleanClose = false;
1375
+ const errPayload = {
1376
+ code: UNEXPECTED_DISCONNECT_CODE,
1377
+ message: "client unexpectedly disconnected"
1378
+ };
1379
+ if (!reqReadable.isClosed()) {
1380
+ reqReadable._pushValue(Err(errPayload));
1381
+ closeReadable();
1432
1382
  }
1433
- this.log?.warn(errMessage, {
1434
- ...loggingMetadata,
1435
- clientId: this.transport.clientId,
1436
- transportMessage: msg,
1437
- validationErrors,
1438
- tags: ["invalid-request"]
1439
- });
1440
- onServerAbort(
1441
- Err({
1442
- code: INVALID_REQUEST_CODE,
1443
- message: errMessage
1444
- })
1445
- );
1383
+ resWritable.close();
1446
1384
  }
1447
- if (isStreamCloseBackwardsCompat(msg.controlFlags, protocolVersion)) {
1448
- reqReader.triggerClose();
1385
+ };
1386
+ const sessionScopedSend = this.transport.getSessionBoundSendFn(
1387
+ from,
1388
+ sessionId
1389
+ );
1390
+ const cancelStream = (streamId2, payload) => {
1391
+ this.cancelStream(from, sessionScopedSend, streamId2, payload);
1392
+ };
1393
+ const onServerCancel = (e) => {
1394
+ if (reqReadable.isClosed() && resWritable.isClosed()) {
1395
+ return;
1396
+ }
1397
+ cleanClose = false;
1398
+ const result = Err(e);
1399
+ if (!reqReadable.isClosed()) {
1400
+ reqReadable._pushValue(result);
1401
+ closeReadable();
1449
1402
  }
1403
+ resWritable.close();
1404
+ cancelStream(streamId, result);
1450
1405
  };
1451
- this.transport.addEventListener("message", onMessage);
1452
- const onFinishedCallbacks = [];
1406
+ const finishedController = new AbortController();
1453
1407
  const cleanup = () => {
1454
- this.transport.removeEventListener("message", onMessage);
1455
- this.transport.removeEventListener("sessionStatus", onSessionStatus);
1456
- handlerAbortController.signal.addEventListener("abort", onHandlerAbort);
1457
- this.openStreams.delete(streamId);
1458
- onFinishedCallbacks.forEach((cb) => {
1459
- try {
1460
- cb();
1461
- } catch {
1462
- }
1463
- });
1464
- onFinishedCallbacks.length = 0;
1408
+ finishedController.abort();
1409
+ this.streams.delete(streamId);
1465
1410
  };
1466
1411
  const procClosesWithResponse = procedure.type === "rpc" || procedure.type === "upload";
1467
- const reqReader = new ReadStreamImpl(() => {
1468
- this.transport.send(from, requestCloseStreamMessage(streamId));
1469
- });
1470
- reqReader.onClose(() => {
1412
+ const reqReadable = new ReadableImpl();
1413
+ const closeReadable = () => {
1414
+ reqReadable._triggerClose();
1471
1415
  if (protocolVersion === "v1.1") {
1472
- if (!procClosesWithResponse && !resWriter.isClosed()) {
1473
- resWriter.close();
1416
+ if (!procClosesWithResponse && !resWritable.isClosed()) {
1417
+ resWritable.close();
1474
1418
  }
1475
1419
  }
1476
- if (resWriter.isClosed()) {
1420
+ if (resWritable.isClosed()) {
1477
1421
  cleanup();
1478
1422
  }
1479
- });
1423
+ };
1480
1424
  if (passInitAsDataForBackwardsCompat) {
1481
- reqReader.pushValue(Ok(initPayload));
1425
+ reqReadable._pushValue(Ok(initPayload));
1482
1426
  }
1483
- const resWriter = new WriteStreamImpl((response) => {
1484
- this.transport.send(from, {
1485
- streamId,
1486
- controlFlags: procClosesWithResponse ? getStreamCloseBackwardsCompat(protocolVersion) : 0,
1487
- payload: response
1488
- });
1489
- });
1490
- resWriter.onClose(() => {
1491
- if (!procClosesWithResponse && cleanClose) {
1492
- const message = closeStreamMessage(streamId);
1493
- message.controlFlags = getStreamCloseBackwardsCompat(protocolVersion);
1494
- this.transport.send(from, closeStreamMessage(streamId));
1495
- }
1496
- if (protocolVersion === "v1.1") {
1497
- if (!reqReader.isClosed()) {
1498
- reqReader.triggerClose();
1427
+ const resWritable = new WritableImpl({
1428
+ writeCb: (response) => {
1429
+ sessionScopedSend({
1430
+ streamId,
1431
+ controlFlags: procClosesWithResponse ? getStreamCloseBackwardsCompat(protocolVersion) : 0,
1432
+ payload: response
1433
+ });
1434
+ if (procClosesWithResponse) {
1435
+ resWritable.close();
1436
+ }
1437
+ },
1438
+ // close callback
1439
+ closeCb: () => {
1440
+ if (!procClosesWithResponse && cleanClose) {
1441
+ const message = closeStreamMessage(streamId);
1442
+ message.controlFlags = getStreamCloseBackwardsCompat(protocolVersion);
1443
+ sessionScopedSend(message);
1444
+ }
1445
+ if (protocolVersion === "v1.1") {
1446
+ if (!reqReadable.isClosed()) {
1447
+ closeReadable();
1448
+ }
1449
+ }
1450
+ if (reqReadable.isClosed()) {
1451
+ cleanup();
1499
1452
  }
1500
- }
1501
- if (reqReader.isClosed()) {
1502
- cleanup();
1503
1453
  }
1504
1454
  });
1505
1455
  const onHandlerError = (err, span) => {
1506
1456
  const errorMsg = coerceErrorString(err);
1507
1457
  span.recordException(err instanceof Error ? err : new Error(errorMsg));
1508
1458
  span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
1509
- onServerAbort(
1510
- Err({
1511
- code: UNCAUGHT_ERROR_CODE,
1512
- message: errorMsg
1513
- })
1459
+ this.log?.error(
1460
+ `${serviceName}.${procedureName} handler threw an uncaught error`,
1461
+ {
1462
+ ...loggingMetadata,
1463
+ transportMessage: {
1464
+ procedureName,
1465
+ serviceName
1466
+ },
1467
+ extras: {
1468
+ error: errorMsg
1469
+ }
1470
+ }
1514
1471
  );
1472
+ onServerCancel({
1473
+ code: UNCAUGHT_ERROR_CODE,
1474
+ message: errorMsg
1475
+ });
1515
1476
  };
1516
- if (isStreamCloseBackwardsCompat(controlFlags, protocolVersion)) {
1517
- reqReader.triggerClose();
1477
+ if (procClosesWithInit) {
1478
+ closeReadable();
1518
1479
  } else if (procedure.type === "rpc" || procedure.type === "subscription") {
1519
- this.log?.warn(`${procedure.type} sent an init without a stream close`, {
1520
- ...loggingMetadata,
1521
- clientId: this.transport.clientId
1522
- });
1480
+ this.log?.warn("sent an init without a stream close", loggingMetadata);
1523
1481
  }
1524
- const serviceContextWithTransportInfo = {
1525
- ...this.getContext(service, serviceName),
1482
+ const handlerContext = {
1483
+ ...serviceContext,
1526
1484
  from,
1527
1485
  sessionId,
1528
1486
  metadata: sessionMetadata,
1529
- abortController: handlerAbortController,
1530
- clientAbortSignal: clientAbortController.signal,
1531
- onRequestFinished: (cb) => {
1532
- if (reqReader.isClosed() && resWriter.isClosed()) {
1533
- try {
1534
- cb();
1535
- } catch {
1536
- }
1537
- return;
1538
- }
1539
- onFinishedCallbacks.push(cb);
1540
- }
1487
+ cancel: () => {
1488
+ onServerCancel({
1489
+ code: CANCEL_CODE,
1490
+ message: "cancelled by server procedure handler"
1491
+ });
1492
+ },
1493
+ signal: finishedController.signal
1541
1494
  };
1542
1495
  switch (procedure.type) {
1543
1496
  case "rpc":
@@ -1549,15 +1502,14 @@ var RiverServer = class {
1549
1502
  tracingCtx,
1550
1503
  async (span) => {
1551
1504
  try {
1552
- const outputMessage = await procedure.handler({
1553
- ctx: serviceContextWithTransportInfo,
1505
+ const responsePayload = await procedure.handler({
1506
+ ctx: handlerContext,
1554
1507
  reqInit: initPayload
1555
1508
  });
1556
- if (resWriter.isClosed()) {
1509
+ if (resWritable.isClosed()) {
1557
1510
  return;
1558
1511
  }
1559
- resWriter.write(outputMessage);
1560
- resWriter.close();
1512
+ resWritable.write(responsePayload);
1561
1513
  } catch (err) {
1562
1514
  onHandlerError(err, span);
1563
1515
  } finally {
@@ -1576,10 +1528,10 @@ var RiverServer = class {
1576
1528
  async (span) => {
1577
1529
  try {
1578
1530
  await procedure.handler({
1579
- ctx: serviceContextWithTransportInfo,
1531
+ ctx: handlerContext,
1580
1532
  reqInit: initPayload,
1581
- reqReader,
1582
- resWriter
1533
+ reqReadable,
1534
+ resWritable
1583
1535
  });
1584
1536
  } catch (err) {
1585
1537
  onHandlerError(err, span);
@@ -1599,9 +1551,9 @@ var RiverServer = class {
1599
1551
  async (span) => {
1600
1552
  try {
1601
1553
  await procedure.handler({
1602
- ctx: serviceContextWithTransportInfo,
1603
- reqInit: passInitAsDataForBackwardsCompat ? {} : initPayload,
1604
- resWriter
1554
+ ctx: handlerContext,
1555
+ reqInit: initPayload,
1556
+ resWritable
1605
1557
  });
1606
1558
  } catch (err) {
1607
1559
  onHandlerError(err, span);
@@ -1620,16 +1572,15 @@ var RiverServer = class {
1620
1572
  tracingCtx,
1621
1573
  async (span) => {
1622
1574
  try {
1623
- const outputMessage = await procedure.handler({
1624
- ctx: serviceContextWithTransportInfo,
1625
- reqInit: passInitAsDataForBackwardsCompat ? {} : initPayload,
1626
- reqReader
1575
+ const responsePayload = await procedure.handler({
1576
+ ctx: handlerContext,
1577
+ reqInit: initPayload,
1578
+ reqReadable
1627
1579
  });
1628
- if (resWriter.isClosed()) {
1580
+ if (resWritable.isClosed()) {
1629
1581
  return;
1630
1582
  }
1631
- resWriter.write(outputMessage);
1632
- resWriter.close();
1583
+ resWritable.write(responsePayload);
1633
1584
  } catch (err) {
1634
1585
  onHandlerError(err, span);
1635
1586
  } finally {
@@ -1638,16 +1589,8 @@ var RiverServer = class {
1638
1589
  }
1639
1590
  );
1640
1591
  break;
1641
- default:
1642
- this.log?.error(
1643
- `got request for invalid procedure type ${procedure.type} at ${serviceName}.${procedureName}`,
1644
- {
1645
- ...loggingMetadata,
1646
- tags: ["invariant-violation"]
1647
- }
1648
- );
1649
- return;
1650
1592
  }
1593
+ return procStream;
1651
1594
  }
1652
1595
  getContext(service, serviceName) {
1653
1596
  const context2 = this.contextMap.get(service);
@@ -1664,22 +1607,20 @@ var RiverServer = class {
1664
1607
  validateNewProcStream(initMessage) {
1665
1608
  const session = this.transport.sessions.get(initMessage.from);
1666
1609
  if (!session) {
1667
- const errMessage = `couldn't find a session for ${initMessage.from}`;
1668
1610
  this.log?.error(`couldn't find session for ${initMessage.from}`, {
1669
1611
  clientId: this.transport.clientId,
1670
1612
  transportMessage: initMessage,
1671
1613
  tags: ["invariant-violation"]
1672
1614
  });
1673
- this.abortStream(
1674
- initMessage.from,
1675
- initMessage.streamId,
1676
- Err({
1677
- code: INTERNAL_RIVER_ERROR_CODE,
1678
- message: errMessage
1679
- })
1680
- );
1681
1615
  return null;
1682
1616
  }
1617
+ const sessionScopedSend = this.transport.getSessionBoundSendFn(
1618
+ initMessage.from,
1619
+ session.id
1620
+ );
1621
+ const cancelStream = (streamId, payload) => {
1622
+ this.cancelStream(initMessage.from, sessionScopedSend, streamId, payload);
1623
+ };
1683
1624
  const sessionMetadata = this.transport.sessionHandshakeMetadata.get(
1684
1625
  session.to
1685
1626
  );
@@ -1689,11 +1630,10 @@ var RiverServer = class {
1689
1630
  ...session.loggingMetadata,
1690
1631
  tags: ["invariant-violation"]
1691
1632
  });
1692
- this.abortStream(
1693
- initMessage.from,
1633
+ cancelStream(
1694
1634
  initMessage.streamId,
1695
1635
  Err({
1696
- code: INTERNAL_RIVER_ERROR_CODE,
1636
+ code: UNCAUGHT_ERROR_CODE,
1697
1637
  message: errMessage
1698
1638
  })
1699
1639
  );
@@ -1707,8 +1647,7 @@ var RiverServer = class {
1707
1647
  transportMessage: initMessage,
1708
1648
  tags: ["invalid-request"]
1709
1649
  });
1710
- this.abortStream(
1711
- initMessage.from,
1650
+ cancelStream(
1712
1651
  initMessage.streamId,
1713
1652
  Err({
1714
1653
  code: INVALID_REQUEST_CODE,
@@ -1721,12 +1660,10 @@ var RiverServer = class {
1721
1660
  const errMessage = `missing service name in stream open message`;
1722
1661
  this.log?.warn(errMessage, {
1723
1662
  ...session.loggingMetadata,
1724
- clientId: this.transport.clientId,
1725
1663
  transportMessage: initMessage,
1726
1664
  tags: ["invalid-request"]
1727
1665
  });
1728
- this.abortStream(
1729
- initMessage.from,
1666
+ cancelStream(
1730
1667
  initMessage.streamId,
1731
1668
  Err({
1732
1669
  code: INVALID_REQUEST_CODE,
@@ -1739,12 +1676,10 @@ var RiverServer = class {
1739
1676
  const errMessage = `missing procedure name in stream open message`;
1740
1677
  this.log?.warn(errMessage, {
1741
1678
  ...session.loggingMetadata,
1742
- clientId: this.transport.clientId,
1743
1679
  transportMessage: initMessage,
1744
1680
  tags: ["invalid-request"]
1745
1681
  });
1746
- this.abortStream(
1747
- initMessage.from,
1682
+ cancelStream(
1748
1683
  initMessage.streamId,
1749
1684
  Err({
1750
1685
  code: INVALID_REQUEST_CODE,
@@ -1761,8 +1696,7 @@ var RiverServer = class {
1761
1696
  transportMessage: initMessage,
1762
1697
  tags: ["invalid-request"]
1763
1698
  });
1764
- this.abortStream(
1765
- initMessage.from,
1699
+ cancelStream(
1766
1700
  initMessage.streamId,
1767
1701
  Err({
1768
1702
  code: INVALID_REQUEST_CODE,
@@ -1776,12 +1710,10 @@ var RiverServer = class {
1776
1710
  const errMessage = `couldn't find a matching procedure for ${initMessage.serviceName}.${initMessage.procedureName}`;
1777
1711
  this.log?.warn(errMessage, {
1778
1712
  ...session.loggingMetadata,
1779
- clientId: this.transport.clientId,
1780
1713
  transportMessage: initMessage,
1781
1714
  tags: ["invalid-request"]
1782
1715
  });
1783
- this.abortStream(
1784
- initMessage.from,
1716
+ cancelStream(
1785
1717
  initMessage.streamId,
1786
1718
  Err({
1787
1719
  code: INVALID_REQUEST_CODE,
@@ -1790,7 +1722,19 @@ var RiverServer = class {
1790
1722
  );
1791
1723
  return null;
1792
1724
  }
1725
+ const serviceContext = this.getContext(service, initMessage.serviceName);
1793
1726
  const procedure = service.procedures[initMessage.procedureName];
1727
+ if (!["rpc", "upload", "stream", "subscription"].includes(procedure.type)) {
1728
+ this.log?.error(
1729
+ `got request for invalid procedure type ${procedure.type} at ${initMessage.serviceName}.${initMessage.procedureName}`,
1730
+ {
1731
+ ...session.loggingMetadata,
1732
+ transportMessage: initMessage,
1733
+ tags: ["invariant-violation"]
1734
+ }
1735
+ );
1736
+ return null;
1737
+ }
1794
1738
  let passInitAsDataForBackwardsCompat = false;
1795
1739
  if (session.protocolVersion === "v1.1" && (procedure.type === "upload" || procedure.type === "stream") && import_value2.Value.Check(procedure.requestData, initMessage.payload) && import_value2.Value.Check(procedure.requestInit, {})) {
1796
1740
  passInitAsDataForBackwardsCompat = true;
@@ -1802,8 +1746,7 @@ var RiverServer = class {
1802
1746
  transportMessage: initMessage,
1803
1747
  tags: ["invalid-request"]
1804
1748
  });
1805
- this.abortStream(
1806
- initMessage.from,
1749
+ cancelStream(
1807
1750
  initMessage.streamId,
1808
1751
  Err({
1809
1752
  code: INVALID_REQUEST_CODE,
@@ -1813,37 +1756,33 @@ var RiverServer = class {
1813
1756
  return null;
1814
1757
  }
1815
1758
  return {
1816
- sessionMetadata,
1817
- procedure,
1759
+ initialSession: session,
1760
+ streamId: initMessage.streamId,
1818
1761
  procedureName: initMessage.procedureName,
1819
- service,
1820
1762
  serviceName: initMessage.serviceName,
1821
- loggingMetadata: {
1822
- ...session.loggingMetadata,
1823
- transportMessage: initMessage
1824
- },
1825
- streamId: initMessage.streamId,
1826
- controlFlags: initMessage.controlFlags,
1827
1763
  tracingCtx: initMessage.tracing,
1828
1764
  initPayload: initMessage.payload,
1829
- from: initMessage.from,
1830
- sessionId: session.id,
1831
- protocolVersion: session.protocolVersion,
1765
+ sessionMetadata,
1766
+ procedure,
1767
+ serviceContext,
1768
+ procClosesWithInit: isStreamCloseBackwardsCompat(
1769
+ initMessage.controlFlags,
1770
+ session.protocolVersion
1771
+ ),
1832
1772
  passInitAsDataForBackwardsCompat
1833
1773
  };
1834
1774
  }
1835
- abortStream(to, streamId, payload) {
1836
- let abortedForSession = this.serverAbortedStreams.get(to);
1837
- if (!abortedForSession) {
1838
- abortedForSession = new LRUSet(this.maxAbortedStreamTombstonesPerSession);
1839
- this.serverAbortedStreams.set(to, abortedForSession);
1775
+ cancelStream(to, sessionScopedSend, streamId, payload) {
1776
+ let cancelledStreamsInSession = this.serverCancelledStreams.get(to);
1777
+ if (!cancelledStreamsInSession) {
1778
+ cancelledStreamsInSession = new LRUSet(
1779
+ this.maxCancelledStreamTombstonesPerSession
1780
+ );
1781
+ this.serverCancelledStreams.set(to, cancelledStreamsInSession);
1840
1782
  }
1841
- abortedForSession.add(streamId);
1842
- this.transport.send(
1843
- to,
1844
- // TODO remove once clients migrate to v2
1845
- this.transport.sessions.get(to)?.protocolVersion === "v1.1" ? closeStreamMessage(streamId) : abortMessage(streamId, payload)
1846
- );
1783
+ cancelledStreamsInSession.add(streamId);
1784
+ const msg = cancelMessage(streamId, payload);
1785
+ sessionScopedSend(msg);
1847
1786
  }
1848
1787
  };
1849
1788
  var LRUSet = class {
@@ -1868,21 +1807,21 @@ var LRUSet = class {
1868
1807
  return this.items.has(item);
1869
1808
  }
1870
1809
  };
1871
- function isStreamAbortBackwardsCompat(controlFlags, protocolVersion) {
1810
+ function isStreamCancelBackwardsCompat(controlFlags, protocolVersion) {
1872
1811
  if (protocolVersion === "v1.1") {
1873
1812
  return false;
1874
1813
  }
1875
- return isStreamAbort(controlFlags);
1814
+ return isStreamCancel(controlFlags);
1876
1815
  }
1877
1816
  function isStreamCloseBackwardsCompat(controlFlags, protocolVersion) {
1878
1817
  if (protocolVersion === "v1.1") {
1879
- return isStreamAbort(controlFlags);
1818
+ return isStreamCancel(controlFlags);
1880
1819
  }
1881
1820
  return isStreamClose(controlFlags);
1882
1821
  }
1883
1822
  function getStreamCloseBackwardsCompat(protocolVersion) {
1884
1823
  if (protocolVersion === "v1.1") {
1885
- return 4 /* StreamAbortBit */;
1824
+ return 4 /* StreamCancelBit */;
1886
1825
  }
1887
1826
  return 8 /* StreamClosedBit */;
1888
1827
  }
@@ -1892,7 +1831,7 @@ function createServer(transport, services, providedServerOptions) {
1892
1831
  services,
1893
1832
  providedServerOptions?.handshakeOptions,
1894
1833
  providedServerOptions?.extendedContext,
1895
- providedServerOptions?.maxAbortedStreamTombstonesPerSession
1834
+ providedServerOptions?.maxCancelledStreamTombstonesPerSession
1896
1835
  );
1897
1836
  }
1898
1837
 
@@ -1905,15 +1844,13 @@ function createServerHandshakeOptions(schema, validate) {
1905
1844
  }
1906
1845
  // Annotate the CommonJS export names for ESM import in node:
1907
1846
  0 && (module.exports = {
1908
- ABORT_CODE,
1847
+ CANCEL_CODE,
1909
1848
  Err,
1910
- INTERNAL_RIVER_ERROR_CODE,
1911
1849
  INVALID_REQUEST_CODE,
1912
1850
  Ok,
1913
1851
  Procedure,
1914
1852
  RIVER_VERSION,
1915
- RequestReaderErrorSchema,
1916
- ResponseReaderErrorSchema,
1853
+ ReaderErrorSchema,
1917
1854
  ServiceSchema,
1918
1855
  UNCAUGHT_ERROR_CODE,
1919
1856
  UNEXPECTED_DISCONNECT_CODE,
@@ -1921,6 +1858,9 @@ function createServerHandshakeOptions(schema, validate) {
1921
1858
  createClientHandshakeOptions,
1922
1859
  createServer,
1923
1860
  createServerHandshakeOptions,
1924
- serializeSchema
1861
+ flattenErrorType,
1862
+ serializeSchema,
1863
+ serializeSchemaV1Compat,
1864
+ unwrapOrThrow
1925
1865
  });
1926
1866
  //# sourceMappingURL=index.cjs.map