@datagrout/conduit 0.6.0 → 0.7.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/index.d.mts CHANGED
@@ -649,9 +649,31 @@ declare class WsTransport extends Transport {
649
649
  private readonly _pending;
650
650
  private readonly _pendingSubscribe;
651
651
  private readonly _subscriptions;
652
+ /**
653
+ * Handle for the recurring ping timer; non-null only while connected.
654
+ * Cleared on disconnect / close. Set indirectly via {@link _startPingTimer}.
655
+ */
656
+ private _pingTimer;
657
+ /**
658
+ * Interval in ms between client-initiated ping frames. Public-readable so
659
+ * tests can inject a small value via {@link WsTransport.setPingInterval};
660
+ * defaults to {@link PING_INTERVAL_MS}.
661
+ */
662
+ private _pingIntervalMs;
652
663
  constructor(url: string, auth?: AuthConfig, _timeout?: number, _identity?: ConduitIdentity);
653
664
  connect(): Promise<void>;
654
665
  disconnect(): Promise<void>;
666
+ /**
667
+ * Override the ping interval (ms) — used by tests to avoid 25-second waits.
668
+ * Must be called BEFORE {@link connect}; has no effect on an already-running
669
+ * timer. In production code, leave the default ({@link PING_INTERVAL_MS}).
670
+ */
671
+ setPingInterval(intervalMs: number): void;
672
+ /** Tracks how many ping frames this transport has sent — for tests. */
673
+ get pingsSent(): number;
674
+ private _pingsSent;
675
+ private _startPingTimer;
676
+ private _stopPingTimer;
655
677
  /**
656
678
  * Open a server-side push subscription for `topic`.
657
679
  *
package/dist/index.d.ts CHANGED
@@ -649,9 +649,31 @@ declare class WsTransport extends Transport {
649
649
  private readonly _pending;
650
650
  private readonly _pendingSubscribe;
651
651
  private readonly _subscriptions;
652
+ /**
653
+ * Handle for the recurring ping timer; non-null only while connected.
654
+ * Cleared on disconnect / close. Set indirectly via {@link _startPingTimer}.
655
+ */
656
+ private _pingTimer;
657
+ /**
658
+ * Interval in ms between client-initiated ping frames. Public-readable so
659
+ * tests can inject a small value via {@link WsTransport.setPingInterval};
660
+ * defaults to {@link PING_INTERVAL_MS}.
661
+ */
662
+ private _pingIntervalMs;
652
663
  constructor(url: string, auth?: AuthConfig, _timeout?: number, _identity?: ConduitIdentity);
653
664
  connect(): Promise<void>;
654
665
  disconnect(): Promise<void>;
666
+ /**
667
+ * Override the ping interval (ms) — used by tests to avoid 25-second waits.
668
+ * Must be called BEFORE {@link connect}; has no effect on an already-running
669
+ * timer. In production code, leave the default ({@link PING_INTERVAL_MS}).
670
+ */
671
+ setPingInterval(intervalMs: number): void;
672
+ /** Tracks how many ping frames this transport has sent — for tests. */
673
+ get pingsSent(): number;
674
+ private _pingsSent;
675
+ private _startPingTimer;
676
+ private _stopPingTimer;
655
677
  /**
656
678
  * Open a server-side push subscription for `topic`.
657
679
  *
package/dist/index.js CHANGED
@@ -836,6 +836,7 @@ var JSONRPCTransport = class extends Transport {
836
836
  // src/transports/ws.ts
837
837
  var SUBPROTOCOL = "datagrout-jsonrpc.v1";
838
838
  var SUBSCRIPTION_BUFFER = 256;
839
+ var PING_INTERVAL_MS = 25e3;
839
840
  var Subscription = class {
840
841
  id;
841
842
  topic;
@@ -901,6 +902,17 @@ var WsTransport = class extends Transport {
901
902
  _pending = /* @__PURE__ */ new Map();
902
903
  _pendingSubscribe = /* @__PURE__ */ new Map();
903
904
  _subscriptions = /* @__PURE__ */ new Map();
905
+ /**
906
+ * Handle for the recurring ping timer; non-null only while connected.
907
+ * Cleared on disconnect / close. Set indirectly via {@link _startPingTimer}.
908
+ */
909
+ _pingTimer = null;
910
+ /**
911
+ * Interval in ms between client-initiated ping frames. Public-readable so
912
+ * tests can inject a small value via {@link WsTransport.setPingInterval};
913
+ * defaults to {@link PING_INTERVAL_MS}.
914
+ */
915
+ _pingIntervalMs = PING_INTERVAL_MS;
904
916
  constructor(url, auth, _timeout, _identity) {
905
917
  super();
906
918
  const scheme = new URL(url).protocol.replace(":", "");
@@ -930,13 +942,16 @@ var WsTransport = class extends Transport {
930
942
  ws.onerror = (_ev) => this._failAll("WS connection error");
931
943
  ws.onclose = () => {
932
944
  this._failAll("WS connection closed");
945
+ this._stopPingTimer();
933
946
  this._ws = null;
934
947
  };
935
948
  this._ws = ws;
949
+ this._startPingTimer();
936
950
  }
937
951
  async disconnect() {
938
952
  const ws = this._ws;
939
953
  this._ws = null;
954
+ this._stopPingTimer();
940
955
  this._failAll("WS connection closed");
941
956
  if (ws !== null) {
942
957
  try {
@@ -945,6 +960,42 @@ var WsTransport = class extends Transport {
945
960
  }
946
961
  }
947
962
  }
963
+ // ── Ping keepalive ────────────────────────────────────────────────────────
964
+ /**
965
+ * Override the ping interval (ms) — used by tests to avoid 25-second waits.
966
+ * Must be called BEFORE {@link connect}; has no effect on an already-running
967
+ * timer. In production code, leave the default ({@link PING_INTERVAL_MS}).
968
+ */
969
+ setPingInterval(intervalMs) {
970
+ this._pingIntervalMs = intervalMs;
971
+ }
972
+ /** Tracks how many ping frames this transport has sent — for tests. */
973
+ get pingsSent() {
974
+ return this._pingsSent;
975
+ }
976
+ _pingsSent = 0;
977
+ _startPingTimer() {
978
+ if (this._pingTimer !== null || this._pingIntervalMs <= 0) return;
979
+ this._pingTimer = setInterval(() => {
980
+ const ws = this._ws;
981
+ if (ws === null) return;
982
+ if (typeof ws.ping === "function") {
983
+ try {
984
+ ws.ping();
985
+ this._pingsSent += 1;
986
+ } catch {
987
+ }
988
+ }
989
+ }, this._pingIntervalMs);
990
+ const t = this._pingTimer;
991
+ if (typeof t.unref === "function") t.unref();
992
+ }
993
+ _stopPingTimer() {
994
+ if (this._pingTimer !== null) {
995
+ clearInterval(this._pingTimer);
996
+ this._pingTimer = null;
997
+ }
998
+ }
948
999
  // ── Subscriptions ─────────────────────────────────────────────────────────
949
1000
  /**
950
1001
  * Open a server-side push subscription for `topic`.
package/dist/index.mjs CHANGED
@@ -621,6 +621,7 @@ var JSONRPCTransport = class extends Transport {
621
621
  // src/transports/ws.ts
622
622
  var SUBPROTOCOL = "datagrout-jsonrpc.v1";
623
623
  var SUBSCRIPTION_BUFFER = 256;
624
+ var PING_INTERVAL_MS = 25e3;
624
625
  var Subscription = class {
625
626
  id;
626
627
  topic;
@@ -686,6 +687,17 @@ var WsTransport = class extends Transport {
686
687
  _pending = /* @__PURE__ */ new Map();
687
688
  _pendingSubscribe = /* @__PURE__ */ new Map();
688
689
  _subscriptions = /* @__PURE__ */ new Map();
690
+ /**
691
+ * Handle for the recurring ping timer; non-null only while connected.
692
+ * Cleared on disconnect / close. Set indirectly via {@link _startPingTimer}.
693
+ */
694
+ _pingTimer = null;
695
+ /**
696
+ * Interval in ms between client-initiated ping frames. Public-readable so
697
+ * tests can inject a small value via {@link WsTransport.setPingInterval};
698
+ * defaults to {@link PING_INTERVAL_MS}.
699
+ */
700
+ _pingIntervalMs = PING_INTERVAL_MS;
689
701
  constructor(url, auth, _timeout, _identity) {
690
702
  super();
691
703
  const scheme = new URL(url).protocol.replace(":", "");
@@ -715,13 +727,16 @@ var WsTransport = class extends Transport {
715
727
  ws.onerror = (_ev) => this._failAll("WS connection error");
716
728
  ws.onclose = () => {
717
729
  this._failAll("WS connection closed");
730
+ this._stopPingTimer();
718
731
  this._ws = null;
719
732
  };
720
733
  this._ws = ws;
734
+ this._startPingTimer();
721
735
  }
722
736
  async disconnect() {
723
737
  const ws = this._ws;
724
738
  this._ws = null;
739
+ this._stopPingTimer();
725
740
  this._failAll("WS connection closed");
726
741
  if (ws !== null) {
727
742
  try {
@@ -730,6 +745,42 @@ var WsTransport = class extends Transport {
730
745
  }
731
746
  }
732
747
  }
748
+ // ── Ping keepalive ────────────────────────────────────────────────────────
749
+ /**
750
+ * Override the ping interval (ms) — used by tests to avoid 25-second waits.
751
+ * Must be called BEFORE {@link connect}; has no effect on an already-running
752
+ * timer. In production code, leave the default ({@link PING_INTERVAL_MS}).
753
+ */
754
+ setPingInterval(intervalMs) {
755
+ this._pingIntervalMs = intervalMs;
756
+ }
757
+ /** Tracks how many ping frames this transport has sent — for tests. */
758
+ get pingsSent() {
759
+ return this._pingsSent;
760
+ }
761
+ _pingsSent = 0;
762
+ _startPingTimer() {
763
+ if (this._pingTimer !== null || this._pingIntervalMs <= 0) return;
764
+ this._pingTimer = setInterval(() => {
765
+ const ws = this._ws;
766
+ if (ws === null) return;
767
+ if (typeof ws.ping === "function") {
768
+ try {
769
+ ws.ping();
770
+ this._pingsSent += 1;
771
+ } catch {
772
+ }
773
+ }
774
+ }, this._pingIntervalMs);
775
+ const t = this._pingTimer;
776
+ if (typeof t.unref === "function") t.unref();
777
+ }
778
+ _stopPingTimer() {
779
+ if (this._pingTimer !== null) {
780
+ clearInterval(this._pingTimer);
781
+ this._pingTimer = null;
782
+ }
783
+ }
733
784
  // ── Subscriptions ─────────────────────────────────────────────────────────
734
785
  /**
735
786
  * Open a server-side push subscription for `topic`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datagrout/conduit",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Production-ready MCP client with mTLS, OAuth 2.1, and semantic discovery",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",