@zlink-systems/stream-connector 0.21.0 → 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.
- package/dist/browser/Contracts/Calls/ZlinkStreamCalls.d.ts +1 -3
- package/dist/browser/Contracts/IZlinkStreamConnector.d.ts +10 -24
- package/dist/browser/Contracts/ZlinkStreamActor.d.ts +10 -0
- package/dist/browser/Contracts/ZlinkStreamConnectorOptions.d.ts +1 -11
- package/dist/browser/Contracts/ZlinkStreamEnums.d.ts +2 -16
- package/dist/browser/Contracts/ZlinkStreamModels.d.ts +16 -14
- package/dist/browser/Contracts/index.d.ts +4 -3
- package/dist/browser/Runtime/Calls/ZlinkStreamCallBuilders.d.ts +5 -7
- package/dist/browser/Runtime/Protocol/ZlinkStreamFrameProtocol.d.ts +3 -5
- package/dist/browser/Runtime/Protocol/ZlinkStreamHeaderCodec.d.ts +2 -7
- package/dist/browser/Runtime/ZlinkStreamActors.d.ts +45 -0
- package/dist/browser/Runtime/ZlinkStreamConnector.d.ts +19 -30
- package/dist/browser/Runtime/ZlinkStreamConnectorLifecycle.d.ts +7 -1
- package/dist/browser/Runtime/ZlinkStreamConnectorOptions.d.ts +1 -2
- package/dist/browser/Runtime/ZlinkStreamFrameSender.d.ts +3 -5
- package/dist/browser/Runtime/ZlinkStreamPendingRequests.d.ts +3 -3
- package/dist/browser/Runtime/ZlinkStreamReceiveDispatcher.d.ts +3 -3
- package/dist/browser/Runtime/ZlinkStreamReceivedMessages.d.ts +1 -0
- package/dist/browser/index.global.js +811 -357
- package/dist/browser/index.mjs +808 -354
- package/package.json +2 -2
- package/dist/browser/Runtime/ZlinkFlowContext.d.ts +0 -15
- package/dist/browser/Runtime/ZlinkStreamDiagnosticsLevelCell.d.ts +0 -16
package/dist/browser/index.mjs
CHANGED
|
@@ -120,7 +120,8 @@ var defaultHeaderFlags = {
|
|
|
120
120
|
hasRequestSeq: 1,
|
|
121
121
|
hasMetadata: 2,
|
|
122
122
|
hasCorrelationId: 8,
|
|
123
|
-
hasFlowId: 16
|
|
123
|
+
hasFlowId: 16,
|
|
124
|
+
hasActorSlot: 32
|
|
124
125
|
};
|
|
125
126
|
var ZLINK_STREAM_FORMAT_MARKER = 242;
|
|
126
127
|
var ZLINK_STREAM_RESPONSE_KIND = 3;
|
|
@@ -167,6 +168,7 @@ function encodeStreamWireHeader(header, flagOverrides) {
|
|
|
167
168
|
}
|
|
168
169
|
const hasCorrelation = correlationBytes !== void 0;
|
|
169
170
|
const hasFlow = header.flowId !== void 0 || header.flowOrigin !== void 0;
|
|
171
|
+
const hasActorSlot = header.actorSlot !== void 0;
|
|
170
172
|
if (hasFlow && (header.flowId === void 0 || header.flowOrigin === void 0)) {
|
|
171
173
|
throw new Error("Stream flow id and origin must be provided together.");
|
|
172
174
|
}
|
|
@@ -174,13 +176,17 @@ function encodeStreamWireHeader(header, flagOverrides) {
|
|
|
174
176
|
if (header.flowOrigin !== void 0 && ![1, 2, 3, 4].includes(header.flowOrigin)) {
|
|
175
177
|
throw new Error("Stream flow origin is invalid.");
|
|
176
178
|
}
|
|
179
|
+
if (header.actorSlot !== void 0 && (!Number.isInteger(header.actorSlot) || header.actorSlot < 1 || header.actorSlot > 65535)) {
|
|
180
|
+
throw new Error("Stream actor slot is invalid.");
|
|
181
|
+
}
|
|
177
182
|
let headerFlags = header.flags;
|
|
178
183
|
headerFlags = hasRequestSeq ? headerFlags | flags.hasRequestSeq : headerFlags & ~flags.hasRequestSeq;
|
|
179
184
|
headerFlags = hasMetadata ? headerFlags | flags.hasMetadata : headerFlags & ~flags.hasMetadata;
|
|
180
185
|
headerFlags = hasCorrelation ? headerFlags | flags.hasCorrelationId : headerFlags & ~flags.hasCorrelationId;
|
|
181
186
|
headerFlags = hasFlow ? headerFlags | flags.hasFlowId : headerFlags & ~flags.hasFlowId;
|
|
187
|
+
headerFlags = hasActorSlot ? headerFlags | flags.hasActorSlot : headerFlags & ~flags.hasActorSlot;
|
|
182
188
|
const metadataBytes = hasMetadata ? encodeStreamWireMetadata(header.metadata) : new Uint8Array();
|
|
183
|
-
const size = 4 + (hasRequestSeq ? 8 : 0) + 1 + nameBytes.length + (hasMetadata ? 2 + metadataBytes.length : 0) + (hasCorrelation ? 1 + correlationBytes.length : 0) + (hasFlow ? 37 : 0);
|
|
189
|
+
const size = 4 + (hasRequestSeq ? 8 : 0) + 1 + nameBytes.length + (hasMetadata ? 2 + metadataBytes.length : 0) + (hasCorrelation ? 1 + correlationBytes.length : 0) + (hasFlow ? 37 : 0) + (hasActorSlot ? 2 : 0);
|
|
184
190
|
const buffer = new Uint8Array(size);
|
|
185
191
|
let offset = 0;
|
|
186
192
|
buffer[offset++] = ZLINK_STREAM_FORMAT_MARKER;
|
|
@@ -213,6 +219,9 @@ function encodeStreamWireHeader(header, flagOverrides) {
|
|
|
213
219
|
offset += 36;
|
|
214
220
|
buffer[offset++] = header.flowOrigin;
|
|
215
221
|
}
|
|
222
|
+
if (hasActorSlot) {
|
|
223
|
+
writeUInt16BE(buffer, offset, header.actorSlot);
|
|
224
|
+
}
|
|
216
225
|
return buffer;
|
|
217
226
|
}
|
|
218
227
|
function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
|
|
@@ -231,7 +240,8 @@ function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
|
|
|
231
240
|
const hasMetadata = (headerFlags & flags.hasMetadata) !== 0;
|
|
232
241
|
const hasCorrelation = (headerFlags & flags.hasCorrelationId) !== 0;
|
|
233
242
|
const hasFlow = (headerFlags & flags.hasFlowId) !== 0;
|
|
234
|
-
|
|
243
|
+
const hasActorSlot = (headerFlags & flags.hasActorSlot) !== 0;
|
|
244
|
+
if ((headerFlags & ~63) !== 0) {
|
|
235
245
|
throw new Error("Unknown mandatory stream header flag.");
|
|
236
246
|
}
|
|
237
247
|
let requestSeq;
|
|
@@ -286,6 +296,17 @@ function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
|
|
|
286
296
|
}
|
|
287
297
|
flowOrigin = includeFlow ? decodedFlowOrigin : void 0;
|
|
288
298
|
}
|
|
299
|
+
let actorSlot;
|
|
300
|
+
if (hasActorSlot) {
|
|
301
|
+
if (header.length - offset < 2) {
|
|
302
|
+
throw new Error("Stream actor slot is incomplete.");
|
|
303
|
+
}
|
|
304
|
+
actorSlot = readUInt16BE(header, offset);
|
|
305
|
+
if (actorSlot === 0) {
|
|
306
|
+
throw new Error("Stream actor slot must not be zero.");
|
|
307
|
+
}
|
|
308
|
+
offset += 2;
|
|
309
|
+
}
|
|
289
310
|
if (offset !== header.length) {
|
|
290
311
|
throw new Error("Stream header has trailing bytes.");
|
|
291
312
|
}
|
|
@@ -298,7 +319,8 @@ function decodeStreamWireHeader(header, flagOverrides, includeFlow = true) {
|
|
|
298
319
|
metadata: decodedMetadata.metadata,
|
|
299
320
|
correlationId,
|
|
300
321
|
flowId,
|
|
301
|
-
flowOrigin
|
|
322
|
+
flowOrigin,
|
|
323
|
+
actorSlot
|
|
302
324
|
};
|
|
303
325
|
}
|
|
304
326
|
function validateFlowId(flowId) {
|
|
@@ -464,13 +486,6 @@ var ZlinkStreamDispatchMode = /* @__PURE__ */ ((ZlinkStreamDispatchMode2) => {
|
|
|
464
486
|
ZlinkStreamDispatchMode2["Immediate"] = "immediate";
|
|
465
487
|
return ZlinkStreamDispatchMode2;
|
|
466
488
|
})(ZlinkStreamDispatchMode || {});
|
|
467
|
-
var ZlinkStreamDiagnosticsLevel = /* @__PURE__ */ ((ZlinkStreamDiagnosticsLevel4) => {
|
|
468
|
-
ZlinkStreamDiagnosticsLevel4["Off"] = "off";
|
|
469
|
-
ZlinkStreamDiagnosticsLevel4["Errors"] = "errors";
|
|
470
|
-
ZlinkStreamDiagnosticsLevel4["Normal"] = "normal";
|
|
471
|
-
ZlinkStreamDiagnosticsLevel4["Detailed"] = "detailed";
|
|
472
|
-
return ZlinkStreamDiagnosticsLevel4;
|
|
473
|
-
})(ZlinkStreamDiagnosticsLevel || {});
|
|
474
489
|
var ZlinkStreamMessageKind = /* @__PURE__ */ ((ZlinkStreamMessageKind2) => {
|
|
475
490
|
ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Send"] = 1] = "Send";
|
|
476
491
|
ZlinkStreamMessageKind2[ZlinkStreamMessageKind2["Request"] = 2] = "Request";
|
|
@@ -486,6 +501,7 @@ var ZlinkStreamHeaderFlags = /* @__PURE__ */ ((ZlinkStreamHeaderFlags2) => {
|
|
|
486
501
|
ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["PayloadCompressed"] = 4] = "PayloadCompressed";
|
|
487
502
|
ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasCorrelationId"] = 8] = "HasCorrelationId";
|
|
488
503
|
ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasFlowId"] = 16] = "HasFlowId";
|
|
504
|
+
ZlinkStreamHeaderFlags2[ZlinkStreamHeaderFlags2["HasActorSlot"] = 32] = "HasActorSlot";
|
|
489
505
|
return ZlinkStreamHeaderFlags2;
|
|
490
506
|
})(ZlinkStreamHeaderFlags || {});
|
|
491
507
|
var ZlinkStreamErrorCode = /* @__PURE__ */ ((ZlinkStreamErrorCode2) => {
|
|
@@ -628,7 +644,11 @@ function unwrapStreamError(error) {
|
|
|
628
644
|
if (error instanceof ZlinkStreamException) {
|
|
629
645
|
return error.error;
|
|
630
646
|
}
|
|
631
|
-
return {
|
|
647
|
+
return {
|
|
648
|
+
code: "remoteError" /* RemoteError */,
|
|
649
|
+
message: error instanceof Error ? error.message : String(error),
|
|
650
|
+
cause: error
|
|
651
|
+
};
|
|
632
652
|
}
|
|
633
653
|
function subscription(dispose) {
|
|
634
654
|
return { dispose };
|
|
@@ -663,7 +683,10 @@ function utf8Decode2(value) {
|
|
|
663
683
|
var zlinkStreamAssert = {
|
|
664
684
|
ensure(condition, message) {
|
|
665
685
|
if (typeof message !== "string" || message.trim().length === 0) {
|
|
666
|
-
throw connectorError(
|
|
686
|
+
throw connectorError(
|
|
687
|
+
"validationFailed" /* ValidationFailed */,
|
|
688
|
+
"zlinkStreamAssert.ensure requires a non-empty diagnostic message."
|
|
689
|
+
);
|
|
667
690
|
}
|
|
668
691
|
if (!condition) {
|
|
669
692
|
throw connectorError("validationFailed" /* ValidationFailed */, message);
|
|
@@ -712,42 +735,56 @@ function validateName(name, allowReserved = false) {
|
|
|
712
735
|
throw connectorError("validationFailed" /* ValidationFailed */, "Message name must not be empty.");
|
|
713
736
|
}
|
|
714
737
|
if (!allowReserved && name.startsWith("$zlink.")) {
|
|
715
|
-
throw connectorError(
|
|
738
|
+
throw connectorError(
|
|
739
|
+
"validationFailed" /* ValidationFailed */,
|
|
740
|
+
"Message name uses a reserved zlink prefix."
|
|
741
|
+
);
|
|
716
742
|
}
|
|
717
743
|
if (utf8Encode2(name).length > 255) {
|
|
718
|
-
throw connectorError(
|
|
744
|
+
throw connectorError(
|
|
745
|
+
"validationFailed" /* ValidationFailed */,
|
|
746
|
+
"Message name must not exceed 255 UTF-8 bytes."
|
|
747
|
+
);
|
|
719
748
|
}
|
|
720
749
|
}
|
|
721
750
|
|
|
722
751
|
// packages/stream-connector/src/Runtime/Calls/ZlinkStreamCallBuilders.ts
|
|
723
752
|
var ZlinkStreamCallBuilderState = class {
|
|
753
|
+
constructor(name, actorSlot, validateActor) {
|
|
754
|
+
this.actorSlot = actorSlot;
|
|
755
|
+
this.validateActor = validateActor;
|
|
756
|
+
this.name = name;
|
|
757
|
+
}
|
|
724
758
|
executed = false;
|
|
725
759
|
name;
|
|
726
760
|
metadata = ZlinkStreamMetadataMap.empty;
|
|
727
761
|
timeoutMs;
|
|
728
762
|
compress = false;
|
|
729
|
-
flow;
|
|
730
|
-
constructor(name) {
|
|
731
|
-
this.name = name;
|
|
732
|
-
}
|
|
733
763
|
ensureNotExecuted() {
|
|
734
764
|
if (this.executed) {
|
|
735
|
-
throw connectorError(
|
|
765
|
+
throw connectorError(
|
|
766
|
+
"validationFailed" /* ValidationFailed */,
|
|
767
|
+
"Builder instances can be executed only once."
|
|
768
|
+
);
|
|
736
769
|
}
|
|
737
770
|
this.executed = true;
|
|
771
|
+
this.validateActor?.();
|
|
738
772
|
}
|
|
739
773
|
resolveMessageName() {
|
|
740
774
|
if (this.name === void 0) {
|
|
741
|
-
throw connectorError(
|
|
775
|
+
throw connectorError(
|
|
776
|
+
"validationFailed" /* ValidationFailed */,
|
|
777
|
+
"Message name is required when the encoded stream payload has no message type."
|
|
778
|
+
);
|
|
742
779
|
}
|
|
743
780
|
return this.name;
|
|
744
781
|
}
|
|
745
782
|
};
|
|
746
783
|
var ZlinkStreamSendBuilder = class {
|
|
747
|
-
constructor(connector, name, payload) {
|
|
784
|
+
constructor(connector, name, payload, actorSlot, validateActor) {
|
|
748
785
|
this.connector = connector;
|
|
749
786
|
this.payload = payload;
|
|
750
|
-
this.state = new ZlinkStreamCallBuilderState(name);
|
|
787
|
+
this.state = new ZlinkStreamCallBuilderState(name, actorSlot, validateActor);
|
|
751
788
|
}
|
|
752
789
|
state;
|
|
753
790
|
packetName(name) {
|
|
@@ -763,10 +800,6 @@ var ZlinkStreamSendBuilder = class {
|
|
|
763
800
|
this.state.compress = true;
|
|
764
801
|
return this;
|
|
765
802
|
}
|
|
766
|
-
flowFrom(flow) {
|
|
767
|
-
this.state.flow = flow;
|
|
768
|
-
return this;
|
|
769
|
-
}
|
|
770
803
|
async submit(signal) {
|
|
771
804
|
throwIfAborted(signal);
|
|
772
805
|
this.state.ensureNotExecuted();
|
|
@@ -778,15 +811,16 @@ var ZlinkStreamSendBuilder = class {
|
|
|
778
811
|
this.state.compress,
|
|
779
812
|
void 0,
|
|
780
813
|
signal,
|
|
781
|
-
|
|
814
|
+
void 0,
|
|
815
|
+
this.state.actorSlot
|
|
782
816
|
);
|
|
783
817
|
}
|
|
784
818
|
};
|
|
785
819
|
var ZlinkStreamRequestBuilder = class {
|
|
786
|
-
constructor(connector, name, payload) {
|
|
820
|
+
constructor(connector, name, payload, actorSlot, validateActor) {
|
|
787
821
|
this.connector = connector;
|
|
788
822
|
this.payload = payload;
|
|
789
|
-
this.state = new ZlinkStreamCallBuilderState(name);
|
|
823
|
+
this.state = new ZlinkStreamCallBuilderState(name, actorSlot, validateActor);
|
|
790
824
|
}
|
|
791
825
|
state;
|
|
792
826
|
packetName(name) {
|
|
@@ -806,10 +840,6 @@ var ZlinkStreamRequestBuilder = class {
|
|
|
806
840
|
this.state.compress = true;
|
|
807
841
|
return this;
|
|
808
842
|
}
|
|
809
|
-
flowFrom(flow) {
|
|
810
|
-
this.state.flow = flow;
|
|
811
|
-
return this;
|
|
812
|
-
}
|
|
813
843
|
submit(signalOrCallback) {
|
|
814
844
|
this.state.ensureNotExecuted();
|
|
815
845
|
const operation = this.connector.requestEncoded(
|
|
@@ -819,7 +849,7 @@ var ZlinkStreamRequestBuilder = class {
|
|
|
819
849
|
this.state.compress,
|
|
820
850
|
this.state.timeoutMs ?? this.connector.options.requestTimeoutMs,
|
|
821
851
|
typeof signalOrCallback === "function" ? void 0 : signalOrCallback,
|
|
822
|
-
this.state.
|
|
852
|
+
this.state.actorSlot
|
|
823
853
|
);
|
|
824
854
|
if (typeof signalOrCallback === "function") {
|
|
825
855
|
operation.then(
|
|
@@ -828,7 +858,9 @@ var ZlinkStreamRequestBuilder = class {
|
|
|
828
858
|
);
|
|
829
859
|
return;
|
|
830
860
|
}
|
|
831
|
-
return operation.then(
|
|
861
|
+
return operation.then(
|
|
862
|
+
(value) => (this.connector.options.codec ?? zlinkStreamJsonCodec).decode(value)
|
|
863
|
+
);
|
|
832
864
|
}
|
|
833
865
|
submitEncoded(signal) {
|
|
834
866
|
this.state.ensureNotExecuted();
|
|
@@ -839,7 +871,7 @@ var ZlinkStreamRequestBuilder = class {
|
|
|
839
871
|
this.state.compress,
|
|
840
872
|
this.state.timeoutMs ?? this.connector.options.requestTimeoutMs,
|
|
841
873
|
signal,
|
|
842
|
-
this.state.
|
|
874
|
+
this.state.actorSlot
|
|
843
875
|
);
|
|
844
876
|
}
|
|
845
877
|
};
|
|
@@ -864,7 +896,12 @@ var ZlinkStreamWaitBuilder = class {
|
|
|
864
896
|
async submit(signal) {
|
|
865
897
|
this.markExecuted();
|
|
866
898
|
const timeoutMs = this.timeoutMs ?? this.connector.options.waitTimeoutMs;
|
|
867
|
-
const message = await this.connector.waitForMessage(
|
|
899
|
+
const message = await this.connector.waitForMessage(
|
|
900
|
+
this.name,
|
|
901
|
+
timeoutMs,
|
|
902
|
+
this.predicate,
|
|
903
|
+
signal
|
|
904
|
+
);
|
|
868
905
|
if (message === void 0) {
|
|
869
906
|
throw connectorError(
|
|
870
907
|
"validationFailed" /* ValidationFailed */,
|
|
@@ -875,7 +912,10 @@ var ZlinkStreamWaitBuilder = class {
|
|
|
875
912
|
}
|
|
876
913
|
ensureConfigurable() {
|
|
877
914
|
if (this.executed) {
|
|
878
|
-
throw connectorError(
|
|
915
|
+
throw connectorError(
|
|
916
|
+
"validationFailed" /* ValidationFailed */,
|
|
917
|
+
"Builder instances can be executed only once."
|
|
918
|
+
);
|
|
879
919
|
}
|
|
880
920
|
}
|
|
881
921
|
markExecuted() {
|
|
@@ -901,9 +941,17 @@ var ZlinkStreamExpectNoneBuilder = class {
|
|
|
901
941
|
async run(signal) {
|
|
902
942
|
this.markExecuted();
|
|
903
943
|
if (this.windowMs === void 0) {
|
|
904
|
-
throw connectorError(
|
|
944
|
+
throw connectorError(
|
|
945
|
+
"validationFailed" /* ValidationFailed */,
|
|
946
|
+
"expectNone requires within(windowMs)."
|
|
947
|
+
);
|
|
905
948
|
}
|
|
906
|
-
const message = await this.connector.waitForMessage(
|
|
949
|
+
const message = await this.connector.waitForMessage(
|
|
950
|
+
this.name,
|
|
951
|
+
this.windowMs,
|
|
952
|
+
() => true,
|
|
953
|
+
signal
|
|
954
|
+
);
|
|
907
955
|
if (message === void 0) {
|
|
908
956
|
return;
|
|
909
957
|
}
|
|
@@ -914,7 +962,10 @@ var ZlinkStreamExpectNoneBuilder = class {
|
|
|
914
962
|
}
|
|
915
963
|
ensureConfigurable() {
|
|
916
964
|
if (this.executed) {
|
|
917
|
-
throw connectorError(
|
|
965
|
+
throw connectorError(
|
|
966
|
+
"validationFailed" /* ValidationFailed */,
|
|
967
|
+
"Builder instances can be executed only once."
|
|
968
|
+
);
|
|
918
969
|
}
|
|
919
970
|
}
|
|
920
971
|
markExecuted() {
|
|
@@ -947,7 +998,10 @@ var ZlinkStreamSequenceBuilder = class {
|
|
|
947
998
|
async run(signal) {
|
|
948
999
|
this.markExecuted();
|
|
949
1000
|
if (this.predicates.length === 0) {
|
|
950
|
-
throw connectorError(
|
|
1001
|
+
throw connectorError(
|
|
1002
|
+
"validationFailed" /* ValidationFailed */,
|
|
1003
|
+
"waitForSequence requires at least one expectation."
|
|
1004
|
+
);
|
|
951
1005
|
}
|
|
952
1006
|
const timeoutMs = this.timeoutMs ?? this.connector.options.waitTimeoutMs;
|
|
953
1007
|
const deadline = Date.now() + timeoutMs;
|
|
@@ -979,7 +1033,10 @@ var ZlinkStreamSequenceBuilder = class {
|
|
|
979
1033
|
}
|
|
980
1034
|
ensureConfigurable() {
|
|
981
1035
|
if (this.executed) {
|
|
982
|
-
throw connectorError(
|
|
1036
|
+
throw connectorError(
|
|
1037
|
+
"validationFailed" /* ValidationFailed */,
|
|
1038
|
+
"Builder instances can be executed only once."
|
|
1039
|
+
);
|
|
983
1040
|
}
|
|
984
1041
|
}
|
|
985
1042
|
markExecuted() {
|
|
@@ -989,7 +1046,10 @@ var ZlinkStreamSequenceBuilder = class {
|
|
|
989
1046
|
};
|
|
990
1047
|
function validateTimeout(timeoutMs) {
|
|
991
1048
|
if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
|
|
992
|
-
throw connectorError(
|
|
1049
|
+
throw connectorError(
|
|
1050
|
+
"validationFailed" /* ValidationFailed */,
|
|
1051
|
+
"Timeout must be a non-negative finite number."
|
|
1052
|
+
);
|
|
993
1053
|
}
|
|
994
1054
|
}
|
|
995
1055
|
|
|
@@ -1005,7 +1065,10 @@ var zlinkStreamLz4CompressionCodec = {
|
|
|
1005
1065
|
function compressPayload(payload, compression, compressionCodec) {
|
|
1006
1066
|
const codec = resolveCompressionCodec(compression, compressionCodec);
|
|
1007
1067
|
if (codec === void 0) {
|
|
1008
|
-
throw connectorError(
|
|
1068
|
+
throw connectorError(
|
|
1069
|
+
"compressionFailed" /* CompressionFailed */,
|
|
1070
|
+
"Compression codec is not configured."
|
|
1071
|
+
);
|
|
1009
1072
|
}
|
|
1010
1073
|
return codec.compress(payload);
|
|
1011
1074
|
}
|
|
@@ -1015,7 +1078,10 @@ function decompressIfNeeded(header, payload, compression, compressionCodec, maxD
|
|
|
1015
1078
|
}
|
|
1016
1079
|
const codec = resolveCompressionCodec(compression, compressionCodec);
|
|
1017
1080
|
if (codec === void 0) {
|
|
1018
|
-
throw connectorError(
|
|
1081
|
+
throw connectorError(
|
|
1082
|
+
"decompressionFailed" /* DecompressionFailed */,
|
|
1083
|
+
"Compression codec is not configured."
|
|
1084
|
+
);
|
|
1019
1085
|
}
|
|
1020
1086
|
try {
|
|
1021
1087
|
const decompressed = codec.decompress(payload, maxDecompressedSize);
|
|
@@ -1048,26 +1114,39 @@ var ZlinkStreamFrameCodec = class {
|
|
|
1048
1114
|
try {
|
|
1049
1115
|
return decodeStreamWireFrame(frame);
|
|
1050
1116
|
} catch (cause) {
|
|
1051
|
-
throw connectorError(
|
|
1117
|
+
throw connectorError(
|
|
1118
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
1119
|
+
"Frame length does not match prefix.",
|
|
1120
|
+
cause
|
|
1121
|
+
);
|
|
1052
1122
|
}
|
|
1053
1123
|
}
|
|
1054
1124
|
};
|
|
1055
1125
|
function splitZlinkStreamFrames(chunk) {
|
|
1056
1126
|
if (chunk.length === 0) {
|
|
1057
|
-
throw connectorError(
|
|
1127
|
+
throw connectorError(
|
|
1128
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
1129
|
+
"Stream frame prefix is incomplete."
|
|
1130
|
+
);
|
|
1058
1131
|
}
|
|
1059
1132
|
const frames = [];
|
|
1060
1133
|
let offset = 0;
|
|
1061
1134
|
while (offset < chunk.length) {
|
|
1062
1135
|
const remaining = chunk.length - offset;
|
|
1063
1136
|
if (remaining < 6) {
|
|
1064
|
-
throw connectorError(
|
|
1137
|
+
throw connectorError(
|
|
1138
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
1139
|
+
"Stream frame prefix is incomplete."
|
|
1140
|
+
);
|
|
1065
1141
|
}
|
|
1066
1142
|
const headerLength = chunk[offset] << 8 | chunk[offset + 1];
|
|
1067
1143
|
const payloadLength = chunk[offset + 2] * 16777216 + (chunk[offset + 3] << 16) + (chunk[offset + 4] << 8) + chunk[offset + 5];
|
|
1068
1144
|
const frameLength = 6 + headerLength + payloadLength;
|
|
1069
1145
|
if (frameLength > remaining) {
|
|
1070
|
-
throw connectorError(
|
|
1146
|
+
throw connectorError(
|
|
1147
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
1148
|
+
"Frame length does not match prefix."
|
|
1149
|
+
);
|
|
1071
1150
|
}
|
|
1072
1151
|
frames.push(chunk.subarray(offset, offset + frameLength));
|
|
1073
1152
|
offset += frameLength;
|
|
@@ -1076,7 +1155,10 @@ function splitZlinkStreamFrames(chunk) {
|
|
|
1076
1155
|
}
|
|
1077
1156
|
function validatePayload(payloadLength, maxPayloadSize) {
|
|
1078
1157
|
if (payloadLength > maxPayloadSize) {
|
|
1079
|
-
throw connectorError(
|
|
1158
|
+
throw connectorError(
|
|
1159
|
+
"validationFailed" /* ValidationFailed */,
|
|
1160
|
+
"Payload exceeds MaxSendPayloadSize."
|
|
1161
|
+
);
|
|
1080
1162
|
}
|
|
1081
1163
|
}
|
|
1082
1164
|
|
|
@@ -1094,14 +1176,22 @@ var ZlinkStreamMetadataCodec = class {
|
|
|
1094
1176
|
}
|
|
1095
1177
|
return size;
|
|
1096
1178
|
} catch (cause) {
|
|
1097
|
-
throw connectorError(
|
|
1179
|
+
throw connectorError(
|
|
1180
|
+
"validationFailed" /* ValidationFailed */,
|
|
1181
|
+
streamWireErrorMessage(cause),
|
|
1182
|
+
cause
|
|
1183
|
+
);
|
|
1098
1184
|
}
|
|
1099
1185
|
}
|
|
1100
1186
|
static write(metadata, destination) {
|
|
1101
1187
|
try {
|
|
1102
1188
|
destination.set(encodeStreamWireMetadata(metadata.values));
|
|
1103
1189
|
} catch (cause) {
|
|
1104
|
-
throw connectorError(
|
|
1190
|
+
throw connectorError(
|
|
1191
|
+
"validationFailed" /* ValidationFailed */,
|
|
1192
|
+
streamWireErrorMessage(cause),
|
|
1193
|
+
cause
|
|
1194
|
+
);
|
|
1105
1195
|
}
|
|
1106
1196
|
}
|
|
1107
1197
|
static decode(metadata) {
|
|
@@ -1109,7 +1199,11 @@ var ZlinkStreamMetadataCodec = class {
|
|
|
1109
1199
|
const values = decodeStreamWireMetadata(metadata);
|
|
1110
1200
|
return values.size === 0 ? ZlinkStreamMetadataMap.empty : ZlinkStreamMetadataMap.from(values);
|
|
1111
1201
|
} catch (cause) {
|
|
1112
|
-
throw connectorError(
|
|
1202
|
+
throw connectorError(
|
|
1203
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
1204
|
+
streamWireErrorMessage(cause),
|
|
1205
|
+
cause
|
|
1206
|
+
);
|
|
1113
1207
|
}
|
|
1114
1208
|
}
|
|
1115
1209
|
};
|
|
@@ -1133,22 +1227,20 @@ var ZlinkStreamHeaderCodec = class {
|
|
|
1133
1227
|
name: header.name,
|
|
1134
1228
|
metadata: header.metadata.values,
|
|
1135
1229
|
correlationId: header.correlationId,
|
|
1136
|
-
|
|
1137
|
-
flowOrigin: encodeFlowOrigin(header.flowOrigin)
|
|
1230
|
+
actorSlot: header.actorSlot
|
|
1138
1231
|
});
|
|
1139
1232
|
} catch (cause) {
|
|
1140
|
-
throw connectorError(
|
|
1233
|
+
throw connectorError(
|
|
1234
|
+
"validationFailed" /* ValidationFailed */,
|
|
1235
|
+
streamWireErrorMessage2(cause),
|
|
1236
|
+
cause
|
|
1237
|
+
);
|
|
1141
1238
|
}
|
|
1142
1239
|
}
|
|
1143
|
-
|
|
1144
|
-
* `includeFlow=false` (diagnostics Off, spec 27 §4) skips reading and
|
|
1145
|
-
* validating the inbound flow fields while the structural length checks in
|
|
1146
|
-
* the wire decoder are preserved.
|
|
1147
|
-
*/
|
|
1148
|
-
static decode(header, includeFlow = true) {
|
|
1240
|
+
static decode(header) {
|
|
1149
1241
|
let decoded;
|
|
1150
1242
|
try {
|
|
1151
|
-
const wire = decodeStreamWireHeader(header, void 0,
|
|
1243
|
+
const wire = decodeStreamWireHeader(header, void 0, false);
|
|
1152
1244
|
const metadata = wire.metadata.size === 0 ? ZlinkStreamMetadataMap.empty : ZlinkStreamMetadataMap.from(wire.metadata);
|
|
1153
1245
|
decoded = {
|
|
1154
1246
|
kind: wire.kind,
|
|
@@ -1158,11 +1250,14 @@ var ZlinkStreamHeaderCodec = class {
|
|
|
1158
1250
|
name: wire.name,
|
|
1159
1251
|
metadata,
|
|
1160
1252
|
correlationId: wire.correlationId,
|
|
1161
|
-
|
|
1162
|
-
flowOrigin: decodeFlowOrigin(wire.flowOrigin)
|
|
1253
|
+
actorSlot: wire.actorSlot
|
|
1163
1254
|
};
|
|
1164
1255
|
} catch (cause) {
|
|
1165
|
-
throw connectorError(
|
|
1256
|
+
throw connectorError(
|
|
1257
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
1258
|
+
streamWireErrorMessage2(cause),
|
|
1259
|
+
cause
|
|
1260
|
+
);
|
|
1166
1261
|
}
|
|
1167
1262
|
validateEnum(decoded.kind, decoded.codec, decoded.flags);
|
|
1168
1263
|
if (!isReplyKind2(decoded.kind)) {
|
|
@@ -1178,7 +1273,7 @@ function isReplyKind2(kind) {
|
|
|
1178
1273
|
function streamWireErrorMessage2(cause) {
|
|
1179
1274
|
return cause instanceof Error ? cause.message : "Stream header is invalid.";
|
|
1180
1275
|
}
|
|
1181
|
-
function buildHeader(kind, name, codec, metadata, compress, requestSeq, correlationId,
|
|
1276
|
+
function buildHeader(kind, name, codec, metadata, compress, requestSeq, correlationId, actorSlot) {
|
|
1182
1277
|
let flags = 0 /* None */;
|
|
1183
1278
|
if (requestSeq !== void 0) {
|
|
1184
1279
|
flags |= 1 /* HasRequestSeq */;
|
|
@@ -1192,27 +1287,49 @@ function buildHeader(kind, name, codec, metadata, compress, requestSeq, correlat
|
|
|
1192
1287
|
if (correlationId !== void 0 && correlationId.length > 0) {
|
|
1193
1288
|
flags |= 8 /* HasCorrelationId */;
|
|
1194
1289
|
}
|
|
1195
|
-
if (
|
|
1196
|
-
return {
|
|
1290
|
+
if (actorSlot !== void 0) flags |= 32 /* HasActorSlot */;
|
|
1291
|
+
return {
|
|
1292
|
+
kind,
|
|
1293
|
+
codec,
|
|
1294
|
+
flags,
|
|
1295
|
+
requestSeq,
|
|
1296
|
+
name,
|
|
1297
|
+
metadata,
|
|
1298
|
+
correlationId,
|
|
1299
|
+
actorSlot
|
|
1300
|
+
};
|
|
1197
1301
|
}
|
|
1198
1302
|
function validateHeaderSemantics(header) {
|
|
1199
1303
|
validateEnum(header.kind, header.codec, header.flags);
|
|
1200
1304
|
const hasRequestSeq = header.requestSeq !== void 0 || (header.flags & 1 /* HasRequestSeq */) !== 0;
|
|
1201
1305
|
const hasMetadata = header.metadata.count > 0 || (header.flags & 2 /* HasMetadata */) !== 0;
|
|
1202
1306
|
if (header.kind === 1 /* Send */ && hasRequestSeq) {
|
|
1203
|
-
throw connectorError(
|
|
1307
|
+
throw connectorError(
|
|
1308
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
1309
|
+
"Send packet must not contain a request sequence."
|
|
1310
|
+
);
|
|
1204
1311
|
}
|
|
1205
1312
|
if ((header.kind === 2 /* Request */ || header.kind === 3 /* Response */) && !hasRequestSeq) {
|
|
1206
|
-
throw connectorError(
|
|
1313
|
+
throw connectorError(
|
|
1314
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
1315
|
+
"Request and response packets must contain a request sequence."
|
|
1316
|
+
);
|
|
1207
1317
|
}
|
|
1208
1318
|
if (header.kind === 4 /* Error */ && header.codec !== 1 /* Json */) {
|
|
1209
|
-
throw connectorError(
|
|
1319
|
+
throw connectorError(
|
|
1320
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
1321
|
+
"Error packet must use the JSON codec."
|
|
1322
|
+
);
|
|
1210
1323
|
}
|
|
1211
1324
|
if (header.kind === 5 /* Control */) {
|
|
1212
1325
|
const hasCorrelation = header.correlationId !== void 0 && header.correlationId.length > 0 || (header.flags & 8 /* HasCorrelationId */) !== 0;
|
|
1213
|
-
const hasFlow =
|
|
1214
|
-
|
|
1215
|
-
|
|
1326
|
+
const hasFlow = (header.flags & 16 /* HasFlowId */) !== 0;
|
|
1327
|
+
const hasActorSlot = header.actorSlot !== void 0 || (header.flags & 32 /* HasActorSlot */) !== 0;
|
|
1328
|
+
if (header.flags !== 0 /* None */ || hasRequestSeq || hasMetadata || hasCorrelation || hasFlow || hasActorSlot || header.codec !== 0 /* Raw */) {
|
|
1329
|
+
throw connectorError(
|
|
1330
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
1331
|
+
"Control packet must use raw codec and must not contain flags."
|
|
1332
|
+
);
|
|
1216
1333
|
}
|
|
1217
1334
|
}
|
|
1218
1335
|
}
|
|
@@ -1223,17 +1340,11 @@ function validateEnum(kind, codec, flags) {
|
|
|
1223
1340
|
if (![0, 1, 2, 3].includes(codec)) {
|
|
1224
1341
|
throw connectorError("frameDecodeFailed" /* FrameDecodeFailed */, "Unknown stream codec.");
|
|
1225
1342
|
}
|
|
1226
|
-
const known = 1 /* HasRequestSeq */ | 2 /* HasMetadata */ | 4 /* PayloadCompressed */ | 8 /* HasCorrelationId */ | 16 /* HasFlowId */;
|
|
1343
|
+
const known = 1 /* HasRequestSeq */ | 2 /* HasMetadata */ | 4 /* PayloadCompressed */ | 8 /* HasCorrelationId */ | 16 /* HasFlowId */ | 32 /* HasActorSlot */;
|
|
1227
1344
|
if ((flags & ~known) !== 0) {
|
|
1228
1345
|
throw connectorError("frameDecodeFailed" /* FrameDecodeFailed */, "Unknown stream header flag.");
|
|
1229
1346
|
}
|
|
1230
1347
|
}
|
|
1231
|
-
function encodeFlowOrigin(origin) {
|
|
1232
|
-
return origin === void 0 ? void 0 : { Inbound: 1, Timer: 2, Application: 3, Lifecycle: 4 }[origin];
|
|
1233
|
-
}
|
|
1234
|
-
function decodeFlowOrigin(origin) {
|
|
1235
|
-
return origin === void 0 ? void 0 : { 1: "Inbound", 2: "Timer", 3: "Application", 4: "Lifecycle" }[origin];
|
|
1236
|
-
}
|
|
1237
1348
|
|
|
1238
1349
|
// packages/stream-connector/src/Runtime/Protocol/ZlinkStreamFrameProtocol.ts
|
|
1239
1350
|
var ZLINK_STREAM_HEARTBEAT_PING = "$zlink.heartbeat.ping";
|
|
@@ -1242,37 +1353,47 @@ var ZlinkStreamFrameProtocol = class {
|
|
|
1242
1353
|
constructor(options) {
|
|
1243
1354
|
this.options = options;
|
|
1244
1355
|
}
|
|
1245
|
-
encode(kind, name, payload, metadata, compress, requestSeq, correlationId,
|
|
1356
|
+
encode(kind, name, payload, metadata, compress, requestSeq, correlationId, actorSlot) {
|
|
1246
1357
|
const payloadBytes = compress ? compressPayload(payload.payload, this.options.compression, this.options.compressionCodec) : payload.payload;
|
|
1247
|
-
const header = buildHeader(
|
|
1358
|
+
const header = buildHeader(
|
|
1359
|
+
kind,
|
|
1360
|
+
name,
|
|
1361
|
+
payload.codec,
|
|
1362
|
+
metadata,
|
|
1363
|
+
compress,
|
|
1364
|
+
requestSeq,
|
|
1365
|
+
correlationId,
|
|
1366
|
+
actorSlot
|
|
1367
|
+
);
|
|
1248
1368
|
return this.encodeFrame(header, payloadBytes);
|
|
1249
1369
|
}
|
|
1250
1370
|
encodeControl(name, payload = new Uint8Array()) {
|
|
1251
|
-
return this.encodeFrame(
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1371
|
+
return this.encodeFrame(
|
|
1372
|
+
{
|
|
1373
|
+
kind: 5 /* Control */,
|
|
1374
|
+
codec: 0 /* Raw */,
|
|
1375
|
+
flags: 0 /* None */,
|
|
1376
|
+
name,
|
|
1377
|
+
metadata: ZlinkStreamMetadataMap.empty
|
|
1378
|
+
},
|
|
1379
|
+
payload
|
|
1380
|
+
);
|
|
1258
1381
|
}
|
|
1259
|
-
decode(frameBytes
|
|
1382
|
+
decode(frameBytes) {
|
|
1260
1383
|
const frame = ZlinkStreamFrameCodec.decode(frameBytes);
|
|
1261
1384
|
return {
|
|
1262
|
-
|
|
1263
|
-
// read nor validated (structural length checks are preserved).
|
|
1264
|
-
header: ZlinkStreamHeaderCodec.decode(frame.header, flowEnabled),
|
|
1385
|
+
header: ZlinkStreamHeaderCodec.decode(frame.header),
|
|
1265
1386
|
payload: frame.payload
|
|
1266
1387
|
};
|
|
1267
1388
|
}
|
|
1268
|
-
|
|
1269
|
-
return this.options.diagnosticsLevel !== "off" /* Off */;
|
|
1270
|
-
}
|
|
1271
|
-
decodeFrames(chunk, flowEnabled = this.flowEnabled()) {
|
|
1389
|
+
decodeFrames(chunk) {
|
|
1272
1390
|
return splitZlinkStreamFrames(chunk).map((frame) => {
|
|
1273
|
-
const decoded = this.decode(frame
|
|
1391
|
+
const decoded = this.decode(frame);
|
|
1274
1392
|
if (decoded.payload.length > this.options.maxReceivePayloadSize) {
|
|
1275
|
-
throw connectorError(
|
|
1393
|
+
throw connectorError(
|
|
1394
|
+
"frameTooLarge" /* FrameTooLarge */,
|
|
1395
|
+
"Payload exceeds MaxReceivePayloadSize."
|
|
1396
|
+
);
|
|
1276
1397
|
}
|
|
1277
1398
|
return decoded;
|
|
1278
1399
|
});
|
|
@@ -1319,12 +1440,6 @@ function parseEndpoint(endpoint) {
|
|
|
1319
1440
|
}
|
|
1320
1441
|
|
|
1321
1442
|
// packages/stream-connector/src/Runtime/ZlinkStreamConnectorOptions.ts
|
|
1322
|
-
var validDiagnosticsLevels = /* @__PURE__ */ new Set([
|
|
1323
|
-
"off" /* Off */,
|
|
1324
|
-
"errors" /* Errors */,
|
|
1325
|
-
"normal" /* Normal */,
|
|
1326
|
-
"detailed" /* Detailed */
|
|
1327
|
-
]);
|
|
1328
1443
|
function normalizeOptions(options, defaultTransportFactory) {
|
|
1329
1444
|
const endpoint = options.endpoint;
|
|
1330
1445
|
if (endpoint.trim().length === 0) {
|
|
@@ -1332,7 +1447,10 @@ function normalizeOptions(options, defaultTransportFactory) {
|
|
|
1332
1447
|
}
|
|
1333
1448
|
const inferredTransport = inferTransport(endpoint);
|
|
1334
1449
|
if (options.transport !== void 0 && options.transport !== inferredTransport) {
|
|
1335
|
-
throw connectorError(
|
|
1450
|
+
throw connectorError(
|
|
1451
|
+
"configurationError" /* ConfigurationError */,
|
|
1452
|
+
"Configured transport conflicts with endpoint scheme."
|
|
1453
|
+
);
|
|
1336
1454
|
}
|
|
1337
1455
|
validatePositive(options.connectTimeoutMs ?? 5e3, "ConnectTimeout");
|
|
1338
1456
|
validatePositive(options.requestTimeoutMs ?? 3e4, "RequestTimeout");
|
|
@@ -1341,7 +1459,6 @@ function normalizeOptions(options, defaultTransportFactory) {
|
|
|
1341
1459
|
validatePositive(options.maxReceivePayloadSize ?? 64 * 1024, "MaxReceivePayloadSize");
|
|
1342
1460
|
validateHeartbeat(options.heartbeat);
|
|
1343
1461
|
validateReconnect(options.reconnect);
|
|
1344
|
-
validateDiagnosticsLevel(options.diagnosticsLevel);
|
|
1345
1462
|
return {
|
|
1346
1463
|
endpoint,
|
|
1347
1464
|
transport: inferredTransport,
|
|
@@ -1367,10 +1484,7 @@ function normalizeOptions(options, defaultTransportFactory) {
|
|
|
1367
1484
|
compressionCodec: resolveCompressionCodec2(options),
|
|
1368
1485
|
nameResolver: options.nameResolver ?? defaultPacketNameResolver,
|
|
1369
1486
|
transportFactory: options.transportFactory ?? defaultTransportFactory,
|
|
1370
|
-
codec: options.codec
|
|
1371
|
-
// Spec 26 §4: the default diagnostics level is Errors, which preserves
|
|
1372
|
-
// the connector's established wire behavior.
|
|
1373
|
-
diagnosticsLevel: options.diagnosticsLevel ?? "errors" /* Errors */
|
|
1487
|
+
codec: options.codec
|
|
1374
1488
|
};
|
|
1375
1489
|
}
|
|
1376
1490
|
var defaultPacketNameResolver = {
|
|
@@ -1386,17 +1500,15 @@ function resolveCompressionCodec2(options) {
|
|
|
1386
1500
|
const compression = options.compression ?? "lz4" /* Lz4 */;
|
|
1387
1501
|
if (compression === "none" /* None */) {
|
|
1388
1502
|
if (options.compressionCodec !== void 0) {
|
|
1389
|
-
throw connectorError(
|
|
1503
|
+
throw connectorError(
|
|
1504
|
+
"configurationError" /* ConfigurationError */,
|
|
1505
|
+
"compressionCodec cannot be set when compression is none."
|
|
1506
|
+
);
|
|
1390
1507
|
}
|
|
1391
1508
|
return void 0;
|
|
1392
1509
|
}
|
|
1393
1510
|
return options.compressionCodec;
|
|
1394
1511
|
}
|
|
1395
|
-
function validateDiagnosticsLevel(level) {
|
|
1396
|
-
if (level !== void 0 && !validDiagnosticsLevels.has(level)) {
|
|
1397
|
-
throw connectorError("configurationError" /* ConfigurationError */, "DiagnosticsLevel is invalid.");
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
1512
|
function validatePositive(value, name) {
|
|
1401
1513
|
if (value <= 0) {
|
|
1402
1514
|
throw connectorError("validationFailed" /* ValidationFailed */, `${name} must be positive.`);
|
|
@@ -1412,7 +1524,10 @@ function validateHeartbeat(options) {
|
|
|
1412
1524
|
validatePositive(intervalMs, "Heartbeat interval");
|
|
1413
1525
|
validatePositive(timeoutMs, "Heartbeat timeout");
|
|
1414
1526
|
if (timeoutMs <= intervalMs) {
|
|
1415
|
-
throw connectorError(
|
|
1527
|
+
throw connectorError(
|
|
1528
|
+
"validationFailed" /* ValidationFailed */,
|
|
1529
|
+
"Heartbeat timeout must be greater than the heartbeat interval."
|
|
1530
|
+
);
|
|
1416
1531
|
}
|
|
1417
1532
|
}
|
|
1418
1533
|
function validateReconnect(options) {
|
|
@@ -1423,33 +1538,20 @@ function validateReconnect(options) {
|
|
|
1423
1538
|
validatePositive(options?.initialDelayMs ?? 250, "Reconnect InitialDelay");
|
|
1424
1539
|
validatePositive(options?.maxDelayMs ?? 5e3, "Reconnect MaxDelay");
|
|
1425
1540
|
if ((options?.backoffFactor ?? 2) < 1) {
|
|
1426
|
-
throw connectorError(
|
|
1541
|
+
throw connectorError(
|
|
1542
|
+
"validationFailed" /* ValidationFailed */,
|
|
1543
|
+
"Reconnect BackoffFactor must be at least 1.0."
|
|
1544
|
+
);
|
|
1427
1545
|
}
|
|
1428
1546
|
const maxAttempts = options?.maxAttempts === void 0 ? 3 : options.maxAttempts;
|
|
1429
1547
|
if (maxAttempts !== null && !(Number.isFinite(maxAttempts) && maxAttempts > 0)) {
|
|
1430
|
-
throw connectorError(
|
|
1548
|
+
throw connectorError(
|
|
1549
|
+
"validationFailed" /* ValidationFailed */,
|
|
1550
|
+
"Reconnect MaxAttempts must be null or positive."
|
|
1551
|
+
);
|
|
1431
1552
|
}
|
|
1432
1553
|
}
|
|
1433
1554
|
|
|
1434
|
-
// packages/stream-connector/src/Runtime/ZlinkStreamDiagnosticsLevelCell.ts
|
|
1435
|
-
var ZlinkStreamDiagnosticsLevelCell = class {
|
|
1436
|
-
current;
|
|
1437
|
-
constructor(initial) {
|
|
1438
|
-
this.current = initial;
|
|
1439
|
-
}
|
|
1440
|
-
get level() {
|
|
1441
|
-
return this.current;
|
|
1442
|
-
}
|
|
1443
|
-
set(level) {
|
|
1444
|
-
const candidate = level;
|
|
1445
|
-
if (candidate === void 0 || candidate === null) {
|
|
1446
|
-
throw connectorError("configurationError" /* ConfigurationError */, "DiagnosticsLevel is invalid.");
|
|
1447
|
-
}
|
|
1448
|
-
validateDiagnosticsLevel(level);
|
|
1449
|
-
this.current = level;
|
|
1450
|
-
}
|
|
1451
|
-
};
|
|
1452
|
-
|
|
1453
1555
|
// packages/stream-connector/src/Runtime/ZlinkStreamPendingRequests.ts
|
|
1454
1556
|
var ZlinkStreamPendingRequests = class {
|
|
1455
1557
|
nextRequestSeq = 1n;
|
|
@@ -1462,14 +1564,21 @@ var ZlinkStreamPendingRequests = class {
|
|
|
1462
1564
|
let timeout;
|
|
1463
1565
|
let resolvePending;
|
|
1464
1566
|
let rejectPending;
|
|
1465
|
-
const promise = new Promise(
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1567
|
+
const promise = new Promise(
|
|
1568
|
+
(resolve, reject) => {
|
|
1569
|
+
timeout = setTimeout(() => {
|
|
1570
|
+
this.active.delete(requestSeq);
|
|
1571
|
+
reject(
|
|
1572
|
+
connectorError(
|
|
1573
|
+
"requestTimeout" /* RequestTimeout */,
|
|
1574
|
+
`Request '${packetName}' timed out.`
|
|
1575
|
+
)
|
|
1576
|
+
);
|
|
1577
|
+
}, timeoutMs);
|
|
1578
|
+
resolvePending = resolve;
|
|
1579
|
+
rejectPending = (error) => reject(connectorError(error.code, error.message, error.cause));
|
|
1580
|
+
}
|
|
1581
|
+
);
|
|
1473
1582
|
this.active.set(requestSeq, {
|
|
1474
1583
|
packetName,
|
|
1475
1584
|
promise,
|
|
@@ -1493,15 +1602,14 @@ var ZlinkStreamPendingRequests = class {
|
|
|
1493
1602
|
});
|
|
1494
1603
|
return { requestSeq, promise };
|
|
1495
1604
|
}
|
|
1496
|
-
/* stream connector spec §5.2: a pending request is matched by request_seq alone.
|
|
1497
|
-
|
|
1498
|
-
resolve(requestSeq, value) {
|
|
1605
|
+
/* stream connector spec §5.2: a pending request is matched by request_seq alone. */
|
|
1606
|
+
resolve(requestSeq, value, metadata) {
|
|
1499
1607
|
const pending = this.active.get(requestSeq);
|
|
1500
1608
|
if (pending === void 0) {
|
|
1501
1609
|
return false;
|
|
1502
1610
|
}
|
|
1503
1611
|
this.active.delete(requestSeq);
|
|
1504
|
-
pending.resolve(value);
|
|
1612
|
+
pending.resolve({ name: pending.packetName, metadata, payload: value });
|
|
1505
1613
|
return true;
|
|
1506
1614
|
}
|
|
1507
1615
|
reject(requestSeq, error) {
|
|
@@ -1637,9 +1745,11 @@ var ZlinkStreamReceivedMessages = class {
|
|
|
1637
1745
|
*/
|
|
1638
1746
|
resetForNewConnection() {
|
|
1639
1747
|
this.receivedCounts.clear();
|
|
1748
|
+
const submittedCallbacks = this.queue.slice(this.queueHead).filter((item) => item?.kind === "callback");
|
|
1640
1749
|
this.queue.length = 0;
|
|
1750
|
+
this.queue.push(...submittedCallbacks);
|
|
1641
1751
|
this.queueHead = 0;
|
|
1642
|
-
this.queuedCount =
|
|
1752
|
+
this.queuedCount = submittedCallbacks.length;
|
|
1643
1753
|
}
|
|
1644
1754
|
/**
|
|
1645
1755
|
* Releases every registered wait surface because the connection it was
|
|
@@ -1668,7 +1778,14 @@ var ZlinkStreamReceivedMessages = class {
|
|
|
1668
1778
|
return;
|
|
1669
1779
|
}
|
|
1670
1780
|
}
|
|
1671
|
-
this.queue.push({ message, signal });
|
|
1781
|
+
this.queue.push({ kind: "message", message, signal });
|
|
1782
|
+
this.queuedCount += 1;
|
|
1783
|
+
if (this.deliverOnArrival) {
|
|
1784
|
+
this.scheduleDrain();
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
enqueueCallback(callback) {
|
|
1788
|
+
this.queue.push({ kind: "callback", callback });
|
|
1672
1789
|
this.queuedCount += 1;
|
|
1673
1790
|
if (this.deliverOnArrival) {
|
|
1674
1791
|
this.scheduleDrain();
|
|
@@ -1695,7 +1812,7 @@ var ZlinkStreamReceivedMessages = class {
|
|
|
1695
1812
|
offerQueued(name, registration) {
|
|
1696
1813
|
for (let index = this.queueHead; index < this.queue.length; index += 1) {
|
|
1697
1814
|
const queued = this.queue[index];
|
|
1698
|
-
if (queued === void 0 || queued.message.name !== name) {
|
|
1815
|
+
if (queued === void 0 || queued.kind !== "message" || queued.message.name !== name) {
|
|
1699
1816
|
continue;
|
|
1700
1817
|
}
|
|
1701
1818
|
if (!registration.consume(queued.message)) {
|
|
@@ -1723,17 +1840,24 @@ var ZlinkStreamReceivedMessages = class {
|
|
|
1723
1840
|
const queued = this.queue[index];
|
|
1724
1841
|
if (queued === void 0) continue;
|
|
1725
1842
|
this.removeAt(index);
|
|
1843
|
+
if (queued.kind === "callback") {
|
|
1844
|
+
await queued.callback();
|
|
1845
|
+
continue;
|
|
1846
|
+
}
|
|
1726
1847
|
const { message, signal } = queued;
|
|
1727
1848
|
const handlers = [...this.handlers.get(message.name)];
|
|
1728
1849
|
for (const handler of handlers) {
|
|
1729
1850
|
try {
|
|
1730
1851
|
await handler(message, signal);
|
|
1731
1852
|
} catch (cause) {
|
|
1732
|
-
await this.events.publishError(
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1853
|
+
await this.events.publishError(
|
|
1854
|
+
{
|
|
1855
|
+
code: "userCallbackFailed" /* UserCallbackFailed */,
|
|
1856
|
+
message: "Typed message handler failed.",
|
|
1857
|
+
cause
|
|
1858
|
+
},
|
|
1859
|
+
signal
|
|
1860
|
+
);
|
|
1737
1861
|
}
|
|
1738
1862
|
}
|
|
1739
1863
|
}
|
|
@@ -1750,7 +1874,7 @@ var ZlinkStreamReceivedMessages = class {
|
|
|
1750
1874
|
findDeliverableIndex() {
|
|
1751
1875
|
for (let index = this.queueHead; index < this.queue.length; index += 1) {
|
|
1752
1876
|
const queued = this.queue[index];
|
|
1753
|
-
if (queued !== void 0 && (this.handlers.get(queued.message.name)?.size ?? 0) > 0) {
|
|
1877
|
+
if (queued !== void 0 && (queued.kind === "callback" || (this.handlers.get(queued.message.name)?.size ?? 0) > 0)) {
|
|
1754
1878
|
return index;
|
|
1755
1879
|
}
|
|
1756
1880
|
}
|
|
@@ -1758,7 +1882,8 @@ var ZlinkStreamReceivedMessages = class {
|
|
|
1758
1882
|
}
|
|
1759
1883
|
hasQueuedMessage(name) {
|
|
1760
1884
|
for (let index = this.queueHead; index < this.queue.length; index += 1) {
|
|
1761
|
-
|
|
1885
|
+
const queued = this.queue[index];
|
|
1886
|
+
if (queued?.kind === "message" && queued.message.name === name) return true;
|
|
1762
1887
|
}
|
|
1763
1888
|
return false;
|
|
1764
1889
|
}
|
|
@@ -1782,17 +1907,24 @@ var ZlinkStreamReceivedMessages = class {
|
|
|
1782
1907
|
|
|
1783
1908
|
// packages/stream-connector/src/Runtime/ZlinkStreamFrameSender.ts
|
|
1784
1909
|
var ZlinkStreamFrameSender = class {
|
|
1785
|
-
constructor(protocol
|
|
1910
|
+
constructor(protocol) {
|
|
1786
1911
|
this.protocol = protocol;
|
|
1787
|
-
this.flowContext = flowContext;
|
|
1788
1912
|
}
|
|
1789
1913
|
pendingWrites = /* @__PURE__ */ new Set();
|
|
1790
|
-
async send(connection, kind, name, payload, metadata, compress, requestSeq, signal, correlationId,
|
|
1914
|
+
async send(connection, kind, name, payload, metadata, compress, requestSeq, signal, correlationId, actorSlot) {
|
|
1791
1915
|
throwIfAborted(signal);
|
|
1792
|
-
const flow = this.protocol.flowEnabled() ? this.flowContext.currentOrCreate(explicitFlow) : void 0;
|
|
1793
1916
|
await this.write(
|
|
1794
1917
|
connection,
|
|
1795
|
-
this.protocol.encode(
|
|
1918
|
+
this.protocol.encode(
|
|
1919
|
+
kind,
|
|
1920
|
+
name,
|
|
1921
|
+
payload,
|
|
1922
|
+
metadata,
|
|
1923
|
+
compress,
|
|
1924
|
+
requestSeq,
|
|
1925
|
+
correlationId,
|
|
1926
|
+
actorSlot
|
|
1927
|
+
),
|
|
1796
1928
|
signal
|
|
1797
1929
|
);
|
|
1798
1930
|
}
|
|
@@ -1827,24 +1959,196 @@ var reasons = {
|
|
|
1827
1959
|
6: "TransportError"
|
|
1828
1960
|
};
|
|
1829
1961
|
function decodeSessionClosing(payload) {
|
|
1830
|
-
if (payload.length < 4 || payload[0] !== 1)
|
|
1962
|
+
if (payload.length < 4 || payload[0] !== 1)
|
|
1963
|
+
throw new Error("Unsupported session-closing version.");
|
|
1831
1964
|
const closeReason = reasons[payload[1]];
|
|
1832
1965
|
if (closeReason === void 0) throw new Error("Unknown session-closing reason.");
|
|
1833
1966
|
const length = payload[2] << 8 | payload[3];
|
|
1834
|
-
if (length > 512 || payload.length !== 4 + length)
|
|
1967
|
+
if (length > 512 || payload.length !== 4 + length)
|
|
1968
|
+
throw new Error("Invalid session-closing diagnostic length.");
|
|
1835
1969
|
const diagnostic = length === 0 ? void 0 : new TextDecoder("utf-8", { fatal: true }).decode(payload.subarray(4));
|
|
1836
1970
|
return { closeReason, diagnostic };
|
|
1837
1971
|
}
|
|
1838
1972
|
|
|
1973
|
+
// packages/stream-connector/src/Runtime/ZlinkStreamActors.ts
|
|
1974
|
+
var ACTOR_BOUND = "$zlink.actor.bound";
|
|
1975
|
+
var ACTOR_UNBOUND = "$zlink.actor.unbound";
|
|
1976
|
+
var zlinkStreamActorBinding = Symbol("zlink.stream.actorBinding");
|
|
1977
|
+
var DefaultZlinkStreamActor = class {
|
|
1978
|
+
constructor(connector, actorId, slot) {
|
|
1979
|
+
this.connector = connector;
|
|
1980
|
+
this.actorId = actorId;
|
|
1981
|
+
this.slot = slot;
|
|
1982
|
+
}
|
|
1983
|
+
bound = true;
|
|
1984
|
+
get isBound() {
|
|
1985
|
+
return this.bound;
|
|
1986
|
+
}
|
|
1987
|
+
send(payload, messageType) {
|
|
1988
|
+
this.ensureBound();
|
|
1989
|
+
return this.connector.sendForActor(this, payload, messageType);
|
|
1990
|
+
}
|
|
1991
|
+
request(payload, messageType) {
|
|
1992
|
+
this.ensureBound();
|
|
1993
|
+
return this.connector.requestForActor(this, payload, messageType);
|
|
1994
|
+
}
|
|
1995
|
+
on(nameOrType, handler, messageType) {
|
|
1996
|
+
return this.connector.onActorMessage(this, nameOrType, handler, messageType);
|
|
1997
|
+
}
|
|
1998
|
+
ensureBound() {
|
|
1999
|
+
if (!this.bound) {
|
|
2000
|
+
throw connectorError(
|
|
2001
|
+
"validationFailed" /* ValidationFailed */,
|
|
2002
|
+
`Actor '${this.actorId}' is no longer bound.`
|
|
2003
|
+
);
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
close() {
|
|
2007
|
+
this.bound = false;
|
|
2008
|
+
}
|
|
2009
|
+
};
|
|
2010
|
+
var ZlinkStreamActors = class {
|
|
2011
|
+
constructor(connector, receivedMessages, events) {
|
|
2012
|
+
this.connector = connector;
|
|
2013
|
+
this.receivedMessages = receivedMessages;
|
|
2014
|
+
this.events = events;
|
|
2015
|
+
}
|
|
2016
|
+
bySlot = /* @__PURE__ */ new Map();
|
|
2017
|
+
byId = /* @__PURE__ */ new Map();
|
|
2018
|
+
issued = [];
|
|
2019
|
+
boundHandlers = /* @__PURE__ */ new Set();
|
|
2020
|
+
unboundHandlers = /* @__PURE__ */ new Set();
|
|
2021
|
+
get snapshot() {
|
|
2022
|
+
return Object.freeze([...this.bySlot.values()]);
|
|
2023
|
+
}
|
|
2024
|
+
find(actorId) {
|
|
2025
|
+
return this.byId.get(actorId);
|
|
2026
|
+
}
|
|
2027
|
+
onBound(handler) {
|
|
2028
|
+
this.boundHandlers.add(handler);
|
|
2029
|
+
return subscription(() => this.boundHandlers.delete(handler));
|
|
2030
|
+
}
|
|
2031
|
+
onUnbound(handler) {
|
|
2032
|
+
this.unboundHandlers.add(handler);
|
|
2033
|
+
return subscription(() => this.unboundHandlers.delete(handler));
|
|
2034
|
+
}
|
|
2035
|
+
processControl(name, payload, signal) {
|
|
2036
|
+
if (name === ACTOR_BOUND) {
|
|
2037
|
+
this.bind(payload, signal);
|
|
2038
|
+
return true;
|
|
2039
|
+
}
|
|
2040
|
+
if (name === ACTOR_UNBOUND) {
|
|
2041
|
+
this.unbind(payload, signal);
|
|
2042
|
+
return true;
|
|
2043
|
+
}
|
|
2044
|
+
return false;
|
|
2045
|
+
}
|
|
2046
|
+
resolve(slot) {
|
|
2047
|
+
const actor = this.bySlot.get(slot);
|
|
2048
|
+
if (actor === void 0) {
|
|
2049
|
+
throw connectorError(
|
|
2050
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
2051
|
+
`Actor slot '${slot}' is not bound.`
|
|
2052
|
+
);
|
|
2053
|
+
}
|
|
2054
|
+
return actor;
|
|
2055
|
+
}
|
|
2056
|
+
closeAll(signal) {
|
|
2057
|
+
for (const actor of this.issued) {
|
|
2058
|
+
if (!actor.isBound) continue;
|
|
2059
|
+
this.bySlot.delete(actor.slot);
|
|
2060
|
+
this.byId.delete(actor.actorId);
|
|
2061
|
+
actor.close();
|
|
2062
|
+
this.queue(this.unboundHandlers, actor, signal);
|
|
2063
|
+
}
|
|
2064
|
+
this.issued.length = 0;
|
|
2065
|
+
}
|
|
2066
|
+
bind(payload, signal) {
|
|
2067
|
+
if (payload.length < 5 || payload[0] !== 1) {
|
|
2068
|
+
throw invalidControl("Actor bound payload is invalid.");
|
|
2069
|
+
}
|
|
2070
|
+
const slot = payload[1] << 8 | payload[2];
|
|
2071
|
+
const idLength = payload[3];
|
|
2072
|
+
if (slot === 0 || idLength === 0 || payload.length !== 4 + idLength) {
|
|
2073
|
+
throw invalidControl("Actor bound payload is invalid.");
|
|
2074
|
+
}
|
|
2075
|
+
let actorId;
|
|
2076
|
+
try {
|
|
2077
|
+
actorId = new TextDecoder("utf-8", { fatal: true }).decode(payload.subarray(4));
|
|
2078
|
+
} catch (cause) {
|
|
2079
|
+
throw connectorError(
|
|
2080
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
2081
|
+
"Actor id is not valid UTF-8.",
|
|
2082
|
+
cause
|
|
2083
|
+
);
|
|
2084
|
+
}
|
|
2085
|
+
if (actorId.length === 0 || this.bySlot.has(slot) || this.byId.has(actorId)) {
|
|
2086
|
+
throw invalidControl("Actor bound identity is already in use.");
|
|
2087
|
+
}
|
|
2088
|
+
const actor = new DefaultZlinkStreamActor(this.connector, actorId, slot);
|
|
2089
|
+
this.bySlot.set(slot, actor);
|
|
2090
|
+
this.byId.set(actorId, actor);
|
|
2091
|
+
this.issued.push(actor);
|
|
2092
|
+
this.queue(this.boundHandlers, actor, signal);
|
|
2093
|
+
}
|
|
2094
|
+
unbind(payload, signal) {
|
|
2095
|
+
if (payload.length !== 3 || payload[0] !== 1) {
|
|
2096
|
+
throw invalidControl("Actor unbound payload is invalid.");
|
|
2097
|
+
}
|
|
2098
|
+
const slot = payload[1] << 8 | payload[2];
|
|
2099
|
+
const actor = this.bySlot.get(slot);
|
|
2100
|
+
if (slot === 0 || actor === void 0) {
|
|
2101
|
+
throw invalidControl(`Actor slot '${slot}' is not bound.`);
|
|
2102
|
+
}
|
|
2103
|
+
this.bySlot.delete(slot);
|
|
2104
|
+
this.byId.delete(actor.actorId);
|
|
2105
|
+
actor.close();
|
|
2106
|
+
this.queue(this.unboundHandlers, actor, signal);
|
|
2107
|
+
}
|
|
2108
|
+
queue(handlers, actor, signal) {
|
|
2109
|
+
this.receivedMessages.enqueueCallback(() => {
|
|
2110
|
+
for (const handler of [...handlers]) {
|
|
2111
|
+
this.invoke(handler, actor, signal);
|
|
2112
|
+
}
|
|
2113
|
+
});
|
|
2114
|
+
}
|
|
2115
|
+
invoke(handler, actor, signal) {
|
|
2116
|
+
try {
|
|
2117
|
+
Promise.resolve(handler(actor, signal)).catch((cause) => {
|
|
2118
|
+
void this.events.publishError(
|
|
2119
|
+
{
|
|
2120
|
+
code: "userCallbackFailed" /* UserCallbackFailed */,
|
|
2121
|
+
message: "Actor lifecycle handler failed.",
|
|
2122
|
+
cause
|
|
2123
|
+
},
|
|
2124
|
+
signal
|
|
2125
|
+
);
|
|
2126
|
+
});
|
|
2127
|
+
} catch (cause) {
|
|
2128
|
+
void this.events.publishError(
|
|
2129
|
+
{
|
|
2130
|
+
code: "userCallbackFailed" /* UserCallbackFailed */,
|
|
2131
|
+
message: "Actor lifecycle handler failed.",
|
|
2132
|
+
cause
|
|
2133
|
+
},
|
|
2134
|
+
signal
|
|
2135
|
+
);
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
};
|
|
2139
|
+
function invalidControl(message) {
|
|
2140
|
+
return connectorError("frameDecodeFailed" /* FrameDecodeFailed */, message);
|
|
2141
|
+
}
|
|
2142
|
+
|
|
1839
2143
|
// packages/stream-connector/src/Runtime/ZlinkStreamReceiveDispatcher.ts
|
|
1840
2144
|
var ZlinkStreamReceiveDispatcher = class {
|
|
1841
|
-
constructor(protocol, pendingRequests, receivedMessages, frameSender, events,
|
|
2145
|
+
constructor(protocol, pendingRequests, receivedMessages, frameSender, events, actors, serverClosing) {
|
|
1842
2146
|
this.protocol = protocol;
|
|
1843
2147
|
this.pendingRequests = pendingRequests;
|
|
1844
2148
|
this.receivedMessages = receivedMessages;
|
|
1845
2149
|
this.frameSender = frameSender;
|
|
1846
2150
|
this.events = events;
|
|
1847
|
-
this.
|
|
2151
|
+
this.actors = actors;
|
|
1848
2152
|
this.serverClosing = serverClosing;
|
|
1849
2153
|
}
|
|
1850
2154
|
/**
|
|
@@ -1871,46 +2175,54 @@ var ZlinkStreamReceiveDispatcher = class {
|
|
|
1871
2175
|
if (frameBytes === void 0) {
|
|
1872
2176
|
return { available: false, inbound: false };
|
|
1873
2177
|
}
|
|
1874
|
-
const flowEnabled = this.protocol.flowEnabled();
|
|
1875
2178
|
let frames;
|
|
1876
2179
|
try {
|
|
1877
|
-
frames = this.protocol.decodeFrames(frameBytes
|
|
2180
|
+
frames = this.protocol.decodeFrames(frameBytes);
|
|
1878
2181
|
} catch (cause) {
|
|
1879
|
-
|
|
1880
|
-
toStreamError(cause, "frameDecodeFailed" /* FrameDecodeFailed */, "Frame decode failed."),
|
|
1881
|
-
signal
|
|
1882
|
-
);
|
|
1883
|
-
return { available: true, inbound: false };
|
|
2182
|
+
throw cause;
|
|
1884
2183
|
}
|
|
1885
2184
|
for (const frame of frames) {
|
|
1886
2185
|
if (isCurrent !== void 0 && !isCurrent()) {
|
|
1887
2186
|
break;
|
|
1888
2187
|
}
|
|
1889
2188
|
try {
|
|
1890
|
-
await this.dispatch(connection, frame.header, frame.payload, signal,
|
|
2189
|
+
await this.dispatch(connection, frame.header, frame.payload, signal, connectionForSend);
|
|
1891
2190
|
} catch (cause) {
|
|
1892
2191
|
if (frame.header.kind === 5 /* Control */ && frame.header.name === ZLINK_STREAM_HEARTBEAT_PING) {
|
|
1893
2192
|
throw cause;
|
|
1894
2193
|
}
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
2194
|
+
const error = toStreamError(
|
|
2195
|
+
cause,
|
|
2196
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
2197
|
+
"Frame dispatch failed."
|
|
1898
2198
|
);
|
|
2199
|
+
if (error.code === "frameDecodeFailed" /* FrameDecodeFailed */) {
|
|
2200
|
+
throw cause;
|
|
2201
|
+
}
|
|
2202
|
+
await this.events.publishError(error, signal);
|
|
1899
2203
|
}
|
|
1900
2204
|
}
|
|
1901
2205
|
return { available: true, inbound: true };
|
|
1902
2206
|
}
|
|
1903
|
-
async dispatch(connection, header, payload, signal,
|
|
2207
|
+
async dispatch(connection, header, payload, signal, connectionForSend) {
|
|
2208
|
+
const actor = header.actorSlot === void 0 ? void 0 : this.actors.resolve(header.actorSlot);
|
|
1904
2209
|
if (header.kind === 3 /* Response */ && header.requestSeq !== void 0) {
|
|
1905
2210
|
try {
|
|
1906
|
-
if (!this.pendingRequests.resolve(
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
2211
|
+
if (!this.pendingRequests.resolve(
|
|
2212
|
+
header.requestSeq,
|
|
2213
|
+
{
|
|
2214
|
+
codec: header.codec,
|
|
2215
|
+
payload: this.protocol.decodePayload(header, payload)
|
|
2216
|
+
},
|
|
2217
|
+
header.metadata
|
|
2218
|
+
)) {
|
|
2219
|
+
await this.events.publishError(
|
|
2220
|
+
{
|
|
2221
|
+
code: "frameDecodeFailed" /* FrameDecodeFailed */,
|
|
2222
|
+
message: `Response request sequence '${header.requestSeq}' has no pending request.`
|
|
2223
|
+
},
|
|
2224
|
+
signal
|
|
2225
|
+
);
|
|
1914
2226
|
}
|
|
1915
2227
|
} catch (cause) {
|
|
1916
2228
|
const decodeError = toStreamError(
|
|
@@ -1918,10 +2230,7 @@ var ZlinkStreamReceiveDispatcher = class {
|
|
|
1918
2230
|
"decompressionFailed" /* DecompressionFailed */,
|
|
1919
2231
|
"Decompression failed."
|
|
1920
2232
|
);
|
|
1921
|
-
if (!this.pendingRequests.reject(
|
|
1922
|
-
header.requestSeq,
|
|
1923
|
-
decodeError
|
|
1924
|
-
)) {
|
|
2233
|
+
if (!this.pendingRequests.reject(header.requestSeq, decodeError)) {
|
|
1925
2234
|
await this.events.publishError(decodeError, signal);
|
|
1926
2235
|
}
|
|
1927
2236
|
}
|
|
@@ -1939,10 +2248,7 @@ var ZlinkStreamReceiveDispatcher = class {
|
|
|
1939
2248
|
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
1940
2249
|
"Remote error payload is invalid."
|
|
1941
2250
|
);
|
|
1942
|
-
if (!this.pendingRequests.reject(
|
|
1943
|
-
header.requestSeq,
|
|
1944
|
-
decodeError
|
|
1945
|
-
)) {
|
|
2251
|
+
if (!this.pendingRequests.reject(header.requestSeq, decodeError)) {
|
|
1946
2252
|
await this.events.publishError(decodeError, signal);
|
|
1947
2253
|
}
|
|
1948
2254
|
}
|
|
@@ -1957,24 +2263,32 @@ var ZlinkStreamReceiveDispatcher = class {
|
|
|
1957
2263
|
return;
|
|
1958
2264
|
}
|
|
1959
2265
|
if (header.kind === 1 /* Send */) {
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
2266
|
+
this.receivedMessages.enqueue(
|
|
2267
|
+
{
|
|
2268
|
+
name: header.name,
|
|
2269
|
+
metadata: header.metadata,
|
|
2270
|
+
payload: { codec: header.codec, payload: this.protocol.decodePayload(header, payload) },
|
|
2271
|
+
actorId: actor?.actorId,
|
|
2272
|
+
[zlinkStreamActorBinding]: actor
|
|
2273
|
+
},
|
|
2274
|
+
signal
|
|
2275
|
+
);
|
|
1968
2276
|
}
|
|
1969
2277
|
}
|
|
1970
2278
|
async dispatchControl(connection, header, payload, signal, connectionForSend) {
|
|
2279
|
+
if (this.actors.processControl(header.name, payload, signal)) {
|
|
2280
|
+
return;
|
|
2281
|
+
}
|
|
1971
2282
|
if (header.name === ZLINK_SESSION_CLOSING) {
|
|
1972
2283
|
const closing = decodeSessionClosing(payload);
|
|
1973
2284
|
await this.serverClosing?.(closing.closeReason);
|
|
1974
2285
|
return;
|
|
1975
2286
|
}
|
|
1976
2287
|
if (payload.length !== 0) {
|
|
1977
|
-
throw connectorError(
|
|
2288
|
+
throw connectorError(
|
|
2289
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
2290
|
+
"Control packet payload must be empty."
|
|
2291
|
+
);
|
|
1978
2292
|
}
|
|
1979
2293
|
if (header.name === ZLINK_STREAM_HEARTBEAT_PING) {
|
|
1980
2294
|
try {
|
|
@@ -2002,7 +2316,11 @@ function decodeRemoteError(protocol, header, payload) {
|
|
|
2002
2316
|
try {
|
|
2003
2317
|
decoded = JSON.parse(utf8Decode2(decodedPayload));
|
|
2004
2318
|
} catch (cause) {
|
|
2005
|
-
throw connectorError(
|
|
2319
|
+
throw connectorError(
|
|
2320
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
2321
|
+
"Remote error payload must be a JSON object.",
|
|
2322
|
+
cause
|
|
2323
|
+
);
|
|
2006
2324
|
}
|
|
2007
2325
|
if (decoded === null || typeof decoded !== "object" || Array.isArray(decoded) || typeof decoded.code !== "string" || typeof decoded.message !== "string") {
|
|
2008
2326
|
throw connectorError(
|
|
@@ -2019,12 +2337,13 @@ function randomizedDelay(baseDelayMs) {
|
|
|
2019
2337
|
return Math.round(baseDelayMs * (0.5 + Math.random() * 0.5));
|
|
2020
2338
|
}
|
|
2021
2339
|
var ZlinkStreamConnectorLifecycle = class {
|
|
2022
|
-
constructor(options, pendingRequests, frameSender, receiveDispatcher, receivedMessages, events) {
|
|
2340
|
+
constructor(options, pendingRequests, frameSender, receiveDispatcher, receivedMessages, actors, events) {
|
|
2023
2341
|
this.options = options;
|
|
2024
2342
|
this.pendingRequests = pendingRequests;
|
|
2025
2343
|
this.frameSender = frameSender;
|
|
2026
2344
|
this.receiveDispatcher = receiveDispatcher;
|
|
2027
2345
|
this.receivedMessages = receivedMessages;
|
|
2346
|
+
this.actors = actors;
|
|
2028
2347
|
this.events = events;
|
|
2029
2348
|
}
|
|
2030
2349
|
receiveLoopAbort;
|
|
@@ -2081,7 +2400,10 @@ var ZlinkStreamConnectorLifecycle = class {
|
|
|
2081
2400
|
this.lateConnectCleanupError = error;
|
|
2082
2401
|
throw error;
|
|
2083
2402
|
}
|
|
2084
|
-
throw connectorError(
|
|
2403
|
+
throw connectorError(
|
|
2404
|
+
"disconnected" /* Disconnected */,
|
|
2405
|
+
"Connector closed while connecting."
|
|
2406
|
+
);
|
|
2085
2407
|
}
|
|
2086
2408
|
this.currentConnection = connection;
|
|
2087
2409
|
this.connectionGeneration += 1;
|
|
@@ -2120,8 +2442,15 @@ var ZlinkStreamConnectorLifecycle = class {
|
|
|
2120
2442
|
}
|
|
2121
2443
|
async serverClosing(reason) {
|
|
2122
2444
|
this.closeReasonValue = reason;
|
|
2123
|
-
const error = {
|
|
2124
|
-
|
|
2445
|
+
const error = {
|
|
2446
|
+
code: "disconnected" /* Disconnected */,
|
|
2447
|
+
message: `Server closed the session: ${reason}.`
|
|
2448
|
+
};
|
|
2449
|
+
await this.disconnectForTransportFailure(
|
|
2450
|
+
error,
|
|
2451
|
+
this.currentConnection,
|
|
2452
|
+
this.connectionGeneration
|
|
2453
|
+
);
|
|
2125
2454
|
}
|
|
2126
2455
|
async closeOnce(signal) {
|
|
2127
2456
|
await this.connectTask?.catch(() => void 0);
|
|
@@ -2145,10 +2474,14 @@ var ZlinkStreamConnectorLifecycle = class {
|
|
|
2145
2474
|
} catch (error) {
|
|
2146
2475
|
errors.push(error);
|
|
2147
2476
|
}
|
|
2148
|
-
this.pendingRequests.failAll({
|
|
2477
|
+
this.pendingRequests.failAll({
|
|
2478
|
+
code: "disconnected" /* Disconnected */,
|
|
2479
|
+
message: "Connector closed."
|
|
2480
|
+
});
|
|
2149
2481
|
this.receivedMessages.connectionEnded();
|
|
2150
|
-
|
|
2151
|
-
this.
|
|
2482
|
+
this.actors.closeAll(signal);
|
|
2483
|
+
this.queueState("closed" /* Closed */, void 0, signal);
|
|
2484
|
+
this.queueDisconnected(signal);
|
|
2152
2485
|
if (errors.length === 1) throw errors[0];
|
|
2153
2486
|
if (errors.length > 1) throw new AggregateError(errors, "Stream connector close failed.");
|
|
2154
2487
|
}
|
|
@@ -2270,7 +2603,11 @@ var ZlinkStreamConnectorLifecycle = class {
|
|
|
2270
2603
|
}
|
|
2271
2604
|
} catch (cause) {
|
|
2272
2605
|
if (signal.aborted) return;
|
|
2273
|
-
const error = toStreamError(
|
|
2606
|
+
const error = toStreamError(
|
|
2607
|
+
cause,
|
|
2608
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
2609
|
+
"Receive loop failed."
|
|
2610
|
+
);
|
|
2274
2611
|
await this.disconnectForTransportFailure(error, connection, generation);
|
|
2275
2612
|
} finally {
|
|
2276
2613
|
this.receiveLoopSleeping = false;
|
|
@@ -2329,7 +2666,11 @@ var ZlinkStreamConnectorLifecycle = class {
|
|
|
2329
2666
|
if (Date.now() - this.lastInboundAt > this.options.heartbeat.timeoutMs) {
|
|
2330
2667
|
this.closeReasonValue = "HeartbeatTimeout";
|
|
2331
2668
|
const error = { code: "disconnected" /* Disconnected */, message: "Heartbeat timed out." };
|
|
2332
|
-
await this.disconnectForTransportFailure(
|
|
2669
|
+
await this.disconnectForTransportFailure(
|
|
2670
|
+
error,
|
|
2671
|
+
this.currentConnection,
|
|
2672
|
+
this.connectionGeneration
|
|
2673
|
+
);
|
|
2333
2674
|
return;
|
|
2334
2675
|
}
|
|
2335
2676
|
const connection = this.currentConnection;
|
|
@@ -2369,6 +2710,7 @@ var ZlinkStreamConnectorLifecycle = class {
|
|
|
2369
2710
|
this.currentConnection = void 0;
|
|
2370
2711
|
this.pendingRequests.failAll(error);
|
|
2371
2712
|
this.receivedMessages.connectionEnded();
|
|
2713
|
+
this.actors.closeAll();
|
|
2372
2714
|
try {
|
|
2373
2715
|
await connection?.close();
|
|
2374
2716
|
} catch {
|
|
@@ -2384,11 +2726,8 @@ var ZlinkStreamConnectorLifecycle = class {
|
|
|
2384
2726
|
*/
|
|
2385
2727
|
async announceDisconnect(error) {
|
|
2386
2728
|
if (this.closeRequested) return;
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
if (announce) {
|
|
2390
|
-
void this.events.publishDisconnected().catch(() => void 0);
|
|
2391
|
-
}
|
|
2729
|
+
this.queueState("disconnected" /* Disconnected */, error);
|
|
2730
|
+
this.queueDisconnected();
|
|
2392
2731
|
if (this.shouldReconnect()) {
|
|
2393
2732
|
queueMicrotask(() => {
|
|
2394
2733
|
void this.connect().catch(() => void 0);
|
|
@@ -2436,16 +2775,35 @@ var ZlinkStreamConnectorLifecycle = class {
|
|
|
2436
2775
|
publishDisconnectedWithoutWaiting(signal) {
|
|
2437
2776
|
void this.publishDisconnectedOnce(signal).catch(() => void 0);
|
|
2438
2777
|
}
|
|
2778
|
+
queueDisconnected(signal) {
|
|
2779
|
+
if (!this.claimDisconnectedPublish()) return;
|
|
2780
|
+
this.receivedMessages.enqueueCallback(() => {
|
|
2781
|
+
void this.events.publishDisconnected(signal).catch(() => void 0);
|
|
2782
|
+
});
|
|
2783
|
+
}
|
|
2784
|
+
queueState(current, error, signal) {
|
|
2785
|
+
const change = this.transitionState(current, error);
|
|
2786
|
+
if (change === void 0) return;
|
|
2787
|
+
this.receivedMessages.enqueueCallback(() => {
|
|
2788
|
+
void this.publishStateChange(change, signal).catch(() => void 0);
|
|
2789
|
+
});
|
|
2790
|
+
}
|
|
2439
2791
|
async setState(current, error, signal) {
|
|
2792
|
+
const change = this.transitionState(current, error);
|
|
2793
|
+
if (change === void 0) return;
|
|
2794
|
+
await this.publishStateChange(change, signal);
|
|
2795
|
+
}
|
|
2796
|
+
transitionState(current, error) {
|
|
2440
2797
|
const previous = this.currentState;
|
|
2441
2798
|
this.currentState = current;
|
|
2442
2799
|
if (previous === current && error === void 0) {
|
|
2443
|
-
return;
|
|
2444
|
-
}
|
|
2445
|
-
await this.events.publishStateChanged({ previous, current, error }, signal);
|
|
2446
|
-
if (error !== void 0) {
|
|
2447
|
-
await this.events.publishError(error, signal);
|
|
2800
|
+
return void 0;
|
|
2448
2801
|
}
|
|
2802
|
+
return { previous, current, error };
|
|
2803
|
+
}
|
|
2804
|
+
async publishStateChange(change, signal) {
|
|
2805
|
+
await this.events.publishStateChanged(change, signal);
|
|
2806
|
+
if (change.error !== void 0) await this.events.publishError(change.error, signal);
|
|
2449
2807
|
}
|
|
2450
2808
|
};
|
|
2451
2809
|
|
|
@@ -2480,36 +2838,6 @@ var ZlinkStreamConnectorEvents = class {
|
|
|
2480
2838
|
}
|
|
2481
2839
|
};
|
|
2482
2840
|
|
|
2483
|
-
// packages/stream-connector/src/Runtime/ZlinkFlowContext.ts
|
|
2484
|
-
var BrowserZlinkFlowContext = class {
|
|
2485
|
-
currentOrCreate(explicit) {
|
|
2486
|
-
return explicit ?? { flowId: this.createUuidV7(), flowOrigin: "Application" };
|
|
2487
|
-
}
|
|
2488
|
-
createInbound(flowId, flowOrigin) {
|
|
2489
|
-
return { flowId: flowId ?? this.createUuidV7(), flowOrigin: flowOrigin ?? "Inbound" };
|
|
2490
|
-
}
|
|
2491
|
-
createUuidV7() {
|
|
2492
|
-
const crypto = globalThis.crypto;
|
|
2493
|
-
if (crypto === void 0) {
|
|
2494
|
-
throw connectorError(
|
|
2495
|
-
"configurationError" /* ConfigurationError */,
|
|
2496
|
-
"The browser entrypoint requires the platform Web Crypto API."
|
|
2497
|
-
);
|
|
2498
|
-
}
|
|
2499
|
-
return formatUuidV7(crypto.getRandomValues(new Uint8Array(16)));
|
|
2500
|
-
}
|
|
2501
|
-
};
|
|
2502
|
-
function formatUuidV7(bytes) {
|
|
2503
|
-
const timestamp = BigInt(Date.now());
|
|
2504
|
-
for (let index = 5; index >= 0; index -= 1) {
|
|
2505
|
-
bytes[index] = Number(timestamp >> BigInt((5 - index) * 8) & 0xffn);
|
|
2506
|
-
}
|
|
2507
|
-
bytes[6] = 112 | bytes[6] & 15;
|
|
2508
|
-
bytes[8] = 128 | bytes[8] & 63;
|
|
2509
|
-
const hex = [...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
2510
|
-
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
2511
|
-
}
|
|
2512
|
-
|
|
2513
2841
|
// packages/stream-connector/src/Runtime/Transport/BrowserWebSocketConnection.ts
|
|
2514
2842
|
var BrowserStreamTransportFactory = class {
|
|
2515
2843
|
async connect(options, signal) {
|
|
@@ -2584,7 +2912,11 @@ var BrowserWebSocketConnection = class {
|
|
|
2584
2912
|
const message = toUint8Array(event.data);
|
|
2585
2913
|
this.messages.push(message);
|
|
2586
2914
|
} catch (cause) {
|
|
2587
|
-
this.error = cause instanceof Error ? cause : connectorError(
|
|
2915
|
+
this.error = cause instanceof Error ? cause : connectorError(
|
|
2916
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
2917
|
+
"WebSocket message decode failed.",
|
|
2918
|
+
cause
|
|
2919
|
+
);
|
|
2588
2920
|
this.closed = true;
|
|
2589
2921
|
this.socket.close();
|
|
2590
2922
|
}
|
|
@@ -2592,19 +2924,28 @@ var BrowserWebSocketConnection = class {
|
|
|
2592
2924
|
};
|
|
2593
2925
|
onClose = () => {
|
|
2594
2926
|
if (!this.closed) {
|
|
2595
|
-
this.error = connectorError(
|
|
2927
|
+
this.error = connectorError(
|
|
2928
|
+
"disconnected" /* Disconnected */,
|
|
2929
|
+
"Remote stream closed the WebSocket connection."
|
|
2930
|
+
);
|
|
2596
2931
|
}
|
|
2597
2932
|
this.closed = true;
|
|
2598
2933
|
this.wakeReader();
|
|
2599
2934
|
};
|
|
2600
2935
|
onError = () => {
|
|
2601
|
-
this.error = connectorError(
|
|
2936
|
+
this.error = connectorError(
|
|
2937
|
+
"disconnected" /* Disconnected */,
|
|
2938
|
+
"Remote stream closed after a WebSocket error."
|
|
2939
|
+
);
|
|
2602
2940
|
this.closed = true;
|
|
2603
2941
|
this.wakeReader();
|
|
2604
2942
|
};
|
|
2605
2943
|
waitForMessage(signal) {
|
|
2606
2944
|
if (this.readWaiter !== void 0) {
|
|
2607
|
-
throw connectorError(
|
|
2945
|
+
throw connectorError(
|
|
2946
|
+
"validationFailed" /* ValidationFailed */,
|
|
2947
|
+
"Only one pending stream read is supported."
|
|
2948
|
+
);
|
|
2608
2949
|
}
|
|
2609
2950
|
return new Promise((resolve, reject) => {
|
|
2610
2951
|
const onAbort = () => {
|
|
@@ -2660,9 +3001,10 @@ function waitForClose(socket, signal) {
|
|
|
2660
3001
|
async function waitForOpen(socket, connectTimeoutMs, signal) {
|
|
2661
3002
|
throwIfAborted(signal);
|
|
2662
3003
|
await new Promise((resolve, reject) => {
|
|
2663
|
-
const timeout = setTimeout(
|
|
2664
|
-
connectorError("connectTimeout" /* ConnectTimeout */, "Connect timed out.")
|
|
2665
|
-
|
|
3004
|
+
const timeout = setTimeout(
|
|
3005
|
+
() => finish(connectorError("connectTimeout" /* ConnectTimeout */, "Connect timed out.")),
|
|
3006
|
+
connectTimeoutMs
|
|
3007
|
+
);
|
|
2666
3008
|
const onOpen = () => finish();
|
|
2667
3009
|
const onClose = () => finish(connectorError("connectTimeout" /* ConnectTimeout */, "Connect closed before opening."));
|
|
2668
3010
|
const onError = () => finish(connectorError("connectTimeout" /* ConnectTimeout */, "Connect failed."));
|
|
@@ -2693,7 +3035,10 @@ function toUint8Array(data) {
|
|
|
2693
3035
|
if (ArrayBuffer.isView(data)) {
|
|
2694
3036
|
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
2695
3037
|
}
|
|
2696
|
-
throw connectorError(
|
|
3038
|
+
throw connectorError(
|
|
3039
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
3040
|
+
"WebSocket text messages are not supported."
|
|
3041
|
+
);
|
|
2697
3042
|
}
|
|
2698
3043
|
|
|
2699
3044
|
// packages/stream-connector/src/Runtime/ZlinkStreamConnector.ts
|
|
@@ -2707,30 +3052,26 @@ var DefaultZlinkStreamConnector = class {
|
|
|
2707
3052
|
pendingRequests = new ZlinkStreamPendingRequests();
|
|
2708
3053
|
frameSender;
|
|
2709
3054
|
receiveDispatcher;
|
|
2710
|
-
|
|
3055
|
+
requestSendingHandlers = /* @__PURE__ */ new Set();
|
|
3056
|
+
replyReceivedHandlers = /* @__PURE__ */ new Set();
|
|
3057
|
+
boundActors;
|
|
2711
3058
|
options;
|
|
2712
3059
|
constructor(options) {
|
|
2713
|
-
const flowContext = new BrowserZlinkFlowContext();
|
|
2714
3060
|
this.options = normalizeOptions(options, new BrowserStreamTransportFactory());
|
|
2715
|
-
this.diagnosticsLevelCell = new ZlinkStreamDiagnosticsLevelCell(this.options.diagnosticsLevel);
|
|
2716
|
-
Object.defineProperty(this.options, "diagnosticsLevel", {
|
|
2717
|
-
enumerable: true,
|
|
2718
|
-
configurable: true,
|
|
2719
|
-
get: () => this.diagnosticsLevelCell.level
|
|
2720
|
-
});
|
|
2721
3061
|
const protocol = new ZlinkStreamFrameProtocol(this.options);
|
|
2722
|
-
this.frameSender = new ZlinkStreamFrameSender(protocol
|
|
3062
|
+
this.frameSender = new ZlinkStreamFrameSender(protocol);
|
|
2723
3063
|
this.receivedMessages = new ZlinkStreamReceivedMessages(
|
|
2724
3064
|
this.events,
|
|
2725
3065
|
this.options.dispatchMode === "immediate" /* Immediate */
|
|
2726
3066
|
);
|
|
3067
|
+
this.boundActors = new ZlinkStreamActors(this, this.receivedMessages, this.events);
|
|
2727
3068
|
this.receiveDispatcher = new ZlinkStreamReceiveDispatcher(
|
|
2728
3069
|
protocol,
|
|
2729
3070
|
this.pendingRequests,
|
|
2730
3071
|
this.receivedMessages,
|
|
2731
3072
|
this.frameSender,
|
|
2732
3073
|
this.events,
|
|
2733
|
-
|
|
3074
|
+
this.boundActors,
|
|
2734
3075
|
(reason) => this.lifecycle.serverClosing(reason)
|
|
2735
3076
|
);
|
|
2736
3077
|
this.lifecycle = new ZlinkStreamConnectorLifecycle(
|
|
@@ -2739,6 +3080,7 @@ var DefaultZlinkStreamConnector = class {
|
|
|
2739
3080
|
this.frameSender,
|
|
2740
3081
|
this.receiveDispatcher,
|
|
2741
3082
|
this.receivedMessages,
|
|
3083
|
+
this.boundActors,
|
|
2742
3084
|
this.events
|
|
2743
3085
|
);
|
|
2744
3086
|
}
|
|
@@ -2754,6 +3096,18 @@ var DefaultZlinkStreamConnector = class {
|
|
|
2754
3096
|
get pendingDispatchCount() {
|
|
2755
3097
|
return this.pendingRequests.count;
|
|
2756
3098
|
}
|
|
3099
|
+
get actors() {
|
|
3100
|
+
return this.boundActors.snapshot;
|
|
3101
|
+
}
|
|
3102
|
+
actor(actorId) {
|
|
3103
|
+
return this.boundActors.find(actorId);
|
|
3104
|
+
}
|
|
3105
|
+
onActorBound(handler) {
|
|
3106
|
+
return this.boundActors.onBound(handler);
|
|
3107
|
+
}
|
|
3108
|
+
onActorUnbound(handler) {
|
|
3109
|
+
return this.boundActors.onUnbound(handler);
|
|
3110
|
+
}
|
|
2757
3111
|
/**
|
|
2758
3112
|
* Spec stream-connector 32 §10: how many packets carrying `name` arrived on
|
|
2759
3113
|
* the current connection. Arrivals are what is counted, so a message a
|
|
@@ -2765,37 +3119,6 @@ var DefaultZlinkStreamConnector = class {
|
|
|
2765
3119
|
validateName(name);
|
|
2766
3120
|
return this.receivedMessages.receivedCount(name);
|
|
2767
3121
|
}
|
|
2768
|
-
/**
|
|
2769
|
-
* Current diagnostics level (spec 26 §4.1, spec stream-connector 32 §13).
|
|
2770
|
-
* Reflects the level set by the most recent {@link setDiagnosticsLevel}
|
|
2771
|
-
* call, or the construction-time option (default
|
|
2772
|
-
* {@link ZlinkStreamDiagnosticsLevel.Errors}) if it was never changed.
|
|
2773
|
-
*/
|
|
2774
|
-
get diagnosticsLevel() {
|
|
2775
|
-
return this.diagnosticsLevelCell.level;
|
|
2776
|
-
}
|
|
2777
|
-
/**
|
|
2778
|
-
* Changes the diagnostics level in place without recreating the connector
|
|
2779
|
-
* (spec 26 §4.1, spec stream-connector 32 §13). The change is an atomic
|
|
2780
|
-
* state update: it applies to processing points that read the level after
|
|
2781
|
-
* this call returns and is never applied retroactively to frames already
|
|
2782
|
-
* built. Rejects unknown values with {@link ZlinkStreamErrorCode.ConfigurationError}.
|
|
2783
|
-
* Spec stream-connector 32 §13: this surface changes the value without
|
|
2784
|
-
* waiting for anything; it is not a blocking call over the asynchronous pair,
|
|
2785
|
-
* which a receive callback would otherwise make wait for its own completion.
|
|
2786
|
-
*/
|
|
2787
|
-
setDiagnosticsLevel(level) {
|
|
2788
|
-
this.diagnosticsLevelCell.set(level);
|
|
2789
|
-
}
|
|
2790
|
-
/**
|
|
2791
|
-
* Asynchronous counterpart of {@link setDiagnosticsLevel} (spec
|
|
2792
|
-
* stream-connector 32 §13). It changes the same value; awaiting it is how a
|
|
2793
|
-
* caller observes the change, and it never replaces the synchronous surface.
|
|
2794
|
-
*/
|
|
2795
|
-
setDiagnosticsLevelAsync(level) {
|
|
2796
|
-
this.setDiagnosticsLevel(level);
|
|
2797
|
-
return Promise.resolve();
|
|
2798
|
-
}
|
|
2799
3122
|
onErrorReceived(handler) {
|
|
2800
3123
|
return this.events.onError(handler);
|
|
2801
3124
|
}
|
|
@@ -2805,6 +3128,14 @@ var DefaultZlinkStreamConnector = class {
|
|
|
2805
3128
|
onConnectionStateChanged(handler) {
|
|
2806
3129
|
return this.events.onStateChanged(handler);
|
|
2807
3130
|
}
|
|
3131
|
+
onRequestSending(handler) {
|
|
3132
|
+
this.requestSendingHandlers.add(handler);
|
|
3133
|
+
return subscription(() => this.requestSendingHandlers.delete(handler));
|
|
3134
|
+
}
|
|
3135
|
+
onReplyReceived(handler) {
|
|
3136
|
+
this.replyReceivedHandlers.add(handler);
|
|
3137
|
+
return subscription(() => this.replyReceivedHandlers.delete(handler));
|
|
3138
|
+
}
|
|
2808
3139
|
async connect(signal) {
|
|
2809
3140
|
await this.lifecycle.connect(signal);
|
|
2810
3141
|
}
|
|
@@ -2822,15 +3153,60 @@ var DefaultZlinkStreamConnector = class {
|
|
|
2822
3153
|
const encoded = this.encodePayload(payload, messageType);
|
|
2823
3154
|
return new ZlinkStreamRequestBuilder(this, this.resolveNameOrDefault(encoded), encoded);
|
|
2824
3155
|
}
|
|
2825
|
-
on(
|
|
2826
|
-
const encodedHandler = (message, signal) => handler(
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
3156
|
+
on(nameOrType, handler, messageType) {
|
|
3157
|
+
const encodedHandler = (message, signal) => handler(
|
|
3158
|
+
{
|
|
3159
|
+
name: message.name,
|
|
3160
|
+
metadata: message.metadata,
|
|
3161
|
+
payload: this.decodePayload(
|
|
3162
|
+
message.payload,
|
|
3163
|
+
messageType ?? (typeof nameOrType === "function" ? nameOrType : void 0)
|
|
3164
|
+
),
|
|
3165
|
+
actorId: message.actorId
|
|
3166
|
+
},
|
|
3167
|
+
signal
|
|
3168
|
+
);
|
|
3169
|
+
return this.receivedMessages.on(this.observedName(nameOrType), encodedHandler);
|
|
3170
|
+
}
|
|
3171
|
+
sendForActor(actor, payload, messageType) {
|
|
3172
|
+
const encoded = this.encodePayload(payload, messageType);
|
|
3173
|
+
return new ZlinkStreamSendBuilder(
|
|
3174
|
+
this,
|
|
3175
|
+
this.resolveNameOrDefault(encoded),
|
|
3176
|
+
encoded,
|
|
3177
|
+
actor.slot,
|
|
3178
|
+
() => actor.ensureBound()
|
|
3179
|
+
);
|
|
3180
|
+
}
|
|
3181
|
+
requestForActor(actor, payload, messageType) {
|
|
3182
|
+
const encoded = this.encodePayload(payload, messageType);
|
|
3183
|
+
return new ZlinkStreamRequestBuilder(
|
|
3184
|
+
this,
|
|
3185
|
+
this.resolveNameOrDefault(encoded),
|
|
3186
|
+
encoded,
|
|
3187
|
+
actor.slot,
|
|
3188
|
+
() => actor.ensureBound()
|
|
3189
|
+
);
|
|
3190
|
+
}
|
|
3191
|
+
onActorMessage(actor, nameOrType, handler, messageType) {
|
|
3192
|
+
const encodedHandler = (message, signal) => {
|
|
3193
|
+
if (message[zlinkStreamActorBinding] !== actor) {
|
|
3194
|
+
return;
|
|
3195
|
+
}
|
|
3196
|
+
return handler(
|
|
3197
|
+
{
|
|
3198
|
+
name: message.name,
|
|
3199
|
+
metadata: message.metadata,
|
|
3200
|
+
payload: this.decodePayload(
|
|
3201
|
+
message.payload,
|
|
3202
|
+
messageType ?? (typeof nameOrType === "function" ? nameOrType : void 0)
|
|
3203
|
+
),
|
|
3204
|
+
actorId: message.actorId
|
|
3205
|
+
},
|
|
3206
|
+
signal
|
|
3207
|
+
);
|
|
3208
|
+
};
|
|
3209
|
+
return this.receivedMessages.on(this.observedName(nameOrType), encodedHandler);
|
|
2834
3210
|
}
|
|
2835
3211
|
waitFor(nameOrType) {
|
|
2836
3212
|
return new ZlinkStreamWaitBuilder(this, this.observedName(nameOrType));
|
|
@@ -2850,7 +3226,10 @@ var DefaultZlinkStreamConnector = class {
|
|
|
2850
3226
|
observedName(nameOrType) {
|
|
2851
3227
|
const name = typeof nameOrType === "function" ? this.options.nameResolver.resolve(nameOrType) : nameOrType;
|
|
2852
3228
|
if (typeof name !== "string") {
|
|
2853
|
-
throw connectorError(
|
|
3229
|
+
throw connectorError(
|
|
3230
|
+
"validationFailed" /* ValidationFailed */,
|
|
3231
|
+
"Packet name must be a string or a payload constructor."
|
|
3232
|
+
);
|
|
2854
3233
|
}
|
|
2855
3234
|
validateName(name);
|
|
2856
3235
|
return name;
|
|
@@ -2870,7 +3249,10 @@ var DefaultZlinkStreamConnector = class {
|
|
|
2870
3249
|
waitForMessage(name, timeoutMs, predicate, signal) {
|
|
2871
3250
|
validateName(name);
|
|
2872
3251
|
if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
|
|
2873
|
-
throw connectorError(
|
|
3252
|
+
throw connectorError(
|
|
3253
|
+
"validationFailed" /* ValidationFailed */,
|
|
3254
|
+
"Timeout must be a non-negative finite number."
|
|
3255
|
+
);
|
|
2874
3256
|
}
|
|
2875
3257
|
throwIfAborted(signal);
|
|
2876
3258
|
return new Promise((resolve, reject) => {
|
|
@@ -2896,30 +3278,35 @@ var DefaultZlinkStreamConnector = class {
|
|
|
2896
3278
|
};
|
|
2897
3279
|
timer = setTimeout(() => finish(), timeoutMs);
|
|
2898
3280
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
2899
|
-
disposable = this.receivedMessages.observe(
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
try {
|
|
2904
|
-
const decoded = {
|
|
2905
|
-
name: message.name,
|
|
2906
|
-
metadata: message.metadata,
|
|
2907
|
-
payload: this.decodeWaitPayload(message.payload),
|
|
2908
|
-
flowId: message.flowId,
|
|
2909
|
-
flowOrigin: message.flowOrigin
|
|
2910
|
-
};
|
|
2911
|
-
if (!predicate(decoded)) {
|
|
3281
|
+
disposable = this.receivedMessages.observe(
|
|
3282
|
+
name,
|
|
3283
|
+
(message) => {
|
|
3284
|
+
if (done) {
|
|
2912
3285
|
return false;
|
|
2913
3286
|
}
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
3287
|
+
try {
|
|
3288
|
+
const decoded = {
|
|
3289
|
+
name: message.name,
|
|
3290
|
+
metadata: message.metadata,
|
|
3291
|
+
payload: this.decodeWaitPayload(message.payload),
|
|
3292
|
+
actorId: message.actorId
|
|
3293
|
+
};
|
|
3294
|
+
if (!predicate(decoded)) {
|
|
3295
|
+
return false;
|
|
3296
|
+
}
|
|
3297
|
+
finish(void 0, decoded);
|
|
3298
|
+
} catch (cause) {
|
|
3299
|
+
finish(cause);
|
|
3300
|
+
}
|
|
3301
|
+
return true;
|
|
3302
|
+
},
|
|
3303
|
+
() => finish(
|
|
3304
|
+
connectorError(
|
|
3305
|
+
"disconnected" /* Disconnected */,
|
|
3306
|
+
`The connection this wait for '${name}' observed has ended.`
|
|
3307
|
+
)
|
|
3308
|
+
)
|
|
3309
|
+
);
|
|
2923
3310
|
});
|
|
2924
3311
|
}
|
|
2925
3312
|
encodePayload(payload, messageType) {
|
|
@@ -2941,7 +3328,7 @@ var DefaultZlinkStreamConnector = class {
|
|
|
2941
3328
|
}
|
|
2942
3329
|
return payload;
|
|
2943
3330
|
}
|
|
2944
|
-
async sendEncoded(kind, name, payload, metadata, compress, requestSeq, signal,
|
|
3331
|
+
async sendEncoded(kind, name, payload, metadata, compress, requestSeq, signal, correlationId, actorSlot) {
|
|
2945
3332
|
await this.frameSender.send(
|
|
2946
3333
|
this.lifecycle.connectionForSend(),
|
|
2947
3334
|
kind,
|
|
@@ -2952,37 +3339,105 @@ var DefaultZlinkStreamConnector = class {
|
|
|
2952
3339
|
requestSeq,
|
|
2953
3340
|
signal,
|
|
2954
3341
|
correlationId,
|
|
2955
|
-
|
|
3342
|
+
actorSlot
|
|
2956
3343
|
);
|
|
2957
3344
|
}
|
|
2958
3345
|
/**
|
|
2959
3346
|
* Per-connector monotonic correlation id (hex). The client generates it on each request
|
|
2960
|
-
* and the server echoes it back on the reply
|
|
3347
|
+
* and the server echoes it back on the reply.
|
|
2961
3348
|
*/
|
|
2962
3349
|
nextCorrelationId() {
|
|
2963
3350
|
this.correlationCounter += 1n;
|
|
2964
3351
|
return this.correlationCounter.toString(16);
|
|
2965
3352
|
}
|
|
2966
|
-
async requestEncoded(name, payload, metadata, compress, timeoutMs, signal,
|
|
2967
|
-
const
|
|
3353
|
+
async requestEncoded(name, payload, metadata, compress, timeoutMs, signal, actorSlot) {
|
|
3354
|
+
const startedAt = Date.now();
|
|
3355
|
+
const actorId = actorSlot === void 0 ? void 0 : this.boundActors.resolve(actorSlot).actorId;
|
|
3356
|
+
let requestMetadata = metadata;
|
|
3357
|
+
const sendingContext = {
|
|
3358
|
+
requestPacketName: name,
|
|
3359
|
+
actorId,
|
|
3360
|
+
setMetadata(key, value) {
|
|
3361
|
+
requestMetadata = requestMetadata.with(key, value);
|
|
3362
|
+
}
|
|
3363
|
+
};
|
|
3364
|
+
let pending;
|
|
2968
3365
|
try {
|
|
3366
|
+
throwIfAborted(signal);
|
|
3367
|
+
for (const handler of [...this.requestSendingHandlers]) {
|
|
3368
|
+
try {
|
|
3369
|
+
handler(sendingContext);
|
|
3370
|
+
} catch (cause) {
|
|
3371
|
+
queueMicrotask(() => {
|
|
3372
|
+
void this.events.publishError(
|
|
3373
|
+
toStreamError(
|
|
3374
|
+
cause,
|
|
3375
|
+
"userCallbackFailed" /* UserCallbackFailed */,
|
|
3376
|
+
"Request sending hook failed."
|
|
3377
|
+
),
|
|
3378
|
+
signal
|
|
3379
|
+
);
|
|
3380
|
+
});
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
pending = this.pendingRequests.create(name, timeoutMs);
|
|
2969
3384
|
await this.sendEncoded(
|
|
2970
3385
|
2 /* Request */,
|
|
2971
3386
|
name,
|
|
2972
3387
|
payload,
|
|
2973
|
-
|
|
3388
|
+
requestMetadata,
|
|
2974
3389
|
compress,
|
|
2975
3390
|
pending.requestSeq,
|
|
2976
3391
|
signal,
|
|
2977
|
-
|
|
2978
|
-
|
|
3392
|
+
this.nextCorrelationId(),
|
|
3393
|
+
actorSlot
|
|
2979
3394
|
);
|
|
2980
|
-
|
|
3395
|
+
const reply = await pending.promise;
|
|
3396
|
+
this.publishReplyReceived(
|
|
3397
|
+
{
|
|
3398
|
+
requestPacketName: name,
|
|
3399
|
+
actorId,
|
|
3400
|
+
succeeded: true,
|
|
3401
|
+
reply: { ...reply, actorId },
|
|
3402
|
+
elapsed: Date.now() - startedAt
|
|
3403
|
+
},
|
|
3404
|
+
signal
|
|
3405
|
+
);
|
|
3406
|
+
return reply.payload;
|
|
2981
3407
|
} catch (error) {
|
|
2982
|
-
this.pendingRequests.cancel(pending.requestSeq);
|
|
3408
|
+
if (pending !== void 0) this.pendingRequests.cancel(pending.requestSeq);
|
|
3409
|
+
this.publishReplyReceived(
|
|
3410
|
+
{
|
|
3411
|
+
requestPacketName: name,
|
|
3412
|
+
actorId,
|
|
3413
|
+
succeeded: false,
|
|
3414
|
+
error: unwrapStreamError(error),
|
|
3415
|
+
elapsed: Date.now() - startedAt
|
|
3416
|
+
},
|
|
3417
|
+
signal
|
|
3418
|
+
);
|
|
2983
3419
|
throw error;
|
|
2984
3420
|
}
|
|
2985
3421
|
}
|
|
3422
|
+
publishReplyReceived(context, signal) {
|
|
3423
|
+
if (this.replyReceivedHandlers.size === 0) return;
|
|
3424
|
+
this.receivedMessages.enqueueCallback(async () => {
|
|
3425
|
+
for (const handler of [...this.replyReceivedHandlers]) {
|
|
3426
|
+
try {
|
|
3427
|
+
await handler(context, signal);
|
|
3428
|
+
} catch (cause) {
|
|
3429
|
+
await this.events.publishError(
|
|
3430
|
+
toStreamError(
|
|
3431
|
+
cause,
|
|
3432
|
+
"userCallbackFailed" /* UserCallbackFailed */,
|
|
3433
|
+
"Reply received hook failed."
|
|
3434
|
+
),
|
|
3435
|
+
signal
|
|
3436
|
+
);
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
});
|
|
3440
|
+
}
|
|
2986
3441
|
resolveNameOrDefault(payload) {
|
|
2987
3442
|
if (payload.messageType === void 0) {
|
|
2988
3443
|
return void 0;
|
|
@@ -3008,7 +3463,6 @@ export {
|
|
|
3008
3463
|
ZlinkStreamCodec,
|
|
3009
3464
|
ZlinkStreamCompression,
|
|
3010
3465
|
ZlinkStreamConnectionState,
|
|
3011
|
-
ZlinkStreamDiagnosticsLevel,
|
|
3012
3466
|
ZlinkStreamDispatchMode,
|
|
3013
3467
|
ZlinkStreamErrorCode,
|
|
3014
3468
|
ZlinkStreamException,
|