@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
@@ -1,39 +1,49 @@
1
1
  import {
2
- ABORT_CODE,
3
2
  AnyResultSchema,
3
+ CANCEL_CODE,
4
4
  Err,
5
5
  ErrResultSchema,
6
- INTERNAL_RIVER_ERROR_CODE,
7
6
  INVALID_REQUEST_CODE,
8
7
  Ok,
9
- Procedure,
10
- ReadStreamImpl,
11
- RequestReaderErrorSchema,
12
- ResponseReaderErrorSchema,
8
+ ReadableImpl,
9
+ ReaderErrorSchema,
13
10
  UNCAUGHT_ERROR_CODE,
14
11
  UNEXPECTED_DISCONNECT_CODE,
15
- WriteStreamImpl
16
- } from "../chunk-MQ6ANR3H.js";
12
+ WritableImpl,
13
+ flattenErrorType,
14
+ unwrapOrThrow
15
+ } from "../chunk-Z4PX66JO.js";
17
16
  import {
18
17
  ControlMessageCloseSchema,
19
18
  ControlMessagePayloadSchema,
20
- abortMessage,
19
+ cancelMessage,
21
20
  closeStreamMessage,
22
21
  coerceErrorString,
23
22
  createHandlerSpan,
24
23
  createProcTelemetryInfo,
25
24
  generateId,
26
25
  getPropagationContext,
27
- isStreamAbort,
26
+ isStreamCancel,
28
27
  isStreamClose,
29
- isStreamCloseRequest,
30
28
  isStreamOpen,
31
- requestCloseStreamMessage,
32
29
  version
33
- } from "../chunk-EETL2L77.js";
30
+ } from "../chunk-GJUUVID2.js";
34
31
 
35
32
  // router/services.ts
36
- import { Type } from "@sinclair/typebox";
33
+ import { Type, Kind } from "@sinclair/typebox";
34
+ function serializeSchemaV1Compat(services, handshakeSchema) {
35
+ const serializedServiceObject = Object.entries(services).reduce((acc, [name, value]) => {
36
+ acc[name] = value.serializeV1Compat();
37
+ return acc;
38
+ }, {});
39
+ const schema = {
40
+ services: serializedServiceObject
41
+ };
42
+ if (handshakeSchema) {
43
+ schema.handshakeSchema = Type.Strict(handshakeSchema);
44
+ }
45
+ return schema;
46
+ }
37
47
  function serializeSchema(services, handshakeSchema) {
38
48
  const serializedServiceObject = Object.entries(services).reduce((acc, [name, value]) => {
39
49
  acc[name] = value.serialize();
@@ -148,12 +158,9 @@ var ServiceSchema = class _ServiceSchema {
148
158
  {
149
159
  init: Type.Strict(procDef.requestInit),
150
160
  output: Type.Strict(procDef.responseData),
161
+ errors: getSerializedProcErrors(procDef),
151
162
  // Only add `description` field if the type declares it.
152
163
  ..."description" in procDef ? { description: procDef.description } : {},
153
- // Only add the `errors` field if the type declares it.
154
- ..."responseError" in procDef ? {
155
- errors: Type.Strict(procDef.responseError)
156
- } : {},
157
164
  type: procDef.type,
158
165
  // Only add the `input` field if the type declares it.
159
166
  ..."requestData" in procDef ? {
@@ -170,7 +177,7 @@ var ServiceSchema = class _ServiceSchema {
170
177
  * protocol v1. This is useful to be able to continue to generate schemas for older
171
178
  * clients as they are still supported.
172
179
  */
173
- serializeBackwardsCompatible() {
180
+ serializeV1Compat() {
174
181
  return {
175
182
  procedures: Object.fromEntries(
176
183
  Object.entries(this.procedures).map(
@@ -183,12 +190,9 @@ var ServiceSchema = class _ServiceSchema {
183
190
  // this is the only change needed to make it compatible.
184
191
  input: Type.Strict(procDef.requestInit),
185
192
  output: Type.Strict(procDef.responseData),
193
+ errors: getSerializedProcErrors(procDef),
186
194
  // Only add `description` field if the type declares it.
187
195
  ..."description" in procDef ? { description: procDef.description } : {},
188
- // Only add the `errors` field if the type declares it.
189
- ..."responseError" in procDef ? {
190
- errors: Type.Strict(procDef.responseError)
191
- } : {},
192
196
  type: procDef.type
193
197
  }
194
198
  ];
@@ -198,12 +202,9 @@ var ServiceSchema = class _ServiceSchema {
198
202
  {
199
203
  init: Type.Strict(procDef.requestInit),
200
204
  output: Type.Strict(procDef.responseData),
205
+ errors: getSerializedProcErrors(procDef),
201
206
  // Only add `description` field if the type declares it.
202
207
  ..."description" in procDef ? { description: procDef.description } : {},
203
- // Only add the `errors` field if the type declares it.
204
- ..."responseError" in procDef ? {
205
- errors: Type.Strict(procDef.responseError)
206
- } : {},
207
208
  type: procDef.type,
208
209
  input: Type.Strict(procDef.requestData)
209
210
  }
@@ -226,6 +227,15 @@ var ServiceSchema = class _ServiceSchema {
226
227
  });
227
228
  }
228
229
  };
230
+ function getSerializedProcErrors(procDef) {
231
+ if (!("responseError" in procDef) || procDef.responseError[Kind] === "Never") {
232
+ return Type.Strict(ReaderErrorSchema);
233
+ }
234
+ const withProtocolErrors = flattenErrorType(
235
+ Type.Union([procDef.responseError, ReaderErrorSchema])
236
+ );
237
+ return Type.Strict(withProtocolErrors);
238
+ }
229
239
  var ServiceScaffold = class {
230
240
  /**
231
241
  * The configuration for this service.
@@ -283,9 +293,86 @@ var ServiceScaffold = class {
283
293
  }
284
294
  };
285
295
 
296
+ // router/procedures.ts
297
+ import { Type as Type2 } from "@sinclair/typebox";
298
+ function rpc({
299
+ requestInit,
300
+ responseData,
301
+ responseError = Type2.Never(),
302
+ description,
303
+ handler
304
+ }) {
305
+ return {
306
+ ...description ? { description } : {},
307
+ type: "rpc",
308
+ requestInit,
309
+ responseData,
310
+ responseError,
311
+ handler
312
+ };
313
+ }
314
+ function upload({
315
+ requestInit,
316
+ requestData,
317
+ responseData,
318
+ responseError = Type2.Never(),
319
+ description,
320
+ handler
321
+ }) {
322
+ return {
323
+ type: "upload",
324
+ ...description ? { description } : {},
325
+ requestInit,
326
+ requestData,
327
+ responseData,
328
+ responseError,
329
+ handler
330
+ };
331
+ }
332
+ function subscription({
333
+ requestInit,
334
+ responseData,
335
+ responseError = Type2.Never(),
336
+ description,
337
+ handler
338
+ }) {
339
+ return {
340
+ type: "subscription",
341
+ ...description ? { description } : {},
342
+ requestInit,
343
+ responseData,
344
+ responseError,
345
+ handler
346
+ };
347
+ }
348
+ function stream({
349
+ requestInit,
350
+ requestData,
351
+ responseData,
352
+ responseError = Type2.Never(),
353
+ description,
354
+ handler
355
+ }) {
356
+ return {
357
+ type: "stream",
358
+ ...description ? { description } : {},
359
+ requestInit,
360
+ requestData,
361
+ responseData,
362
+ responseError,
363
+ handler
364
+ };
365
+ }
366
+ var Procedure = {
367
+ rpc,
368
+ upload,
369
+ subscription,
370
+ stream
371
+ };
372
+
286
373
  // router/client.ts
287
374
  import { Value } from "@sinclair/typebox/value";
288
- var OutputErrResultSchema = ErrResultSchema(ResponseReaderErrorSchema);
375
+ var ReaderErrResultSchema = ErrResultSchema(ReaderErrorSchema);
289
376
  var noop = () => {
290
377
  };
291
378
  function _createRecursiveProxy(callback, path) {
@@ -346,6 +433,11 @@ function createClient(transport, serverId, providedClientOptions = {}) {
346
433
  }, []);
347
434
  }
348
435
  function handleProc(procType, transport, serverId, init, serviceName, procedureName, abortSignal) {
436
+ const session = transport.sessions.get(serverId) ?? transport.createUnconnectedSession(serverId);
437
+ const sessionScopedSend = transport.getSessionBoundSendFn(
438
+ serverId,
439
+ session.id
440
+ );
349
441
  const procClosesWithInit = procType === "rpc" || procType === "subscription";
350
442
  const streamId = generateId();
351
443
  const { span, ctx } = createProcTelemetryInfo(
@@ -356,61 +448,61 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
356
448
  streamId
357
449
  );
358
450
  let cleanClose = true;
359
- const reqWriter = new WriteStreamImpl((rawIn) => {
360
- transport.send(serverId, {
361
- streamId,
362
- payload: rawIn,
363
- controlFlags: 0,
364
- tracing: getPropagationContext(ctx)
365
- });
366
- });
367
- reqWriter.onClose(() => {
368
- span.addEvent("reqWriter closed");
369
- if (!procClosesWithInit && cleanClose) {
370
- transport.send(serverId, closeStreamMessage(streamId));
371
- }
372
- if (resReader.isClosed()) {
373
- cleanup();
451
+ const reqWritable = new WritableImpl({
452
+ writeCb: (rawIn) => {
453
+ sessionScopedSend({
454
+ streamId,
455
+ payload: rawIn,
456
+ controlFlags: 0
457
+ });
458
+ },
459
+ // close callback
460
+ closeCb: () => {
461
+ span.addEvent("reqWritable closed");
462
+ if (!procClosesWithInit && cleanClose) {
463
+ sessionScopedSend(closeStreamMessage(streamId));
464
+ }
465
+ if (resReadable.isClosed()) {
466
+ cleanup();
467
+ }
374
468
  }
375
469
  });
376
- const resReader = new ReadStreamImpl(() => {
377
- transport.send(serverId, requestCloseStreamMessage(streamId));
378
- });
379
- resReader.onClose(() => {
380
- span.addEvent("resReader closed");
381
- if (reqWriter.isClosed()) {
470
+ const resReadable = new ReadableImpl();
471
+ const closeReadable = () => {
472
+ resReadable._triggerClose();
473
+ span.addEvent("resReadable closed");
474
+ if (reqWritable.isClosed()) {
382
475
  cleanup();
383
476
  }
384
- });
477
+ };
385
478
  function cleanup() {
386
479
  transport.removeEventListener("message", onMessage);
387
480
  transport.removeEventListener("sessionStatus", onSessionStatus);
388
- abortSignal?.removeEventListener("abort", onClientAbort);
481
+ abortSignal?.removeEventListener("abort", onClientCancel);
389
482
  span.end();
390
483
  }
391
- function onClientAbort() {
392
- if (resReader.isClosed() && reqWriter.isClosed()) {
484
+ function onClientCancel() {
485
+ if (resReadable.isClosed() && reqWritable.isClosed()) {
393
486
  return;
394
487
  }
395
- span.addEvent("sending abort");
488
+ span.addEvent("sending cancel");
396
489
  cleanClose = false;
397
- if (!resReader.isClosed()) {
398
- resReader.pushValue(
490
+ if (!resReadable.isClosed()) {
491
+ resReadable._pushValue(
399
492
  Err({
400
- code: ABORT_CODE,
401
- message: "Aborted by client"
493
+ code: CANCEL_CODE,
494
+ message: "cancelled by client"
402
495
  })
403
496
  );
404
- resReader.triggerClose();
497
+ closeReadable();
405
498
  }
406
- reqWriter.close();
407
- transport.send(
408
- serverId,
409
- abortMessage(
499
+ reqWritable.close();
500
+ sessionScopedSend(
501
+ cancelMessage(
410
502
  streamId,
411
503
  Err({
412
- code: ABORT_CODE,
413
- message: "Aborted by client"
504
+ code: CANCEL_CODE,
505
+ message: "cancelled by client"
414
506
  })
415
507
  )
416
508
  );
@@ -419,47 +511,44 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
419
511
  if (msg.streamId !== streamId)
420
512
  return;
421
513
  if (msg.to !== transport.clientId) {
422
- transport.log?.error("Got stream message from unexpected client", {
514
+ transport.log?.error("got stream message from unexpected client", {
423
515
  clientId: transport.clientId,
424
516
  transportMessage: msg
425
517
  });
426
518
  return;
427
519
  }
428
- if (isStreamCloseRequest(msg.controlFlags)) {
429
- reqWriter.triggerCloseRequest();
430
- }
431
- if (isStreamAbort(msg.controlFlags)) {
520
+ if (isStreamCancel(msg.controlFlags)) {
432
521
  cleanClose = false;
433
- span.addEvent("received abort");
434
- let abortResult;
435
- if (Value.Check(OutputErrResultSchema, msg.payload)) {
436
- abortResult = msg.payload;
522
+ span.addEvent("received cancel");
523
+ let cancelResult;
524
+ if (Value.Check(ReaderErrResultSchema, msg.payload)) {
525
+ cancelResult = msg.payload;
437
526
  } else {
438
- abortResult = Err({
439
- code: ABORT_CODE,
440
- message: "Stream aborted with invalid payload"
527
+ cancelResult = Err({
528
+ code: CANCEL_CODE,
529
+ message: "stream cancelled with invalid payload"
441
530
  });
442
531
  transport.log?.error(
443
- "Got stream abort without a valid protocol error",
532
+ "got stream cancel without a valid protocol error",
444
533
  {
445
534
  clientId: transport.clientId,
446
535
  transportMessage: msg,
447
536
  validationErrors: [
448
- ...Value.Errors(OutputErrResultSchema, msg.payload)
537
+ ...Value.Errors(ReaderErrResultSchema, msg.payload)
449
538
  ]
450
539
  }
451
540
  );
452
541
  }
453
- if (!resReader.isClosed()) {
454
- resReader.pushValue(abortResult);
455
- resReader.triggerClose();
542
+ if (!resReadable.isClosed()) {
543
+ resReadable._pushValue(cancelResult);
544
+ closeReadable();
456
545
  }
457
- reqWriter.close();
546
+ reqWritable.close();
458
547
  return;
459
548
  }
460
- if (resReader.isClosed()) {
461
- span.recordException("Received message after output stream is closed");
462
- transport.log?.error("Received message after output stream is closed", {
549
+ if (resReadable.isClosed()) {
550
+ span.recordException("received message after response stream is closed");
551
+ transport.log?.error("received message after response stream is closed", {
463
552
  clientId: transport.clientId,
464
553
  transportMessage: msg
465
554
  });
@@ -467,7 +556,7 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
467
556
  }
468
557
  if (!Value.Check(ControlMessageCloseSchema, msg.payload)) {
469
558
  if (Value.Check(AnyResultSchema, msg.payload)) {
470
- resReader.pushValue(msg.payload);
559
+ resReadable._pushValue(msg.payload);
471
560
  } else {
472
561
  transport.log?.error(
473
562
  "Got non-control payload, but was not a valid result",
@@ -480,33 +569,36 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
480
569
  }
481
570
  }
482
571
  if (isStreamClose(msg.controlFlags)) {
483
- span.addEvent("received output close");
484
- resReader.triggerClose();
572
+ span.addEvent("received response close");
573
+ if (resReadable.isClosed()) {
574
+ transport.log?.error(
575
+ "received stream close but readable was already closed"
576
+ );
577
+ } else {
578
+ closeReadable();
579
+ }
485
580
  }
486
581
  }
487
582
  function onSessionStatus(evt) {
488
- if (evt.status !== "disconnect") {
489
- return;
490
- }
491
- if (evt.session.to !== serverId) {
583
+ if (evt.status !== "disconnect" || evt.session.to !== serverId || session.id !== evt.session.id) {
492
584
  return;
493
585
  }
494
586
  cleanClose = false;
495
- if (!resReader.isClosed()) {
496
- resReader.pushValue(
587
+ if (!resReadable.isClosed()) {
588
+ resReadable._pushValue(
497
589
  Err({
498
590
  code: UNEXPECTED_DISCONNECT_CODE,
499
591
  message: `${serverId} unexpectedly disconnected`
500
592
  })
501
593
  );
594
+ closeReadable();
502
595
  }
503
- reqWriter.close();
504
- resReader.triggerClose();
596
+ reqWritable.close();
505
597
  }
506
- abortSignal?.addEventListener("abort", onClientAbort);
598
+ abortSignal?.addEventListener("abort", onClientCancel);
507
599
  transport.addEventListener("message", onMessage);
508
600
  transport.addEventListener("sessionStatus", onSessionStatus);
509
- transport.send(serverId, {
601
+ sessionScopedSend({
510
602
  streamId,
511
603
  serviceName,
512
604
  procedureName,
@@ -515,34 +607,39 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
515
607
  controlFlags: procClosesWithInit ? 2 /* StreamOpenBit */ | 8 /* StreamClosedBit */ : 2 /* StreamOpenBit */
516
608
  });
517
609
  if (procClosesWithInit) {
518
- reqWriter.close();
610
+ reqWritable.close();
519
611
  }
520
612
  if (procType === "subscription") {
521
- return { resReader };
613
+ return {
614
+ resReadable
615
+ };
522
616
  }
523
617
  if (procType === "rpc") {
524
- return getSingleMessage(resReader, transport.log);
618
+ return getSingleMessage(resReadable, transport.log);
525
619
  }
526
620
  if (procType === "upload") {
527
621
  let didFinalize = false;
528
622
  return {
529
- reqWriter,
530
- async finalize() {
623
+ reqWritable,
624
+ finalize: () => {
531
625
  if (didFinalize) {
532
626
  throw new Error("upload stream already finalized");
533
627
  }
534
628
  didFinalize = true;
535
- if (!reqWriter.isClosed()) {
536
- reqWriter.close();
629
+ if (!reqWritable.isClosed()) {
630
+ reqWritable.close();
537
631
  }
538
- return getSingleMessage(resReader, transport.log);
632
+ return getSingleMessage(resReadable, transport.log);
539
633
  }
540
634
  };
541
635
  }
542
- return { reqWriter, resReader };
636
+ return {
637
+ resReadable,
638
+ reqWritable
639
+ };
543
640
  }
544
- async function getSingleMessage(resReader, log) {
545
- const ret = await resReader.asArray();
641
+ async function getSingleMessage(resReadable, log) {
642
+ const ret = await resReadable.collect();
546
643
  if (ret.length > 1) {
547
644
  log?.error("Expected single message from server, got multiple");
548
645
  }
@@ -550,25 +647,31 @@ async function getSingleMessage(resReader, log) {
550
647
  }
551
648
 
552
649
  // router/server.ts
650
+ import { Type as Type3 } from "@sinclair/typebox";
553
651
  import { Value as Value2 } from "@sinclair/typebox/value";
554
652
  import { SpanStatusCode } from "@opentelemetry/api";
555
- var InputErrResultSchema = ErrResultSchema(RequestReaderErrorSchema);
653
+ var CancelResultSchema = ErrResultSchema(
654
+ Type3.Object({
655
+ code: Type3.Literal(CANCEL_CODE),
656
+ message: Type3.String()
657
+ })
658
+ );
556
659
  var RiverServer = class {
557
660
  transport;
558
661
  contextMap;
559
662
  log;
560
663
  /**
561
- * We create a tombstones for streams aborted by the server
664
+ * We create a tombstones for streams cancelled by the server
562
665
  * so that we don't hit errors when the client has inflight
563
- * requests it sent before it saw the abort.
564
- * We track aborted streams for every session separately, so
666
+ * requests it sent before it saw the cancel.
667
+ * We track cancelled streams for every client separately, so
565
668
  * that bad clients don't affect good clients.
566
669
  */
567
- serverAbortedStreams;
568
- maxAbortedStreamTombstonesPerSession;
569
- openStreams;
670
+ serverCancelledStreams;
671
+ maxCancelledStreamTombstonesPerSession;
672
+ streams;
570
673
  services;
571
- constructor(transport, services, handshakeOptions, extendedContext, maxAbortedStreamTombstonesPerSession = 200) {
674
+ constructor(transport, services, handshakeOptions, extendedContext, maxCancelledStreamTombstonesPerSession = 200) {
572
675
  const instances = {};
573
676
  this.services = instances;
574
677
  this.contextMap = /* @__PURE__ */ new Map();
@@ -584,34 +687,40 @@ var RiverServer = class {
584
687
  transport.extendHandshake(handshakeOptions);
585
688
  }
586
689
  this.transport = transport;
587
- this.openStreams = /* @__PURE__ */ new Set();
588
- this.serverAbortedStreams = /* @__PURE__ */ new Map();
589
- this.maxAbortedStreamTombstonesPerSession = maxAbortedStreamTombstonesPerSession;
690
+ this.streams = /* @__PURE__ */ new Map();
691
+ this.serverCancelledStreams = /* @__PURE__ */ new Map();
692
+ this.maxCancelledStreamTombstonesPerSession = maxCancelledStreamTombstonesPerSession;
590
693
  this.log = transport.log;
591
- const handleMessage = (msg) => {
592
- if (msg.to !== this.transport.clientId) {
694
+ const handleCreatingNewStreams = (message) => {
695
+ if (message.to !== this.transport.clientId) {
593
696
  this.log?.info(
594
697
  `got msg with destination that isn't this server, ignoring`,
595
698
  {
596
699
  clientId: this.transport.clientId,
597
- transportMessage: msg
700
+ transportMessage: message
598
701
  }
599
702
  );
600
703
  return;
601
704
  }
602
- if (this.openStreams.has(msg.streamId)) {
705
+ const streamId = message.streamId;
706
+ const stream2 = this.streams.get(streamId);
707
+ if (stream2) {
708
+ stream2.handleMsg(message);
603
709
  return;
604
710
  }
605
- if (this.serverAbortedStreams.get(msg.from)?.has(msg.streamId)) {
711
+ if (this.serverCancelledStreams.get(message.from)?.has(streamId)) {
606
712
  return;
607
713
  }
608
- const validated = this.validateNewProcStream(msg);
609
- if (!validated) {
714
+ const newStreamProps = this.validateNewProcStream(message);
715
+ if (!newStreamProps) {
610
716
  return;
611
717
  }
612
- this.createNewProcStream(validated);
718
+ const newStream = this.createNewProcStream({
719
+ ...newStreamProps,
720
+ ...message
721
+ });
722
+ this.streams.set(streamId, newStream);
613
723
  };
614
- this.transport.addEventListener("message", handleMessage);
615
724
  const handleSessionStatus = (evt) => {
616
725
  if (evt.status !== "disconnect")
617
726
  return;
@@ -620,256 +729,258 @@ var RiverServer = class {
620
729
  `got session disconnect from ${disconnectedClientId}, cleaning up streams`,
621
730
  evt.session.loggingMetadata
622
731
  );
623
- this.serverAbortedStreams.delete(disconnectedClientId);
732
+ for (const stream2 of this.streams.values()) {
733
+ if (stream2.from === disconnectedClientId) {
734
+ stream2.handleSessionDisconnect();
735
+ }
736
+ }
737
+ this.serverCancelledStreams.delete(disconnectedClientId);
624
738
  };
625
- this.transport.addEventListener("sessionStatus", handleSessionStatus);
626
- this.transport.addEventListener("transportStatus", (evt) => {
739
+ const handleTransportStatus = (evt) => {
627
740
  if (evt.status !== "closed")
628
741
  return;
629
- this.transport.removeEventListener("message", handleMessage);
742
+ this.transport.removeEventListener("message", handleCreatingNewStreams);
630
743
  this.transport.removeEventListener("sessionStatus", handleSessionStatus);
631
- });
632
- }
633
- createNewProcStream({
634
- procedure,
635
- procedureName,
636
- service,
637
- serviceName,
638
- sessionMetadata,
639
- loggingMetadata,
640
- streamId,
641
- controlFlags,
642
- initPayload,
643
- from,
644
- sessionId,
645
- tracingCtx,
646
- protocolVersion,
647
- passInitAsDataForBackwardsCompat
648
- }) {
649
- this.openStreams.add(streamId);
650
- let cleanClose = true;
651
- const onServerAbort = (errResult) => {
652
- if (reqReader.isClosed() && resWriter.isClosed()) {
653
- return;
654
- }
655
- cleanClose = false;
656
- if (!reqReader.isClosed()) {
657
- reqReader.pushValue(errResult);
658
- reqReader.triggerClose();
659
- }
660
- resWriter.close();
661
- this.abortStream(from, streamId, errResult);
662
- };
663
- const onHandlerAbort = () => {
664
- onServerAbort(
665
- Err({
666
- code: ABORT_CODE,
667
- message: "Aborted by server procedure handler"
668
- })
744
+ this.transport.removeEventListener(
745
+ "transportStatus",
746
+ handleTransportStatus
669
747
  );
670
748
  };
671
- const handlerAbortController = new AbortController();
672
- handlerAbortController.signal.addEventListener("abort", onHandlerAbort);
673
- const clientAbortController = new AbortController();
674
- const onSessionStatus = (evt) => {
675
- if (evt.status !== "disconnect") {
676
- return;
677
- }
678
- if (evt.session.to !== from) {
679
- return;
680
- }
681
- cleanClose = false;
682
- const errPayload = {
683
- code: UNEXPECTED_DISCONNECT_CODE,
684
- message: `client unexpectedly disconnected`
685
- };
686
- if (!reqReader.isClosed()) {
687
- reqReader.pushValue(Err(errPayload));
688
- reqReader.triggerClose();
689
- }
690
- clientAbortController.abort(errPayload);
691
- resWriter.close();
692
- };
693
- this.transport.addEventListener("sessionStatus", onSessionStatus);
749
+ this.transport.addEventListener("message", handleCreatingNewStreams);
750
+ this.transport.addEventListener("sessionStatus", handleSessionStatus);
751
+ this.transport.addEventListener("transportStatus", handleTransportStatus);
752
+ }
753
+ createNewProcStream(props) {
754
+ const {
755
+ streamId,
756
+ initialSession,
757
+ procedureName,
758
+ serviceName,
759
+ procedure,
760
+ sessionMetadata,
761
+ serviceContext,
762
+ initPayload,
763
+ tracingCtx,
764
+ procClosesWithInit,
765
+ passInitAsDataForBackwardsCompat
766
+ } = props;
767
+ const {
768
+ to: from,
769
+ loggingMetadata,
770
+ protocolVersion,
771
+ id: sessionId
772
+ } = initialSession;
773
+ let cleanClose = true;
694
774
  const onMessage = (msg) => {
695
- if (streamId !== msg.streamId) {
696
- return;
697
- }
698
775
  if (msg.from !== from) {
699
- this.log?.error("Got stream message from unexpected client", {
776
+ this.log?.error("got stream message from unexpected client", {
700
777
  ...loggingMetadata,
701
- clientId: this.transport.clientId,
702
778
  transportMessage: msg,
703
779
  tags: ["invariant-violation"]
704
780
  });
705
781
  return;
706
782
  }
707
- if (isStreamCloseRequest(msg.controlFlags)) {
708
- resWriter.triggerCloseRequest();
709
- }
710
- if (isStreamAbortBackwardsCompat(msg.controlFlags, protocolVersion)) {
711
- let abortResult;
712
- if (Value2.Check(InputErrResultSchema, msg.payload)) {
713
- abortResult = msg.payload;
783
+ if (isStreamCancelBackwardsCompat(msg.controlFlags, protocolVersion)) {
784
+ let cancelResult;
785
+ if (Value2.Check(CancelResultSchema, msg.payload)) {
786
+ cancelResult = msg.payload;
714
787
  } else {
715
- abortResult = Err({
716
- code: ABORT_CODE,
717
- message: "Stream aborted, client sent invalid payload"
788
+ cancelResult = Err({
789
+ code: CANCEL_CODE,
790
+ message: "stream cancelled, client sent invalid payload"
718
791
  });
719
- this.log?.warn("Got stream abort without a valid protocol error", {
792
+ this.log?.warn("got stream cancel without a valid protocol error", {
720
793
  ...loggingMetadata,
721
- clientId: this.transport.clientId,
722
794
  transportMessage: msg,
723
795
  validationErrors: [
724
- ...Value2.Errors(InputErrResultSchema, msg.payload)
796
+ ...Value2.Errors(CancelResultSchema, msg.payload)
725
797
  ],
726
798
  tags: ["invalid-request"]
727
799
  });
728
800
  }
729
- if (!reqReader.isClosed()) {
730
- reqReader.pushValue(abortResult);
731
- reqReader.triggerClose();
801
+ if (!reqReadable.isClosed()) {
802
+ reqReadable._pushValue(cancelResult);
803
+ closeReadable();
732
804
  }
733
- resWriter.close();
734
- clientAbortController.abort(abortResult.payload);
805
+ resWritable.close();
735
806
  return;
736
807
  }
737
- if (reqReader.isClosed()) {
738
- this.log?.warn("Received message after input stream is closed", {
808
+ if (reqReadable.isClosed()) {
809
+ this.log?.warn("received message after request stream is closed", {
739
810
  ...loggingMetadata,
740
- clientId: this.transport.clientId,
741
811
  transportMessage: msg,
742
812
  tags: ["invalid-request"]
743
813
  });
744
- onServerAbort(
745
- Err({
746
- code: INVALID_REQUEST_CODE,
747
- message: "Received message after input stream is closed"
748
- })
749
- );
814
+ onServerCancel({
815
+ code: INVALID_REQUEST_CODE,
816
+ message: "received message after request stream is closed"
817
+ });
750
818
  return;
751
819
  }
752
820
  if ("requestData" in procedure && Value2.Check(procedure.requestData, msg.payload)) {
753
- reqReader.pushValue(Ok(msg.payload));
754
- } else if (!Value2.Check(ControlMessagePayloadSchema, msg.payload)) {
755
- const validationErrors = [
821
+ reqReadable._pushValue(Ok(msg.payload));
822
+ if (isStreamCloseBackwardsCompat(msg.controlFlags, protocolVersion)) {
823
+ closeReadable();
824
+ }
825
+ return;
826
+ }
827
+ if (Value2.Check(ControlMessagePayloadSchema, msg.payload) && isStreamCloseBackwardsCompat(msg.controlFlags, protocolVersion)) {
828
+ closeReadable();
829
+ return;
830
+ }
831
+ let validationErrors;
832
+ let errMessage;
833
+ if ("requestData" in procedure) {
834
+ errMessage = "expected requestData or control payload";
835
+ validationErrors = [
836
+ ...Value2.Errors(procedure.responseData, msg.payload)
837
+ ];
838
+ } else {
839
+ validationErrors = [
756
840
  ...Value2.Errors(ControlMessagePayloadSchema, msg.payload)
757
841
  ];
758
- let errMessage = "Expected control payload for procedure with no input";
759
- if ("requestData" in procedure) {
760
- errMessage = "Expected either control or input payload, validation failed for both";
761
- validationErrors.push(
762
- ...Value2.Errors(procedure.responseData, msg.payload)
763
- );
842
+ errMessage = "expected control payload";
843
+ }
844
+ this.log?.warn(errMessage, {
845
+ ...loggingMetadata,
846
+ transportMessage: msg,
847
+ validationErrors,
848
+ tags: ["invalid-request"]
849
+ });
850
+ onServerCancel({
851
+ code: INVALID_REQUEST_CODE,
852
+ message: errMessage
853
+ });
854
+ };
855
+ const procStream = {
856
+ from,
857
+ streamId,
858
+ procedureName,
859
+ serviceName,
860
+ sessionMetadata,
861
+ procedure,
862
+ handleMsg: onMessage,
863
+ handleSessionDisconnect: () => {
864
+ cleanClose = false;
865
+ const errPayload = {
866
+ code: UNEXPECTED_DISCONNECT_CODE,
867
+ message: "client unexpectedly disconnected"
868
+ };
869
+ if (!reqReadable.isClosed()) {
870
+ reqReadable._pushValue(Err(errPayload));
871
+ closeReadable();
764
872
  }
765
- this.log?.warn(errMessage, {
766
- ...loggingMetadata,
767
- clientId: this.transport.clientId,
768
- transportMessage: msg,
769
- validationErrors,
770
- tags: ["invalid-request"]
771
- });
772
- onServerAbort(
773
- Err({
774
- code: INVALID_REQUEST_CODE,
775
- message: errMessage
776
- })
777
- );
873
+ resWritable.close();
778
874
  }
779
- if (isStreamCloseBackwardsCompat(msg.controlFlags, protocolVersion)) {
780
- reqReader.triggerClose();
875
+ };
876
+ const sessionScopedSend = this.transport.getSessionBoundSendFn(
877
+ from,
878
+ sessionId
879
+ );
880
+ const cancelStream = (streamId2, payload) => {
881
+ this.cancelStream(from, sessionScopedSend, streamId2, payload);
882
+ };
883
+ const onServerCancel = (e) => {
884
+ if (reqReadable.isClosed() && resWritable.isClosed()) {
885
+ return;
886
+ }
887
+ cleanClose = false;
888
+ const result = Err(e);
889
+ if (!reqReadable.isClosed()) {
890
+ reqReadable._pushValue(result);
891
+ closeReadable();
781
892
  }
893
+ resWritable.close();
894
+ cancelStream(streamId, result);
782
895
  };
783
- this.transport.addEventListener("message", onMessage);
784
- const onFinishedCallbacks = [];
896
+ const finishedController = new AbortController();
785
897
  const cleanup = () => {
786
- this.transport.removeEventListener("message", onMessage);
787
- this.transport.removeEventListener("sessionStatus", onSessionStatus);
788
- handlerAbortController.signal.addEventListener("abort", onHandlerAbort);
789
- this.openStreams.delete(streamId);
790
- onFinishedCallbacks.forEach((cb) => {
791
- try {
792
- cb();
793
- } catch {
794
- }
795
- });
796
- onFinishedCallbacks.length = 0;
898
+ finishedController.abort();
899
+ this.streams.delete(streamId);
797
900
  };
798
901
  const procClosesWithResponse = procedure.type === "rpc" || procedure.type === "upload";
799
- const reqReader = new ReadStreamImpl(() => {
800
- this.transport.send(from, requestCloseStreamMessage(streamId));
801
- });
802
- reqReader.onClose(() => {
902
+ const reqReadable = new ReadableImpl();
903
+ const closeReadable = () => {
904
+ reqReadable._triggerClose();
803
905
  if (protocolVersion === "v1.1") {
804
- if (!procClosesWithResponse && !resWriter.isClosed()) {
805
- resWriter.close();
906
+ if (!procClosesWithResponse && !resWritable.isClosed()) {
907
+ resWritable.close();
806
908
  }
807
909
  }
808
- if (resWriter.isClosed()) {
910
+ if (resWritable.isClosed()) {
809
911
  cleanup();
810
912
  }
811
- });
913
+ };
812
914
  if (passInitAsDataForBackwardsCompat) {
813
- reqReader.pushValue(Ok(initPayload));
915
+ reqReadable._pushValue(Ok(initPayload));
814
916
  }
815
- const resWriter = new WriteStreamImpl((response) => {
816
- this.transport.send(from, {
817
- streamId,
818
- controlFlags: procClosesWithResponse ? getStreamCloseBackwardsCompat(protocolVersion) : 0,
819
- payload: response
820
- });
821
- });
822
- resWriter.onClose(() => {
823
- if (!procClosesWithResponse && cleanClose) {
824
- const message = closeStreamMessage(streamId);
825
- message.controlFlags = getStreamCloseBackwardsCompat(protocolVersion);
826
- this.transport.send(from, closeStreamMessage(streamId));
827
- }
828
- if (protocolVersion === "v1.1") {
829
- if (!reqReader.isClosed()) {
830
- reqReader.triggerClose();
917
+ const resWritable = new WritableImpl({
918
+ writeCb: (response) => {
919
+ sessionScopedSend({
920
+ streamId,
921
+ controlFlags: procClosesWithResponse ? getStreamCloseBackwardsCompat(protocolVersion) : 0,
922
+ payload: response
923
+ });
924
+ if (procClosesWithResponse) {
925
+ resWritable.close();
926
+ }
927
+ },
928
+ // close callback
929
+ closeCb: () => {
930
+ if (!procClosesWithResponse && cleanClose) {
931
+ const message = closeStreamMessage(streamId);
932
+ message.controlFlags = getStreamCloseBackwardsCompat(protocolVersion);
933
+ sessionScopedSend(message);
934
+ }
935
+ if (protocolVersion === "v1.1") {
936
+ if (!reqReadable.isClosed()) {
937
+ closeReadable();
938
+ }
939
+ }
940
+ if (reqReadable.isClosed()) {
941
+ cleanup();
831
942
  }
832
- }
833
- if (reqReader.isClosed()) {
834
- cleanup();
835
943
  }
836
944
  });
837
945
  const onHandlerError = (err, span) => {
838
946
  const errorMsg = coerceErrorString(err);
839
947
  span.recordException(err instanceof Error ? err : new Error(errorMsg));
840
948
  span.setStatus({ code: SpanStatusCode.ERROR });
841
- onServerAbort(
842
- Err({
843
- code: UNCAUGHT_ERROR_CODE,
844
- message: errorMsg
845
- })
949
+ this.log?.error(
950
+ `${serviceName}.${procedureName} handler threw an uncaught error`,
951
+ {
952
+ ...loggingMetadata,
953
+ transportMessage: {
954
+ procedureName,
955
+ serviceName
956
+ },
957
+ extras: {
958
+ error: errorMsg
959
+ }
960
+ }
846
961
  );
962
+ onServerCancel({
963
+ code: UNCAUGHT_ERROR_CODE,
964
+ message: errorMsg
965
+ });
847
966
  };
848
- if (isStreamCloseBackwardsCompat(controlFlags, protocolVersion)) {
849
- reqReader.triggerClose();
967
+ if (procClosesWithInit) {
968
+ closeReadable();
850
969
  } else if (procedure.type === "rpc" || procedure.type === "subscription") {
851
- this.log?.warn(`${procedure.type} sent an init without a stream close`, {
852
- ...loggingMetadata,
853
- clientId: this.transport.clientId
854
- });
970
+ this.log?.warn("sent an init without a stream close", loggingMetadata);
855
971
  }
856
- const serviceContextWithTransportInfo = {
857
- ...this.getContext(service, serviceName),
972
+ const handlerContext = {
973
+ ...serviceContext,
858
974
  from,
859
975
  sessionId,
860
976
  metadata: sessionMetadata,
861
- abortController: handlerAbortController,
862
- clientAbortSignal: clientAbortController.signal,
863
- onRequestFinished: (cb) => {
864
- if (reqReader.isClosed() && resWriter.isClosed()) {
865
- try {
866
- cb();
867
- } catch {
868
- }
869
- return;
870
- }
871
- onFinishedCallbacks.push(cb);
872
- }
977
+ cancel: () => {
978
+ onServerCancel({
979
+ code: CANCEL_CODE,
980
+ message: "cancelled by server procedure handler"
981
+ });
982
+ },
983
+ signal: finishedController.signal
873
984
  };
874
985
  switch (procedure.type) {
875
986
  case "rpc":
@@ -881,15 +992,14 @@ var RiverServer = class {
881
992
  tracingCtx,
882
993
  async (span) => {
883
994
  try {
884
- const outputMessage = await procedure.handler({
885
- ctx: serviceContextWithTransportInfo,
995
+ const responsePayload = await procedure.handler({
996
+ ctx: handlerContext,
886
997
  reqInit: initPayload
887
998
  });
888
- if (resWriter.isClosed()) {
999
+ if (resWritable.isClosed()) {
889
1000
  return;
890
1001
  }
891
- resWriter.write(outputMessage);
892
- resWriter.close();
1002
+ resWritable.write(responsePayload);
893
1003
  } catch (err) {
894
1004
  onHandlerError(err, span);
895
1005
  } finally {
@@ -908,10 +1018,10 @@ var RiverServer = class {
908
1018
  async (span) => {
909
1019
  try {
910
1020
  await procedure.handler({
911
- ctx: serviceContextWithTransportInfo,
1021
+ ctx: handlerContext,
912
1022
  reqInit: initPayload,
913
- reqReader,
914
- resWriter
1023
+ reqReadable,
1024
+ resWritable
915
1025
  });
916
1026
  } catch (err) {
917
1027
  onHandlerError(err, span);
@@ -931,9 +1041,9 @@ var RiverServer = class {
931
1041
  async (span) => {
932
1042
  try {
933
1043
  await procedure.handler({
934
- ctx: serviceContextWithTransportInfo,
935
- reqInit: passInitAsDataForBackwardsCompat ? {} : initPayload,
936
- resWriter
1044
+ ctx: handlerContext,
1045
+ reqInit: initPayload,
1046
+ resWritable
937
1047
  });
938
1048
  } catch (err) {
939
1049
  onHandlerError(err, span);
@@ -952,16 +1062,15 @@ var RiverServer = class {
952
1062
  tracingCtx,
953
1063
  async (span) => {
954
1064
  try {
955
- const outputMessage = await procedure.handler({
956
- ctx: serviceContextWithTransportInfo,
957
- reqInit: passInitAsDataForBackwardsCompat ? {} : initPayload,
958
- reqReader
1065
+ const responsePayload = await procedure.handler({
1066
+ ctx: handlerContext,
1067
+ reqInit: initPayload,
1068
+ reqReadable
959
1069
  });
960
- if (resWriter.isClosed()) {
1070
+ if (resWritable.isClosed()) {
961
1071
  return;
962
1072
  }
963
- resWriter.write(outputMessage);
964
- resWriter.close();
1073
+ resWritable.write(responsePayload);
965
1074
  } catch (err) {
966
1075
  onHandlerError(err, span);
967
1076
  } finally {
@@ -970,16 +1079,8 @@ var RiverServer = class {
970
1079
  }
971
1080
  );
972
1081
  break;
973
- default:
974
- this.log?.error(
975
- `got request for invalid procedure type ${procedure.type} at ${serviceName}.${procedureName}`,
976
- {
977
- ...loggingMetadata,
978
- tags: ["invariant-violation"]
979
- }
980
- );
981
- return;
982
1082
  }
1083
+ return procStream;
983
1084
  }
984
1085
  getContext(service, serviceName) {
985
1086
  const context = this.contextMap.get(service);
@@ -996,22 +1097,20 @@ var RiverServer = class {
996
1097
  validateNewProcStream(initMessage) {
997
1098
  const session = this.transport.sessions.get(initMessage.from);
998
1099
  if (!session) {
999
- const errMessage = `couldn't find a session for ${initMessage.from}`;
1000
1100
  this.log?.error(`couldn't find session for ${initMessage.from}`, {
1001
1101
  clientId: this.transport.clientId,
1002
1102
  transportMessage: initMessage,
1003
1103
  tags: ["invariant-violation"]
1004
1104
  });
1005
- this.abortStream(
1006
- initMessage.from,
1007
- initMessage.streamId,
1008
- Err({
1009
- code: INTERNAL_RIVER_ERROR_CODE,
1010
- message: errMessage
1011
- })
1012
- );
1013
1105
  return null;
1014
1106
  }
1107
+ const sessionScopedSend = this.transport.getSessionBoundSendFn(
1108
+ initMessage.from,
1109
+ session.id
1110
+ );
1111
+ const cancelStream = (streamId, payload) => {
1112
+ this.cancelStream(initMessage.from, sessionScopedSend, streamId, payload);
1113
+ };
1015
1114
  const sessionMetadata = this.transport.sessionHandshakeMetadata.get(
1016
1115
  session.to
1017
1116
  );
@@ -1021,11 +1120,10 @@ var RiverServer = class {
1021
1120
  ...session.loggingMetadata,
1022
1121
  tags: ["invariant-violation"]
1023
1122
  });
1024
- this.abortStream(
1025
- initMessage.from,
1123
+ cancelStream(
1026
1124
  initMessage.streamId,
1027
1125
  Err({
1028
- code: INTERNAL_RIVER_ERROR_CODE,
1126
+ code: UNCAUGHT_ERROR_CODE,
1029
1127
  message: errMessage
1030
1128
  })
1031
1129
  );
@@ -1039,8 +1137,7 @@ var RiverServer = class {
1039
1137
  transportMessage: initMessage,
1040
1138
  tags: ["invalid-request"]
1041
1139
  });
1042
- this.abortStream(
1043
- initMessage.from,
1140
+ cancelStream(
1044
1141
  initMessage.streamId,
1045
1142
  Err({
1046
1143
  code: INVALID_REQUEST_CODE,
@@ -1053,12 +1150,10 @@ var RiverServer = class {
1053
1150
  const errMessage = `missing service name in stream open message`;
1054
1151
  this.log?.warn(errMessage, {
1055
1152
  ...session.loggingMetadata,
1056
- clientId: this.transport.clientId,
1057
1153
  transportMessage: initMessage,
1058
1154
  tags: ["invalid-request"]
1059
1155
  });
1060
- this.abortStream(
1061
- initMessage.from,
1156
+ cancelStream(
1062
1157
  initMessage.streamId,
1063
1158
  Err({
1064
1159
  code: INVALID_REQUEST_CODE,
@@ -1071,12 +1166,10 @@ var RiverServer = class {
1071
1166
  const errMessage = `missing procedure name in stream open message`;
1072
1167
  this.log?.warn(errMessage, {
1073
1168
  ...session.loggingMetadata,
1074
- clientId: this.transport.clientId,
1075
1169
  transportMessage: initMessage,
1076
1170
  tags: ["invalid-request"]
1077
1171
  });
1078
- this.abortStream(
1079
- initMessage.from,
1172
+ cancelStream(
1080
1173
  initMessage.streamId,
1081
1174
  Err({
1082
1175
  code: INVALID_REQUEST_CODE,
@@ -1093,8 +1186,7 @@ var RiverServer = class {
1093
1186
  transportMessage: initMessage,
1094
1187
  tags: ["invalid-request"]
1095
1188
  });
1096
- this.abortStream(
1097
- initMessage.from,
1189
+ cancelStream(
1098
1190
  initMessage.streamId,
1099
1191
  Err({
1100
1192
  code: INVALID_REQUEST_CODE,
@@ -1108,12 +1200,10 @@ var RiverServer = class {
1108
1200
  const errMessage = `couldn't find a matching procedure for ${initMessage.serviceName}.${initMessage.procedureName}`;
1109
1201
  this.log?.warn(errMessage, {
1110
1202
  ...session.loggingMetadata,
1111
- clientId: this.transport.clientId,
1112
1203
  transportMessage: initMessage,
1113
1204
  tags: ["invalid-request"]
1114
1205
  });
1115
- this.abortStream(
1116
- initMessage.from,
1206
+ cancelStream(
1117
1207
  initMessage.streamId,
1118
1208
  Err({
1119
1209
  code: INVALID_REQUEST_CODE,
@@ -1122,7 +1212,19 @@ var RiverServer = class {
1122
1212
  );
1123
1213
  return null;
1124
1214
  }
1215
+ const serviceContext = this.getContext(service, initMessage.serviceName);
1125
1216
  const procedure = service.procedures[initMessage.procedureName];
1217
+ if (!["rpc", "upload", "stream", "subscription"].includes(procedure.type)) {
1218
+ this.log?.error(
1219
+ `got request for invalid procedure type ${procedure.type} at ${initMessage.serviceName}.${initMessage.procedureName}`,
1220
+ {
1221
+ ...session.loggingMetadata,
1222
+ transportMessage: initMessage,
1223
+ tags: ["invariant-violation"]
1224
+ }
1225
+ );
1226
+ return null;
1227
+ }
1126
1228
  let passInitAsDataForBackwardsCompat = false;
1127
1229
  if (session.protocolVersion === "v1.1" && (procedure.type === "upload" || procedure.type === "stream") && Value2.Check(procedure.requestData, initMessage.payload) && Value2.Check(procedure.requestInit, {})) {
1128
1230
  passInitAsDataForBackwardsCompat = true;
@@ -1134,8 +1236,7 @@ var RiverServer = class {
1134
1236
  transportMessage: initMessage,
1135
1237
  tags: ["invalid-request"]
1136
1238
  });
1137
- this.abortStream(
1138
- initMessage.from,
1239
+ cancelStream(
1139
1240
  initMessage.streamId,
1140
1241
  Err({
1141
1242
  code: INVALID_REQUEST_CODE,
@@ -1145,37 +1246,33 @@ var RiverServer = class {
1145
1246
  return null;
1146
1247
  }
1147
1248
  return {
1148
- sessionMetadata,
1149
- procedure,
1249
+ initialSession: session,
1250
+ streamId: initMessage.streamId,
1150
1251
  procedureName: initMessage.procedureName,
1151
- service,
1152
1252
  serviceName: initMessage.serviceName,
1153
- loggingMetadata: {
1154
- ...session.loggingMetadata,
1155
- transportMessage: initMessage
1156
- },
1157
- streamId: initMessage.streamId,
1158
- controlFlags: initMessage.controlFlags,
1159
1253
  tracingCtx: initMessage.tracing,
1160
1254
  initPayload: initMessage.payload,
1161
- from: initMessage.from,
1162
- sessionId: session.id,
1163
- protocolVersion: session.protocolVersion,
1255
+ sessionMetadata,
1256
+ procedure,
1257
+ serviceContext,
1258
+ procClosesWithInit: isStreamCloseBackwardsCompat(
1259
+ initMessage.controlFlags,
1260
+ session.protocolVersion
1261
+ ),
1164
1262
  passInitAsDataForBackwardsCompat
1165
1263
  };
1166
1264
  }
1167
- abortStream(to, streamId, payload) {
1168
- let abortedForSession = this.serverAbortedStreams.get(to);
1169
- if (!abortedForSession) {
1170
- abortedForSession = new LRUSet(this.maxAbortedStreamTombstonesPerSession);
1171
- this.serverAbortedStreams.set(to, abortedForSession);
1265
+ cancelStream(to, sessionScopedSend, streamId, payload) {
1266
+ let cancelledStreamsInSession = this.serverCancelledStreams.get(to);
1267
+ if (!cancelledStreamsInSession) {
1268
+ cancelledStreamsInSession = new LRUSet(
1269
+ this.maxCancelledStreamTombstonesPerSession
1270
+ );
1271
+ this.serverCancelledStreams.set(to, cancelledStreamsInSession);
1172
1272
  }
1173
- abortedForSession.add(streamId);
1174
- this.transport.send(
1175
- to,
1176
- // TODO remove once clients migrate to v2
1177
- this.transport.sessions.get(to)?.protocolVersion === "v1.1" ? closeStreamMessage(streamId) : abortMessage(streamId, payload)
1178
- );
1273
+ cancelledStreamsInSession.add(streamId);
1274
+ const msg = cancelMessage(streamId, payload);
1275
+ sessionScopedSend(msg);
1179
1276
  }
1180
1277
  };
1181
1278
  var LRUSet = class {
@@ -1200,21 +1297,21 @@ var LRUSet = class {
1200
1297
  return this.items.has(item);
1201
1298
  }
1202
1299
  };
1203
- function isStreamAbortBackwardsCompat(controlFlags, protocolVersion) {
1300
+ function isStreamCancelBackwardsCompat(controlFlags, protocolVersion) {
1204
1301
  if (protocolVersion === "v1.1") {
1205
1302
  return false;
1206
1303
  }
1207
- return isStreamAbort(controlFlags);
1304
+ return isStreamCancel(controlFlags);
1208
1305
  }
1209
1306
  function isStreamCloseBackwardsCompat(controlFlags, protocolVersion) {
1210
1307
  if (protocolVersion === "v1.1") {
1211
- return isStreamAbort(controlFlags);
1308
+ return isStreamCancel(controlFlags);
1212
1309
  }
1213
1310
  return isStreamClose(controlFlags);
1214
1311
  }
1215
1312
  function getStreamCloseBackwardsCompat(protocolVersion) {
1216
1313
  if (protocolVersion === "v1.1") {
1217
- return 4 /* StreamAbortBit */;
1314
+ return 4 /* StreamCancelBit */;
1218
1315
  }
1219
1316
  return 8 /* StreamClosedBit */;
1220
1317
  }
@@ -1224,7 +1321,7 @@ function createServer(transport, services, providedServerOptions) {
1224
1321
  services,
1225
1322
  providedServerOptions?.handshakeOptions,
1226
1323
  providedServerOptions?.extendedContext,
1227
- providedServerOptions?.maxAbortedStreamTombstonesPerSession
1324
+ providedServerOptions?.maxCancelledStreamTombstonesPerSession
1228
1325
  );
1229
1326
  }
1230
1327
 
@@ -1236,15 +1333,13 @@ function createServerHandshakeOptions(schema, validate) {
1236
1333
  return { schema, validate };
1237
1334
  }
1238
1335
  export {
1239
- ABORT_CODE,
1336
+ CANCEL_CODE,
1240
1337
  Err,
1241
- INTERNAL_RIVER_ERROR_CODE,
1242
1338
  INVALID_REQUEST_CODE,
1243
1339
  Ok,
1244
1340
  Procedure,
1245
1341
  version as RIVER_VERSION,
1246
- RequestReaderErrorSchema,
1247
- ResponseReaderErrorSchema,
1342
+ ReaderErrorSchema,
1248
1343
  ServiceSchema,
1249
1344
  UNCAUGHT_ERROR_CODE,
1250
1345
  UNEXPECTED_DISCONNECT_CODE,
@@ -1252,6 +1347,9 @@ export {
1252
1347
  createClientHandshakeOptions,
1253
1348
  createServer,
1254
1349
  createServerHandshakeOptions,
1255
- serializeSchema
1350
+ flattenErrorType,
1351
+ serializeSchema,
1352
+ serializeSchemaV1Compat,
1353
+ unwrapOrThrow
1256
1354
  };
1257
1355
  //# sourceMappingURL=index.js.map