@actuallab/rpc 14.4.14 → 15.0.21
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 +69 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +69 -27
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1014,6 +1014,14 @@ var RpcError = class extends Error {
|
|
|
1014
1014
|
this.typeName = typeName;
|
|
1015
1015
|
}
|
|
1016
1016
|
};
|
|
1017
|
+
var CANCELLATION_TYPE_NAMES = /* @__PURE__ */ new Set([
|
|
1018
|
+
"System.OperationCanceledException",
|
|
1019
|
+
"System.Threading.Tasks.TaskCanceledException",
|
|
1020
|
+
"ActualLab.Rpc.RpcRerouteException"
|
|
1021
|
+
]);
|
|
1022
|
+
function isCancellationTypeName(typeName) {
|
|
1023
|
+
return typeName !== void 0 && CANCELLATION_TYPE_NAMES.has(typeName);
|
|
1024
|
+
}
|
|
1017
1025
|
var REMOTE_EXCEPTION_TYPE_REF = "ActualLab.Serialization.RemoteException, ActualLab.Core";
|
|
1018
1026
|
var genericErrorFilter = () => ({
|
|
1019
1027
|
TypeRef: REMOTE_EXCEPTION_TYPE_REF,
|
|
@@ -1173,15 +1181,21 @@ var RpcSystemCallHandler = class {
|
|
|
1173
1181
|
const call = peer.outboundCalls.get(relatedId);
|
|
1174
1182
|
if (call !== void 0) {
|
|
1175
1183
|
call.completedStage |= RpcCallStage.ResultReady;
|
|
1176
|
-
|
|
1184
|
+
const errorInfo = args[0];
|
|
1185
|
+
const typeName = extractTypeName(errorInfo?.TypeRef ?? errorInfo?.typeRef);
|
|
1186
|
+
const isCancelled = !call.removeOnOk && isCancellationTypeName(typeName);
|
|
1187
|
+
if (call.removeOnOk || isCancelled) {
|
|
1177
1188
|
peer.outboundCalls.remove(relatedId);
|
|
1178
1189
|
}
|
|
1179
|
-
const errorInfo = args[0];
|
|
1180
1190
|
const msg = errorInfo?.Message ?? errorInfo?.message ?? "RPC error";
|
|
1181
|
-
const typeName = extractTypeName(errorInfo?.TypeRef ?? errorInfo?.typeRef);
|
|
1182
1191
|
if (typeName === "ActualLab.Rpc.RpcRerouteException")
|
|
1183
1192
|
warnLog4?.log("Got RpcRerouteException from remote peer:", msg);
|
|
1184
|
-
|
|
1193
|
+
const error = new RpcError(msg, typeName);
|
|
1194
|
+
if (isCancelled)
|
|
1195
|
+
error.name = "AbortError";
|
|
1196
|
+
call.result.reject(error);
|
|
1197
|
+
if (isCancelled)
|
|
1198
|
+
call.onDisconnect();
|
|
1185
1199
|
}
|
|
1186
1200
|
break;
|
|
1187
1201
|
}
|
|
@@ -2479,6 +2493,7 @@ function toRpcStream(value, peer) {
|
|
|
2479
2493
|
}
|
|
2480
2494
|
|
|
2481
2495
|
// src/rpc-remote-object-tracker.ts
|
|
2496
|
+
var { warnLog: warnLog7 } = getLogs("RpcRemoteObjectTracker");
|
|
2482
2497
|
var RpcRemoteObjectTracker = class {
|
|
2483
2498
|
_objects = /* @__PURE__ */ new Map();
|
|
2484
2499
|
register(obj) {
|
|
@@ -2509,8 +2524,17 @@ var RpcRemoteObjectTracker = class {
|
|
|
2509
2524
|
}
|
|
2510
2525
|
reconnectAll() {
|
|
2511
2526
|
for (const obj of this._objects.values()) {
|
|
2512
|
-
|
|
2513
|
-
|
|
2527
|
+
try {
|
|
2528
|
+
if (obj.allowReconnect) obj.reconnect();
|
|
2529
|
+
else obj.disconnect();
|
|
2530
|
+
} catch (e) {
|
|
2531
|
+
warnLog7?.log(`Failed to reconnect ${obj.id.localId}, disconnecting it`, e);
|
|
2532
|
+
try {
|
|
2533
|
+
obj.disconnect();
|
|
2534
|
+
} catch (e2) {
|
|
2535
|
+
warnLog7?.log(`Failed to disconnect ${obj.id.localId}`, e2);
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2514
2538
|
}
|
|
2515
2539
|
}
|
|
2516
2540
|
};
|
|
@@ -2735,7 +2759,7 @@ function yieldToEventLoop() {
|
|
|
2735
2759
|
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
2736
2760
|
}
|
|
2737
2761
|
var RPC_CLOSE_CODE_UNSUPPORTED_FORMAT = 4001;
|
|
2738
|
-
var { debugLog: debugLog2, infoLog, warnLog:
|
|
2762
|
+
var { debugLog: debugLog2, infoLog, warnLog: warnLog8, errorLog: errorLog2 } = getLogs("RpcPeer");
|
|
2739
2763
|
var defaultConnectionUrlResolver = async (peer) => {
|
|
2740
2764
|
const formatKey = peer.serializationFormat.key;
|
|
2741
2765
|
const proof = await peer.computeReconnectProof();
|
|
@@ -3207,9 +3231,13 @@ var RpcPeer = class {
|
|
|
3207
3231
|
this._keepAliveTimer ??= setInterval(() => {
|
|
3208
3232
|
const conn = this.wireConnection;
|
|
3209
3233
|
if (conn !== void 0) {
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3234
|
+
try {
|
|
3235
|
+
this.hub.systemCallSender.keepAlive(conn, this.serializationFormat, [
|
|
3236
|
+
...this.remoteObjects.keys()
|
|
3237
|
+
]);
|
|
3238
|
+
} catch (e) {
|
|
3239
|
+
warnLog8?.log(`'${this.ref}': Failed to send keep-alive`, e);
|
|
3240
|
+
}
|
|
3213
3241
|
}
|
|
3214
3242
|
}, this.keepAlivePeriodMs);
|
|
3215
3243
|
if (this._keepAliveWatchdog !== void 0)
|
|
@@ -3217,7 +3245,7 @@ var RpcPeer = class {
|
|
|
3217
3245
|
this._keepAliveWatchdog = setTimeout(() => {
|
|
3218
3246
|
this._keepAliveWatchdog = void 0;
|
|
3219
3247
|
if (this._connection === void 0) return;
|
|
3220
|
-
|
|
3248
|
+
warnLog8?.log(
|
|
3221
3249
|
`'${this.ref}': no keep-alive for ${this.keepAliveTimeoutMs}ms \u2014 force-closing connection`
|
|
3222
3250
|
);
|
|
3223
3251
|
this._connection.close();
|
|
@@ -3418,7 +3446,7 @@ var RpcClientPeer = class extends RpcPeer {
|
|
|
3418
3446
|
this._setConnectionState(1 /* Connecting */);
|
|
3419
3447
|
const retryDelay = this.hub.reconnectDelayer.getDelay(this._tryIndex, this._stopController.signal);
|
|
3420
3448
|
if (retryDelay.isLimitExceeded) {
|
|
3421
|
-
|
|
3449
|
+
warnLog8?.log(`'${this.ref}': Reconnect limit exceeded - shutting down`);
|
|
3422
3450
|
this._disposed = true;
|
|
3423
3451
|
break;
|
|
3424
3452
|
}
|
|
@@ -3467,7 +3495,7 @@ var RpcClientPeer = class extends RpcPeer {
|
|
|
3467
3495
|
);
|
|
3468
3496
|
} catch (e) {
|
|
3469
3497
|
if (e instanceof import_core7.TimeoutError) {
|
|
3470
|
-
|
|
3498
|
+
warnLog8?.log(`'${this.ref}': Connect timed out after ${connectTimeoutMs}ms`);
|
|
3471
3499
|
conn.close();
|
|
3472
3500
|
}
|
|
3473
3501
|
throw e;
|
|
@@ -3482,7 +3510,7 @@ var RpcClientPeer = class extends RpcPeer {
|
|
|
3482
3510
|
this.nextOwnHandshakeIndex()
|
|
3483
3511
|
);
|
|
3484
3512
|
} catch (e) {
|
|
3485
|
-
|
|
3513
|
+
warnLog8?.log(`'${this.ref}': Failed to send handshake`, e);
|
|
3486
3514
|
throw e;
|
|
3487
3515
|
}
|
|
3488
3516
|
const handshakeTimeoutMs = this.handshakeTimeoutMs;
|
|
@@ -3495,7 +3523,7 @@ var RpcClientPeer = class extends RpcPeer {
|
|
|
3495
3523
|
);
|
|
3496
3524
|
} catch (e) {
|
|
3497
3525
|
if (e instanceof import_core7.TimeoutError) {
|
|
3498
|
-
|
|
3526
|
+
warnLog8?.log(`'${this.ref}': Handshake timed out after ${handshakeTimeoutMs}ms`);
|
|
3499
3527
|
conn.close();
|
|
3500
3528
|
}
|
|
3501
3529
|
throw e;
|
|
@@ -3525,7 +3553,7 @@ var RpcClientPeer = class extends RpcPeer {
|
|
|
3525
3553
|
this._setConnectionState(0 /* Disconnected */);
|
|
3526
3554
|
if (this._disposed) break;
|
|
3527
3555
|
if (lastCloseCode === RPC_CLOSE_CODE_UNSUPPORTED_FORMAT) {
|
|
3528
|
-
|
|
3556
|
+
warnLog8?.log(`'${this.ref}': Unsupported serialization format - shutting down`);
|
|
3529
3557
|
this.unsupportedFormat.trigger({ reason: lastCloseReason });
|
|
3530
3558
|
this._disposed = true;
|
|
3531
3559
|
break;
|
|
@@ -3593,8 +3621,10 @@ var RpcClientPeer = class extends RpcPeer {
|
|
|
3593
3621
|
call.sentAt = Date.now();
|
|
3594
3622
|
}
|
|
3595
3623
|
let unknownIds = null;
|
|
3624
|
+
let isReconciled = false;
|
|
3596
3625
|
if (!isPeerChanged && eligible.length > 0) {
|
|
3597
3626
|
unknownIds = await this._reconcileReconnect(eligible, closedSignal);
|
|
3627
|
+
isReconciled = unknownIds !== null;
|
|
3598
3628
|
}
|
|
3599
3629
|
const YIELD_BATCH = 20;
|
|
3600
3630
|
let resentSinceYield = 0;
|
|
@@ -3607,6 +3637,17 @@ var RpcClientPeer = class extends RpcPeer {
|
|
|
3607
3637
|
if (unknownIds !== null && !unknownIds.has(call.callId)) {
|
|
3608
3638
|
continue;
|
|
3609
3639
|
}
|
|
3640
|
+
if (!(call.remoteExecutionMode & 4)) {
|
|
3641
|
+
if (!isReconciled)
|
|
3642
|
+
continue;
|
|
3643
|
+
if (!call.result.isCompleted)
|
|
3644
|
+
call.result.reject(new Error(
|
|
3645
|
+
"Outbound call failed: the peer does not know the call after reconnect and AllowResend is not set."
|
|
3646
|
+
));
|
|
3647
|
+
call.onDisconnect();
|
|
3648
|
+
this.outboundCalls.remove(call.callId);
|
|
3649
|
+
continue;
|
|
3650
|
+
}
|
|
3610
3651
|
call.sentAt = Date.now();
|
|
3611
3652
|
this._sendWireData(call.serializedWireData);
|
|
3612
3653
|
resentSinceYield++;
|
|
@@ -3619,7 +3660,8 @@ var RpcClientPeer = class extends RpcPeer {
|
|
|
3619
3660
|
/**
|
|
3620
3661
|
* Ask the server which call IDs in `eligible` it no longer recognizes
|
|
3621
3662
|
* via `$sys.Reconnect:3`. Returns the set of call IDs that need to be
|
|
3622
|
-
* resent
|
|
3663
|
+
* resent, or `null` if the reconciliation failed: the caller then
|
|
3664
|
+
* resends everything that allows it.
|
|
3623
3665
|
*
|
|
3624
3666
|
* Wire format of the `completedStages` argument is chosen per wire format:
|
|
3625
3667
|
* - JSON (json5np): plain object `{"<stage>": "<base64-of-bytes>"}` —
|
|
@@ -3643,7 +3685,7 @@ var RpcClientPeer = class extends RpcPeer {
|
|
|
3643
3685
|
arr.push(call.callId);
|
|
3644
3686
|
}
|
|
3645
3687
|
if (byStage.size === 0) {
|
|
3646
|
-
return
|
|
3688
|
+
return null;
|
|
3647
3689
|
}
|
|
3648
3690
|
const isBinary = this.serializationFormat.isBinary;
|
|
3649
3691
|
const stagesArg = isBinary ? /* @__PURE__ */ new Map() : {};
|
|
@@ -3667,10 +3709,10 @@ var RpcClientPeer = class extends RpcPeer {
|
|
|
3667
3709
|
);
|
|
3668
3710
|
const result = await reconnectCall.result;
|
|
3669
3711
|
const bytes = _toBytes2(result);
|
|
3670
|
-
if (bytes === null) return
|
|
3712
|
+
if (bytes === null) return null;
|
|
3671
3713
|
return new Set(IncreasingSeqCompressor.deserialize(bytes));
|
|
3672
3714
|
} catch {
|
|
3673
|
-
return
|
|
3715
|
+
return null;
|
|
3674
3716
|
}
|
|
3675
3717
|
}
|
|
3676
3718
|
/** Detects a server-peer identity change by comparing the incoming
|
|
@@ -3780,7 +3822,7 @@ function warnReconnectProofUnavailable(ref, reason) {
|
|
|
3780
3822
|
if (isReconnectProofUnavailableWarned)
|
|
3781
3823
|
return;
|
|
3782
3824
|
isReconnectProofUnavailableWarned = true;
|
|
3783
|
-
|
|
3825
|
+
warnLog8?.log(
|
|
3784
3826
|
`'${ref}': ${reason} - connecting without a reconnect proof. This fails if the server requires one (RequireReconnectProof).`
|
|
3785
3827
|
);
|
|
3786
3828
|
}
|
|
@@ -3861,7 +3903,7 @@ var RpcClientPeerReconnectDelayer = class extends import_core8.RetryDelayer {
|
|
|
3861
3903
|
};
|
|
3862
3904
|
|
|
3863
3905
|
// src/rpc-service-host.ts
|
|
3864
|
-
var { warnLog:
|
|
3906
|
+
var { warnLog: warnLog9 } = getLogs("RpcServiceHost");
|
|
3865
3907
|
var RpcServiceHost = class {
|
|
3866
3908
|
_methods = /* @__PURE__ */ new Map();
|
|
3867
3909
|
register(def, impl, receiver = impl) {
|
|
@@ -3878,7 +3920,7 @@ var RpcServiceHost = class {
|
|
|
3878
3920
|
async dispatch(wireMethod, args, context) {
|
|
3879
3921
|
const entry = this._methods.get(wireMethod);
|
|
3880
3922
|
if (entry === void 0) {
|
|
3881
|
-
|
|
3923
|
+
warnLog9?.log(`Method not found: ${wireMethod}`);
|
|
3882
3924
|
throw new Error(`Method not found: ${wireMethod}`);
|
|
3883
3925
|
}
|
|
3884
3926
|
if (context !== void 0 && entry.def.callTypeId !== 0) {
|
|
@@ -4411,7 +4453,7 @@ function computeMethodHash(methodName) {
|
|
|
4411
4453
|
}
|
|
4412
4454
|
|
|
4413
4455
|
// src/rpc-method-registry.ts
|
|
4414
|
-
var { warnLog:
|
|
4456
|
+
var { warnLog: warnLog10 } = getLogs("RpcMethodRegistry");
|
|
4415
4457
|
var RpcMethodRegistry = class {
|
|
4416
4458
|
_nameToHash = /* @__PURE__ */ new Map();
|
|
4417
4459
|
_hashToName = /* @__PURE__ */ new Map();
|
|
@@ -4421,7 +4463,7 @@ var RpcMethodRegistry = class {
|
|
|
4421
4463
|
const hash = computeMethodHash(methodName);
|
|
4422
4464
|
const existing = this._hashToName.get(hash);
|
|
4423
4465
|
if (existing !== void 0 && existing !== methodName) {
|
|
4424
|
-
|
|
4466
|
+
warnLog10?.log(`hash collision: "${methodName}" and "${existing}" both hash to ${hash}`);
|
|
4425
4467
|
return;
|
|
4426
4468
|
}
|
|
4427
4469
|
this._nameToHash.set(methodName, hash);
|
|
@@ -4454,7 +4496,7 @@ var RpcMethodRegistry = class {
|
|
|
4454
4496
|
};
|
|
4455
4497
|
|
|
4456
4498
|
// src/rpc-hub.ts
|
|
4457
|
-
var { warnLog:
|
|
4499
|
+
var { warnLog: warnLog11 } = getLogs("RpcHub");
|
|
4458
4500
|
var RpcHub = class {
|
|
4459
4501
|
hubId;
|
|
4460
4502
|
peers = /* @__PURE__ */ new Map();
|
|
@@ -4519,7 +4561,7 @@ var RpcHub = class {
|
|
|
4519
4561
|
if (peer !== void 0) {
|
|
4520
4562
|
peer.close();
|
|
4521
4563
|
this.peers.delete(ref);
|
|
4522
|
-
|
|
4564
|
+
warnLog11?.log(`'${ref}': peer is removed from RpcHub`);
|
|
4523
4565
|
}
|
|
4524
4566
|
}
|
|
4525
4567
|
/** Get or create a peer by ref. If the peer does not exist:
|