@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 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
- if (call.removeOnOk) {
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
- call.result.reject(new RpcError(msg, typeName));
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
- if (obj.allowReconnect) obj.reconnect();
2513
- else obj.disconnect();
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: warnLog7, errorLog: errorLog2 } = getLogs("RpcPeer");
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
- this.hub.systemCallSender.keepAlive(conn, this.serializationFormat, [
3211
- ...this.remoteObjects.keys()
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
- warnLog7?.log(
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
- warnLog7?.log(`'${this.ref}': Reconnect limit exceeded - shutting down`);
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
- warnLog7?.log(`'${this.ref}': Connect timed out after ${connectTimeoutMs}ms`);
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
- warnLog7?.log(`'${this.ref}': Failed to send handshake`, e);
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
- warnLog7?.log(`'${this.ref}': Handshake timed out after ${handshakeTimeoutMs}ms`);
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
- warnLog7?.log(`'${this.ref}': Unsupported serialization format - shutting down`);
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. On any failure, falls back to "resend everything".
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 new Set(eligible.map((c) => c.callId));
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 new Set(eligible.map((c) => c.callId));
3712
+ if (bytes === null) return null;
3671
3713
  return new Set(IncreasingSeqCompressor.deserialize(bytes));
3672
3714
  } catch {
3673
- return new Set(eligible.map((c) => c.callId));
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
- warnLog7?.log(
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: warnLog8 } = getLogs("RpcServiceHost");
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
- warnLog8?.log(`Method not found: ${wireMethod}`);
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: warnLog9 } = getLogs("RpcMethodRegistry");
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
- warnLog9?.log(`hash collision: "${methodName}" and "${existing}" both hash to ${hash}`);
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: warnLog10 } = getLogs("RpcHub");
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
- warnLog10?.log(`'${ref}': peer is removed from RpcHub`);
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: