@actuallab/rpc 12.3.4 → 12.3.14
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/index.cjs +86 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -6
- package/dist/index.d.ts +40 -6
- package/dist/index.js +85 -17
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -52,6 +52,7 @@ __export(index_exports, {
|
|
|
52
52
|
RpcPeerConnectionKind: () => RpcPeerConnectionKind,
|
|
53
53
|
RpcPeerStateKind: () => RpcPeerStateKind,
|
|
54
54
|
RpcPeerStateMonitor: () => RpcPeerStateMonitor,
|
|
55
|
+
RpcRemoteExecutionMode: () => RpcRemoteExecutionMode,
|
|
55
56
|
RpcRemoteObjectTracker: () => RpcRemoteObjectTracker,
|
|
56
57
|
RpcSerializationFormat: () => RpcSerializationFormat,
|
|
57
58
|
RpcSerializationFormatResolver: () => RpcSerializationFormatResolver,
|
|
@@ -614,6 +615,18 @@ function createMessageChannelPair() {
|
|
|
614
615
|
}
|
|
615
616
|
|
|
616
617
|
// src/rpc-service-def.ts
|
|
618
|
+
var RpcRemoteExecutionMode = {
|
|
619
|
+
/** Wait for connection if disconnected when the call is made. */
|
|
620
|
+
AwaitForConnection: 1,
|
|
621
|
+
/** Resend on reconnection to the same peer. */
|
|
622
|
+
AllowReconnect: 2,
|
|
623
|
+
/** Resend on reconnection to a different peer (implies AllowReconnect). */
|
|
624
|
+
AllowResend: 6,
|
|
625
|
+
// 4 | AllowReconnect
|
|
626
|
+
/** Default: wait + reconnect + resend. */
|
|
627
|
+
Default: 7
|
|
628
|
+
// AwaitForConnection | AllowResend
|
|
629
|
+
};
|
|
617
630
|
var RpcType = {
|
|
618
631
|
object: /* @__PURE__ */ Symbol("object"),
|
|
619
632
|
stream: /* @__PURE__ */ Symbol("stream"),
|
|
@@ -630,6 +643,7 @@ function defineRpcService(name, methods) {
|
|
|
630
643
|
const cleanName = colonIndex >= 0 ? key.substring(0, colonIndex) : key;
|
|
631
644
|
const wireArgCount = input.wireArgCount ?? input.args.length + 1;
|
|
632
645
|
const mapKey = `${cleanName}:${wireArgCount}`;
|
|
646
|
+
const isNoWait = input.returns === RpcType.noWait;
|
|
633
647
|
map.set(mapKey, {
|
|
634
648
|
name: cleanName,
|
|
635
649
|
serviceName: name,
|
|
@@ -637,7 +651,8 @@ function defineRpcService(name, methods) {
|
|
|
637
651
|
wireArgCount,
|
|
638
652
|
callTypeId: input.callTypeId ?? 0,
|
|
639
653
|
stream: input.returns === RpcType.stream,
|
|
640
|
-
noWait:
|
|
654
|
+
noWait: isNoWait,
|
|
655
|
+
remoteExecutionMode: isNoWait ? 0 : input.remoteExecutionMode ?? RpcRemoteExecutionMode.Default
|
|
641
656
|
});
|
|
642
657
|
}
|
|
643
658
|
return { name, methods: map };
|
|
@@ -649,14 +664,17 @@ var RpcOutboundCall = class {
|
|
|
649
664
|
callId;
|
|
650
665
|
method;
|
|
651
666
|
result = new import_core3.PromiseSource();
|
|
667
|
+
/** Bitfield of RpcRemoteExecutionMode flags controlling reconnect/resend behavior. */
|
|
668
|
+
remoteExecutionMode;
|
|
652
669
|
/** Whether to remove this call from the tracker on $sys.Ok. Default: true.
|
|
653
670
|
* Subclasses (e.g. compute calls) override to false to stay in tracker for invalidation. */
|
|
654
671
|
removeOnOk = true;
|
|
655
672
|
/** The serialized wire data — stored for re-sending on reconnect. */
|
|
656
673
|
serializedWireData = "";
|
|
657
|
-
constructor(callId, method) {
|
|
674
|
+
constructor(callId, method, remoteExecutionMode = 7) {
|
|
658
675
|
this.callId = callId;
|
|
659
676
|
this.method = method;
|
|
677
|
+
this.remoteExecutionMode = remoteExecutionMode;
|
|
660
678
|
}
|
|
661
679
|
/** Called when the connection is lost. Subclasses can override to resolve invalidation promises. */
|
|
662
680
|
onDisconnect() {
|
|
@@ -769,6 +787,8 @@ var RpcStreamSender = class _RpcStreamSender {
|
|
|
769
787
|
_lastAckedIndex = 0;
|
|
770
788
|
_ackWaiting = null;
|
|
771
789
|
_resetRequested = false;
|
|
790
|
+
_abortController = new AbortController();
|
|
791
|
+
_iterator = null;
|
|
772
792
|
constructor(peer, ackPeriod = DEFAULT_ACK_PERIOD, ackAdvance = DEFAULT_ACK_ADVANCE, allowReconnect = true, isRealTime = false, canSkipTo = () => true) {
|
|
773
793
|
const localId = peer.sharedObjects.nextId();
|
|
774
794
|
this.id = { hostId: peer.hub.hubId, localId };
|
|
@@ -779,6 +799,10 @@ var RpcStreamSender = class _RpcStreamSender {
|
|
|
779
799
|
this.ackPeriod = ackPeriod;
|
|
780
800
|
this.ackAdvance = ackAdvance;
|
|
781
801
|
}
|
|
802
|
+
/** AbortSignal that is aborted when the sender is disconnected. */
|
|
803
|
+
get abortSignal() {
|
|
804
|
+
return this._abortController.signal;
|
|
805
|
+
}
|
|
782
806
|
/** Returns the stream reference string for the $sys.Ok response. */
|
|
783
807
|
toRef() {
|
|
784
808
|
return `${this.id.hostId},${this.id.localId},${this.ackPeriod},${this.ackAdvance},${this.allowReconnect ? "1" : "0"},${this.isRealTime ? "1" : "0"}`;
|
|
@@ -805,8 +829,7 @@ var RpcStreamSender = class _RpcStreamSender {
|
|
|
805
829
|
}
|
|
806
830
|
/** Called by system call handler when $sys.AckEnd is received from the client. */
|
|
807
831
|
onAckEnd(_hostId) {
|
|
808
|
-
this.
|
|
809
|
-
this.peer.sharedObjects.unregister(this);
|
|
832
|
+
this.disconnect();
|
|
810
833
|
}
|
|
811
834
|
/** Send a single item to the client. */
|
|
812
835
|
sendItem(item) {
|
|
@@ -863,6 +886,7 @@ var RpcStreamSender = class _RpcStreamSender {
|
|
|
863
886
|
async writeFrom(source) {
|
|
864
887
|
await this._started.promise;
|
|
865
888
|
const iterator = source[Symbol.asyncIterator]();
|
|
889
|
+
this._iterator = iterator;
|
|
866
890
|
try {
|
|
867
891
|
for (; ; ) {
|
|
868
892
|
const next = await iterator.next();
|
|
@@ -927,10 +951,20 @@ var RpcStreamSender = class _RpcStreamSender {
|
|
|
927
951
|
reconnect() {
|
|
928
952
|
}
|
|
929
953
|
disconnect() {
|
|
954
|
+
if (this._ended) return;
|
|
930
955
|
this._ended = true;
|
|
956
|
+
this._abortController.abort();
|
|
931
957
|
if (!this._started.isCompleted) {
|
|
932
958
|
this._started.resolve();
|
|
933
959
|
}
|
|
960
|
+
if (this._ackWaiting) {
|
|
961
|
+
this._ackWaiting.resolve();
|
|
962
|
+
this._ackWaiting = null;
|
|
963
|
+
}
|
|
964
|
+
if (this._iterator) {
|
|
965
|
+
void this._iterator.return?.(void 0);
|
|
966
|
+
this._iterator = null;
|
|
967
|
+
}
|
|
934
968
|
this.peer.sharedObjects.unregister(this);
|
|
935
969
|
}
|
|
936
970
|
};
|
|
@@ -995,7 +1029,7 @@ var RpcStream = class _RpcStream {
|
|
|
995
1029
|
_iterating = false;
|
|
996
1030
|
_ackSentUpTo = 0;
|
|
997
1031
|
constructor(sourceOrRef, optionsOrPeer) {
|
|
998
|
-
if (
|
|
1032
|
+
if (_isStreamSource(sourceOrRef)) {
|
|
999
1033
|
const options = optionsOrPeer ?? {};
|
|
1000
1034
|
this.kind = RpcObjectKind.Local;
|
|
1001
1035
|
this.localSource = sourceOrRef;
|
|
@@ -1056,7 +1090,8 @@ var RpcStream = class _RpcStream {
|
|
|
1056
1090
|
);
|
|
1057
1091
|
peer.sharedObjects.register(sender);
|
|
1058
1092
|
this._sender = sender;
|
|
1059
|
-
this.
|
|
1093
|
+
const source = typeof this.localSource === "function" ? this.localSource(sender.abortSignal) : this.localSource;
|
|
1094
|
+
this._whenSent = sender.writeFrom(source);
|
|
1060
1095
|
this._toRefValue = peer.format.isBinary ? {
|
|
1061
1096
|
SerializedId: [sender.id.hostId, sender.id.localId],
|
|
1062
1097
|
AckPeriod: sender.ackPeriod,
|
|
@@ -1136,7 +1171,10 @@ var RpcStream = class _RpcStream {
|
|
|
1136
1171
|
}
|
|
1137
1172
|
}
|
|
1138
1173
|
disconnect() {
|
|
1139
|
-
if (this.kind === RpcObjectKind.Local)
|
|
1174
|
+
if (this.kind === RpcObjectKind.Local) {
|
|
1175
|
+
this._sender?.disconnect();
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1140
1178
|
if (this._completed) return;
|
|
1141
1179
|
this._completed = true;
|
|
1142
1180
|
this._completionError = new Error("Peer disconnected.");
|
|
@@ -1145,7 +1183,8 @@ var RpcStream = class _RpcStream {
|
|
|
1145
1183
|
// -- AsyncIterable --
|
|
1146
1184
|
[Symbol.asyncIterator]() {
|
|
1147
1185
|
if (this.kind === RpcObjectKind.Local) {
|
|
1148
|
-
|
|
1186
|
+
const source = typeof this.localSource === "function" ? this.localSource(new AbortController().signal) : this.localSource;
|
|
1187
|
+
return source[Symbol.asyncIterator]();
|
|
1149
1188
|
}
|
|
1150
1189
|
if (this._iterating)
|
|
1151
1190
|
throw new Error("RpcStream can only be iterated once.");
|
|
@@ -1226,7 +1265,8 @@ var RpcStream = class _RpcStream {
|
|
|
1226
1265
|
}
|
|
1227
1266
|
}
|
|
1228
1267
|
};
|
|
1229
|
-
function
|
|
1268
|
+
function _isStreamSource(value) {
|
|
1269
|
+
if (typeof value === "function") return true;
|
|
1230
1270
|
return value !== null && typeof value === "object" && Symbol.asyncIterator in value;
|
|
1231
1271
|
}
|
|
1232
1272
|
function resolveStreamRefs(value, peer) {
|
|
@@ -1761,7 +1801,7 @@ var RpcPeer = class {
|
|
|
1761
1801
|
}
|
|
1762
1802
|
call(method, args, options) {
|
|
1763
1803
|
const callId = this.outbound.nextId();
|
|
1764
|
-
const outboundCall = options?.outboundCallFactory ? options.outboundCallFactory(callId, method) : new RpcOutboundCall(callId, method);
|
|
1804
|
+
const outboundCall = options?.outboundCallFactory ? options.outboundCallFactory(callId, method) : new RpcOutboundCall(callId, method, options?.remoteExecutionMode ?? 7);
|
|
1765
1805
|
const envelope = {
|
|
1766
1806
|
Method: method,
|
|
1767
1807
|
RelatedId: callId,
|
|
@@ -2098,7 +2138,18 @@ var RpcClientPeer = class extends RpcPeer {
|
|
|
2098
2138
|
}
|
|
2099
2139
|
const trackerCalls = [...this.outbound.values()];
|
|
2100
2140
|
for (const call of trackerCalls) {
|
|
2101
|
-
|
|
2141
|
+
const mode = call.remoteExecutionMode;
|
|
2142
|
+
if (!(mode & 2)) {
|
|
2143
|
+
if (!call.result.isCompleted)
|
|
2144
|
+
call.result.reject(new Error("Outbound call failed: disconnected and AllowReconnect is not set."));
|
|
2145
|
+
call.onDisconnect();
|
|
2146
|
+
this.outbound.remove(call.callId);
|
|
2147
|
+
} else if (_isPeerChanged && !(mode & 4)) {
|
|
2148
|
+
if (!call.result.isCompleted)
|
|
2149
|
+
call.result.reject(new Error("Outbound call failed: reconnected to a different peer and AllowResend is not set."));
|
|
2150
|
+
call.onDisconnect();
|
|
2151
|
+
this.outbound.remove(call.callId);
|
|
2152
|
+
} else if (!call.removeOnOk && call.result.isCompleted) {
|
|
2102
2153
|
call.onDisconnect();
|
|
2103
2154
|
this.outbound.remove(call.callId);
|
|
2104
2155
|
} else {
|
|
@@ -2122,6 +2173,9 @@ var RpcServerPeer = class extends RpcPeer {
|
|
|
2122
2173
|
/** Accept an incoming connection — sets up message handling and handshake response. */
|
|
2123
2174
|
accept(conn) {
|
|
2124
2175
|
this.setupConnection(conn);
|
|
2176
|
+
conn.closed.add(() => {
|
|
2177
|
+
this.sharedObjects.disconnectAll();
|
|
2178
|
+
});
|
|
2125
2179
|
}
|
|
2126
2180
|
_onHandshakeReceived(_handshake) {
|
|
2127
2181
|
if (this._connection !== void 0) {
|
|
@@ -2201,7 +2255,8 @@ function rpcMethod(options) {
|
|
|
2201
2255
|
methods[methodName] = {
|
|
2202
2256
|
...methods[methodName],
|
|
2203
2257
|
argCount: target.length,
|
|
2204
|
-
returns: options?.returns
|
|
2258
|
+
returns: options?.returns,
|
|
2259
|
+
remoteExecutionMode: options?.remoteExecutionMode
|
|
2205
2260
|
};
|
|
2206
2261
|
return target;
|
|
2207
2262
|
};
|
|
@@ -2816,7 +2871,8 @@ var RpcHub = class {
|
|
|
2816
2871
|
const methods = /* @__PURE__ */ new Map();
|
|
2817
2872
|
for (const [name, byArgCount] of overloads) {
|
|
2818
2873
|
if (byArgCount.size === 1) {
|
|
2819
|
-
|
|
2874
|
+
const [[, singleFn]] = byArgCount;
|
|
2875
|
+
methods.set(name, singleFn);
|
|
2820
2876
|
} else {
|
|
2821
2877
|
methods.set(name, (...args) => {
|
|
2822
2878
|
const fn = byArgCount.get(args.length);
|
|
@@ -2846,6 +2902,7 @@ var RpcHub = class {
|
|
|
2846
2902
|
for (const [name, meta] of Object.entries(methodsMeta)) {
|
|
2847
2903
|
const wireArgCount = meta.argCount + 1;
|
|
2848
2904
|
const mapKey = `${name}:${wireArgCount}`;
|
|
2905
|
+
const isNoWait = meta.returns === RpcType.noWait;
|
|
2849
2906
|
methods.set(mapKey, {
|
|
2850
2907
|
name,
|
|
2851
2908
|
serviceName: svcMeta.name,
|
|
@@ -2853,7 +2910,8 @@ var RpcHub = class {
|
|
|
2853
2910
|
wireArgCount,
|
|
2854
2911
|
callTypeId: 0,
|
|
2855
2912
|
stream: meta.returns === RpcType.stream,
|
|
2856
|
-
noWait:
|
|
2913
|
+
noWait: isNoWait,
|
|
2914
|
+
remoteExecutionMode: isNoWait ? 0 : meta.remoteExecutionMode ?? RpcRemoteExecutionMode.Default
|
|
2857
2915
|
});
|
|
2858
2916
|
}
|
|
2859
2917
|
return { name: svcMeta.name, methods };
|
|
@@ -2871,6 +2929,8 @@ var RpcHub = class {
|
|
|
2871
2929
|
/** Create a client method for the given methodDef. Override in FusionHub for custom call types. */
|
|
2872
2930
|
_createClientMethod(peer, methodDef) {
|
|
2873
2931
|
const wireName = wireMethodName(methodDef);
|
|
2932
|
+
const mode = methodDef.remoteExecutionMode;
|
|
2933
|
+
const mustCheckConnection = !(mode & RpcRemoteExecutionMode.AwaitForConnection);
|
|
2874
2934
|
if (methodDef.noWait) {
|
|
2875
2935
|
return (...args) => {
|
|
2876
2936
|
const callArgs = args.slice(0, methodDef.argCount);
|
|
@@ -2879,6 +2939,8 @@ var RpcHub = class {
|
|
|
2879
2939
|
}
|
|
2880
2940
|
if (methodDef.stream) {
|
|
2881
2941
|
return async (...args) => {
|
|
2942
|
+
if (mustCheckConnection && !peer.isConnected)
|
|
2943
|
+
throw new Error("Outbound call failed: not connected and AwaitForConnection is not set.");
|
|
2882
2944
|
const callArgs = args.slice(0, methodDef.argCount);
|
|
2883
2945
|
const outboundCall = peer.call(wireName, callArgs);
|
|
2884
2946
|
const result = await outboundCall.result.promise;
|
|
@@ -2892,8 +2954,10 @@ var RpcHub = class {
|
|
|
2892
2954
|
return stream;
|
|
2893
2955
|
};
|
|
2894
2956
|
}
|
|
2895
|
-
const callOptions = methodDef.callTypeId !== 0 ? { callTypeId: methodDef.callTypeId } : void 0;
|
|
2957
|
+
const callOptions = methodDef.callTypeId !== 0 || mode !== RpcRemoteExecutionMode.Default ? { callTypeId: methodDef.callTypeId, remoteExecutionMode: mode } : void 0;
|
|
2896
2958
|
return async (...args) => {
|
|
2959
|
+
if (mustCheckConnection && !peer.isConnected)
|
|
2960
|
+
throw new Error("Outbound call failed: not connected and AwaitForConnection is not set.");
|
|
2897
2961
|
const callArgs = args.slice(0, methodDef.argCount);
|
|
2898
2962
|
const outboundCall = peer.call(wireName, callArgs, callOptions);
|
|
2899
2963
|
const result = await outboundCall.result.promise;
|
|
@@ -2916,7 +2980,7 @@ function createRpcClient(peer, serviceDef) {
|
|
|
2916
2980
|
const methods = /* @__PURE__ */ new Map();
|
|
2917
2981
|
for (const [name, byArgCount] of overloads) {
|
|
2918
2982
|
if (byArgCount.size === 1) {
|
|
2919
|
-
const methodDef = byArgCount
|
|
2983
|
+
const [[, methodDef]] = byArgCount;
|
|
2920
2984
|
methods.set(name, createMethod(peer, methodDef));
|
|
2921
2985
|
} else {
|
|
2922
2986
|
const fns = /* @__PURE__ */ new Map();
|
|
@@ -2941,10 +3005,14 @@ function createRpcClient(peer, serviceDef) {
|
|
|
2941
3005
|
});
|
|
2942
3006
|
}
|
|
2943
3007
|
function createMethod(peer, methodDef) {
|
|
3008
|
+
const mode = methodDef.remoteExecutionMode;
|
|
3009
|
+
const mustCheckConnection = !(mode & RpcRemoteExecutionMode.AwaitForConnection);
|
|
2944
3010
|
return async (...args) => {
|
|
3011
|
+
if (mustCheckConnection && !peer.isConnected)
|
|
3012
|
+
throw new Error("Outbound call failed: not connected and AwaitForConnection is not set.");
|
|
2945
3013
|
const callArgs = args.slice(0, methodDef.argCount);
|
|
2946
3014
|
const wireName = wireMethodName(methodDef);
|
|
2947
|
-
const options = methodDef.callTypeId !== 0 ? { callTypeId: methodDef.callTypeId } : void 0;
|
|
3015
|
+
const options = methodDef.callTypeId !== 0 || mode !== RpcRemoteExecutionMode.Default ? { callTypeId: methodDef.callTypeId, remoteExecutionMode: mode } : void 0;
|
|
2948
3016
|
const outboundCall = peer.call(wireName, callArgs, options);
|
|
2949
3017
|
return outboundCall.result.promise;
|
|
2950
3018
|
};
|
|
@@ -3159,6 +3227,7 @@ var RpcPeerStateMonitor = class {
|
|
|
3159
3227
|
RpcPeerConnectionKind,
|
|
3160
3228
|
RpcPeerStateKind,
|
|
3161
3229
|
RpcPeerStateMonitor,
|
|
3230
|
+
RpcRemoteExecutionMode,
|
|
3162
3231
|
RpcRemoteObjectTracker,
|
|
3163
3232
|
RpcSerializationFormat,
|
|
3164
3233
|
RpcSerializationFormatResolver,
|