@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.d.cts CHANGED
@@ -380,6 +380,19 @@ declare function createMessageChannelPair(): [
380
380
  RpcMessageChannelConnection
381
381
  ];
382
382
 
383
+ /** Controls outbound RPC call behavior regarding connection waiting, reconnection, and resending. */
384
+ declare const RpcRemoteExecutionMode: {
385
+ /** Wait for connection if disconnected when the call is made. */
386
+ readonly AwaitForConnection: 1;
387
+ /** Resend on reconnection to the same peer. */
388
+ readonly AllowReconnect: 2;
389
+ /** Resend on reconnection to a different peer (implies AllowReconnect). */
390
+ readonly AllowResend: 6;
391
+ /** Default: wait + reconnect + resend. */
392
+ readonly Default: 7;
393
+ };
394
+ /** Bitfield combination of RpcRemoteExecutionMode flags. */
395
+ type RpcRemoteExecutionMode = number;
383
396
  /** Describes a single method on an RPC service. */
384
397
  interface RpcMethodDef {
385
398
  readonly name: string;
@@ -389,6 +402,7 @@ interface RpcMethodDef {
389
402
  readonly callTypeId: number;
390
403
  readonly stream: boolean;
391
404
  readonly noWait: boolean;
405
+ readonly remoteExecutionMode: RpcRemoteExecutionMode;
392
406
  }
393
407
  /** Describes an RPC service — its name and method definitions. */
394
408
  interface RpcServiceDef {
@@ -401,6 +415,8 @@ interface RpcMethodDefInput {
401
415
  callTypeId?: number;
402
416
  /** Override for wireArgCount. Default: args.length + 1 (assumes a CancellationToken slot). */
403
417
  wireArgCount?: number;
418
+ /** Override for remoteExecutionMode. Default: RpcRemoteExecutionMode.Default (7). NoWait methods always use 0. */
419
+ remoteExecutionMode?: RpcRemoteExecutionMode;
404
420
  }
405
421
  declare const RpcType: {
406
422
  readonly object: symbol;
@@ -417,12 +433,14 @@ declare class RpcOutboundCall {
417
433
  readonly callId: number;
418
434
  readonly method: string;
419
435
  readonly result: PromiseSource<unknown>;
436
+ /** Bitfield of RpcRemoteExecutionMode flags controlling reconnect/resend behavior. */
437
+ readonly remoteExecutionMode: number;
420
438
  /** Whether to remove this call from the tracker on $sys.Ok. Default: true.
421
439
  * Subclasses (e.g. compute calls) override to false to stay in tracker for invalidation. */
422
440
  readonly removeOnOk: boolean;
423
441
  /** The serialized wire data — stored for re-sending on reconnect. */
424
442
  serializedWireData: string | Uint8Array;
425
- constructor(callId: number, method: string);
443
+ constructor(callId: number, method: string, remoteExecutionMode?: number);
426
444
  /** Called when the connection is lost. Subclasses can override to resolve invalidation promises. */
427
445
  onDisconnect(): void;
428
446
  }
@@ -483,6 +501,8 @@ declare class RpcServiceHost {
483
501
  interface MethodMeta {
484
502
  argCount: number;
485
503
  returns?: symbol;
504
+ /** Bitfield of RpcRemoteExecutionMode flags. */
505
+ remoteExecutionMode?: number;
486
506
  [key: symbol]: unknown;
487
507
  }
488
508
  interface ServiceMeta {
@@ -495,9 +515,10 @@ declare function getMethodsMeta(cls: AnyConstructor): Record<string, MethodMeta>
495
515
  declare function getServiceMeta(cls: AnyConstructor): ServiceMeta | undefined;
496
516
  /** Class decorator — stores the RPC service wire name. */
497
517
  declare function rpcService(serviceName: string): <T extends AnyConstructor>(_target: T, context: ClassDecoratorContext<T>) => void;
498
- /** Method decorator — stores RPC method metadata (argCount, returns). Does NOT wrap the method. */
518
+ /** Method decorator — stores RPC method metadata (argCount, returns, remoteExecutionMode). Does NOT wrap the method. */
499
519
  declare function rpcMethod(options?: {
500
520
  returns?: symbol;
521
+ remoteExecutionMode?: number;
501
522
  }): <This, Args extends unknown[], Return>(target: (this: This, ...args: Args) => Return, context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>) => (this: This, ...args: Args) => Return;
502
523
 
503
524
  /**
@@ -631,6 +652,8 @@ interface RpcCallOptions {
631
652
  outboundCallFactory?: (id: number, method: string) => RpcOutboundCall;
632
653
  /** AbortSignal for caller-initiated cancellation. */
633
654
  signal?: AbortSignal;
655
+ /** Bitfield of RpcRemoteExecutionMode flags (default: 7 = Default). */
656
+ remoteExecutionMode?: number;
634
657
  }
635
658
  /** Data extracted from an inbound $sys.Handshake message. */
636
659
  interface RemoteHandshake {
@@ -754,6 +777,13 @@ interface RpcStreamRef {
754
777
  readonly allowReconnect: boolean;
755
778
  readonly isRealTime: boolean;
756
779
  }
780
+ /**
781
+ * A stream source is either a plain async iterable or a factory function
782
+ * that receives an AbortSignal and returns an async iterable.
783
+ * The AbortSignal is aborted when the sender is disconnected, allowing
784
+ * the source to release resources (e.g., camera, microphone) promptly.
785
+ */
786
+ type RpcStreamSource<T> = AsyncIterable<T> | ((abortSignal: AbortSignal) => AsyncIterable<T>);
757
787
  /** Configuration options for creating a local (origin-side) RpcStream. */
758
788
  interface RpcStreamOptions<T> {
759
789
  ackPeriod?: number;
@@ -787,7 +817,7 @@ declare class RpcStream<T> implements AsyncIterable<T>, IRpcObject {
787
817
  readonly canSkipTo: (item: T) => boolean;
788
818
  readonly ackPeriod: number;
789
819
  readonly ackAdvance: number;
790
- readonly localSource?: AsyncIterable<T>;
820
+ readonly localSource?: RpcStreamSource<T>;
791
821
  readonly peer: RpcPeer;
792
822
  private _sender?;
793
823
  private _toRefValue?;
@@ -801,8 +831,8 @@ declare class RpcStream<T> implements AsyncIterable<T>, IRpcObject {
801
831
  private _started;
802
832
  private _iterating;
803
833
  private _ackSentUpTo;
804
- /** Create a local (origin-side) stream wrapping an async iterable with optional configuration. */
805
- constructor(source: AsyncIterable<T>, options?: RpcStreamOptions<T>);
834
+ /** Create a local (origin-side) stream wrapping an async iterable or source factory with optional configuration. */
835
+ constructor(source: RpcStreamSource<T>, options?: RpcStreamOptions<T>);
806
836
  /** Create a remote (target-side) stream from a parsed stream reference and peer. */
807
837
  constructor(ref: RpcStreamRef, peer: RpcPeer);
808
838
  /**
@@ -874,7 +904,11 @@ declare class RpcStreamSender<T> implements IRpcObject {
874
904
  private _lastAckedIndex;
875
905
  private _ackWaiting;
876
906
  private _resetRequested;
907
+ private _abortController;
908
+ private _iterator;
877
909
  constructor(peer: RpcPeer, ackPeriod?: number, ackAdvance?: number, allowReconnect?: boolean, isRealTime?: boolean, canSkipTo?: (item: T) => boolean);
910
+ /** AbortSignal that is aborted when the sender is disconnected. */
911
+ get abortSignal(): AbortSignal;
878
912
  /** Returns the stream reference string for the $sys.Ok response. */
879
913
  toRef(): string;
880
914
  /** Called by system call handler when $sys.Ack is received from the client. */
@@ -968,4 +1002,4 @@ declare function xxh3_64str(input: string, seed?: bigint): bigint;
968
1002
  */
969
1003
  declare function computeMethodHash(methodName: string): number;
970
1004
 
971
- export { ARG_DELIMITER, ENVELOPE_DELIMITER, FRAME_DELIMITER, type IRpcObject, type MethodMeta, RPC_CLOSE_CODE_UNSUPPORTED_FORMAT, type RemoteHandshake, type RpcCallOptions, RpcCallTypeId, RpcClientPeer, RpcClientPeerReconnectDelayer, type RpcConnection, type RpcConnectionUrlResolver, type RpcDeserializedMessage, type RpcDispatchContext, RpcHub, RpcInboundCall, RpcInboundCallTracker, RpcJsonSerializationFormat, type RpcMessage, RpcMessageChannelConnection, RpcMessagePackCompactSerializationFormat, RpcMessagePackSerializationFormat, type RpcMethodDef, type RpcMethodDefInput, RpcMethodRegistry, type RpcObjectId, RpcObjectKind, RpcOutboundCall, RpcOutboundCallTracker, RpcPeer, RpcPeerConnectionKind, type RpcPeerState, RpcPeerStateKind, RpcPeerStateMonitor, type RpcReceivedMessage, RpcRemoteObjectTracker, RpcSerializationFormat, RpcSerializationFormatResolver, RpcServerPeer, type RpcServiceDef, RpcServiceHost, type RpcServiceImpl, RpcSharedObjectTracker, RpcStream, type RpcStreamOptions, type RpcStreamRef, RpcStreamSender, RpcSystemCallHandler, RpcSystemCallSender, RpcSystemCalls, RpcType, RpcWebSocketConnection, type RpcWireData, type ServiceMeta, type WebSocketLike, type WebSocketServer, WebSocketState, computeMethodHash, createBinaryEncoder, createMessageChannelPair, createRpcClient, defaultBinaryDecoder, defaultBinaryEncoder, defaultConnectionUrlResolver, defineRpcService, deserializeBinaryMessage, deserializeCompactBinaryMessage, deserializeMessage, getMethodsMeta, getServiceMeta, getStateDescription, isConnected, likelyConnected, parseStreamRef, resolveStreamRefs, rpcMethod, rpcService, serializeBinaryFrame, serializeBinaryMessage, serializeCompactBinaryMessage, serializeFrame, serializeMessage, splitBinaryFrame, splitCompactBinaryFrame, splitFrame, wireMethodName, xxh3_64, xxh3_64str };
1005
+ export { ARG_DELIMITER, ENVELOPE_DELIMITER, FRAME_DELIMITER, type IRpcObject, type MethodMeta, RPC_CLOSE_CODE_UNSUPPORTED_FORMAT, type RemoteHandshake, type RpcCallOptions, RpcCallTypeId, RpcClientPeer, RpcClientPeerReconnectDelayer, type RpcConnection, type RpcConnectionUrlResolver, type RpcDeserializedMessage, type RpcDispatchContext, RpcHub, RpcInboundCall, RpcInboundCallTracker, RpcJsonSerializationFormat, type RpcMessage, RpcMessageChannelConnection, RpcMessagePackCompactSerializationFormat, RpcMessagePackSerializationFormat, type RpcMethodDef, type RpcMethodDefInput, RpcMethodRegistry, type RpcObjectId, RpcObjectKind, RpcOutboundCall, RpcOutboundCallTracker, RpcPeer, RpcPeerConnectionKind, type RpcPeerState, RpcPeerStateKind, RpcPeerStateMonitor, type RpcReceivedMessage, RpcRemoteExecutionMode, RpcRemoteObjectTracker, RpcSerializationFormat, RpcSerializationFormatResolver, RpcServerPeer, type RpcServiceDef, RpcServiceHost, type RpcServiceImpl, RpcSharedObjectTracker, RpcStream, type RpcStreamOptions, type RpcStreamRef, RpcStreamSender, type RpcStreamSource, RpcSystemCallHandler, RpcSystemCallSender, RpcSystemCalls, RpcType, RpcWebSocketConnection, type RpcWireData, type ServiceMeta, type WebSocketLike, type WebSocketServer, WebSocketState, computeMethodHash, createBinaryEncoder, createMessageChannelPair, createRpcClient, defaultBinaryDecoder, defaultBinaryEncoder, defaultConnectionUrlResolver, defineRpcService, deserializeBinaryMessage, deserializeCompactBinaryMessage, deserializeMessage, getMethodsMeta, getServiceMeta, getStateDescription, isConnected, likelyConnected, parseStreamRef, resolveStreamRefs, rpcMethod, rpcService, serializeBinaryFrame, serializeBinaryMessage, serializeCompactBinaryMessage, serializeFrame, serializeMessage, splitBinaryFrame, splitCompactBinaryFrame, splitFrame, wireMethodName, xxh3_64, xxh3_64str };
package/dist/index.d.ts CHANGED
@@ -380,6 +380,19 @@ declare function createMessageChannelPair(): [
380
380
  RpcMessageChannelConnection
381
381
  ];
382
382
 
383
+ /** Controls outbound RPC call behavior regarding connection waiting, reconnection, and resending. */
384
+ declare const RpcRemoteExecutionMode: {
385
+ /** Wait for connection if disconnected when the call is made. */
386
+ readonly AwaitForConnection: 1;
387
+ /** Resend on reconnection to the same peer. */
388
+ readonly AllowReconnect: 2;
389
+ /** Resend on reconnection to a different peer (implies AllowReconnect). */
390
+ readonly AllowResend: 6;
391
+ /** Default: wait + reconnect + resend. */
392
+ readonly Default: 7;
393
+ };
394
+ /** Bitfield combination of RpcRemoteExecutionMode flags. */
395
+ type RpcRemoteExecutionMode = number;
383
396
  /** Describes a single method on an RPC service. */
384
397
  interface RpcMethodDef {
385
398
  readonly name: string;
@@ -389,6 +402,7 @@ interface RpcMethodDef {
389
402
  readonly callTypeId: number;
390
403
  readonly stream: boolean;
391
404
  readonly noWait: boolean;
405
+ readonly remoteExecutionMode: RpcRemoteExecutionMode;
392
406
  }
393
407
  /** Describes an RPC service — its name and method definitions. */
394
408
  interface RpcServiceDef {
@@ -401,6 +415,8 @@ interface RpcMethodDefInput {
401
415
  callTypeId?: number;
402
416
  /** Override for wireArgCount. Default: args.length + 1 (assumes a CancellationToken slot). */
403
417
  wireArgCount?: number;
418
+ /** Override for remoteExecutionMode. Default: RpcRemoteExecutionMode.Default (7). NoWait methods always use 0. */
419
+ remoteExecutionMode?: RpcRemoteExecutionMode;
404
420
  }
405
421
  declare const RpcType: {
406
422
  readonly object: symbol;
@@ -417,12 +433,14 @@ declare class RpcOutboundCall {
417
433
  readonly callId: number;
418
434
  readonly method: string;
419
435
  readonly result: PromiseSource<unknown>;
436
+ /** Bitfield of RpcRemoteExecutionMode flags controlling reconnect/resend behavior. */
437
+ readonly remoteExecutionMode: number;
420
438
  /** Whether to remove this call from the tracker on $sys.Ok. Default: true.
421
439
  * Subclasses (e.g. compute calls) override to false to stay in tracker for invalidation. */
422
440
  readonly removeOnOk: boolean;
423
441
  /** The serialized wire data — stored for re-sending on reconnect. */
424
442
  serializedWireData: string | Uint8Array;
425
- constructor(callId: number, method: string);
443
+ constructor(callId: number, method: string, remoteExecutionMode?: number);
426
444
  /** Called when the connection is lost. Subclasses can override to resolve invalidation promises. */
427
445
  onDisconnect(): void;
428
446
  }
@@ -483,6 +501,8 @@ declare class RpcServiceHost {
483
501
  interface MethodMeta {
484
502
  argCount: number;
485
503
  returns?: symbol;
504
+ /** Bitfield of RpcRemoteExecutionMode flags. */
505
+ remoteExecutionMode?: number;
486
506
  [key: symbol]: unknown;
487
507
  }
488
508
  interface ServiceMeta {
@@ -495,9 +515,10 @@ declare function getMethodsMeta(cls: AnyConstructor): Record<string, MethodMeta>
495
515
  declare function getServiceMeta(cls: AnyConstructor): ServiceMeta | undefined;
496
516
  /** Class decorator — stores the RPC service wire name. */
497
517
  declare function rpcService(serviceName: string): <T extends AnyConstructor>(_target: T, context: ClassDecoratorContext<T>) => void;
498
- /** Method decorator — stores RPC method metadata (argCount, returns). Does NOT wrap the method. */
518
+ /** Method decorator — stores RPC method metadata (argCount, returns, remoteExecutionMode). Does NOT wrap the method. */
499
519
  declare function rpcMethod(options?: {
500
520
  returns?: symbol;
521
+ remoteExecutionMode?: number;
501
522
  }): <This, Args extends unknown[], Return>(target: (this: This, ...args: Args) => Return, context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>) => (this: This, ...args: Args) => Return;
502
523
 
503
524
  /**
@@ -631,6 +652,8 @@ interface RpcCallOptions {
631
652
  outboundCallFactory?: (id: number, method: string) => RpcOutboundCall;
632
653
  /** AbortSignal for caller-initiated cancellation. */
633
654
  signal?: AbortSignal;
655
+ /** Bitfield of RpcRemoteExecutionMode flags (default: 7 = Default). */
656
+ remoteExecutionMode?: number;
634
657
  }
635
658
  /** Data extracted from an inbound $sys.Handshake message. */
636
659
  interface RemoteHandshake {
@@ -754,6 +777,13 @@ interface RpcStreamRef {
754
777
  readonly allowReconnect: boolean;
755
778
  readonly isRealTime: boolean;
756
779
  }
780
+ /**
781
+ * A stream source is either a plain async iterable or a factory function
782
+ * that receives an AbortSignal and returns an async iterable.
783
+ * The AbortSignal is aborted when the sender is disconnected, allowing
784
+ * the source to release resources (e.g., camera, microphone) promptly.
785
+ */
786
+ type RpcStreamSource<T> = AsyncIterable<T> | ((abortSignal: AbortSignal) => AsyncIterable<T>);
757
787
  /** Configuration options for creating a local (origin-side) RpcStream. */
758
788
  interface RpcStreamOptions<T> {
759
789
  ackPeriod?: number;
@@ -787,7 +817,7 @@ declare class RpcStream<T> implements AsyncIterable<T>, IRpcObject {
787
817
  readonly canSkipTo: (item: T) => boolean;
788
818
  readonly ackPeriod: number;
789
819
  readonly ackAdvance: number;
790
- readonly localSource?: AsyncIterable<T>;
820
+ readonly localSource?: RpcStreamSource<T>;
791
821
  readonly peer: RpcPeer;
792
822
  private _sender?;
793
823
  private _toRefValue?;
@@ -801,8 +831,8 @@ declare class RpcStream<T> implements AsyncIterable<T>, IRpcObject {
801
831
  private _started;
802
832
  private _iterating;
803
833
  private _ackSentUpTo;
804
- /** Create a local (origin-side) stream wrapping an async iterable with optional configuration. */
805
- constructor(source: AsyncIterable<T>, options?: RpcStreamOptions<T>);
834
+ /** Create a local (origin-side) stream wrapping an async iterable or source factory with optional configuration. */
835
+ constructor(source: RpcStreamSource<T>, options?: RpcStreamOptions<T>);
806
836
  /** Create a remote (target-side) stream from a parsed stream reference and peer. */
807
837
  constructor(ref: RpcStreamRef, peer: RpcPeer);
808
838
  /**
@@ -874,7 +904,11 @@ declare class RpcStreamSender<T> implements IRpcObject {
874
904
  private _lastAckedIndex;
875
905
  private _ackWaiting;
876
906
  private _resetRequested;
907
+ private _abortController;
908
+ private _iterator;
877
909
  constructor(peer: RpcPeer, ackPeriod?: number, ackAdvance?: number, allowReconnect?: boolean, isRealTime?: boolean, canSkipTo?: (item: T) => boolean);
910
+ /** AbortSignal that is aborted when the sender is disconnected. */
911
+ get abortSignal(): AbortSignal;
878
912
  /** Returns the stream reference string for the $sys.Ok response. */
879
913
  toRef(): string;
880
914
  /** Called by system call handler when $sys.Ack is received from the client. */
@@ -968,4 +1002,4 @@ declare function xxh3_64str(input: string, seed?: bigint): bigint;
968
1002
  */
969
1003
  declare function computeMethodHash(methodName: string): number;
970
1004
 
971
- export { ARG_DELIMITER, ENVELOPE_DELIMITER, FRAME_DELIMITER, type IRpcObject, type MethodMeta, RPC_CLOSE_CODE_UNSUPPORTED_FORMAT, type RemoteHandshake, type RpcCallOptions, RpcCallTypeId, RpcClientPeer, RpcClientPeerReconnectDelayer, type RpcConnection, type RpcConnectionUrlResolver, type RpcDeserializedMessage, type RpcDispatchContext, RpcHub, RpcInboundCall, RpcInboundCallTracker, RpcJsonSerializationFormat, type RpcMessage, RpcMessageChannelConnection, RpcMessagePackCompactSerializationFormat, RpcMessagePackSerializationFormat, type RpcMethodDef, type RpcMethodDefInput, RpcMethodRegistry, type RpcObjectId, RpcObjectKind, RpcOutboundCall, RpcOutboundCallTracker, RpcPeer, RpcPeerConnectionKind, type RpcPeerState, RpcPeerStateKind, RpcPeerStateMonitor, type RpcReceivedMessage, RpcRemoteObjectTracker, RpcSerializationFormat, RpcSerializationFormatResolver, RpcServerPeer, type RpcServiceDef, RpcServiceHost, type RpcServiceImpl, RpcSharedObjectTracker, RpcStream, type RpcStreamOptions, type RpcStreamRef, RpcStreamSender, RpcSystemCallHandler, RpcSystemCallSender, RpcSystemCalls, RpcType, RpcWebSocketConnection, type RpcWireData, type ServiceMeta, type WebSocketLike, type WebSocketServer, WebSocketState, computeMethodHash, createBinaryEncoder, createMessageChannelPair, createRpcClient, defaultBinaryDecoder, defaultBinaryEncoder, defaultConnectionUrlResolver, defineRpcService, deserializeBinaryMessage, deserializeCompactBinaryMessage, deserializeMessage, getMethodsMeta, getServiceMeta, getStateDescription, isConnected, likelyConnected, parseStreamRef, resolveStreamRefs, rpcMethod, rpcService, serializeBinaryFrame, serializeBinaryMessage, serializeCompactBinaryMessage, serializeFrame, serializeMessage, splitBinaryFrame, splitCompactBinaryFrame, splitFrame, wireMethodName, xxh3_64, xxh3_64str };
1005
+ export { ARG_DELIMITER, ENVELOPE_DELIMITER, FRAME_DELIMITER, type IRpcObject, type MethodMeta, RPC_CLOSE_CODE_UNSUPPORTED_FORMAT, type RemoteHandshake, type RpcCallOptions, RpcCallTypeId, RpcClientPeer, RpcClientPeerReconnectDelayer, type RpcConnection, type RpcConnectionUrlResolver, type RpcDeserializedMessage, type RpcDispatchContext, RpcHub, RpcInboundCall, RpcInboundCallTracker, RpcJsonSerializationFormat, type RpcMessage, RpcMessageChannelConnection, RpcMessagePackCompactSerializationFormat, RpcMessagePackSerializationFormat, type RpcMethodDef, type RpcMethodDefInput, RpcMethodRegistry, type RpcObjectId, RpcObjectKind, RpcOutboundCall, RpcOutboundCallTracker, RpcPeer, RpcPeerConnectionKind, type RpcPeerState, RpcPeerStateKind, RpcPeerStateMonitor, type RpcReceivedMessage, RpcRemoteExecutionMode, RpcRemoteObjectTracker, RpcSerializationFormat, RpcSerializationFormatResolver, RpcServerPeer, type RpcServiceDef, RpcServiceHost, type RpcServiceImpl, RpcSharedObjectTracker, RpcStream, type RpcStreamOptions, type RpcStreamRef, RpcStreamSender, type RpcStreamSource, RpcSystemCallHandler, RpcSystemCallSender, RpcSystemCalls, RpcType, RpcWebSocketConnection, type RpcWireData, type ServiceMeta, type WebSocketLike, type WebSocketServer, WebSocketState, computeMethodHash, createBinaryEncoder, createMessageChannelPair, createRpcClient, defaultBinaryDecoder, defaultBinaryEncoder, defaultConnectionUrlResolver, defineRpcService, deserializeBinaryMessage, deserializeCompactBinaryMessage, deserializeMessage, getMethodsMeta, getServiceMeta, getStateDescription, isConnected, likelyConnected, parseStreamRef, resolveStreamRefs, rpcMethod, rpcService, serializeBinaryFrame, serializeBinaryMessage, serializeCompactBinaryMessage, serializeFrame, serializeMessage, splitBinaryFrame, splitCompactBinaryFrame, splitFrame, wireMethodName, xxh3_64, xxh3_64str };
package/dist/index.js CHANGED
@@ -515,6 +515,18 @@ function createMessageChannelPair() {
515
515
  }
516
516
 
517
517
  // src/rpc-service-def.ts
518
+ var RpcRemoteExecutionMode = {
519
+ /** Wait for connection if disconnected when the call is made. */
520
+ AwaitForConnection: 1,
521
+ /** Resend on reconnection to the same peer. */
522
+ AllowReconnect: 2,
523
+ /** Resend on reconnection to a different peer (implies AllowReconnect). */
524
+ AllowResend: 6,
525
+ // 4 | AllowReconnect
526
+ /** Default: wait + reconnect + resend. */
527
+ Default: 7
528
+ // AwaitForConnection | AllowResend
529
+ };
518
530
  var RpcType = {
519
531
  object: /* @__PURE__ */ Symbol("object"),
520
532
  stream: /* @__PURE__ */ Symbol("stream"),
@@ -531,6 +543,7 @@ function defineRpcService(name, methods) {
531
543
  const cleanName = colonIndex >= 0 ? key.substring(0, colonIndex) : key;
532
544
  const wireArgCount = input.wireArgCount ?? input.args.length + 1;
533
545
  const mapKey = `${cleanName}:${wireArgCount}`;
546
+ const isNoWait = input.returns === RpcType.noWait;
534
547
  map.set(mapKey, {
535
548
  name: cleanName,
536
549
  serviceName: name,
@@ -538,7 +551,8 @@ function defineRpcService(name, methods) {
538
551
  wireArgCount,
539
552
  callTypeId: input.callTypeId ?? 0,
540
553
  stream: input.returns === RpcType.stream,
541
- noWait: input.returns === RpcType.noWait
554
+ noWait: isNoWait,
555
+ remoteExecutionMode: isNoWait ? 0 : input.remoteExecutionMode ?? RpcRemoteExecutionMode.Default
542
556
  });
543
557
  }
544
558
  return { name, methods: map };
@@ -550,14 +564,17 @@ var RpcOutboundCall = class {
550
564
  callId;
551
565
  method;
552
566
  result = new PromiseSource2();
567
+ /** Bitfield of RpcRemoteExecutionMode flags controlling reconnect/resend behavior. */
568
+ remoteExecutionMode;
553
569
  /** Whether to remove this call from the tracker on $sys.Ok. Default: true.
554
570
  * Subclasses (e.g. compute calls) override to false to stay in tracker for invalidation. */
555
571
  removeOnOk = true;
556
572
  /** The serialized wire data — stored for re-sending on reconnect. */
557
573
  serializedWireData = "";
558
- constructor(callId, method) {
574
+ constructor(callId, method, remoteExecutionMode = 7) {
559
575
  this.callId = callId;
560
576
  this.method = method;
577
+ this.remoteExecutionMode = remoteExecutionMode;
561
578
  }
562
579
  /** Called when the connection is lost. Subclasses can override to resolve invalidation promises. */
563
580
  onDisconnect() {
@@ -670,6 +687,8 @@ var RpcStreamSender = class _RpcStreamSender {
670
687
  _lastAckedIndex = 0;
671
688
  _ackWaiting = null;
672
689
  _resetRequested = false;
690
+ _abortController = new AbortController();
691
+ _iterator = null;
673
692
  constructor(peer, ackPeriod = DEFAULT_ACK_PERIOD, ackAdvance = DEFAULT_ACK_ADVANCE, allowReconnect = true, isRealTime = false, canSkipTo = () => true) {
674
693
  const localId = peer.sharedObjects.nextId();
675
694
  this.id = { hostId: peer.hub.hubId, localId };
@@ -680,6 +699,10 @@ var RpcStreamSender = class _RpcStreamSender {
680
699
  this.ackPeriod = ackPeriod;
681
700
  this.ackAdvance = ackAdvance;
682
701
  }
702
+ /** AbortSignal that is aborted when the sender is disconnected. */
703
+ get abortSignal() {
704
+ return this._abortController.signal;
705
+ }
683
706
  /** Returns the stream reference string for the $sys.Ok response. */
684
707
  toRef() {
685
708
  return `${this.id.hostId},${this.id.localId},${this.ackPeriod},${this.ackAdvance},${this.allowReconnect ? "1" : "0"},${this.isRealTime ? "1" : "0"}`;
@@ -706,8 +729,7 @@ var RpcStreamSender = class _RpcStreamSender {
706
729
  }
707
730
  /** Called by system call handler when $sys.AckEnd is received from the client. */
708
731
  onAckEnd(_hostId) {
709
- this._ended = true;
710
- this.peer.sharedObjects.unregister(this);
732
+ this.disconnect();
711
733
  }
712
734
  /** Send a single item to the client. */
713
735
  sendItem(item) {
@@ -764,6 +786,7 @@ var RpcStreamSender = class _RpcStreamSender {
764
786
  async writeFrom(source) {
765
787
  await this._started.promise;
766
788
  const iterator = source[Symbol.asyncIterator]();
789
+ this._iterator = iterator;
767
790
  try {
768
791
  for (; ; ) {
769
792
  const next = await iterator.next();
@@ -828,10 +851,20 @@ var RpcStreamSender = class _RpcStreamSender {
828
851
  reconnect() {
829
852
  }
830
853
  disconnect() {
854
+ if (this._ended) return;
831
855
  this._ended = true;
856
+ this._abortController.abort();
832
857
  if (!this._started.isCompleted) {
833
858
  this._started.resolve();
834
859
  }
860
+ if (this._ackWaiting) {
861
+ this._ackWaiting.resolve();
862
+ this._ackWaiting = null;
863
+ }
864
+ if (this._iterator) {
865
+ void this._iterator.return?.(void 0);
866
+ this._iterator = null;
867
+ }
835
868
  this.peer.sharedObjects.unregister(this);
836
869
  }
837
870
  };
@@ -896,7 +929,7 @@ var RpcStream = class _RpcStream {
896
929
  _iterating = false;
897
930
  _ackSentUpTo = 0;
898
931
  constructor(sourceOrRef, optionsOrPeer) {
899
- if (_isAsyncIterable(sourceOrRef)) {
932
+ if (_isStreamSource(sourceOrRef)) {
900
933
  const options = optionsOrPeer ?? {};
901
934
  this.kind = RpcObjectKind.Local;
902
935
  this.localSource = sourceOrRef;
@@ -957,7 +990,8 @@ var RpcStream = class _RpcStream {
957
990
  );
958
991
  peer.sharedObjects.register(sender);
959
992
  this._sender = sender;
960
- this._whenSent = sender.writeFrom(this.localSource);
993
+ const source = typeof this.localSource === "function" ? this.localSource(sender.abortSignal) : this.localSource;
994
+ this._whenSent = sender.writeFrom(source);
961
995
  this._toRefValue = peer.format.isBinary ? {
962
996
  SerializedId: [sender.id.hostId, sender.id.localId],
963
997
  AckPeriod: sender.ackPeriod,
@@ -1037,7 +1071,10 @@ var RpcStream = class _RpcStream {
1037
1071
  }
1038
1072
  }
1039
1073
  disconnect() {
1040
- if (this.kind === RpcObjectKind.Local) return;
1074
+ if (this.kind === RpcObjectKind.Local) {
1075
+ this._sender?.disconnect();
1076
+ return;
1077
+ }
1041
1078
  if (this._completed) return;
1042
1079
  this._completed = true;
1043
1080
  this._completionError = new Error("Peer disconnected.");
@@ -1046,7 +1083,8 @@ var RpcStream = class _RpcStream {
1046
1083
  // -- AsyncIterable --
1047
1084
  [Symbol.asyncIterator]() {
1048
1085
  if (this.kind === RpcObjectKind.Local) {
1049
- return this.localSource[Symbol.asyncIterator]();
1086
+ const source = typeof this.localSource === "function" ? this.localSource(new AbortController().signal) : this.localSource;
1087
+ return source[Symbol.asyncIterator]();
1050
1088
  }
1051
1089
  if (this._iterating)
1052
1090
  throw new Error("RpcStream can only be iterated once.");
@@ -1127,7 +1165,8 @@ var RpcStream = class _RpcStream {
1127
1165
  }
1128
1166
  }
1129
1167
  };
1130
- function _isAsyncIterable(value) {
1168
+ function _isStreamSource(value) {
1169
+ if (typeof value === "function") return true;
1131
1170
  return value !== null && typeof value === "object" && Symbol.asyncIterator in value;
1132
1171
  }
1133
1172
  function resolveStreamRefs(value, peer) {
@@ -1662,7 +1701,7 @@ var RpcPeer = class {
1662
1701
  }
1663
1702
  call(method, args, options) {
1664
1703
  const callId = this.outbound.nextId();
1665
- const outboundCall = options?.outboundCallFactory ? options.outboundCallFactory(callId, method) : new RpcOutboundCall(callId, method);
1704
+ const outboundCall = options?.outboundCallFactory ? options.outboundCallFactory(callId, method) : new RpcOutboundCall(callId, method, options?.remoteExecutionMode ?? 7);
1666
1705
  const envelope = {
1667
1706
  Method: method,
1668
1707
  RelatedId: callId,
@@ -1999,7 +2038,18 @@ var RpcClientPeer = class extends RpcPeer {
1999
2038
  }
2000
2039
  const trackerCalls = [...this.outbound.values()];
2001
2040
  for (const call of trackerCalls) {
2002
- if (!call.removeOnOk && call.result.isCompleted) {
2041
+ const mode = call.remoteExecutionMode;
2042
+ if (!(mode & 2)) {
2043
+ if (!call.result.isCompleted)
2044
+ call.result.reject(new Error("Outbound call failed: disconnected and AllowReconnect is not set."));
2045
+ call.onDisconnect();
2046
+ this.outbound.remove(call.callId);
2047
+ } else if (_isPeerChanged && !(mode & 4)) {
2048
+ if (!call.result.isCompleted)
2049
+ call.result.reject(new Error("Outbound call failed: reconnected to a different peer and AllowResend is not set."));
2050
+ call.onDisconnect();
2051
+ this.outbound.remove(call.callId);
2052
+ } else if (!call.removeOnOk && call.result.isCompleted) {
2003
2053
  call.onDisconnect();
2004
2054
  this.outbound.remove(call.callId);
2005
2055
  } else {
@@ -2023,6 +2073,9 @@ var RpcServerPeer = class extends RpcPeer {
2023
2073
  /** Accept an incoming connection — sets up message handling and handshake response. */
2024
2074
  accept(conn) {
2025
2075
  this.setupConnection(conn);
2076
+ conn.closed.add(() => {
2077
+ this.sharedObjects.disconnectAll();
2078
+ });
2026
2079
  }
2027
2080
  _onHandshakeReceived(_handshake) {
2028
2081
  if (this._connection !== void 0) {
@@ -2102,7 +2155,8 @@ function rpcMethod(options) {
2102
2155
  methods[methodName] = {
2103
2156
  ...methods[methodName],
2104
2157
  argCount: target.length,
2105
- returns: options?.returns
2158
+ returns: options?.returns,
2159
+ remoteExecutionMode: options?.remoteExecutionMode
2106
2160
  };
2107
2161
  return target;
2108
2162
  };
@@ -2717,7 +2771,8 @@ var RpcHub = class {
2717
2771
  const methods = /* @__PURE__ */ new Map();
2718
2772
  for (const [name, byArgCount] of overloads) {
2719
2773
  if (byArgCount.size === 1) {
2720
- methods.set(name, byArgCount.values().next().value);
2774
+ const [[, singleFn]] = byArgCount;
2775
+ methods.set(name, singleFn);
2721
2776
  } else {
2722
2777
  methods.set(name, (...args) => {
2723
2778
  const fn = byArgCount.get(args.length);
@@ -2747,6 +2802,7 @@ var RpcHub = class {
2747
2802
  for (const [name, meta] of Object.entries(methodsMeta)) {
2748
2803
  const wireArgCount = meta.argCount + 1;
2749
2804
  const mapKey = `${name}:${wireArgCount}`;
2805
+ const isNoWait = meta.returns === RpcType.noWait;
2750
2806
  methods.set(mapKey, {
2751
2807
  name,
2752
2808
  serviceName: svcMeta.name,
@@ -2754,7 +2810,8 @@ var RpcHub = class {
2754
2810
  wireArgCount,
2755
2811
  callTypeId: 0,
2756
2812
  stream: meta.returns === RpcType.stream,
2757
- noWait: meta.returns === RpcType.noWait
2813
+ noWait: isNoWait,
2814
+ remoteExecutionMode: isNoWait ? 0 : meta.remoteExecutionMode ?? RpcRemoteExecutionMode.Default
2758
2815
  });
2759
2816
  }
2760
2817
  return { name: svcMeta.name, methods };
@@ -2772,6 +2829,8 @@ var RpcHub = class {
2772
2829
  /** Create a client method for the given methodDef. Override in FusionHub for custom call types. */
2773
2830
  _createClientMethod(peer, methodDef) {
2774
2831
  const wireName = wireMethodName(methodDef);
2832
+ const mode = methodDef.remoteExecutionMode;
2833
+ const mustCheckConnection = !(mode & RpcRemoteExecutionMode.AwaitForConnection);
2775
2834
  if (methodDef.noWait) {
2776
2835
  return (...args) => {
2777
2836
  const callArgs = args.slice(0, methodDef.argCount);
@@ -2780,6 +2839,8 @@ var RpcHub = class {
2780
2839
  }
2781
2840
  if (methodDef.stream) {
2782
2841
  return async (...args) => {
2842
+ if (mustCheckConnection && !peer.isConnected)
2843
+ throw new Error("Outbound call failed: not connected and AwaitForConnection is not set.");
2783
2844
  const callArgs = args.slice(0, methodDef.argCount);
2784
2845
  const outboundCall = peer.call(wireName, callArgs);
2785
2846
  const result = await outboundCall.result.promise;
@@ -2793,8 +2854,10 @@ var RpcHub = class {
2793
2854
  return stream;
2794
2855
  };
2795
2856
  }
2796
- const callOptions = methodDef.callTypeId !== 0 ? { callTypeId: methodDef.callTypeId } : void 0;
2857
+ const callOptions = methodDef.callTypeId !== 0 || mode !== RpcRemoteExecutionMode.Default ? { callTypeId: methodDef.callTypeId, remoteExecutionMode: mode } : void 0;
2797
2858
  return async (...args) => {
2859
+ if (mustCheckConnection && !peer.isConnected)
2860
+ throw new Error("Outbound call failed: not connected and AwaitForConnection is not set.");
2798
2861
  const callArgs = args.slice(0, methodDef.argCount);
2799
2862
  const outboundCall = peer.call(wireName, callArgs, callOptions);
2800
2863
  const result = await outboundCall.result.promise;
@@ -2817,7 +2880,7 @@ function createRpcClient(peer, serviceDef) {
2817
2880
  const methods = /* @__PURE__ */ new Map();
2818
2881
  for (const [name, byArgCount] of overloads) {
2819
2882
  if (byArgCount.size === 1) {
2820
- const methodDef = byArgCount.values().next().value;
2883
+ const [[, methodDef]] = byArgCount;
2821
2884
  methods.set(name, createMethod(peer, methodDef));
2822
2885
  } else {
2823
2886
  const fns = /* @__PURE__ */ new Map();
@@ -2842,10 +2905,14 @@ function createRpcClient(peer, serviceDef) {
2842
2905
  });
2843
2906
  }
2844
2907
  function createMethod(peer, methodDef) {
2908
+ const mode = methodDef.remoteExecutionMode;
2909
+ const mustCheckConnection = !(mode & RpcRemoteExecutionMode.AwaitForConnection);
2845
2910
  return async (...args) => {
2911
+ if (mustCheckConnection && !peer.isConnected)
2912
+ throw new Error("Outbound call failed: not connected and AwaitForConnection is not set.");
2846
2913
  const callArgs = args.slice(0, methodDef.argCount);
2847
2914
  const wireName = wireMethodName(methodDef);
2848
- const options = methodDef.callTypeId !== 0 ? { callTypeId: methodDef.callTypeId } : void 0;
2915
+ const options = methodDef.callTypeId !== 0 || mode !== RpcRemoteExecutionMode.Default ? { callTypeId: methodDef.callTypeId, remoteExecutionMode: mode } : void 0;
2849
2916
  const outboundCall = peer.call(wireName, callArgs, options);
2850
2917
  return outboundCall.result.promise;
2851
2918
  };
@@ -3059,6 +3126,7 @@ export {
3059
3126
  RpcPeerConnectionKind,
3060
3127
  RpcPeerStateKind,
3061
3128
  RpcPeerStateMonitor,
3129
+ RpcRemoteExecutionMode,
3062
3130
  RpcRemoteObjectTracker,
3063
3131
  RpcSerializationFormat,
3064
3132
  RpcSerializationFormatResolver,