@datagrout/conduit 0.3.0 → 0.5.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/README.md +52 -2
- package/dist/{chunk-RED5DKGI.mjs → chunk-26DYCD4G.mjs} +4 -30
- package/dist/chunk-CIESM3BP.mjs +33 -0
- package/dist/chunk-SWH5Y2U7.mjs +69 -0
- package/dist/index.d.mts +294 -10
- package/dist/index.d.ts +294 -10
- package/dist/index.js +478 -5
- package/dist/index.mjs +410 -11
- package/dist/{oauth-OMPWCI2X.mjs → oauth-NSDC2G7W.mjs} +2 -1
- package/dist/onramp-743RJTNI.mjs +13 -0
- package/package.json +4 -2
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
OAuthTokenProvider,
|
|
3
|
-
__esm,
|
|
4
|
-
__export,
|
|
5
|
-
__require,
|
|
6
|
-
__toCommonJS,
|
|
7
3
|
deriveTokenEndpoint,
|
|
8
4
|
init_oauth,
|
|
9
5
|
oauth_exports
|
|
10
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-26DYCD4G.mjs";
|
|
7
|
+
import {
|
|
8
|
+
registerAndExchange,
|
|
9
|
+
registerOnly
|
|
10
|
+
} from "./chunk-SWH5Y2U7.mjs";
|
|
11
|
+
import {
|
|
12
|
+
__esm,
|
|
13
|
+
__export,
|
|
14
|
+
__require,
|
|
15
|
+
__toCommonJS
|
|
16
|
+
} from "./chunk-CIESM3BP.mjs";
|
|
11
17
|
|
|
12
18
|
// src/identity.ts
|
|
13
19
|
var identity_exports = {};
|
|
@@ -589,6 +595,295 @@ var JSONRPCTransport = class extends Transport {
|
|
|
589
595
|
}
|
|
590
596
|
};
|
|
591
597
|
|
|
598
|
+
// src/transports/ws.ts
|
|
599
|
+
var SUBPROTOCOL = "datagrout-jsonrpc.v1";
|
|
600
|
+
var SUBSCRIPTION_BUFFER = 256;
|
|
601
|
+
var Subscription = class {
|
|
602
|
+
id;
|
|
603
|
+
topic;
|
|
604
|
+
_queue = [];
|
|
605
|
+
_waiters = [];
|
|
606
|
+
_rejecters = [];
|
|
607
|
+
_closed = false;
|
|
608
|
+
constructor(id, topic) {
|
|
609
|
+
this.id = id;
|
|
610
|
+
this.topic = topic;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Wait for the next event from this subscription.
|
|
614
|
+
*
|
|
615
|
+
* @throws When the subscription has been closed.
|
|
616
|
+
*/
|
|
617
|
+
recv() {
|
|
618
|
+
if (this._queue.length > 0) {
|
|
619
|
+
return Promise.resolve(this._queue.shift());
|
|
620
|
+
}
|
|
621
|
+
if (this._closed) {
|
|
622
|
+
return Promise.reject(new Error("Subscription closed"));
|
|
623
|
+
}
|
|
624
|
+
return new Promise((resolve, reject) => {
|
|
625
|
+
this._waiters.push(resolve);
|
|
626
|
+
this._rejecters.push(reject);
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
async *[Symbol.asyncIterator]() {
|
|
630
|
+
while (this._queue.length > 0 || !this._closed) {
|
|
631
|
+
try {
|
|
632
|
+
yield await this.recv();
|
|
633
|
+
} catch {
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
// ── Internal ───────────────────────────────────────────────────────────────
|
|
639
|
+
_enqueue(event) {
|
|
640
|
+
if (this._waiters.length > 0) {
|
|
641
|
+
const resolve = this._waiters.shift();
|
|
642
|
+
this._rejecters.shift();
|
|
643
|
+
resolve(event);
|
|
644
|
+
} else if (this._queue.length < SUBSCRIPTION_BUFFER) {
|
|
645
|
+
this._queue.push(event);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
_close() {
|
|
649
|
+
this._closed = true;
|
|
650
|
+
const err = new Error("Subscription closed");
|
|
651
|
+
for (const reject of this._rejecters) {
|
|
652
|
+
reject(err);
|
|
653
|
+
}
|
|
654
|
+
this._waiters.length = 0;
|
|
655
|
+
this._rejecters.length = 0;
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
var WsTransport = class extends Transport {
|
|
659
|
+
_url;
|
|
660
|
+
_auth;
|
|
661
|
+
_ws = null;
|
|
662
|
+
_nextId = 0;
|
|
663
|
+
_pending = /* @__PURE__ */ new Map();
|
|
664
|
+
_pendingSubscribe = /* @__PURE__ */ new Map();
|
|
665
|
+
_subscriptions = /* @__PURE__ */ new Map();
|
|
666
|
+
constructor(url, auth, _timeout, _identity) {
|
|
667
|
+
super();
|
|
668
|
+
const scheme = new URL(url).protocol.replace(":", "");
|
|
669
|
+
if (scheme !== "ws" && scheme !== "wss") {
|
|
670
|
+
throw new Error(`WS transport requires a ws:// or wss:// URL, got ${scheme}://`);
|
|
671
|
+
}
|
|
672
|
+
this._url = url;
|
|
673
|
+
this._auth = auth;
|
|
674
|
+
}
|
|
675
|
+
// ── Lifecycle ─────────────────────────────────────────────────────────────
|
|
676
|
+
async connect() {
|
|
677
|
+
if (this._ws !== null) return;
|
|
678
|
+
const WsImpl = await resolveWebSocketImpl();
|
|
679
|
+
const headers = buildUpgradeHeaders(this._auth);
|
|
680
|
+
const ws = new WsImpl(this._url, [SUBPROTOCOL], {
|
|
681
|
+
headers
|
|
682
|
+
});
|
|
683
|
+
await new Promise((resolve, reject) => {
|
|
684
|
+
ws.onopen = () => resolve();
|
|
685
|
+
ws.onerror = (ev) => reject(new Error(`WS connect failed: ${ev.message ?? "unknown"}`));
|
|
686
|
+
});
|
|
687
|
+
ws.onmessage = (ev) => this._handleMessage(ev.data);
|
|
688
|
+
ws.onerror = (_ev) => this._failAll("WS connection error");
|
|
689
|
+
ws.onclose = () => {
|
|
690
|
+
this._failAll("WS connection closed");
|
|
691
|
+
this._ws = null;
|
|
692
|
+
};
|
|
693
|
+
this._ws = ws;
|
|
694
|
+
}
|
|
695
|
+
async disconnect() {
|
|
696
|
+
const ws = this._ws;
|
|
697
|
+
this._ws = null;
|
|
698
|
+
this._failAll("WS connection closed");
|
|
699
|
+
if (ws !== null) {
|
|
700
|
+
try {
|
|
701
|
+
ws.close();
|
|
702
|
+
} catch {
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
// ── Subscriptions ─────────────────────────────────────────────────────────
|
|
707
|
+
/**
|
|
708
|
+
* Open a server-side push subscription for `topic`.
|
|
709
|
+
*
|
|
710
|
+
* @param topic - Dotted namespace topic, e.g.
|
|
711
|
+
* `"agents.my-agent-id.events"` or `"tasks.task-123.*"`.
|
|
712
|
+
* @returns A {@link Subscription} handle whose async-for loop delivers events.
|
|
713
|
+
*/
|
|
714
|
+
async subscribe(topic) {
|
|
715
|
+
this._requireConnected();
|
|
716
|
+
const id = this._mintId();
|
|
717
|
+
return new Promise((resolve, reject) => {
|
|
718
|
+
this._pendingSubscribe.set(id, { topic, resolve, reject });
|
|
719
|
+
this._send({ jsonrpc: "2.0", id, method: "subscribe", params: { topic } });
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Cancel a server-side subscription.
|
|
724
|
+
*
|
|
725
|
+
* The local {@link Subscription} queue is closed immediately.
|
|
726
|
+
*
|
|
727
|
+
* @param subscriptionId - The `id` field from the {@link Subscription}
|
|
728
|
+
* returned by {@link subscribe}.
|
|
729
|
+
*/
|
|
730
|
+
async unsubscribe(subscriptionId) {
|
|
731
|
+
this._requireConnected();
|
|
732
|
+
const sub = this._subscriptions.get(subscriptionId);
|
|
733
|
+
if (sub !== void 0) {
|
|
734
|
+
this._subscriptions.delete(subscriptionId);
|
|
735
|
+
sub._close();
|
|
736
|
+
}
|
|
737
|
+
const id = this._mintId();
|
|
738
|
+
const ackPromise = new Promise((resolve, reject) => {
|
|
739
|
+
this._pending.set(id, { resolve, reject });
|
|
740
|
+
});
|
|
741
|
+
this._send({
|
|
742
|
+
jsonrpc: "2.0",
|
|
743
|
+
id,
|
|
744
|
+
method: "unsubscribe",
|
|
745
|
+
params: { subscription: subscriptionId }
|
|
746
|
+
});
|
|
747
|
+
await Promise.race([
|
|
748
|
+
ackPromise,
|
|
749
|
+
new Promise((resolve) => setTimeout(resolve, 5e3))
|
|
750
|
+
]);
|
|
751
|
+
this._pending.delete(id);
|
|
752
|
+
}
|
|
753
|
+
// ── Transport base implementation ─────────────────────────────────────────
|
|
754
|
+
async listTools(options) {
|
|
755
|
+
return await this._request("tools/list", options);
|
|
756
|
+
}
|
|
757
|
+
async callTool(name, args, _options) {
|
|
758
|
+
return this._request("tools/call", { name, arguments: args });
|
|
759
|
+
}
|
|
760
|
+
async listResources(_options) {
|
|
761
|
+
return await this._request("resources/list");
|
|
762
|
+
}
|
|
763
|
+
async readResource(uri, _options) {
|
|
764
|
+
return this._request("resources/read", { uri });
|
|
765
|
+
}
|
|
766
|
+
async listPrompts(_options) {
|
|
767
|
+
return await this._request("prompts/list");
|
|
768
|
+
}
|
|
769
|
+
async getPrompt(name, args, _options) {
|
|
770
|
+
return this._request("prompts/get", { name, arguments: args });
|
|
771
|
+
}
|
|
772
|
+
// ── Internal ──────────────────────────────────────────────────────────────
|
|
773
|
+
_mintId() {
|
|
774
|
+
return `ws-${++this._nextId}`;
|
|
775
|
+
}
|
|
776
|
+
_requireConnected() {
|
|
777
|
+
if (this._ws === null) {
|
|
778
|
+
throw new Error("WS transport not connected. Call connect() first.");
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
_send(payload) {
|
|
782
|
+
this._ws.send(JSON.stringify(payload));
|
|
783
|
+
}
|
|
784
|
+
async _request(method, params) {
|
|
785
|
+
this._requireConnected();
|
|
786
|
+
const id = this._mintId();
|
|
787
|
+
return new Promise((resolve, reject) => {
|
|
788
|
+
this._pending.set(id, { resolve, reject });
|
|
789
|
+
this._send({ jsonrpc: "2.0", id, method, ...params !== void 0 ? { params } : {} });
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
_handleMessage(data) {
|
|
793
|
+
let msg;
|
|
794
|
+
try {
|
|
795
|
+
msg = JSON.parse(data);
|
|
796
|
+
} catch {
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
if (!("id" in msg)) {
|
|
800
|
+
if (msg["method"] === "notification") {
|
|
801
|
+
this._routeNotification(msg["params"]);
|
|
802
|
+
}
|
|
803
|
+
return;
|
|
804
|
+
}
|
|
805
|
+
const msgId = String(msg["id"]);
|
|
806
|
+
const pendingSub = this._pendingSubscribe.get(msgId);
|
|
807
|
+
if (pendingSub !== void 0) {
|
|
808
|
+
this._pendingSubscribe.delete(msgId);
|
|
809
|
+
const err = msg["error"];
|
|
810
|
+
if (err !== void 0) {
|
|
811
|
+
pendingSub.reject(new Error(String(err["message"] ?? "Subscribe failed")));
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
const result = msg["result"] ?? {};
|
|
815
|
+
const subId = String(result["subscription"] ?? msgId);
|
|
816
|
+
const sub = new Subscription(subId, pendingSub.topic);
|
|
817
|
+
this._subscriptions.set(subId, sub);
|
|
818
|
+
pendingSub.resolve(sub);
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
const pending = this._pending.get(msgId);
|
|
822
|
+
if (pending !== void 0) {
|
|
823
|
+
this._pending.delete(msgId);
|
|
824
|
+
const err = msg["error"];
|
|
825
|
+
if (err !== void 0) {
|
|
826
|
+
pending.reject(new Error(String(err["message"] ?? "RPC error")));
|
|
827
|
+
} else {
|
|
828
|
+
pending.resolve(msg["result"]);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
_routeNotification(params) {
|
|
833
|
+
if (params === void 0) return;
|
|
834
|
+
const subId = params["subscription"];
|
|
835
|
+
if (typeof subId !== "string") return;
|
|
836
|
+
const sub = this._subscriptions.get(subId);
|
|
837
|
+
if (sub === void 0) return;
|
|
838
|
+
sub._enqueue({
|
|
839
|
+
subscription: subId,
|
|
840
|
+
event: String(params["event"] ?? ""),
|
|
841
|
+
data: params["data"]
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
_failAll(reason) {
|
|
845
|
+
const err = new Error(reason);
|
|
846
|
+
for (const { reject } of this._pending.values()) {
|
|
847
|
+
reject(err);
|
|
848
|
+
}
|
|
849
|
+
this._pending.clear();
|
|
850
|
+
for (const { reject } of this._pendingSubscribe.values()) {
|
|
851
|
+
reject(err);
|
|
852
|
+
}
|
|
853
|
+
this._pendingSubscribe.clear();
|
|
854
|
+
for (const sub of this._subscriptions.values()) {
|
|
855
|
+
sub._close();
|
|
856
|
+
}
|
|
857
|
+
this._subscriptions.clear();
|
|
858
|
+
}
|
|
859
|
+
};
|
|
860
|
+
function buildUpgradeHeaders(auth) {
|
|
861
|
+
const headers = {};
|
|
862
|
+
if (auth === void 0) return headers;
|
|
863
|
+
if ("bearer" in auth && auth.bearer !== void 0) {
|
|
864
|
+
headers["Authorization"] = `Bearer ${auth.bearer}`;
|
|
865
|
+
} else if ("apiKey" in auth && auth.apiKey !== void 0) {
|
|
866
|
+
headers["X-API-Key"] = auth.apiKey;
|
|
867
|
+
} else if ("basic" in auth && auth.basic !== void 0) {
|
|
868
|
+
const encoded = Buffer.from(`${auth.basic.username}:${auth.basic.password}`).toString("base64");
|
|
869
|
+
headers["Authorization"] = `Basic ${encoded}`;
|
|
870
|
+
}
|
|
871
|
+
return headers;
|
|
872
|
+
}
|
|
873
|
+
async function resolveWebSocketImpl() {
|
|
874
|
+
if (typeof globalThis.WebSocket !== "undefined") {
|
|
875
|
+
return globalThis.WebSocket;
|
|
876
|
+
}
|
|
877
|
+
try {
|
|
878
|
+
const { default: WS } = await import("ws");
|
|
879
|
+
return WS;
|
|
880
|
+
} catch {
|
|
881
|
+
throw new Error(
|
|
882
|
+
"No WebSocket implementation found. Install the 'ws' package: npm install ws"
|
|
883
|
+
);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
592
887
|
// src/client.ts
|
|
593
888
|
init_identity();
|
|
594
889
|
|
|
@@ -1109,13 +1404,15 @@ var Client2 = class _Client {
|
|
|
1109
1404
|
this.isDg = isDgUrl(this.url);
|
|
1110
1405
|
this.useIntelligentInterface = options.useIntelligentInterface ?? this.isDg;
|
|
1111
1406
|
this.maxRetries = options.maxRetries ?? 3;
|
|
1112
|
-
|
|
1113
|
-
if (identity === void 0 && this.isDg && !options.disableMtls) {
|
|
1114
|
-
identity = ConduitIdentity.tryDiscover(options.identityDir) ?? void 0;
|
|
1115
|
-
}
|
|
1407
|
+
const identity = options.identity ?? (options.identityAuto ? ConduitIdentity.tryDiscover(options.identityDir) ?? void 0 : void 0);
|
|
1116
1408
|
const transportType = options.transport || "mcp";
|
|
1117
1409
|
if (transportType === "mcp") {
|
|
1118
1410
|
this.transport = new MCPTransport(this.url, this.auth, identity);
|
|
1411
|
+
} else if (transportType === "websocket") {
|
|
1412
|
+
let wsUrl = this.url;
|
|
1413
|
+
if (wsUrl.startsWith("https://")) wsUrl = "wss://" + wsUrl.slice(8);
|
|
1414
|
+
else if (wsUrl.startsWith("http://")) wsUrl = "ws://" + wsUrl.slice(7);
|
|
1415
|
+
this.transport = new WsTransport(wsUrl, this.auth, options.timeout, identity);
|
|
1119
1416
|
} else {
|
|
1120
1417
|
const rpcUrl = this.url.endsWith("/mcp") ? this.url.slice(0, -4) + "/rpc" : this.url;
|
|
1121
1418
|
this.transport = new JSONRPCTransport(rpcUrl, this.auth, options.timeout, identity);
|
|
@@ -1176,7 +1473,7 @@ var Client2 = class _Client {
|
|
|
1176
1473
|
* @param options.substrateEndpoint - Override the DG Substrate endpoint.
|
|
1177
1474
|
*/
|
|
1178
1475
|
static async bootstrapIdentityOAuth(options) {
|
|
1179
|
-
const { OAuthTokenProvider: OAuthTokenProvider2, deriveTokenEndpoint: deriveTokenEndpoint2 } = await import("./oauth-
|
|
1476
|
+
const { OAuthTokenProvider: OAuthTokenProvider2, deriveTokenEndpoint: deriveTokenEndpoint2 } = await import("./oauth-NSDC2G7W.mjs");
|
|
1180
1477
|
const tokenEndpoint = deriveTokenEndpoint2(options.url);
|
|
1181
1478
|
const provider = new OAuthTokenProvider2({
|
|
1182
1479
|
clientId: options.clientId,
|
|
@@ -1192,6 +1489,60 @@ var Client2 = class _Client {
|
|
|
1192
1489
|
substrateEndpoint: options.substrateEndpoint
|
|
1193
1490
|
});
|
|
1194
1491
|
}
|
|
1492
|
+
/**
|
|
1493
|
+
* Register autonomously with DG and bootstrap an mTLS identity.
|
|
1494
|
+
*
|
|
1495
|
+
* The all-in-one flow: onramp (no prior credentials required) →
|
|
1496
|
+
* OAuth token exchange → mTLS identity registration and persistence.
|
|
1497
|
+
*
|
|
1498
|
+
* On subsequent runs the saved mTLS identity is auto-discovered and
|
|
1499
|
+
* no credentials are needed.
|
|
1500
|
+
*
|
|
1501
|
+
* @param options.opts - Onramp registration options.
|
|
1502
|
+
* @param options.url - MCP server URL. Required if the onramp
|
|
1503
|
+
* response does not include `mcpUrl`.
|
|
1504
|
+
* @param options.identityDir - Custom identity storage directory.
|
|
1505
|
+
*
|
|
1506
|
+
* @example
|
|
1507
|
+
* ```ts
|
|
1508
|
+
* import { Client } from './client';
|
|
1509
|
+
* import type { OnrampOptions } from './onramp';
|
|
1510
|
+
*
|
|
1511
|
+
* const client = await Client.bootstrapOnramp({
|
|
1512
|
+
* opts: {
|
|
1513
|
+
* gateway: 'https://app.datagrout.ai',
|
|
1514
|
+
* agentName: 'my-research-agent',
|
|
1515
|
+
* agentType: 'claude-sonnet-4-6',
|
|
1516
|
+
* },
|
|
1517
|
+
* });
|
|
1518
|
+
* await client.connect();
|
|
1519
|
+
* ```
|
|
1520
|
+
*/
|
|
1521
|
+
static async bootstrapOnramp(options) {
|
|
1522
|
+
const { _doRegister, _exchangeToken } = await import("./onramp-743RJTNI.mjs");
|
|
1523
|
+
const dir = options.identityDir || DEFAULT_IDENTITY_DIR;
|
|
1524
|
+
const existing = ConduitIdentity.tryDiscover(dir);
|
|
1525
|
+
if (existing && !existing.needsRotation(7)) {
|
|
1526
|
+
if (!options.url) {
|
|
1527
|
+
throw new Error("'url' must be provided when an existing identity is reused");
|
|
1528
|
+
}
|
|
1529
|
+
return new _Client({ url: options.url, identity: existing, identityDir: dir });
|
|
1530
|
+
}
|
|
1531
|
+
const creds = await _doRegister(options.opts);
|
|
1532
|
+
const token = await _exchangeToken(creds);
|
|
1533
|
+
const url = creds.mcpUrl ?? options.url;
|
|
1534
|
+
if (!url) {
|
|
1535
|
+
throw new Error(
|
|
1536
|
+
"'url' must be provided when mcpUrl is absent from the onramp response"
|
|
1537
|
+
);
|
|
1538
|
+
}
|
|
1539
|
+
return _Client.bootstrapIdentity({
|
|
1540
|
+
url,
|
|
1541
|
+
authToken: token,
|
|
1542
|
+
name: options.opts.agentName,
|
|
1543
|
+
identityDir: options.identityDir
|
|
1544
|
+
});
|
|
1545
|
+
}
|
|
1195
1546
|
// ===== Lifecycle =====
|
|
1196
1547
|
/**
|
|
1197
1548
|
* Establish the underlying transport connection.
|
|
@@ -1350,6 +1701,50 @@ var Client2 = class _Client {
|
|
|
1350
1701
|
this.ensureInitialized();
|
|
1351
1702
|
return this.sendWithRetry(() => this.transport.getPrompt(name, args, options));
|
|
1352
1703
|
}
|
|
1704
|
+
// ===== WebSocket push subscriptions =====
|
|
1705
|
+
/**
|
|
1706
|
+
* Subscribe to a server-push topic (WebSocket transport only).
|
|
1707
|
+
*
|
|
1708
|
+
* Requires `transport: 'websocket'` when constructing the client.
|
|
1709
|
+
*
|
|
1710
|
+
* @param topic - Dotted namespace topic, e.g.
|
|
1711
|
+
* `"agents.my-agent-id.events"` or `"tasks.task-123.*"`.
|
|
1712
|
+
* @returns A {@link Subscription} handle. Consume events with
|
|
1713
|
+
* {@link Subscription.recv} or an `for await` loop.
|
|
1714
|
+
*
|
|
1715
|
+
* @example
|
|
1716
|
+
* ```ts
|
|
1717
|
+
* const sub = await client.subscribe('agents.my-agent-id.events');
|
|
1718
|
+
* for await (const event of sub) {
|
|
1719
|
+
* console.log(event.event, event.data);
|
|
1720
|
+
* }
|
|
1721
|
+
* await client.unsubscribe(sub.id);
|
|
1722
|
+
* ```
|
|
1723
|
+
*/
|
|
1724
|
+
async subscribe(topic) {
|
|
1725
|
+
this.ensureInitialized();
|
|
1726
|
+
if (!(this.transport instanceof WsTransport)) {
|
|
1727
|
+
throw new Error(
|
|
1728
|
+
"subscribe() requires transport: 'websocket'. Reinitialise the client with transport: 'websocket'."
|
|
1729
|
+
);
|
|
1730
|
+
}
|
|
1731
|
+
return this.transport.subscribe(topic);
|
|
1732
|
+
}
|
|
1733
|
+
/**
|
|
1734
|
+
* Cancel a server-side push subscription.
|
|
1735
|
+
*
|
|
1736
|
+
* @param subscriptionId - The `id` from the {@link Subscription} returned
|
|
1737
|
+
* by {@link subscribe}.
|
|
1738
|
+
*/
|
|
1739
|
+
async unsubscribe(subscriptionId) {
|
|
1740
|
+
this.ensureInitialized();
|
|
1741
|
+
if (!(this.transport instanceof WsTransport)) {
|
|
1742
|
+
throw new Error(
|
|
1743
|
+
"unsubscribe() requires transport: 'websocket'. Reinitialise the client with transport: 'websocket'."
|
|
1744
|
+
);
|
|
1745
|
+
}
|
|
1746
|
+
return this.transport.unsubscribe(subscriptionId);
|
|
1747
|
+
}
|
|
1353
1748
|
// ===== DG-awareness helpers =====
|
|
1354
1749
|
warnIfNotDg(method) {
|
|
1355
1750
|
if (!this.isDg && !this.dgWarned) {
|
|
@@ -1640,7 +2035,7 @@ function buildToolMeta(raw) {
|
|
|
1640
2035
|
}
|
|
1641
2036
|
|
|
1642
2037
|
// src/index.ts
|
|
1643
|
-
var version = "0.
|
|
2038
|
+
var version = "0.5.0";
|
|
1644
2039
|
export {
|
|
1645
2040
|
AuthError,
|
|
1646
2041
|
Client2 as Client,
|
|
@@ -1656,6 +2051,8 @@ export {
|
|
|
1656
2051
|
OAuthTokenProvider,
|
|
1657
2052
|
RateLimitError,
|
|
1658
2053
|
ServerError,
|
|
2054
|
+
SUBPROTOCOL as WS_SUBPROTOCOL,
|
|
2055
|
+
WsTransport,
|
|
1659
2056
|
deriveTokenEndpoint,
|
|
1660
2057
|
extractMeta,
|
|
1661
2058
|
fetchDgCaCert,
|
|
@@ -1663,7 +2060,9 @@ export {
|
|
|
1663
2060
|
generateKeypair,
|
|
1664
2061
|
isDgUrl,
|
|
1665
2062
|
refreshCaCert,
|
|
2063
|
+
registerAndExchange,
|
|
1666
2064
|
registerIdentity,
|
|
2065
|
+
registerOnly,
|
|
1667
2066
|
rotateIdentity,
|
|
1668
2067
|
saveIdentity,
|
|
1669
2068
|
version
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrout/conduit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.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",
|
|
@@ -45,10 +45,12 @@
|
|
|
45
45
|
"url": "https://github.com/DataGrout/conduit-sdk/issues"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
48
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
49
|
+
"ws": "^8.18.0"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
52
|
"@types/node": "^20.11.0",
|
|
53
|
+
"@types/ws": "^8.5.10",
|
|
52
54
|
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
|
53
55
|
"@typescript-eslint/parser": "^6.19.0",
|
|
54
56
|
"eslint": "^8.56.0",
|