@datagrout/conduit 0.5.0 → 0.6.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.
@@ -73,7 +73,9 @@ var init_oauth = __esm({
73
73
  }
74
74
  if (!response.ok) {
75
75
  const text = await response.text().catch(() => "");
76
- throw new Error(`OAuth token endpoint returned ${response.status}: ${text}`);
76
+ throw new Error(
77
+ `OAuth token endpoint returned ${response.status}: ${text}`
78
+ );
77
79
  }
78
80
  const data = await response.json();
79
81
  const expiresIn = data.expires_in ?? 3600;
@@ -22,7 +22,9 @@ async function _doRegister(opts) {
22
22
  });
23
23
  if (!completeResp.ok) {
24
24
  const text = await completeResp.text();
25
- throw new Error(`onramp complete rejected (HTTP ${completeResp.status}): ${text}`);
25
+ throw new Error(
26
+ `onramp complete rejected (HTTP ${completeResp.status}): ${text}`
27
+ );
26
28
  }
27
29
  const data = await completeResp.json();
28
30
  return {
package/dist/index.d.mts CHANGED
@@ -226,7 +226,7 @@ declare function fetchWithIdentity(url: string, init: RequestInit, identity: Con
226
226
  * - `"unlimited"` — authenticated DataGrout users; the gateway never blocks them.
227
227
  * - `{ perHour: number }` — unauthenticated callers hitting a per-hour cap.
228
228
  */
229
- type RateLimit = 'unlimited' | {
229
+ type RateLimit = "unlimited" | {
230
230
  perHour: number;
231
231
  };
232
232
  /**
@@ -414,7 +414,7 @@ interface ClientOptions {
414
414
  * This option is kept for backward compatibility and has no effect.
415
415
  */
416
416
  disableMtls?: boolean;
417
- transport?: 'mcp' | 'jsonrpc' | 'websocket';
417
+ transport?: "mcp" | "jsonrpc" | "websocket";
418
418
  timeout?: number;
419
419
  /**
420
420
  * Maximum number of automatic retries on "server not initialized" errors.
@@ -437,7 +437,7 @@ interface PerformOptions {
437
437
  tool: string;
438
438
  args: Record<string, any>;
439
439
  demux?: boolean;
440
- demuxMode?: 'strict' | 'fuzzy';
440
+ demuxMode?: "strict" | "fuzzy";
441
441
  }
442
442
  interface GuideRequestOptions {
443
443
  goal?: string;
package/dist/index.d.ts CHANGED
@@ -226,7 +226,7 @@ declare function fetchWithIdentity(url: string, init: RequestInit, identity: Con
226
226
  * - `"unlimited"` — authenticated DataGrout users; the gateway never blocks them.
227
227
  * - `{ perHour: number }` — unauthenticated callers hitting a per-hour cap.
228
228
  */
229
- type RateLimit = 'unlimited' | {
229
+ type RateLimit = "unlimited" | {
230
230
  perHour: number;
231
231
  };
232
232
  /**
@@ -414,7 +414,7 @@ interface ClientOptions {
414
414
  * This option is kept for backward compatibility and has no effect.
415
415
  */
416
416
  disableMtls?: boolean;
417
- transport?: 'mcp' | 'jsonrpc' | 'websocket';
417
+ transport?: "mcp" | "jsonrpc" | "websocket";
418
418
  timeout?: number;
419
419
  /**
420
420
  * Maximum number of automatic retries on "server not initialized" errors.
@@ -437,7 +437,7 @@ interface PerformOptions {
437
437
  tool: string;
438
438
  args: Record<string, any>;
439
439
  demux?: boolean;
440
- demuxMode?: 'strict' | 'fuzzy';
440
+ demuxMode?: "strict" | "fuzzy";
441
441
  }
442
442
  interface GuideRequestOptions {
443
443
  goal?: string;
package/dist/index.js CHANGED
@@ -101,7 +101,9 @@ var init_oauth = __esm({
101
101
  }
102
102
  if (!response.ok) {
103
103
  const text = await response.text().catch(() => "");
104
- throw new Error(`OAuth token endpoint returned ${response.status}: ${text}`);
104
+ throw new Error(
105
+ `OAuth token endpoint returned ${response.status}: ${text}`
106
+ );
105
107
  }
106
108
  const data = await response.json();
107
109
  const expiresIn = data.expires_in ?? 3600;
@@ -136,7 +138,9 @@ async function fetchWithIdentity(url, init, identity) {
136
138
  port: parsedUrl.port || 443,
137
139
  path: parsedUrl.pathname + parsedUrl.search,
138
140
  method: (init.method ?? "GET").toUpperCase(),
139
- headers: flattenHeaders(init.headers),
141
+ headers: flattenHeaders(
142
+ init.headers
143
+ ),
140
144
  cert: identity.certPem,
141
145
  key: identity.keyPem,
142
146
  ...identity.caPem ? { ca: identity.caPem } : {}
@@ -220,7 +224,9 @@ var init_identity = __esm({
220
224
  */
221
225
  static fromPaths(certPath, keyPath, caPath) {
222
226
  if (typeof process === "undefined" || !process.versions?.node) {
223
- throw new Error("ConduitIdentity.fromPaths() is only available in Node.js environments");
227
+ throw new Error(
228
+ "ConduitIdentity.fromPaths() is only available in Node.js environments"
229
+ );
224
230
  }
225
231
  const fs2 = require("fs");
226
232
  const certPem = fs2.readFileSync(certPath, "utf8");
@@ -244,7 +250,9 @@ var init_identity = __esm({
244
250
  if (!certPem) return null;
245
251
  const keyPem = process.env.CONDUIT_MTLS_KEY;
246
252
  if (!keyPem) {
247
- throw new Error("CONDUIT_MTLS_CERT is set but CONDUIT_MTLS_KEY is missing");
253
+ throw new Error(
254
+ "CONDUIT_MTLS_CERT is set but CONDUIT_MTLS_KEY is missing"
255
+ );
248
256
  }
249
257
  const caPem = process.env.CONDUIT_MTLS_CA || void 0;
250
258
  return _ConduitIdentity.fromPem(certPem, keyPem, caPem);
@@ -334,7 +342,11 @@ var init_identity = __esm({
334
342
  const keyPath = `${dir}/identity_key.pem`;
335
343
  if (!fs2.existsSync(certPath) || !fs2.existsSync(keyPath)) return null;
336
344
  const caPath = `${dir}/ca.pem`;
337
- return _ConduitIdentity.fromPaths(certPath, keyPath, fs2.existsSync(caPath) ? caPath : void 0);
345
+ return _ConduitIdentity.fromPaths(
346
+ certPath,
347
+ keyPath,
348
+ fs2.existsSync(caPath) ? caPath : void 0
349
+ );
338
350
  } catch {
339
351
  return null;
340
352
  }
@@ -374,7 +386,9 @@ async function _doRegister(opts) {
374
386
  });
375
387
  if (!completeResp.ok) {
376
388
  const text = await completeResp.text();
377
- throw new Error(`onramp complete rejected (HTTP ${completeResp.status}): ${text}`);
389
+ throw new Error(
390
+ `onramp complete rejected (HTTP ${completeResp.status}): ${text}`
391
+ );
378
392
  }
379
393
  const data = await completeResp.json();
380
394
  return {
@@ -565,6 +579,9 @@ var MCPTransport = class extends Transport {
565
579
  throw new Error("Not connected. Call connect() first.");
566
580
  }
567
581
  const result = await this.client.callTool({ name, arguments: args });
582
+ if (result?.structuredContent !== void 0) {
583
+ return result.structuredContent;
584
+ }
568
585
  const content = result?.content;
569
586
  if (Array.isArray(content) && content.length > 0) {
570
587
  const first = content[0];
@@ -575,6 +592,7 @@ var MCPTransport = class extends Transport {
575
592
  return { text: first.text };
576
593
  }
577
594
  }
595
+ return first;
578
596
  }
579
597
  return result;
580
598
  }
@@ -671,7 +689,11 @@ var InvalidConfigError = class extends ConduitError {
671
689
 
672
690
  // src/transports/jsonrpc.ts
673
691
  function unwrapContent(result) {
674
- if (result && Array.isArray(result.content) && result.content.length > 0) {
692
+ if (!result) return result;
693
+ if (result.structuredContent !== void 0) {
694
+ return result.structuredContent;
695
+ }
696
+ if (Array.isArray(result.content) && result.content.length > 0) {
675
697
  const first = result.content[0];
676
698
  if (first && typeof first.text === "string") {
677
699
  try {
@@ -680,6 +702,7 @@ function unwrapContent(result) {
680
702
  return { text: first.text };
681
703
  }
682
704
  }
705
+ return first;
683
706
  }
684
707
  return result;
685
708
  }
@@ -706,7 +729,9 @@ var JSONRPCTransport = class extends Transport {
706
729
  this.identity = identity;
707
730
  this.timeout = timeout;
708
731
  if (identity?.needsRotation(30)) {
709
- console.warn("[conduit] mTLS certificate expires within 30 days \u2014 consider rotating");
732
+ console.warn(
733
+ "[conduit] mTLS certificate expires within 30 days \u2014 consider rotating"
734
+ );
710
735
  }
711
736
  if (auth?.clientCredentials) {
712
737
  const cc = auth.clientCredentials;
@@ -739,7 +764,9 @@ var JSONRPCTransport = class extends Transport {
739
764
  } else if (this.auth?.bearer) {
740
765
  headers["Authorization"] = `Bearer ${this.auth.bearer}`;
741
766
  } else if (this.auth?.basic) {
742
- const credentials = btoa(`${this.auth.basic.username}:${this.auth.basic.password}`);
767
+ const credentials = btoa(
768
+ `${this.auth.basic.username}:${this.auth.basic.password}`
769
+ );
743
770
  headers["Authorization"] = `Basic ${credentials}`;
744
771
  } else if (this.auth?.custom) {
745
772
  Object.assign(headers, this.auth.custom);
@@ -878,7 +905,9 @@ var WsTransport = class extends Transport {
878
905
  super();
879
906
  const scheme = new URL(url).protocol.replace(":", "");
880
907
  if (scheme !== "ws" && scheme !== "wss") {
881
- throw new Error(`WS transport requires a ws:// or wss:// URL, got ${scheme}://`);
908
+ throw new Error(
909
+ `WS transport requires a ws:// or wss:// URL, got ${scheme}://`
910
+ );
882
911
  }
883
912
  this._url = url;
884
913
  this._auth = auth;
@@ -893,7 +922,9 @@ var WsTransport = class extends Transport {
893
922
  });
894
923
  await new Promise((resolve, reject) => {
895
924
  ws.onopen = () => resolve();
896
- ws.onerror = (ev) => reject(new Error(`WS connect failed: ${ev.message ?? "unknown"}`));
925
+ ws.onerror = (ev) => reject(
926
+ new Error(`WS connect failed: ${ev.message ?? "unknown"}`)
927
+ );
897
928
  });
898
929
  ws.onmessage = (ev) => this._handleMessage(ev.data);
899
930
  ws.onerror = (_ev) => this._failAll("WS connection error");
@@ -927,7 +958,12 @@ var WsTransport = class extends Transport {
927
958
  const id = this._mintId();
928
959
  return new Promise((resolve, reject) => {
929
960
  this._pendingSubscribe.set(id, { topic, resolve, reject });
930
- this._send({ jsonrpc: "2.0", id, method: "subscribe", params: { topic } });
961
+ this._send({
962
+ jsonrpc: "2.0",
963
+ id,
964
+ method: "subscribe",
965
+ params: { topic }
966
+ });
931
967
  });
932
968
  }
933
969
  /**
@@ -997,7 +1033,12 @@ var WsTransport = class extends Transport {
997
1033
  const id = this._mintId();
998
1034
  return new Promise((resolve, reject) => {
999
1035
  this._pending.set(id, { resolve, reject });
1000
- this._send({ jsonrpc: "2.0", id, method, ...params !== void 0 ? { params } : {} });
1036
+ this._send({
1037
+ jsonrpc: "2.0",
1038
+ id,
1039
+ method,
1040
+ ...params !== void 0 ? { params } : {}
1041
+ });
1001
1042
  });
1002
1043
  }
1003
1044
  _handleMessage(data) {
@@ -1009,7 +1050,9 @@ var WsTransport = class extends Transport {
1009
1050
  }
1010
1051
  if (!("id" in msg)) {
1011
1052
  if (msg["method"] === "notification") {
1012
- this._routeNotification(msg["params"]);
1053
+ this._routeNotification(
1054
+ msg["params"]
1055
+ );
1013
1056
  }
1014
1057
  return;
1015
1058
  }
@@ -1019,7 +1062,9 @@ var WsTransport = class extends Transport {
1019
1062
  this._pendingSubscribe.delete(msgId);
1020
1063
  const err = msg["error"];
1021
1064
  if (err !== void 0) {
1022
- pendingSub.reject(new Error(String(err["message"] ?? "Subscribe failed")));
1065
+ pendingSub.reject(
1066
+ new Error(String(err["message"] ?? "Subscribe failed"))
1067
+ );
1023
1068
  return;
1024
1069
  }
1025
1070
  const result = msg["result"] ?? {};
@@ -1076,7 +1121,9 @@ function buildUpgradeHeaders(auth) {
1076
1121
  } else if ("apiKey" in auth && auth.apiKey !== void 0) {
1077
1122
  headers["X-API-Key"] = auth.apiKey;
1078
1123
  } else if ("basic" in auth && auth.basic !== void 0) {
1079
- const encoded = Buffer.from(`${auth.basic.username}:${auth.basic.password}`).toString("base64");
1124
+ const encoded = Buffer.from(
1125
+ `${auth.basic.username}:${auth.basic.password}`
1126
+ ).toString("base64");
1080
1127
  headers["Authorization"] = `Basic ${encoded}`;
1081
1128
  }
1082
1129
  return headers;
@@ -1115,7 +1162,9 @@ async function fetchDgCaCert(url = DG_CA_URL) {
1115
1162
  }
1116
1163
  const pem = await resp.text();
1117
1164
  if (!pem.includes("-----BEGIN CERTIFICATE-----")) {
1118
- throw new Error(`Response from ${url} does not look like a PEM certificate`);
1165
+ throw new Error(
1166
+ `Response from ${url} does not look like a PEM certificate`
1167
+ );
1119
1168
  }
1120
1169
  return pem;
1121
1170
  }
@@ -1131,7 +1180,10 @@ function generateKeypair() {
1131
1180
  namedCurve: "P-256"
1132
1181
  });
1133
1182
  return {
1134
- privateKeyPem: privateKey.export({ type: "pkcs8", format: "pem" }),
1183
+ privateKeyPem: privateKey.export({
1184
+ type: "pkcs8",
1185
+ format: "pem"
1186
+ }),
1135
1187
  publicKeyPem: publicKey.export({ type: "spki", format: "pem" })
1136
1188
  };
1137
1189
  }
@@ -1171,9 +1223,17 @@ async function registerIdentity(keypair, opts) {
1171
1223
  };
1172
1224
  }
1173
1225
  async function rotateIdentity(opts) {
1174
- const { privateKey, publicKey } = crypto.generateKeyPairSync("ec", { namedCurve: "P-256" });
1175
- const publicKeyPem = publicKey.export({ type: "spki", format: "pem" });
1176
- const privateKeyPem = privateKey.export({ type: "pkcs8", format: "pem" });
1226
+ const { privateKey, publicKey } = crypto.generateKeyPairSync("ec", {
1227
+ namedCurve: "P-256"
1228
+ });
1229
+ const publicKeyPem = publicKey.export({
1230
+ type: "spki",
1231
+ format: "pem"
1232
+ });
1233
+ const privateKeyPem = privateKey.export({
1234
+ type: "pkcs8",
1235
+ format: "pem"
1236
+ });
1177
1237
  const url = opts.endpoint.replace(/\/$/, "") + "/rotate";
1178
1238
  const https = await import("https");
1179
1239
  const urlModule = await import("url");
@@ -1188,7 +1248,10 @@ async function rotateIdentity(opts) {
1188
1248
  cert: opts.currentCertPem,
1189
1249
  key: opts.currentKeyPem
1190
1250
  };
1191
- const body = JSON.stringify({ public_key_pem: publicKeyPem, name: opts.name });
1251
+ const body = JSON.stringify({
1252
+ public_key_pem: publicKeyPem,
1253
+ name: opts.name
1254
+ });
1192
1255
  const req = https.request(reqOptions, (res) => {
1193
1256
  let data = "";
1194
1257
  res.on("data", (chunk) => {
@@ -1198,7 +1261,9 @@ async function rotateIdentity(opts) {
1198
1261
  if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
1199
1262
  resolve(data);
1200
1263
  } else {
1201
- reject(new Error(`Rotation failed (HTTP ${res.statusCode}): ${data}`));
1264
+ reject(
1265
+ new Error(`Rotation failed (HTTP ${res.statusCode}): ${data}`)
1266
+ );
1202
1267
  }
1203
1268
  });
1204
1269
  });
@@ -1298,8 +1363,12 @@ var PrismNamespace = class {
1298
1363
  data: options.data,
1299
1364
  source_type: options.sourceType,
1300
1365
  target_type: options.targetType,
1301
- ...options.sourceAnnotations && { source_annotations: options.sourceAnnotations },
1302
- ...options.targetAnnotations && { target_annotations: options.targetAnnotations },
1366
+ ...options.sourceAnnotations && {
1367
+ source_annotations: options.sourceAnnotations
1368
+ },
1369
+ ...options.targetAnnotations && {
1370
+ target_annotations: options.targetAnnotations
1371
+ },
1303
1372
  ...options.context && { context: options.context }
1304
1373
  };
1305
1374
  return this.callDg("prism.focus", params);
@@ -1324,7 +1393,9 @@ var LogicNamespace = class {
1324
1393
  statement = opts.statement;
1325
1394
  }
1326
1395
  if (!statement && !opts?.facts?.length) {
1327
- throw new InvalidConfigError("remember() requires either a statement or facts");
1396
+ throw new InvalidConfigError(
1397
+ "remember() requires either a statement or facts"
1398
+ );
1328
1399
  }
1329
1400
  const params = { tag: opts?.tag ?? "default" };
1330
1401
  if (opts?.facts) {
@@ -1345,7 +1416,9 @@ var LogicNamespace = class {
1345
1416
  question = opts.question;
1346
1417
  }
1347
1418
  if (!question && !opts?.patterns?.length) {
1348
- throw new InvalidConfigError("query() requires either a question or patterns");
1419
+ throw new InvalidConfigError(
1420
+ "query() requires either a question or patterns"
1421
+ );
1349
1422
  }
1350
1423
  const params = { limit: opts?.limit ?? 50 };
1351
1424
  if (opts?.patterns) {
@@ -1358,7 +1431,9 @@ var LogicNamespace = class {
1358
1431
  /** Retract facts from the logic cell (`data-grout/logic.forget`). */
1359
1432
  async forget(options) {
1360
1433
  if (!options.handles?.length && !options.pattern) {
1361
- throw new InvalidConfigError("forget() requires either handles or pattern");
1434
+ throw new InvalidConfigError(
1435
+ "forget() requires either handles or pattern"
1436
+ );
1362
1437
  }
1363
1438
  const params = {};
1364
1439
  if (options.handles) params.handles = options.handles;
@@ -1367,13 +1442,18 @@ var LogicNamespace = class {
1367
1442
  }
1368
1443
  /** Reflect on the logic cell (`data-grout/logic.reflect`). */
1369
1444
  async reflect(options) {
1370
- const params = { summary_only: options?.summaryOnly ?? false };
1445
+ const params = {
1446
+ summary_only: options?.summaryOnly ?? false
1447
+ };
1371
1448
  if (options?.entity) params.entity = options.entity;
1372
1449
  return this.callDg("logic.reflect", params);
1373
1450
  }
1374
1451
  /** Add a constraint rule (`data-grout/logic.constrain`). */
1375
1452
  async constrain(rule, options) {
1376
- const params = { rule, tag: options?.tag ?? "constraint" };
1453
+ const params = {
1454
+ rule,
1455
+ tag: options?.tag ?? "constraint"
1456
+ };
1377
1457
  return this.callDg("logic.constrain", params);
1378
1458
  }
1379
1459
  /** Hydrate the logic cell from external data (`data-grout/logic.hydrate`). */
@@ -1535,7 +1615,9 @@ var FlowNamespace = class {
1535
1615
  /** Get details for a specific execution (`data-grout/inspect.execution-details`). */
1536
1616
  async details(executionId) {
1537
1617
  this.warn("inspect.execution-details");
1538
- return this.callDg("inspect.execution-details", { execution_id: executionId });
1618
+ return this.callDg("inspect.execution-details", {
1619
+ execution_id: executionId
1620
+ });
1539
1621
  }
1540
1622
  };
1541
1623
 
@@ -1623,10 +1705,20 @@ var Client2 = class _Client {
1623
1705
  let wsUrl = this.url;
1624
1706
  if (wsUrl.startsWith("https://")) wsUrl = "wss://" + wsUrl.slice(8);
1625
1707
  else if (wsUrl.startsWith("http://")) wsUrl = "ws://" + wsUrl.slice(7);
1626
- this.transport = new WsTransport(wsUrl, this.auth, options.timeout, identity);
1708
+ this.transport = new WsTransport(
1709
+ wsUrl,
1710
+ this.auth,
1711
+ options.timeout,
1712
+ identity
1713
+ );
1627
1714
  } else {
1628
1715
  const rpcUrl = this.url.endsWith("/mcp") ? this.url.slice(0, -4) + "/rpc" : this.url;
1629
- this.transport = new JSONRPCTransport(rpcUrl, this.auth, options.timeout, identity);
1716
+ this.transport = new JSONRPCTransport(
1717
+ rpcUrl,
1718
+ this.auth,
1719
+ options.timeout,
1720
+ identity
1721
+ );
1630
1722
  }
1631
1723
  }
1632
1724
  // ===== Bootstrap / seamless mTLS =====
@@ -1735,9 +1827,15 @@ var Client2 = class _Client {
1735
1827
  const existing = ConduitIdentity.tryDiscover(dir);
1736
1828
  if (existing && !existing.needsRotation(7)) {
1737
1829
  if (!options.url) {
1738
- throw new Error("'url' must be provided when an existing identity is reused");
1830
+ throw new Error(
1831
+ "'url' must be provided when an existing identity is reused"
1832
+ );
1739
1833
  }
1740
- return new _Client({ url: options.url, identity: existing, identityDir: dir });
1834
+ return new _Client({
1835
+ url: options.url,
1836
+ identity: existing,
1837
+ identityDir: dir
1838
+ });
1741
1839
  }
1742
1840
  const creds = await _doRegister2(options.opts);
1743
1841
  const token = await _exchangeToken2(creds);
@@ -1805,7 +1903,9 @@ var Client2 = class _Client {
1805
1903
  // ===== Namespace Accessors =====
1806
1904
  callDgTool = async (tool, params) => {
1807
1905
  this.ensureInitialized();
1808
- return this.sendWithRetry(() => this.transport.callTool(`data-grout/${tool}`, params));
1906
+ return this.sendWithRetry(
1907
+ () => this.transport.callTool(`data-grout/${tool}`, params)
1908
+ );
1809
1909
  };
1810
1910
  /** Data transformation, charting, rendering, and type bridging. */
1811
1911
  get prism() {
@@ -1821,7 +1921,10 @@ var Client2 = class _Client {
1821
1921
  }
1822
1922
  /** Work product registration, listing, and retrieval. */
1823
1923
  get deliverables() {
1824
- return new DeliverablesNamespace(this.callDgTool, (m) => this.warnIfNotDg(m));
1924
+ return new DeliverablesNamespace(
1925
+ this.callDgTool,
1926
+ (m) => this.warnIfNotDg(m)
1927
+ );
1825
1928
  }
1826
1929
  /** Cache listing and inspection. */
1827
1930
  get ephemerals() {
@@ -1910,7 +2013,9 @@ var Client2 = class _Client {
1910
2013
  */
1911
2014
  async getPrompt(name, args, options) {
1912
2015
  this.ensureInitialized();
1913
- return this.sendWithRetry(() => this.transport.getPrompt(name, args, options));
2016
+ return this.sendWithRetry(
2017
+ () => this.transport.getPrompt(name, args, options)
2018
+ );
1914
2019
  }
1915
2020
  // ===== WebSocket push subscriptions =====
1916
2021
  /**
@@ -2011,7 +2116,7 @@ var Client2 = class _Client {
2011
2116
  outputSchema: r.output_contract || r.output_schema || r.outputSchema
2012
2117
  })),
2013
2118
  total: result.total ?? tools.length,
2014
- limit: result.limit ?? (options.limit ?? 10)
2119
+ limit: result.limit ?? options.limit ?? 10
2015
2120
  };
2016
2121
  }
2017
2122
  /**
@@ -2127,8 +2232,10 @@ var Client2 = class _Client {
2127
2232
  if (options.k !== void 0) params.k = options.k;
2128
2233
  if (options.policy) params.policy = options.policy;
2129
2234
  if (options.have) params.have = options.have;
2130
- if (options.returnCallHandles !== void 0) params.return_call_handles = options.returnCallHandles;
2131
- if (options.exposeVirtualSkills !== void 0) params.expose_virtual_skills = options.exposeVirtualSkills;
2235
+ if (options.returnCallHandles !== void 0)
2236
+ params.return_call_handles = options.returnCallHandles;
2237
+ if (options.exposeVirtualSkills !== void 0)
2238
+ params.expose_virtual_skills = options.exposeVirtualSkills;
2132
2239
  if (options.modelOverrides) params.model_overrides = options.modelOverrides;
2133
2240
  return this.sendWithRetry(
2134
2241
  () => this.transport.callTool("data-grout/discovery.plan", params)
package/dist/index.mjs CHANGED
@@ -3,11 +3,11 @@ import {
3
3
  deriveTokenEndpoint,
4
4
  init_oauth,
5
5
  oauth_exports
6
- } from "./chunk-26DYCD4G.mjs";
6
+ } from "./chunk-LW7VX5SZ.mjs";
7
7
  import {
8
8
  registerAndExchange,
9
9
  registerOnly
10
- } from "./chunk-SWH5Y2U7.mjs";
10
+ } from "./chunk-W56N7X6V.mjs";
11
11
  import {
12
12
  __esm,
13
13
  __export,
@@ -35,7 +35,9 @@ async function fetchWithIdentity(url, init, identity) {
35
35
  port: parsedUrl.port || 443,
36
36
  path: parsedUrl.pathname + parsedUrl.search,
37
37
  method: (init.method ?? "GET").toUpperCase(),
38
- headers: flattenHeaders(init.headers),
38
+ headers: flattenHeaders(
39
+ init.headers
40
+ ),
39
41
  cert: identity.certPem,
40
42
  key: identity.keyPem,
41
43
  ...identity.caPem ? { ca: identity.caPem } : {}
@@ -119,7 +121,9 @@ var init_identity = __esm({
119
121
  */
120
122
  static fromPaths(certPath, keyPath, caPath) {
121
123
  if (typeof process === "undefined" || !process.versions?.node) {
122
- throw new Error("ConduitIdentity.fromPaths() is only available in Node.js environments");
124
+ throw new Error(
125
+ "ConduitIdentity.fromPaths() is only available in Node.js environments"
126
+ );
123
127
  }
124
128
  const fs2 = __require("fs");
125
129
  const certPem = fs2.readFileSync(certPath, "utf8");
@@ -143,7 +147,9 @@ var init_identity = __esm({
143
147
  if (!certPem) return null;
144
148
  const keyPem = process.env.CONDUIT_MTLS_KEY;
145
149
  if (!keyPem) {
146
- throw new Error("CONDUIT_MTLS_CERT is set but CONDUIT_MTLS_KEY is missing");
150
+ throw new Error(
151
+ "CONDUIT_MTLS_CERT is set but CONDUIT_MTLS_KEY is missing"
152
+ );
147
153
  }
148
154
  const caPem = process.env.CONDUIT_MTLS_CA || void 0;
149
155
  return _ConduitIdentity.fromPem(certPem, keyPem, caPem);
@@ -233,7 +239,11 @@ var init_identity = __esm({
233
239
  const keyPath = `${dir}/identity_key.pem`;
234
240
  if (!fs2.existsSync(certPath) || !fs2.existsSync(keyPath)) return null;
235
241
  const caPath = `${dir}/ca.pem`;
236
- return _ConduitIdentity.fromPaths(certPath, keyPath, fs2.existsSync(caPath) ? caPath : void 0);
242
+ return _ConduitIdentity.fromPaths(
243
+ certPath,
244
+ keyPath,
245
+ fs2.existsSync(caPath) ? caPath : void 0
246
+ );
237
247
  } catch {
238
248
  return null;
239
249
  }
@@ -354,6 +364,9 @@ var MCPTransport = class extends Transport {
354
364
  throw new Error("Not connected. Call connect() first.");
355
365
  }
356
366
  const result = await this.client.callTool({ name, arguments: args });
367
+ if (result?.structuredContent !== void 0) {
368
+ return result.structuredContent;
369
+ }
357
370
  const content = result?.content;
358
371
  if (Array.isArray(content) && content.length > 0) {
359
372
  const first = content[0];
@@ -364,6 +377,7 @@ var MCPTransport = class extends Transport {
364
377
  return { text: first.text };
365
378
  }
366
379
  }
380
+ return first;
367
381
  }
368
382
  return result;
369
383
  }
@@ -460,7 +474,11 @@ var InvalidConfigError = class extends ConduitError {
460
474
 
461
475
  // src/transports/jsonrpc.ts
462
476
  function unwrapContent(result) {
463
- if (result && Array.isArray(result.content) && result.content.length > 0) {
477
+ if (!result) return result;
478
+ if (result.structuredContent !== void 0) {
479
+ return result.structuredContent;
480
+ }
481
+ if (Array.isArray(result.content) && result.content.length > 0) {
464
482
  const first = result.content[0];
465
483
  if (first && typeof first.text === "string") {
466
484
  try {
@@ -469,6 +487,7 @@ function unwrapContent(result) {
469
487
  return { text: first.text };
470
488
  }
471
489
  }
490
+ return first;
472
491
  }
473
492
  return result;
474
493
  }
@@ -495,7 +514,9 @@ var JSONRPCTransport = class extends Transport {
495
514
  this.identity = identity;
496
515
  this.timeout = timeout;
497
516
  if (identity?.needsRotation(30)) {
498
- console.warn("[conduit] mTLS certificate expires within 30 days \u2014 consider rotating");
517
+ console.warn(
518
+ "[conduit] mTLS certificate expires within 30 days \u2014 consider rotating"
519
+ );
499
520
  }
500
521
  if (auth?.clientCredentials) {
501
522
  const cc = auth.clientCredentials;
@@ -528,7 +549,9 @@ var JSONRPCTransport = class extends Transport {
528
549
  } else if (this.auth?.bearer) {
529
550
  headers["Authorization"] = `Bearer ${this.auth.bearer}`;
530
551
  } else if (this.auth?.basic) {
531
- const credentials = btoa(`${this.auth.basic.username}:${this.auth.basic.password}`);
552
+ const credentials = btoa(
553
+ `${this.auth.basic.username}:${this.auth.basic.password}`
554
+ );
532
555
  headers["Authorization"] = `Basic ${credentials}`;
533
556
  } else if (this.auth?.custom) {
534
557
  Object.assign(headers, this.auth.custom);
@@ -667,7 +690,9 @@ var WsTransport = class extends Transport {
667
690
  super();
668
691
  const scheme = new URL(url).protocol.replace(":", "");
669
692
  if (scheme !== "ws" && scheme !== "wss") {
670
- throw new Error(`WS transport requires a ws:// or wss:// URL, got ${scheme}://`);
693
+ throw new Error(
694
+ `WS transport requires a ws:// or wss:// URL, got ${scheme}://`
695
+ );
671
696
  }
672
697
  this._url = url;
673
698
  this._auth = auth;
@@ -682,7 +707,9 @@ var WsTransport = class extends Transport {
682
707
  });
683
708
  await new Promise((resolve, reject) => {
684
709
  ws.onopen = () => resolve();
685
- ws.onerror = (ev) => reject(new Error(`WS connect failed: ${ev.message ?? "unknown"}`));
710
+ ws.onerror = (ev) => reject(
711
+ new Error(`WS connect failed: ${ev.message ?? "unknown"}`)
712
+ );
686
713
  });
687
714
  ws.onmessage = (ev) => this._handleMessage(ev.data);
688
715
  ws.onerror = (_ev) => this._failAll("WS connection error");
@@ -716,7 +743,12 @@ var WsTransport = class extends Transport {
716
743
  const id = this._mintId();
717
744
  return new Promise((resolve, reject) => {
718
745
  this._pendingSubscribe.set(id, { topic, resolve, reject });
719
- this._send({ jsonrpc: "2.0", id, method: "subscribe", params: { topic } });
746
+ this._send({
747
+ jsonrpc: "2.0",
748
+ id,
749
+ method: "subscribe",
750
+ params: { topic }
751
+ });
720
752
  });
721
753
  }
722
754
  /**
@@ -786,7 +818,12 @@ var WsTransport = class extends Transport {
786
818
  const id = this._mintId();
787
819
  return new Promise((resolve, reject) => {
788
820
  this._pending.set(id, { resolve, reject });
789
- this._send({ jsonrpc: "2.0", id, method, ...params !== void 0 ? { params } : {} });
821
+ this._send({
822
+ jsonrpc: "2.0",
823
+ id,
824
+ method,
825
+ ...params !== void 0 ? { params } : {}
826
+ });
790
827
  });
791
828
  }
792
829
  _handleMessage(data) {
@@ -798,7 +835,9 @@ var WsTransport = class extends Transport {
798
835
  }
799
836
  if (!("id" in msg)) {
800
837
  if (msg["method"] === "notification") {
801
- this._routeNotification(msg["params"]);
838
+ this._routeNotification(
839
+ msg["params"]
840
+ );
802
841
  }
803
842
  return;
804
843
  }
@@ -808,7 +847,9 @@ var WsTransport = class extends Transport {
808
847
  this._pendingSubscribe.delete(msgId);
809
848
  const err = msg["error"];
810
849
  if (err !== void 0) {
811
- pendingSub.reject(new Error(String(err["message"] ?? "Subscribe failed")));
850
+ pendingSub.reject(
851
+ new Error(String(err["message"] ?? "Subscribe failed"))
852
+ );
812
853
  return;
813
854
  }
814
855
  const result = msg["result"] ?? {};
@@ -865,7 +906,9 @@ function buildUpgradeHeaders(auth) {
865
906
  } else if ("apiKey" in auth && auth.apiKey !== void 0) {
866
907
  headers["X-API-Key"] = auth.apiKey;
867
908
  } else if ("basic" in auth && auth.basic !== void 0) {
868
- const encoded = Buffer.from(`${auth.basic.username}:${auth.basic.password}`).toString("base64");
909
+ const encoded = Buffer.from(
910
+ `${auth.basic.username}:${auth.basic.password}`
911
+ ).toString("base64");
869
912
  headers["Authorization"] = `Basic ${encoded}`;
870
913
  }
871
914
  return headers;
@@ -904,7 +947,9 @@ async function fetchDgCaCert(url = DG_CA_URL) {
904
947
  }
905
948
  const pem = await resp.text();
906
949
  if (!pem.includes("-----BEGIN CERTIFICATE-----")) {
907
- throw new Error(`Response from ${url} does not look like a PEM certificate`);
950
+ throw new Error(
951
+ `Response from ${url} does not look like a PEM certificate`
952
+ );
908
953
  }
909
954
  return pem;
910
955
  }
@@ -920,7 +965,10 @@ function generateKeypair() {
920
965
  namedCurve: "P-256"
921
966
  });
922
967
  return {
923
- privateKeyPem: privateKey.export({ type: "pkcs8", format: "pem" }),
968
+ privateKeyPem: privateKey.export({
969
+ type: "pkcs8",
970
+ format: "pem"
971
+ }),
924
972
  publicKeyPem: publicKey.export({ type: "spki", format: "pem" })
925
973
  };
926
974
  }
@@ -960,9 +1008,17 @@ async function registerIdentity(keypair, opts) {
960
1008
  };
961
1009
  }
962
1010
  async function rotateIdentity(opts) {
963
- const { privateKey, publicKey } = crypto.generateKeyPairSync("ec", { namedCurve: "P-256" });
964
- const publicKeyPem = publicKey.export({ type: "spki", format: "pem" });
965
- const privateKeyPem = privateKey.export({ type: "pkcs8", format: "pem" });
1011
+ const { privateKey, publicKey } = crypto.generateKeyPairSync("ec", {
1012
+ namedCurve: "P-256"
1013
+ });
1014
+ const publicKeyPem = publicKey.export({
1015
+ type: "spki",
1016
+ format: "pem"
1017
+ });
1018
+ const privateKeyPem = privateKey.export({
1019
+ type: "pkcs8",
1020
+ format: "pem"
1021
+ });
966
1022
  const url = opts.endpoint.replace(/\/$/, "") + "/rotate";
967
1023
  const https = await import("https");
968
1024
  const urlModule = await import("url");
@@ -977,7 +1033,10 @@ async function rotateIdentity(opts) {
977
1033
  cert: opts.currentCertPem,
978
1034
  key: opts.currentKeyPem
979
1035
  };
980
- const body = JSON.stringify({ public_key_pem: publicKeyPem, name: opts.name });
1036
+ const body = JSON.stringify({
1037
+ public_key_pem: publicKeyPem,
1038
+ name: opts.name
1039
+ });
981
1040
  const req = https.request(reqOptions, (res) => {
982
1041
  let data = "";
983
1042
  res.on("data", (chunk) => {
@@ -987,7 +1046,9 @@ async function rotateIdentity(opts) {
987
1046
  if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
988
1047
  resolve(data);
989
1048
  } else {
990
- reject(new Error(`Rotation failed (HTTP ${res.statusCode}): ${data}`));
1049
+ reject(
1050
+ new Error(`Rotation failed (HTTP ${res.statusCode}): ${data}`)
1051
+ );
991
1052
  }
992
1053
  });
993
1054
  });
@@ -1087,8 +1148,12 @@ var PrismNamespace = class {
1087
1148
  data: options.data,
1088
1149
  source_type: options.sourceType,
1089
1150
  target_type: options.targetType,
1090
- ...options.sourceAnnotations && { source_annotations: options.sourceAnnotations },
1091
- ...options.targetAnnotations && { target_annotations: options.targetAnnotations },
1151
+ ...options.sourceAnnotations && {
1152
+ source_annotations: options.sourceAnnotations
1153
+ },
1154
+ ...options.targetAnnotations && {
1155
+ target_annotations: options.targetAnnotations
1156
+ },
1092
1157
  ...options.context && { context: options.context }
1093
1158
  };
1094
1159
  return this.callDg("prism.focus", params);
@@ -1113,7 +1178,9 @@ var LogicNamespace = class {
1113
1178
  statement = opts.statement;
1114
1179
  }
1115
1180
  if (!statement && !opts?.facts?.length) {
1116
- throw new InvalidConfigError("remember() requires either a statement or facts");
1181
+ throw new InvalidConfigError(
1182
+ "remember() requires either a statement or facts"
1183
+ );
1117
1184
  }
1118
1185
  const params = { tag: opts?.tag ?? "default" };
1119
1186
  if (opts?.facts) {
@@ -1134,7 +1201,9 @@ var LogicNamespace = class {
1134
1201
  question = opts.question;
1135
1202
  }
1136
1203
  if (!question && !opts?.patterns?.length) {
1137
- throw new InvalidConfigError("query() requires either a question or patterns");
1204
+ throw new InvalidConfigError(
1205
+ "query() requires either a question or patterns"
1206
+ );
1138
1207
  }
1139
1208
  const params = { limit: opts?.limit ?? 50 };
1140
1209
  if (opts?.patterns) {
@@ -1147,7 +1216,9 @@ var LogicNamespace = class {
1147
1216
  /** Retract facts from the logic cell (`data-grout/logic.forget`). */
1148
1217
  async forget(options) {
1149
1218
  if (!options.handles?.length && !options.pattern) {
1150
- throw new InvalidConfigError("forget() requires either handles or pattern");
1219
+ throw new InvalidConfigError(
1220
+ "forget() requires either handles or pattern"
1221
+ );
1151
1222
  }
1152
1223
  const params = {};
1153
1224
  if (options.handles) params.handles = options.handles;
@@ -1156,13 +1227,18 @@ var LogicNamespace = class {
1156
1227
  }
1157
1228
  /** Reflect on the logic cell (`data-grout/logic.reflect`). */
1158
1229
  async reflect(options) {
1159
- const params = { summary_only: options?.summaryOnly ?? false };
1230
+ const params = {
1231
+ summary_only: options?.summaryOnly ?? false
1232
+ };
1160
1233
  if (options?.entity) params.entity = options.entity;
1161
1234
  return this.callDg("logic.reflect", params);
1162
1235
  }
1163
1236
  /** Add a constraint rule (`data-grout/logic.constrain`). */
1164
1237
  async constrain(rule, options) {
1165
- const params = { rule, tag: options?.tag ?? "constraint" };
1238
+ const params = {
1239
+ rule,
1240
+ tag: options?.tag ?? "constraint"
1241
+ };
1166
1242
  return this.callDg("logic.constrain", params);
1167
1243
  }
1168
1244
  /** Hydrate the logic cell from external data (`data-grout/logic.hydrate`). */
@@ -1324,7 +1400,9 @@ var FlowNamespace = class {
1324
1400
  /** Get details for a specific execution (`data-grout/inspect.execution-details`). */
1325
1401
  async details(executionId) {
1326
1402
  this.warn("inspect.execution-details");
1327
- return this.callDg("inspect.execution-details", { execution_id: executionId });
1403
+ return this.callDg("inspect.execution-details", {
1404
+ execution_id: executionId
1405
+ });
1328
1406
  }
1329
1407
  };
1330
1408
 
@@ -1412,10 +1490,20 @@ var Client2 = class _Client {
1412
1490
  let wsUrl = this.url;
1413
1491
  if (wsUrl.startsWith("https://")) wsUrl = "wss://" + wsUrl.slice(8);
1414
1492
  else if (wsUrl.startsWith("http://")) wsUrl = "ws://" + wsUrl.slice(7);
1415
- this.transport = new WsTransport(wsUrl, this.auth, options.timeout, identity);
1493
+ this.transport = new WsTransport(
1494
+ wsUrl,
1495
+ this.auth,
1496
+ options.timeout,
1497
+ identity
1498
+ );
1416
1499
  } else {
1417
1500
  const rpcUrl = this.url.endsWith("/mcp") ? this.url.slice(0, -4) + "/rpc" : this.url;
1418
- this.transport = new JSONRPCTransport(rpcUrl, this.auth, options.timeout, identity);
1501
+ this.transport = new JSONRPCTransport(
1502
+ rpcUrl,
1503
+ this.auth,
1504
+ options.timeout,
1505
+ identity
1506
+ );
1419
1507
  }
1420
1508
  }
1421
1509
  // ===== Bootstrap / seamless mTLS =====
@@ -1473,7 +1561,7 @@ var Client2 = class _Client {
1473
1561
  * @param options.substrateEndpoint - Override the DG Substrate endpoint.
1474
1562
  */
1475
1563
  static async bootstrapIdentityOAuth(options) {
1476
- const { OAuthTokenProvider: OAuthTokenProvider2, deriveTokenEndpoint: deriveTokenEndpoint2 } = await import("./oauth-NSDC2G7W.mjs");
1564
+ const { OAuthTokenProvider: OAuthTokenProvider2, deriveTokenEndpoint: deriveTokenEndpoint2 } = await import("./oauth-T2D3EDCN.mjs");
1477
1565
  const tokenEndpoint = deriveTokenEndpoint2(options.url);
1478
1566
  const provider = new OAuthTokenProvider2({
1479
1567
  clientId: options.clientId,
@@ -1519,14 +1607,20 @@ var Client2 = class _Client {
1519
1607
  * ```
1520
1608
  */
1521
1609
  static async bootstrapOnramp(options) {
1522
- const { _doRegister, _exchangeToken } = await import("./onramp-743RJTNI.mjs");
1610
+ const { _doRegister, _exchangeToken } = await import("./onramp-RDGV3FOI.mjs");
1523
1611
  const dir = options.identityDir || DEFAULT_IDENTITY_DIR;
1524
1612
  const existing = ConduitIdentity.tryDiscover(dir);
1525
1613
  if (existing && !existing.needsRotation(7)) {
1526
1614
  if (!options.url) {
1527
- throw new Error("'url' must be provided when an existing identity is reused");
1615
+ throw new Error(
1616
+ "'url' must be provided when an existing identity is reused"
1617
+ );
1528
1618
  }
1529
- return new _Client({ url: options.url, identity: existing, identityDir: dir });
1619
+ return new _Client({
1620
+ url: options.url,
1621
+ identity: existing,
1622
+ identityDir: dir
1623
+ });
1530
1624
  }
1531
1625
  const creds = await _doRegister(options.opts);
1532
1626
  const token = await _exchangeToken(creds);
@@ -1594,7 +1688,9 @@ var Client2 = class _Client {
1594
1688
  // ===== Namespace Accessors =====
1595
1689
  callDgTool = async (tool, params) => {
1596
1690
  this.ensureInitialized();
1597
- return this.sendWithRetry(() => this.transport.callTool(`data-grout/${tool}`, params));
1691
+ return this.sendWithRetry(
1692
+ () => this.transport.callTool(`data-grout/${tool}`, params)
1693
+ );
1598
1694
  };
1599
1695
  /** Data transformation, charting, rendering, and type bridging. */
1600
1696
  get prism() {
@@ -1610,7 +1706,10 @@ var Client2 = class _Client {
1610
1706
  }
1611
1707
  /** Work product registration, listing, and retrieval. */
1612
1708
  get deliverables() {
1613
- return new DeliverablesNamespace(this.callDgTool, (m) => this.warnIfNotDg(m));
1709
+ return new DeliverablesNamespace(
1710
+ this.callDgTool,
1711
+ (m) => this.warnIfNotDg(m)
1712
+ );
1614
1713
  }
1615
1714
  /** Cache listing and inspection. */
1616
1715
  get ephemerals() {
@@ -1699,7 +1798,9 @@ var Client2 = class _Client {
1699
1798
  */
1700
1799
  async getPrompt(name, args, options) {
1701
1800
  this.ensureInitialized();
1702
- return this.sendWithRetry(() => this.transport.getPrompt(name, args, options));
1801
+ return this.sendWithRetry(
1802
+ () => this.transport.getPrompt(name, args, options)
1803
+ );
1703
1804
  }
1704
1805
  // ===== WebSocket push subscriptions =====
1705
1806
  /**
@@ -1800,7 +1901,7 @@ var Client2 = class _Client {
1800
1901
  outputSchema: r.output_contract || r.output_schema || r.outputSchema
1801
1902
  })),
1802
1903
  total: result.total ?? tools.length,
1803
- limit: result.limit ?? (options.limit ?? 10)
1904
+ limit: result.limit ?? options.limit ?? 10
1804
1905
  };
1805
1906
  }
1806
1907
  /**
@@ -1916,8 +2017,10 @@ var Client2 = class _Client {
1916
2017
  if (options.k !== void 0) params.k = options.k;
1917
2018
  if (options.policy) params.policy = options.policy;
1918
2019
  if (options.have) params.have = options.have;
1919
- if (options.returnCallHandles !== void 0) params.return_call_handles = options.returnCallHandles;
1920
- if (options.exposeVirtualSkills !== void 0) params.expose_virtual_skills = options.exposeVirtualSkills;
2020
+ if (options.returnCallHandles !== void 0)
2021
+ params.return_call_handles = options.returnCallHandles;
2022
+ if (options.exposeVirtualSkills !== void 0)
2023
+ params.expose_virtual_skills = options.exposeVirtualSkills;
1921
2024
  if (options.modelOverrides) params.model_overrides = options.modelOverrides;
1922
2025
  return this.sendWithRetry(
1923
2026
  () => this.transport.callTool("data-grout/discovery.plan", params)
@@ -2,7 +2,7 @@ import {
2
2
  OAuthTokenProvider,
3
3
  deriveTokenEndpoint,
4
4
  init_oauth
5
- } from "./chunk-26DYCD4G.mjs";
5
+ } from "./chunk-LW7VX5SZ.mjs";
6
6
  import "./chunk-CIESM3BP.mjs";
7
7
  init_oauth();
8
8
  export {
@@ -3,7 +3,7 @@ import {
3
3
  _exchangeToken,
4
4
  registerAndExchange,
5
5
  registerOnly
6
- } from "./chunk-SWH5Y2U7.mjs";
6
+ } from "./chunk-W56N7X6V.mjs";
7
7
  import "./chunk-CIESM3BP.mjs";
8
8
  export {
9
9
  _doRegister,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datagrout/conduit",
3
- "version": "0.5.0",
3
+ "version": "0.6.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",