@replit/river 0.21.1 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunk-FDLAPYCK.js → chunk-DZOATC6M.js} +2 -2
  3. package/dist/{chunk-JMXO5L2X.js → chunk-MJUFKPBT.js} +354 -398
  4. package/dist/chunk-MJUFKPBT.js.map +1 -0
  5. package/dist/{chunk-5WFL722S.js → chunk-PCKHBAVP.js} +94 -3
  6. package/dist/chunk-PCKHBAVP.js.map +1 -0
  7. package/dist/{chunk-NCXUFDVL.js → chunk-VOJVLWVX.js} +360 -516
  8. package/dist/chunk-VOJVLWVX.js.map +1 -0
  9. package/dist/chunk-ZF2UFTNN.js +60 -0
  10. package/dist/chunk-ZF2UFTNN.js.map +1 -0
  11. package/dist/{connection-76c5ed01.d.ts → connection-5685d817.d.ts} +6 -4
  12. package/dist/{connection-975b25c9.d.ts → connection-7582fb92.d.ts} +1 -1
  13. package/dist/{index-dfad460e.d.ts → index-a6fe0edd.d.ts} +55 -59
  14. package/dist/logging/index.d.cts +2 -1
  15. package/dist/logging/index.d.ts +2 -1
  16. package/dist/router/index.cjs +405 -502
  17. package/dist/router/index.cjs.map +1 -1
  18. package/dist/router/index.d.cts +12 -6
  19. package/dist/router/index.d.ts +12 -6
  20. package/dist/router/index.js +4 -3
  21. package/dist/{services-9c496c6e.d.ts → services-be91b485.d.ts} +21 -52
  22. package/dist/{services-7b716dcf.d.ts → services-eb9326a1.d.ts} +21 -52
  23. package/dist/transport/impls/uds/client.cjs +197 -155
  24. package/dist/transport/impls/uds/client.cjs.map +1 -1
  25. package/dist/transport/impls/uds/client.d.cts +3 -2
  26. package/dist/transport/impls/uds/client.d.ts +3 -2
  27. package/dist/transport/impls/uds/client.js +3 -3
  28. package/dist/transport/impls/uds/server.cjs +280 -266
  29. package/dist/transport/impls/uds/server.cjs.map +1 -1
  30. package/dist/transport/impls/uds/server.d.cts +3 -2
  31. package/dist/transport/impls/uds/server.d.ts +3 -2
  32. package/dist/transport/impls/uds/server.js +3 -3
  33. package/dist/transport/impls/ws/client.cjs +251 -214
  34. package/dist/transport/impls/ws/client.cjs.map +1 -1
  35. package/dist/transport/impls/ws/client.d.cts +6 -6
  36. package/dist/transport/impls/ws/client.d.ts +6 -6
  37. package/dist/transport/impls/ws/client.js +33 -48
  38. package/dist/transport/impls/ws/client.js.map +1 -1
  39. package/dist/transport/impls/ws/server.cjs +302 -280
  40. package/dist/transport/impls/ws/server.cjs.map +1 -1
  41. package/dist/transport/impls/ws/server.d.cts +5 -4
  42. package/dist/transport/impls/ws/server.d.ts +5 -4
  43. package/dist/transport/impls/ws/server.js +3 -3
  44. package/dist/transport/impls/ws/server.js.map +1 -1
  45. package/dist/transport/index.cjs +400 -396
  46. package/dist/transport/index.cjs.map +1 -1
  47. package/dist/transport/index.d.cts +25 -14
  48. package/dist/transport/index.d.ts +25 -14
  49. package/dist/transport/index.js +2 -2
  50. package/dist/util/testHelpers.cjs +59 -14
  51. package/dist/util/testHelpers.cjs.map +1 -1
  52. package/dist/util/testHelpers.d.cts +14 -5
  53. package/dist/util/testHelpers.d.ts +14 -5
  54. package/dist/util/testHelpers.js +12 -5
  55. package/dist/util/testHelpers.js.map +1 -1
  56. package/dist/wslike-e0b32dd5.d.ts +40 -0
  57. package/package.json +4 -5
  58. package/dist/chunk-3Y7AB5EB.js +0 -42
  59. package/dist/chunk-3Y7AB5EB.js.map +0 -1
  60. package/dist/chunk-5WFL722S.js.map +0 -1
  61. package/dist/chunk-JMXO5L2X.js.map +0 -1
  62. package/dist/chunk-NCXUFDVL.js.map +0 -1
  63. /package/dist/{chunk-FDLAPYCK.js.map → chunk-DZOATC6M.js.map} +0 -0
@@ -35,14 +35,18 @@ module.exports = __toCommonJS(router_exports);
35
35
 
36
36
  // router/services.ts
37
37
  var import_typebox = require("@sinclair/typebox");
38
- function serializeSchema(services) {
39
- return Object.entries(services).reduce(
40
- (acc, [name, value]) => {
41
- acc[name] = value.serialize();
42
- return acc;
43
- },
44
- {}
45
- );
38
+ function serializeSchema(services, handshakeSchema) {
39
+ const serializedServiceObject = Object.entries(services).reduce((acc, [name, value]) => {
40
+ acc[name] = value.serialize();
41
+ return acc;
42
+ }, {});
43
+ const schema = {
44
+ services: serializedServiceObject
45
+ };
46
+ if (handshakeSchema) {
47
+ schema.handshakeSchema = import_typebox.Type.Strict(handshakeSchema);
48
+ }
49
+ return schema;
46
50
  }
47
51
  var ServiceSchema = class _ServiceSchema {
48
52
  /**
@@ -322,9 +326,6 @@ var Procedure = {
322
326
  stream
323
327
  };
324
328
 
325
- // router/client.ts
326
- var import_api2 = require("@opentelemetry/api");
327
-
328
329
  // node_modules/p-defer/index.js
329
330
  function pDefer() {
330
331
  const deferred = {};
@@ -707,8 +708,58 @@ var log = void 0;
707
708
 
708
709
  // tracing/index.ts
709
710
  var import_api = require("@opentelemetry/api");
710
- var tracer = import_api.trace.getTracer("river");
711
- var tracing_default = tracer;
711
+
712
+ // package.json
713
+ var version = "0.23.0";
714
+
715
+ // tracing/index.ts
716
+ function getPropagationContext(ctx) {
717
+ const tracing = {
718
+ traceparent: "",
719
+ tracestate: ""
720
+ };
721
+ import_api.propagation.inject(ctx, tracing);
722
+ return tracing;
723
+ }
724
+ function createProcTelemetryInfo(kind, serviceName, procedureName, streamId) {
725
+ const ctx = import_api.context.active();
726
+ const span = tracer.startSpan(
727
+ `procedure call ${serviceName}.${procedureName}`,
728
+ {
729
+ attributes: {
730
+ component: "river",
731
+ "river.method.kind": kind,
732
+ "river.method.service": serviceName,
733
+ "river.method.name": procedureName,
734
+ "river.streamId": streamId,
735
+ "span.kind": "client"
736
+ },
737
+ kind: import_api.SpanKind.CLIENT
738
+ },
739
+ ctx
740
+ );
741
+ return { span, ctx };
742
+ }
743
+ function createHandlerSpan(kind, message, fn) {
744
+ const ctx = message.tracing ? import_api.propagation.extract(import_api.context.active(), message.tracing) : import_api.context.active();
745
+ return tracer.startActiveSpan(
746
+ `procedure handler ${message.serviceName}.${message.procedureName}`,
747
+ {
748
+ attributes: {
749
+ component: "river",
750
+ "river.method.kind": kind,
751
+ "river.method.service": message.serviceName,
752
+ "river.method.name": message.procedureName,
753
+ "river.streamId": message.streamId,
754
+ "span.kind": "server"
755
+ },
756
+ kind: import_api.SpanKind.SERVER
757
+ },
758
+ ctx,
759
+ fn
760
+ );
761
+ }
762
+ var tracer = import_api.trace.getTracer("river", version);
712
763
 
713
764
  // router/client.ts
714
765
  var noop = () => {
@@ -735,7 +786,10 @@ var defaultClientOptions = {
735
786
  connectOnInvoke: true,
736
787
  eagerlyConnect: true
737
788
  };
738
- var createClient = (transport, serverId, providedClientOptions = {}) => {
789
+ function createClient(transport, serverId, providedClientOptions = {}) {
790
+ if (providedClientOptions.handshakeOptions) {
791
+ transport.extendHandshake(providedClientOptions.handshakeOptions);
792
+ }
739
793
  const options = { ...defaultClientOptions, ...providedClientOptions };
740
794
  if (options.eagerlyConnect) {
741
795
  void transport.connect(serverId);
@@ -771,7 +825,7 @@ var createClient = (transport, serverId, providedClientOptions = {}) => {
771
825
  throw new Error(`invalid river call, unknown procedure type ${procType}`);
772
826
  }
773
827
  }, []);
774
- };
828
+ }
775
829
  function createSessionDisconnectHandler(from, cb) {
776
830
  return (evt) => {
777
831
  if (evt.status === "disconnect" && evt.session.to === from) {
@@ -781,318 +835,254 @@ function createSessionDisconnectHandler(from, cb) {
781
835
  }
782
836
  function handleRpc(transport, serverId, input, serviceName, procedureName) {
783
837
  const streamId = (0, import_nanoid2.nanoid)();
784
- return tracing_default.startActiveSpan(
785
- `${serviceName}.${procedureName}`,
786
- {
787
- attributes: {
788
- component: "river",
789
- "river.method.kind": "rpc",
790
- "river.method.service": serviceName,
791
- "river.method.name": procedureName,
792
- "river.streamId": streamId,
793
- "span.kind": "client"
794
- },
795
- kind: import_api2.SpanKind.CLIENT
796
- },
797
- (span) => {
798
- const tracing = { traceparent: "", tracestate: "" };
799
- import_api2.propagation.inject(import_api2.context.active(), tracing);
800
- transport.send(serverId, {
801
- streamId,
802
- serviceName,
803
- procedureName,
804
- tracing,
805
- payload: input,
806
- controlFlags: 2 /* StreamOpenBit */ | 4 /* StreamClosedBit */
807
- });
808
- const responsePromise = new Promise((resolve) => {
809
- const onSessionStatus = createSessionDisconnectHandler(serverId, () => {
810
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
811
- cleanup();
812
- resolve(
813
- Err({
814
- code: UNEXPECTED_DISCONNECT,
815
- message: `${serverId} unexpectedly disconnected`
816
- })
817
- );
818
- });
819
- function cleanup() {
820
- transport.removeEventListener("message", onMessage);
821
- transport.removeEventListener("sessionStatus", onSessionStatus);
822
- span.end();
823
- }
824
- function onMessage(msg) {
825
- if (msg.streamId !== streamId)
826
- return;
827
- if (msg.to !== transport.clientId)
828
- return;
829
- if (msg.payload && typeof msg.payload === "object" && "ok" in msg.payload) {
830
- span.setStatus({
831
- code: msg.payload.ok ? import_api2.SpanStatusCode.OK : import_api2.SpanStatusCode.ERROR
832
- });
833
- }
834
- cleanup();
835
- resolve(msg.payload);
836
- }
837
- transport.addEventListener("message", onMessage);
838
- transport.addEventListener("sessionStatus", onSessionStatus);
839
- });
840
- return responsePromise;
841
- }
838
+ const { span, ctx } = createProcTelemetryInfo(
839
+ "rpc",
840
+ serviceName,
841
+ procedureName,
842
+ streamId
842
843
  );
844
+ transport.send(serverId, {
845
+ streamId,
846
+ serviceName,
847
+ procedureName,
848
+ payload: input,
849
+ tracing: getPropagationContext(ctx),
850
+ controlFlags: 2 /* StreamOpenBit */ | 4 /* StreamClosedBit */
851
+ });
852
+ const responsePromise = new Promise((resolve) => {
853
+ const onSessionStatus = createSessionDisconnectHandler(serverId, () => {
854
+ cleanup();
855
+ resolve(
856
+ Err({
857
+ code: UNEXPECTED_DISCONNECT,
858
+ message: `${serverId} unexpectedly disconnected`
859
+ })
860
+ );
861
+ });
862
+ function cleanup() {
863
+ transport.removeEventListener("message", onMessage);
864
+ transport.removeEventListener("sessionStatus", onSessionStatus);
865
+ span.end();
866
+ }
867
+ function onMessage(msg) {
868
+ if (msg.streamId !== streamId)
869
+ return;
870
+ if (msg.to !== transport.clientId)
871
+ return;
872
+ cleanup();
873
+ resolve(msg.payload);
874
+ }
875
+ transport.addEventListener("message", onMessage);
876
+ transport.addEventListener("sessionStatus", onSessionStatus);
877
+ });
878
+ return responsePromise;
843
879
  }
844
880
  function handleStream(transport, serverId, init, serviceName, procedureName) {
845
881
  const streamId = (0, import_nanoid2.nanoid)();
846
- return tracing_default.startActiveSpan(
847
- `${serviceName}.${procedureName}`,
848
- {
849
- attributes: {
850
- component: "river",
851
- "river.method.kind": init ? "stream-with-init" : "stream",
852
- "river.method.service": serviceName,
853
- "river.method.name": procedureName,
854
- "river.streamId": streamId,
855
- "span.kind": "client"
856
- },
857
- kind: import_api2.SpanKind.CLIENT
858
- },
859
- (span) => {
860
- const tracing = { traceparent: "", tracestate: "" };
861
- import_api2.propagation.inject(import_api2.context.active(), tracing);
862
- const inputStream = pushable({ objectMode: true });
863
- const outputStream = pushable({ objectMode: true });
864
- let firstMessage = true;
865
- let healthyClose = true;
866
- if (init) {
867
- transport.send(serverId, {
868
- streamId,
869
- serviceName,
870
- procedureName,
871
- tracing,
872
- payload: init,
873
- controlFlags: 2 /* StreamOpenBit */
874
- });
875
- firstMessage = false;
876
- }
877
- const pipeInputToTransport = async () => {
878
- for await (const rawIn of inputStream) {
879
- const m = {
880
- streamId,
881
- payload: rawIn,
882
- controlFlags: 0
883
- };
884
- if (firstMessage) {
885
- m.serviceName = serviceName;
886
- m.procedureName = procedureName;
887
- m.tracing = tracing;
888
- m.controlFlags |= 2 /* StreamOpenBit */;
889
- firstMessage = false;
890
- }
891
- transport.send(serverId, m);
892
- }
893
- if (!healthyClose)
894
- return;
895
- transport.sendCloseStream(serverId, streamId);
896
- span.setStatus({ code: import_api2.SpanStatusCode.OK });
882
+ const { span, ctx } = createProcTelemetryInfo(
883
+ "stream",
884
+ serviceName,
885
+ procedureName,
886
+ streamId
887
+ );
888
+ const inputStream = pushable({ objectMode: true });
889
+ const outputStream = pushable({ objectMode: true });
890
+ let firstMessage = true;
891
+ let healthyClose = true;
892
+ if (init) {
893
+ transport.send(serverId, {
894
+ streamId,
895
+ serviceName,
896
+ procedureName,
897
+ payload: init,
898
+ tracing: getPropagationContext(ctx),
899
+ controlFlags: 2 /* StreamOpenBit */
900
+ });
901
+ firstMessage = false;
902
+ }
903
+ const pipeInputToTransport = async () => {
904
+ for await (const rawIn of inputStream) {
905
+ const m = {
906
+ streamId,
907
+ payload: rawIn,
908
+ controlFlags: 0
897
909
  };
898
- void pipeInputToTransport();
899
- function onMessage(msg) {
900
- if (msg.streamId !== streamId)
901
- return;
902
- if (msg.to !== transport.clientId)
903
- return;
904
- if (isStreamClose(msg.controlFlags)) {
905
- cleanup();
906
- } else {
907
- outputStream.push(msg.payload);
908
- }
909
- }
910
- function cleanup() {
911
- inputStream.end();
912
- outputStream.end();
913
- transport.removeEventListener("message", onMessage);
914
- transport.removeEventListener("sessionStatus", onSessionStatus);
915
- span.end();
910
+ if (firstMessage) {
911
+ m.serviceName = serviceName;
912
+ m.procedureName = procedureName;
913
+ m.tracing = getPropagationContext(ctx);
914
+ m.controlFlags |= 2 /* StreamOpenBit */;
915
+ firstMessage = false;
916
916
  }
917
- const onSessionStatus = createSessionDisconnectHandler(serverId, () => {
918
- outputStream.push(
919
- Err({
920
- code: UNEXPECTED_DISCONNECT,
921
- message: `${serverId} unexpectedly disconnected`
922
- })
923
- );
924
- healthyClose = false;
925
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
926
- cleanup();
927
- });
928
- transport.addEventListener("message", onMessage);
929
- transport.addEventListener("sessionStatus", onSessionStatus);
930
- return [inputStream, outputStream, cleanup];
917
+ transport.send(serverId, m);
931
918
  }
932
- );
919
+ if (!healthyClose)
920
+ return;
921
+ transport.sendCloseStream(serverId, streamId);
922
+ };
923
+ void pipeInputToTransport();
924
+ function onMessage(msg) {
925
+ if (msg.streamId !== streamId)
926
+ return;
927
+ if (msg.to !== transport.clientId)
928
+ return;
929
+ if (isStreamClose(msg.controlFlags)) {
930
+ cleanup();
931
+ } else {
932
+ outputStream.push(msg.payload);
933
+ }
934
+ }
935
+ function cleanup() {
936
+ inputStream.end();
937
+ outputStream.end();
938
+ transport.removeEventListener("message", onMessage);
939
+ transport.removeEventListener("sessionStatus", onSessionStatus);
940
+ span.end();
941
+ }
942
+ const onSessionStatus = createSessionDisconnectHandler(serverId, () => {
943
+ outputStream.push(
944
+ Err({
945
+ code: UNEXPECTED_DISCONNECT,
946
+ message: `${serverId} unexpectedly disconnected`
947
+ })
948
+ );
949
+ healthyClose = false;
950
+ cleanup();
951
+ });
952
+ transport.addEventListener("message", onMessage);
953
+ transport.addEventListener("sessionStatus", onSessionStatus);
954
+ return [inputStream, outputStream, cleanup];
933
955
  }
934
956
  function handleSubscribe(transport, serverId, input, serviceName, procedureName) {
935
957
  const streamId = (0, import_nanoid2.nanoid)();
936
- return tracing_default.startActiveSpan(
937
- `${serviceName}.${procedureName}`,
938
- {
939
- attributes: {
940
- component: "river",
941
- "river.method.kind": "subscribe",
942
- "river.method.service": serviceName,
943
- "river.method.name": procedureName,
944
- "river.streamId": streamId,
945
- "span.kind": "client"
946
- },
947
- kind: import_api2.SpanKind.CLIENT
948
- },
949
- (span) => {
950
- const tracing = { traceparent: "", tracestate: "" };
951
- import_api2.propagation.inject(import_api2.context.active(), tracing);
952
- transport.send(serverId, {
953
- streamId,
954
- serviceName,
955
- procedureName,
956
- tracing,
957
- payload: input,
958
- controlFlags: 2 /* StreamOpenBit */
959
- });
960
- let healthyClose = true;
961
- const outputStream = pushable({ objectMode: true });
962
- function onMessage(msg) {
963
- if (msg.streamId !== streamId)
964
- return;
965
- if (msg.to !== transport.clientId)
966
- return;
967
- if (isStreamClose(msg.controlFlags)) {
968
- cleanup();
969
- } else {
970
- outputStream.push(msg.payload);
971
- }
972
- }
973
- function cleanup() {
974
- outputStream.end();
975
- transport.removeEventListener("message", onMessage);
976
- transport.removeEventListener("sessionStatus", onSessionStatus);
977
- span.end();
978
- }
979
- const closeHandler = () => {
980
- cleanup();
981
- if (!healthyClose)
982
- return;
983
- transport.sendCloseStream(serverId, streamId);
984
- };
985
- const onSessionStatus = createSessionDisconnectHandler(serverId, () => {
986
- outputStream.push(
987
- Err({
988
- code: UNEXPECTED_DISCONNECT,
989
- message: `${serverId} unexpectedly disconnected`
990
- })
991
- );
992
- healthyClose = false;
993
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
994
- cleanup();
995
- });
996
- transport.addEventListener("message", onMessage);
997
- transport.addEventListener("sessionStatus", onSessionStatus);
998
- return [outputStream, closeHandler];
999
- }
958
+ const { span, ctx } = createProcTelemetryInfo(
959
+ "subscription",
960
+ serviceName,
961
+ procedureName,
962
+ streamId
1000
963
  );
964
+ transport.send(serverId, {
965
+ streamId,
966
+ serviceName,
967
+ procedureName,
968
+ payload: input,
969
+ tracing: getPropagationContext(ctx),
970
+ controlFlags: 2 /* StreamOpenBit */
971
+ });
972
+ let healthyClose = true;
973
+ const outputStream = pushable({ objectMode: true });
974
+ function onMessage(msg) {
975
+ if (msg.streamId !== streamId)
976
+ return;
977
+ if (msg.to !== transport.clientId)
978
+ return;
979
+ if (isStreamClose(msg.controlFlags)) {
980
+ cleanup();
981
+ } else {
982
+ outputStream.push(msg.payload);
983
+ }
984
+ }
985
+ function cleanup() {
986
+ outputStream.end();
987
+ transport.removeEventListener("message", onMessage);
988
+ transport.removeEventListener("sessionStatus", onSessionStatus);
989
+ span.end();
990
+ }
991
+ const closeHandler = () => {
992
+ cleanup();
993
+ if (!healthyClose)
994
+ return;
995
+ transport.sendCloseStream(serverId, streamId);
996
+ };
997
+ const onSessionStatus = createSessionDisconnectHandler(serverId, () => {
998
+ outputStream.push(
999
+ Err({
1000
+ code: UNEXPECTED_DISCONNECT,
1001
+ message: `${serverId} unexpectedly disconnected`
1002
+ })
1003
+ );
1004
+ healthyClose = false;
1005
+ cleanup();
1006
+ });
1007
+ transport.addEventListener("message", onMessage);
1008
+ transport.addEventListener("sessionStatus", onSessionStatus);
1009
+ return [outputStream, closeHandler];
1001
1010
  }
1002
1011
  function handleUpload(transport, serverId, init, serviceName, procedureName) {
1003
1012
  const streamId = (0, import_nanoid2.nanoid)();
1004
- return tracing_default.startActiveSpan(
1005
- `${serviceName}.${procedureName}`,
1006
- {
1007
- attributes: {
1008
- component: "river",
1009
- "river.method.kind": init ? "upload-with-init" : "upload",
1010
- "river.method.service": serviceName,
1011
- "river.method.name": procedureName,
1012
- "river.streamId": streamId,
1013
- "span.kind": "client"
1014
- },
1015
- kind: import_api2.SpanKind.CLIENT
1016
- },
1017
- (span) => {
1018
- const tracing = { traceparent: "", tracestate: "" };
1019
- import_api2.propagation.inject(import_api2.context.active(), tracing);
1020
- const inputStream = pushable({ objectMode: true });
1021
- let firstMessage = true;
1022
- let healthyClose = true;
1023
- if (init) {
1024
- transport.send(serverId, {
1025
- streamId,
1026
- serviceName,
1027
- procedureName,
1028
- tracing,
1029
- payload: init,
1030
- controlFlags: 2 /* StreamOpenBit */
1031
- });
1013
+ const { span, ctx } = createProcTelemetryInfo(
1014
+ "upload",
1015
+ serviceName,
1016
+ procedureName,
1017
+ streamId
1018
+ );
1019
+ const inputStream = pushable({ objectMode: true });
1020
+ let firstMessage = true;
1021
+ let healthyClose = true;
1022
+ if (init) {
1023
+ transport.send(serverId, {
1024
+ streamId,
1025
+ serviceName,
1026
+ procedureName,
1027
+ payload: init,
1028
+ tracing: getPropagationContext(ctx),
1029
+ controlFlags: 2 /* StreamOpenBit */
1030
+ });
1031
+ firstMessage = false;
1032
+ }
1033
+ const pipeInputToTransport = async () => {
1034
+ for await (const rawIn of inputStream) {
1035
+ const m = {
1036
+ streamId,
1037
+ payload: rawIn,
1038
+ controlFlags: 0
1039
+ };
1040
+ if (firstMessage) {
1041
+ m.serviceName = serviceName;
1042
+ m.procedureName = procedureName;
1043
+ m.tracing = getPropagationContext(ctx);
1044
+ m.controlFlags |= 2 /* StreamOpenBit */;
1032
1045
  firstMessage = false;
1033
1046
  }
1034
- const pipeInputToTransport = async () => {
1035
- for await (const rawIn of inputStream) {
1036
- const m = {
1037
- streamId,
1038
- payload: rawIn,
1039
- controlFlags: 0
1040
- };
1041
- if (firstMessage) {
1042
- m.serviceName = serviceName;
1043
- m.procedureName = procedureName;
1044
- m.tracing = tracing;
1045
- m.controlFlags |= 2 /* StreamOpenBit */;
1046
- firstMessage = false;
1047
- }
1048
- transport.send(serverId, m);
1049
- }
1050
- if (!healthyClose)
1051
- return;
1052
- transport.sendCloseStream(serverId, streamId);
1053
- };
1054
- void pipeInputToTransport();
1055
- const responsePromise = new Promise((resolve) => {
1056
- const onSessionStatus = createSessionDisconnectHandler(serverId, () => {
1057
- healthyClose = false;
1058
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
1059
- cleanup();
1060
- resolve(
1061
- Err({
1062
- code: UNEXPECTED_DISCONNECT,
1063
- message: `${serverId} unexpectedly disconnected`
1064
- })
1065
- );
1066
- });
1067
- function cleanup() {
1068
- inputStream.end();
1069
- transport.removeEventListener("message", onMessage);
1070
- transport.removeEventListener("sessionStatus", onSessionStatus);
1071
- span.end();
1072
- }
1073
- function onMessage(msg) {
1074
- if (msg.streamId !== streamId)
1075
- return;
1076
- if (msg.to !== transport.clientId)
1077
- return;
1078
- if (msg.payload && typeof msg.payload === "object" && "ok" in msg.payload) {
1079
- span.setStatus({
1080
- code: msg.payload.ok ? import_api2.SpanStatusCode.OK : import_api2.SpanStatusCode.ERROR
1081
- });
1082
- }
1083
- cleanup();
1084
- resolve(msg.payload);
1085
- }
1086
- transport.addEventListener("message", onMessage);
1087
- transport.addEventListener("sessionStatus", onSessionStatus);
1088
- });
1089
- return [inputStream, responsePromise];
1047
+ transport.send(serverId, m);
1090
1048
  }
1091
- );
1049
+ if (!healthyClose)
1050
+ return;
1051
+ transport.sendCloseStream(serverId, streamId);
1052
+ };
1053
+ void pipeInputToTransport();
1054
+ const responsePromise = new Promise((resolve) => {
1055
+ const onSessionStatus = createSessionDisconnectHandler(serverId, () => {
1056
+ healthyClose = false;
1057
+ cleanup();
1058
+ resolve(
1059
+ Err({
1060
+ code: UNEXPECTED_DISCONNECT,
1061
+ message: `${serverId} unexpectedly disconnected`
1062
+ })
1063
+ );
1064
+ });
1065
+ function cleanup() {
1066
+ inputStream.end();
1067
+ transport.removeEventListener("message", onMessage);
1068
+ transport.removeEventListener("sessionStatus", onSessionStatus);
1069
+ span.end();
1070
+ }
1071
+ function onMessage(msg) {
1072
+ if (msg.streamId !== streamId)
1073
+ return;
1074
+ if (msg.to !== transport.clientId)
1075
+ return;
1076
+ cleanup();
1077
+ resolve(msg.payload);
1078
+ }
1079
+ transport.addEventListener("message", onMessage);
1080
+ transport.addEventListener("sessionStatus", onSessionStatus);
1081
+ });
1082
+ return [inputStream, responsePromise];
1092
1083
  }
1093
1084
 
1094
1085
  // router/server.ts
1095
- var import_api3 = require("@opentelemetry/api");
1096
1086
  var import_value = require("@sinclair/typebox/value");
1097
1087
 
1098
1088
  // util/stringify.ts
@@ -1104,6 +1094,7 @@ function coerceErrorString(err) {
1104
1094
  }
1105
1095
 
1106
1096
  // router/server.ts
1097
+ var import_api2 = require("@opentelemetry/api");
1107
1098
  var RiverServer = class {
1108
1099
  transport;
1109
1100
  services;
@@ -1113,7 +1104,7 @@ var RiverServer = class {
1113
1104
  // map of client to their open streams by streamId
1114
1105
  clientStreams;
1115
1106
  disconnectedSessions;
1116
- constructor(transport, services, extendedContext) {
1107
+ constructor(transport, services, handshakeOptions, extendedContext) {
1117
1108
  const instances = {};
1118
1109
  this.services = instances;
1119
1110
  this.contextMap = /* @__PURE__ */ new Map();
@@ -1125,6 +1116,9 @@ var RiverServer = class {
1125
1116
  state: instance.state
1126
1117
  });
1127
1118
  }
1119
+ if (handshakeOptions) {
1120
+ transport.extendHandshake(handshakeOptions);
1121
+ }
1128
1122
  this.transport = transport;
1129
1123
  this.disconnectedSessions = /* @__PURE__ */ new Set();
1130
1124
  this.streamMap = /* @__PURE__ */ new Map();
@@ -1174,9 +1168,9 @@ var RiverServer = class {
1174
1168
  this.transport.removeEventListener("message", this.onMessage);
1175
1169
  this.transport.removeEventListener("sessionStatus", this.onSessionStatus);
1176
1170
  await Promise.all([...this.streamMap.keys()].map(this.cleanupStream));
1177
- for (const context3 of this.contextMap.values()) {
1178
- if (Symbol.dispose in context3.state) {
1179
- const dispose = context3.state[Symbol.dispose];
1171
+ for (const context2 of this.contextMap.values()) {
1172
+ if (Symbol.dispose in context2.state) {
1173
+ const dispose = context2.state[Symbol.dispose];
1180
1174
  if (typeof dispose === "function") {
1181
1175
  dispose();
1182
1176
  }
@@ -1209,10 +1203,6 @@ var RiverServer = class {
1209
1203
  });
1210
1204
  return;
1211
1205
  }
1212
- let activeContext = import_api3.context.active();
1213
- if (message.tracing) {
1214
- activeContext = import_api3.propagation.extract(activeContext, message.tracing);
1215
- }
1216
1206
  const service = this.services[message.serviceName];
1217
1207
  const serviceContext = this.getContext(service, message.serviceName);
1218
1208
  if (!(message.procedureName in service.procedures)) {
@@ -1276,12 +1266,8 @@ var RiverServer = class {
1276
1266
  `procedure ${message.serviceName}.${message.procedureName} threw an uncaught error: ${errorMsg}`,
1277
1267
  session.loggingMetadata
1278
1268
  );
1279
- if (err instanceof Error) {
1280
- span.recordException(err);
1281
- } else {
1282
- span.recordException(errorMsg);
1283
- }
1284
- span.setStatus({ code: import_api3.SpanStatusCode.ERROR });
1269
+ span.recordException(err instanceof Error ? err : new Error(errorMsg));
1270
+ span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
1285
1271
  outgoing.push(
1286
1272
  Err({
1287
1273
  code: UNCAUGHT_ERROR,
@@ -1289,7 +1275,8 @@ var RiverServer = class {
1289
1275
  })
1290
1276
  );
1291
1277
  };
1292
- if (session.metadata === void 0) {
1278
+ const sessionMeta = this.transport.sessionHandshakeMetadata.get(session);
1279
+ if (!sessionMeta) {
1293
1280
  log?.error(`session doesn't have handshake metadata`, {
1294
1281
  ...session.loggingMetadata,
1295
1282
  tags: ["invariant-violation"]
@@ -1303,37 +1290,53 @@ var RiverServer = class {
1303
1290
  to: message.to,
1304
1291
  from: message.from,
1305
1292
  streamId: message.streamId,
1306
- // we've already validated that the session has handshake metadata
1307
- session
1293
+ session,
1294
+ metadata: sessionMeta
1308
1295
  };
1309
1296
  switch (procedure.type) {
1310
1297
  case "rpc":
1311
- inputHandler = (async () => {
1312
- const inputMessage = await incoming.next();
1313
- if (inputMessage.done) {
1314
- return;
1298
+ inputHandler = createHandlerSpan(
1299
+ procedure.type,
1300
+ message,
1301
+ async (span) => {
1302
+ const inputMessage = await incoming.next();
1303
+ if (inputMessage.done) {
1304
+ return;
1305
+ }
1306
+ try {
1307
+ const outputMessage = await procedure.handler(
1308
+ serviceContextWithTransportInfo,
1309
+ inputMessage.value
1310
+ );
1311
+ outgoing.push(outputMessage);
1312
+ } catch (err) {
1313
+ errorHandler(err, span);
1314
+ } finally {
1315
+ span.end();
1316
+ }
1315
1317
  }
1316
- await tracing_default.startActiveSpan(
1317
- `${message.serviceName}.${message.procedureName}`,
1318
- {
1319
- attributes: {
1320
- component: "river",
1321
- "river.method.kind": "rpc",
1322
- "river.method.service": message.serviceName,
1323
- "river.method.name": message.procedureName,
1324
- "river.streamId": message.streamId,
1325
- "span.kind": "server"
1326
- },
1327
- kind: import_api3.SpanKind.SERVER
1328
- },
1329
- activeContext,
1318
+ );
1319
+ break;
1320
+ case "stream":
1321
+ if (procHasInitMessage) {
1322
+ inputHandler = createHandlerSpan(
1323
+ procedure.type,
1324
+ message,
1330
1325
  async (span) => {
1326
+ const initMessage = await incoming.next();
1327
+ if (initMessage.done) {
1328
+ return;
1329
+ }
1331
1330
  try {
1332
- const outputMessage = await procedure.handler(
1331
+ const dispose = await procedure.handler(
1333
1332
  serviceContextWithTransportInfo,
1334
- inputMessage.value
1333
+ initMessage.value,
1334
+ incoming,
1335
+ outgoing
1335
1336
  );
1336
- outgoing.push(outputMessage);
1337
+ if (dispose) {
1338
+ disposables.push(dispose);
1339
+ }
1337
1340
  } catch (err) {
1338
1341
  errorHandler(err, span);
1339
1342
  } finally {
@@ -1341,67 +1344,10 @@ var RiverServer = class {
1341
1344
  }
1342
1345
  }
1343
1346
  );
1344
- })();
1345
- break;
1346
- case "stream":
1347
- if (procHasInitMessage) {
1348
- inputHandler = (async () => {
1349
- const initMessage = await incoming.next();
1350
- if (initMessage.done) {
1351
- return;
1352
- }
1353
- await tracing_default.startActiveSpan(
1354
- `${message.serviceName}.${message.procedureName}`,
1355
- {
1356
- attributes: {
1357
- component: "river",
1358
- "river.method.kind": "stream-with-init",
1359
- "river.method.service": message.serviceName,
1360
- "river.method.name": message.procedureName,
1361
- "river.streamId": message.streamId,
1362
- "span.kind": "server"
1363
- },
1364
- kind: import_api3.SpanKind.SERVER
1365
- },
1366
- activeContext,
1367
- async (span) => {
1368
- try {
1369
- const dispose = await procedure.handler(
1370
- serviceContextWithTransportInfo,
1371
- initMessage.value,
1372
- incoming,
1373
- outgoing
1374
- );
1375
- if (dispose) {
1376
- disposables.push(() => {
1377
- dispose();
1378
- span.end();
1379
- });
1380
- } else {
1381
- span.end();
1382
- }
1383
- } catch (err) {
1384
- errorHandler(err, span);
1385
- span.end();
1386
- }
1387
- }
1388
- );
1389
- })();
1390
1347
  } else {
1391
- inputHandler = tracing_default.startActiveSpan(
1392
- `${message.serviceName}.${message.procedureName}`,
1393
- {
1394
- attributes: {
1395
- component: "river",
1396
- "river.method.kind": "stream",
1397
- "river.method.service": message.serviceName,
1398
- "river.method.name": message.procedureName,
1399
- "river.streamId": message.streamId,
1400
- "span.kind": "server"
1401
- },
1402
- kind: import_api3.SpanKind.SERVER
1403
- },
1404
- activeContext,
1348
+ inputHandler = createHandlerSpan(
1349
+ procedure.type,
1350
+ message,
1405
1351
  async (span) => {
1406
1352
  try {
1407
1353
  const dispose = await procedure.handler(
@@ -1410,15 +1356,11 @@ var RiverServer = class {
1410
1356
  outgoing
1411
1357
  );
1412
1358
  if (dispose) {
1413
- disposables.push(() => {
1414
- dispose();
1415
- span.end();
1416
- });
1417
- } else {
1418
- span.end();
1359
+ disposables.push(dispose);
1419
1360
  }
1420
1361
  } catch (err) {
1421
1362
  errorHandler(err, span);
1363
+ } finally {
1422
1364
  span.end();
1423
1365
  }
1424
1366
  }
@@ -1426,102 +1368,61 @@ var RiverServer = class {
1426
1368
  }
1427
1369
  break;
1428
1370
  case "subscription":
1429
- inputHandler = (async () => {
1430
- const inputMessage = await incoming.next();
1431
- if (inputMessage.done) {
1432
- return;
1371
+ inputHandler = createHandlerSpan(
1372
+ procedure.type,
1373
+ message,
1374
+ async (span) => {
1375
+ const inputMessage = await incoming.next();
1376
+ if (inputMessage.done) {
1377
+ return;
1378
+ }
1379
+ try {
1380
+ const dispose = await procedure.handler(
1381
+ serviceContextWithTransportInfo,
1382
+ inputMessage.value,
1383
+ outgoing
1384
+ );
1385
+ if (dispose) {
1386
+ disposables.push(dispose);
1387
+ }
1388
+ } catch (err) {
1389
+ errorHandler(err, span);
1390
+ } finally {
1391
+ span.end();
1392
+ }
1433
1393
  }
1434
- await tracing_default.startActiveSpan(
1435
- `${message.serviceName}.${message.procedureName}`,
1436
- {
1437
- attributes: {
1438
- component: "river",
1439
- "river.method.kind": "subscription",
1440
- "river.method.service": message.serviceName,
1441
- "river.method.name": message.procedureName,
1442
- "river.streamId": message.streamId,
1443
- "span.kind": "server"
1444
- },
1445
- kind: import_api3.SpanKind.SERVER
1446
- },
1447
- activeContext,
1394
+ );
1395
+ break;
1396
+ case "upload":
1397
+ if (procHasInitMessage) {
1398
+ inputHandler = createHandlerSpan(
1399
+ procedure.type,
1400
+ message,
1448
1401
  async (span) => {
1402
+ const initMessage = await incoming.next();
1403
+ if (initMessage.done) {
1404
+ return;
1405
+ }
1449
1406
  try {
1450
- const dispose = await procedure.handler(
1407
+ const outputMessage = await procedure.handler(
1451
1408
  serviceContextWithTransportInfo,
1452
- inputMessage.value,
1453
- outgoing
1409
+ initMessage.value,
1410
+ incoming
1454
1411
  );
1455
- if (dispose) {
1456
- disposables.push(() => {
1457
- dispose();
1458
- span.end();
1459
- });
1460
- } else {
1461
- span.end();
1412
+ if (!this.disconnectedSessions.has(message.from)) {
1413
+ outgoing.push(outputMessage);
1462
1414
  }
1463
1415
  } catch (err) {
1464
1416
  errorHandler(err, span);
1417
+ } finally {
1465
1418
  span.end();
1466
1419
  }
1467
1420
  }
1468
1421
  );
1469
- })();
1470
- break;
1471
- case "upload":
1472
- if (procHasInitMessage) {
1473
- inputHandler = (async () => {
1474
- const initMessage = await incoming.next();
1475
- if (initMessage.done) {
1476
- return;
1477
- }
1478
- await tracing_default.startActiveSpan(
1479
- `${message.serviceName}.${message.procedureName}`,
1480
- {
1481
- attributes: {
1482
- component: "river",
1483
- "river.method.kind": "upload-with-init",
1484
- "river.method.service": message.serviceName,
1485
- "river.method.name": message.procedureName,
1486
- "river.streamId": message.streamId,
1487
- "span.kind": "server"
1488
- },
1489
- kind: import_api3.SpanKind.SERVER
1490
- },
1491
- activeContext,
1492
- async (span) => {
1493
- try {
1494
- const outputMessage = await procedure.handler(
1495
- serviceContextWithTransportInfo,
1496
- initMessage.value,
1497
- incoming
1498
- );
1499
- if (!this.disconnectedSessions.has(message.from)) {
1500
- outgoing.push(outputMessage);
1501
- }
1502
- } catch (err) {
1503
- errorHandler(err, span);
1504
- } finally {
1505
- span.end();
1506
- }
1507
- }
1508
- );
1509
- })();
1510
1422
  } else {
1511
- inputHandler = tracing_default.startActiveSpan(
1512
- `${message.serviceName}.${message.procedureName}`,
1513
- {
1514
- attributes: {
1515
- component: "river",
1516
- "river.method.kind": "upload",
1517
- "river.method.service": message.serviceName,
1518
- "river.method.name": message.procedureName,
1519
- "river.streamId": message.streamId,
1520
- "span.kind": "server"
1521
- },
1522
- kind: import_api3.SpanKind.SERVER
1523
- },
1524
- activeContext,
1423
+ inputHandler = createHandlerSpan(
1424
+ procedure.type,
1425
+ message,
1525
1426
  async (span) => {
1526
1427
  try {
1527
1428
  const outputMessage = await procedure.handler(
@@ -1587,8 +1488,8 @@ var RiverServer = class {
1587
1488
  }
1588
1489
  }
1589
1490
  getContext(service, serviceName) {
1590
- const context3 = this.contextMap.get(service);
1591
- if (!context3) {
1491
+ const context2 = this.contextMap.get(service);
1492
+ if (!context2) {
1592
1493
  const err = `no context found for ${serviceName}`;
1593
1494
  log?.error(err, {
1594
1495
  clientId: this.transport.clientId,
@@ -1596,7 +1497,7 @@ var RiverServer = class {
1596
1497
  });
1597
1498
  throw new Error(err);
1598
1499
  }
1599
- return context3;
1500
+ return context2;
1600
1501
  }
1601
1502
  cleanupStream = async (id) => {
1602
1503
  const stream2 = this.streamMap.get(id);
@@ -1610,12 +1511,14 @@ var RiverServer = class {
1610
1511
  this.streamMap.delete(id);
1611
1512
  };
1612
1513
  };
1613
- function createServer(transport, services, extendedContext) {
1614
- return new RiverServer(transport, services, extendedContext);
1514
+ function createServer(transport, services, providedServerOptions) {
1515
+ return new RiverServer(
1516
+ transport,
1517
+ services,
1518
+ providedServerOptions?.handshakeOptions,
1519
+ providedServerOptions?.extendedContext
1520
+ );
1615
1521
  }
1616
-
1617
- // package.json
1618
- var version = "0.21.1";
1619
1522
  // Annotate the CommonJS export names for ESM import in node:
1620
1523
  0 && (module.exports = {
1621
1524
  Err,