@hol-org/rb-client 0.1.172 → 0.1.174

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.js CHANGED
@@ -1,8 +1,7 @@
1
- // ../../src/services/registry-broker/client/encryption.ts
2
- import * as path from "path";
3
- import { Buffer as Buffer2 } from "buffer";
4
- import { randomBytes } from "crypto";
5
- import { secp256k1 } from "@noble/curves/secp256k1.js";
1
+ // ../../src/services/registry-broker/client/base-client.ts
2
+ import { Buffer as Buffer5 } from "buffer";
3
+ import { secp256k1 as secp256k12 } from "@noble/curves/secp256k1.js";
4
+ import { ZodError } from "zod";
6
5
 
7
6
  // ../../src/services/registry-broker/schemas.ts
8
7
  import { z as z2 } from "zod";
@@ -1294,6 +1293,50 @@ var skillDeprecationsResponseSchema = z2.object({
1294
1293
  name: z2.string(),
1295
1294
  items: z2.array(skillDeprecationRecordSchema)
1296
1295
  }).passthrough();
1296
+ var skillPublisherQuickstartCommandSchema = z2.object({
1297
+ id: z2.string(),
1298
+ label: z2.string(),
1299
+ description: z2.string(),
1300
+ command: z2.string(),
1301
+ href: z2.string().nullable().optional()
1302
+ }).passthrough();
1303
+ var skillPublisherTemplatePresetSchema = z2.object({
1304
+ presetId: z2.string(),
1305
+ label: z2.string(),
1306
+ description: z2.string(),
1307
+ recommendedFor: z2.string(),
1308
+ command: z2.string()
1309
+ }).passthrough();
1310
+ var skillPublisherMetadataSchema = z2.object({
1311
+ cliPackageUrl: z2.string(),
1312
+ cliCommand: z2.string(),
1313
+ actionMarketplaceUrl: z2.string(),
1314
+ repositoryUrl: z2.string(),
1315
+ guideUrl: z2.string().nullable().optional(),
1316
+ docsUrl: z2.string().nullable().optional(),
1317
+ submitUrl: z2.string().nullable().optional(),
1318
+ skillsIndexUrl: z2.string().nullable().optional(),
1319
+ quickstartCommands: z2.array(skillPublisherQuickstartCommandSchema),
1320
+ templatePresets: z2.array(skillPublisherTemplatePresetSchema)
1321
+ }).passthrough();
1322
+ var skillTrustTierSchema = z2.enum([
1323
+ "unpublished",
1324
+ "published",
1325
+ "verified",
1326
+ "hardened"
1327
+ ]);
1328
+ var skillStatusChecksSchema = z2.object({
1329
+ repoCommitIntegrity: z2.boolean(),
1330
+ manifestIntegrity: z2.boolean(),
1331
+ domainProof: z2.boolean()
1332
+ }).passthrough();
1333
+ var skillStatusNextStepSchema = z2.object({
1334
+ id: z2.string(),
1335
+ label: z2.string(),
1336
+ description: z2.string(),
1337
+ href: z2.string().nullable().optional(),
1338
+ command: z2.string().nullable().optional()
1339
+ }).passthrough();
1297
1340
  var skillBadgeMetricSchema = z2.enum([
1298
1341
  "version",
1299
1342
  "status",
@@ -1302,10 +1345,22 @@ var skillBadgeMetricSchema = z2.enum([
1302
1345
  "manifest",
1303
1346
  "domain",
1304
1347
  "trust",
1348
+ "tier",
1305
1349
  "safety",
1306
1350
  "upvotes",
1307
1351
  "updated"
1308
1352
  ]);
1353
+ var skillStatusResponseSchema = z2.object({
1354
+ name: z2.string(),
1355
+ version: z2.string().nullable(),
1356
+ published: z2.boolean(),
1357
+ verifiedDomain: z2.boolean(),
1358
+ trustTier: skillTrustTierSchema,
1359
+ badgeMetric: skillBadgeMetricSchema,
1360
+ checks: skillStatusChecksSchema,
1361
+ nextSteps: z2.array(skillStatusNextStepSchema),
1362
+ publisher: skillPublisherMetadataSchema.nullable().optional()
1363
+ }).passthrough();
1309
1364
  var skillBadgeStyleSchema = z2.enum([
1310
1365
  "flat",
1311
1366
  "flat-square",
@@ -1419,7 +1474,8 @@ var skillRegistryConfigResponseSchema = z2.object({
1419
1474
  maxFiles: z2.number().int().nullable().optional(),
1420
1475
  maxTotalSizeBytes: z2.number().int().nullable().optional(),
1421
1476
  allowedMimeTypes: z2.array(z2.string()).nullable().optional(),
1422
- network: z2.union([z2.literal("mainnet"), z2.literal("testnet")]).nullable().optional()
1477
+ network: z2.union([z2.literal("mainnet"), z2.literal("testnet")]).nullable().optional(),
1478
+ publisher: skillPublisherMetadataSchema.nullable().optional()
1423
1479
  }).passthrough();
1424
1480
  var skillRegistryOwnershipResponseSchema = z2.object({
1425
1481
  name: z2.string(),
@@ -1582,285 +1638,171 @@ var skillVerificationDomainProofVerifyResponseSchema = z2.object({
1582
1638
  signal: skillVerificationDomainProofSignalSchema
1583
1639
  }).passthrough();
1584
1640
 
1585
- // ../../src/utils/is-browser.ts
1586
- var isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined";
1587
-
1588
- // ../../src/utils/dynamic-import.ts
1589
- var nodeRequire;
1590
- function isModuleNotFound(specifier, error) {
1591
- if (!error || typeof error !== "object") {
1641
+ // ../../src/services/registry-broker/client/chat-history.ts
1642
+ import { Buffer as Buffer2 } from "buffer";
1643
+ function identitiesMatch(a, b) {
1644
+ if (!a && !b) {
1645
+ return true;
1646
+ }
1647
+ if (!a || !b) {
1592
1648
  return false;
1593
1649
  }
1594
- const code = Reflect.get(error, "code");
1595
- const message = Reflect.get(error, "message");
1596
- const messageText = typeof message === "string" ? message : "";
1597
- if (typeof code === "string" && code.includes("MODULE_NOT_FOUND")) {
1598
- return messageText.includes(specifier);
1650
+ if (a.uaid && b.uaid && a.uaid.toLowerCase() === b.uaid.toLowerCase()) {
1651
+ return true;
1599
1652
  }
1600
- if (messageText) {
1601
- const lowered = messageText.toLowerCase();
1602
- if (lowered.includes("cannot find module") || lowered.includes("module not found") || lowered.includes("cannot find package")) {
1603
- return lowered.includes(specifier.toLowerCase());
1604
- }
1653
+ if (a.ledgerAccountId && b.ledgerAccountId && a.ledgerAccountId.toLowerCase() === b.ledgerAccountId.toLowerCase()) {
1654
+ return true;
1655
+ }
1656
+ if (a.userId && b.userId && a.userId === b.userId) {
1657
+ return true;
1658
+ }
1659
+ if (a.email && b.email && a.email.toLowerCase() === b.email.toLowerCase()) {
1660
+ return true;
1605
1661
  }
1606
1662
  return false;
1607
1663
  }
1608
- async function resolveNodeRequire() {
1609
- if (nodeRequire !== void 0) {
1610
- return nodeRequire;
1664
+ async function fetchHistorySnapshot(conversationContexts, client, sessionId, options) {
1665
+ if (!sessionId || sessionId.trim().length === 0) {
1666
+ throw new Error("sessionId is required to fetch chat history");
1611
1667
  }
1612
- if (isBrowser) {
1613
- nodeRequire = null;
1614
- return nodeRequire;
1668
+ const raw = await client.requestJson(
1669
+ `/chat/session/${encodeURIComponent(sessionId)}/history`,
1670
+ {
1671
+ method: "GET"
1672
+ }
1673
+ );
1674
+ const snapshot = client.parseWithSchema(
1675
+ raw,
1676
+ chatHistorySnapshotResponseSchema,
1677
+ "chat history snapshot response"
1678
+ );
1679
+ return attachDecryptedHistory(
1680
+ conversationContexts,
1681
+ client,
1682
+ sessionId,
1683
+ snapshot,
1684
+ options
1685
+ );
1686
+ }
1687
+ function attachDecryptedHistory(conversationContexts, client, sessionId, snapshot, options) {
1688
+ const shouldDecrypt = options?.decrypt !== void 0 ? options.decrypt : client.encryptionOptions?.autoDecryptHistory === true;
1689
+ if (!shouldDecrypt) {
1690
+ return snapshot;
1615
1691
  }
1616
- try {
1617
- const globalObject = typeof global !== "undefined" ? global : globalThis;
1618
- const req = globalObject.process?.mainModule?.require ?? globalObject.require;
1619
- nodeRequire = typeof req === "function" && typeof req.resolve === "function" ? req : null;
1620
- } catch {
1621
- nodeRequire = null;
1692
+ const requiresContext = snapshot.history.some(
1693
+ (entry) => Boolean(entry.cipherEnvelope)
1694
+ );
1695
+ if (!requiresContext) {
1696
+ return {
1697
+ ...snapshot,
1698
+ decryptedHistory: snapshot.history.map((entry) => ({
1699
+ entry,
1700
+ plaintext: entry.content
1701
+ }))
1702
+ };
1622
1703
  }
1623
- return nodeRequire;
1704
+ const context = resolveDecryptionContext(
1705
+ conversationContexts,
1706
+ client,
1707
+ sessionId,
1708
+ options
1709
+ );
1710
+ if (!context) {
1711
+ throw new Error(
1712
+ "Unable to decrypt chat history: encryption context unavailable"
1713
+ );
1714
+ }
1715
+ const decryptedHistory = snapshot.history.map((entry) => ({
1716
+ entry,
1717
+ plaintext: decryptHistoryEntryFromContext(client, entry, context)
1718
+ }));
1719
+ return { ...snapshot, decryptedHistory };
1624
1720
  }
1625
- async function dynamicImport(specifier) {
1626
- try {
1627
- return await import(specifier);
1628
- } catch (error) {
1629
- if (isModuleNotFound(specifier, error)) {
1630
- return null;
1631
- }
1632
- throw error;
1721
+ function registerConversationContextForEncryption(conversationContexts, context) {
1722
+ const normalized = {
1723
+ sessionId: context.sessionId,
1724
+ sharedSecret: Buffer2.from(context.sharedSecret),
1725
+ identity: context.identity ? { ...context.identity } : void 0
1726
+ };
1727
+ const entries = conversationContexts.get(context.sessionId) ?? [];
1728
+ const existingIndex = entries.findIndex(
1729
+ (existing) => identitiesMatch(existing.identity, normalized.identity)
1730
+ );
1731
+ if (existingIndex >= 0) {
1732
+ entries[existingIndex] = normalized;
1733
+ } else {
1734
+ entries.push(normalized);
1633
1735
  }
1736
+ conversationContexts.set(context.sessionId, entries);
1634
1737
  }
1635
- async function optionalImport(specifier, options = {}) {
1636
- if (isBrowser) {
1637
- return dynamicImport(specifier);
1738
+ function resolveDecryptionContext(conversationContexts, client, sessionId, options) {
1739
+ if (options?.sharedSecret) {
1740
+ return {
1741
+ sessionId,
1742
+ sharedSecret: client.normalizeSharedSecret(options.sharedSecret),
1743
+ identity: options.identity
1744
+ };
1638
1745
  }
1639
- if (!options.preferImport) {
1640
- const requireFn = await resolveNodeRequire();
1641
- if (requireFn) {
1642
- try {
1643
- return requireFn(specifier);
1644
- } catch (error) {
1645
- if (!isModuleNotFound(specifier, error)) {
1646
- throw error;
1647
- }
1648
- }
1746
+ const contexts = conversationContexts.get(sessionId);
1747
+ if (!contexts || contexts.length === 0) {
1748
+ return null;
1749
+ }
1750
+ if (options?.identity) {
1751
+ const match = contexts.find(
1752
+ (context) => identitiesMatch(context.identity, options.identity)
1753
+ );
1754
+ if (match) {
1755
+ return match;
1649
1756
  }
1650
1757
  }
1651
- return dynamicImport(specifier);
1758
+ return contexts[0];
1652
1759
  }
1653
- function optionalImportSync(specifier) {
1654
- if (isBrowser) {
1655
- return null;
1760
+ function decryptHistoryEntryFromContext(client, entry, context) {
1761
+ const envelope = entry.cipherEnvelope;
1762
+ if (!envelope) {
1763
+ return entry.content;
1656
1764
  }
1765
+ const secret = Buffer2.from(context.sharedSecret);
1657
1766
  try {
1658
- const globalObject = typeof global !== "undefined" ? global : globalThis;
1659
- const req = globalObject.process?.mainModule?.require ?? globalObject.require;
1660
- if (typeof req === "function" && typeof req.resolve === "function") {
1661
- return req(specifier);
1662
- }
1663
- } catch (error) {
1664
- if (!isModuleNotFound(specifier, error)) {
1665
- throw error;
1666
- }
1767
+ return client.encryption.decryptCipherEnvelope({
1768
+ envelope,
1769
+ sharedSecret: secret
1770
+ });
1771
+ } catch (_error) {
1772
+ return null;
1667
1773
  }
1668
- return null;
1669
1774
  }
1670
1775
 
1671
- // ../../src/services/registry-broker/client/encryption.ts
1672
- var getFs = async () => {
1673
- const fsModule = await optionalImport("node:fs");
1674
- if (fsModule && typeof fsModule.existsSync === "function" && typeof fsModule.readFileSync === "function" && typeof fsModule.writeFileSync === "function" && typeof fsModule.appendFileSync === "function") {
1675
- return fsModule;
1776
+ // ../../src/services/registry-broker/client/utils.ts
1777
+ var DEFAULT_USER_AGENT = "@hol-org/rb-client";
1778
+ var DEFAULT_PROGRESS_INTERVAL_MS = 1500;
1779
+ var DEFAULT_PROGRESS_TIMEOUT_MS = 5 * 60 * 1e3;
1780
+ var DEFAULT_BASE_URL = "https://hol.org/registry/api/v1";
1781
+ var JSON_CONTENT_TYPE = /application\/json/i;
1782
+ var DEFAULT_HISTORY_TOP_UP_HBAR = 0.25;
1783
+ var MINIMUM_REGISTRATION_AUTO_TOP_UP_CREDITS = 1;
1784
+ var stripTrailingSlashes = (value) => {
1785
+ let end = value.length;
1786
+ while (end > 0 && value.charCodeAt(end - 1) === 47) {
1787
+ end -= 1;
1676
1788
  }
1677
- return null;
1789
+ return end === value.length ? value : value.slice(0, end);
1678
1790
  };
1679
- async function registerEncryptionKey(client, payload) {
1680
- const raw = await client.requestJson("/encryption/keys", {
1681
- method: "POST",
1682
- headers: { "content-type": "application/json" },
1683
- body: payload
1684
- });
1685
- return client.parseWithSchema(
1686
- raw,
1687
- registerEncryptionKeyResponseSchema,
1688
- "register encryption key response"
1689
- );
1690
- }
1691
- function normalizeAutoRegisterIdentity(config) {
1692
- const identity = {};
1693
- if (config.uaid) {
1694
- identity.uaid = config.uaid;
1695
- }
1696
- if (config.ledgerAccountId) {
1697
- identity.ledgerAccountId = config.ledgerAccountId;
1698
- if (config.ledgerNetwork) {
1699
- identity.ledgerNetwork = config.ledgerNetwork;
1700
- }
1791
+ var createAbortError = () => typeof DOMException === "function" ? new DOMException("Aborted", "AbortError") : new Error("The operation was aborted");
1792
+ var normaliseHeaderName = (name) => name.trim().toLowerCase();
1793
+ var isBrowserRuntime = () => typeof window !== "undefined" && typeof window.fetch === "function";
1794
+ var toJsonValue = (value) => {
1795
+ if (value === null) {
1796
+ return null;
1701
1797
  }
1702
- if (config.email) {
1703
- identity.email = config.email;
1798
+ if (value instanceof Date) {
1799
+ return value.toISOString();
1704
1800
  }
1705
- if (identity.uaid || identity.ledgerAccountId || identity.email) {
1706
- return identity;
1801
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
1802
+ return value;
1707
1803
  }
1708
- return null;
1709
- }
1710
- function derivePublicKeyFromPrivateKey(client, privateKey) {
1711
- const normalized = client.hexToBuffer(privateKey);
1712
- const publicKey = secp256k1.getPublicKey(normalized, true);
1713
- return Buffer2.from(publicKey).toString("hex");
1714
- }
1715
- async function resolveAutoRegisterKeyMaterial(client, config) {
1716
- if (config.publicKey?.trim()) {
1717
- return { publicKey: config.publicKey.trim() };
1718
- }
1719
- let privateKey = config.privateKey?.trim();
1720
- const envVar = config.envVar ?? "RB_ENCRYPTION_PRIVATE_KEY";
1721
- if (!privateKey && envVar && process?.env?.[envVar]?.trim()) {
1722
- privateKey = process.env[envVar]?.trim();
1723
- }
1724
- if (!privateKey && config.generateIfMissing) {
1725
- const pair = await client.generateEncryptionKeyPair({
1726
- keyType: config.keyType ?? "secp256k1",
1727
- envVar,
1728
- envPath: config.envPath,
1729
- overwrite: config.overwriteEnv
1730
- });
1731
- return { publicKey: pair.publicKey, privateKey: pair.privateKey };
1732
- }
1733
- if (privateKey) {
1734
- const publicKey = derivePublicKeyFromPrivateKey(client, privateKey);
1735
- return { publicKey, privateKey };
1736
- }
1737
- return null;
1738
- }
1739
- async function autoRegisterEncryptionKey(client, config) {
1740
- const identity = normalizeAutoRegisterIdentity(config);
1741
- if (!identity) {
1742
- throw new Error(
1743
- "Auto-registration requires uaid, ledgerAccountId, or email"
1744
- );
1745
- }
1746
- const material = await resolveAutoRegisterKeyMaterial(client, config);
1747
- if (!material) {
1748
- throw new Error(
1749
- "Unable to resolve encryption public key for auto-registration"
1750
- );
1751
- }
1752
- await registerEncryptionKey(client, {
1753
- keyType: config.keyType ?? "secp256k1",
1754
- publicKey: material.publicKey,
1755
- ...identity
1756
- });
1757
- return material;
1758
- }
1759
- async function ensureAgentEncryptionKey(client, options) {
1760
- return autoRegisterEncryptionKey(client, {
1761
- ...options,
1762
- uaid: options.uaid,
1763
- enabled: true
1764
- });
1765
- }
1766
- function createEncryptionApi(client) {
1767
- return {
1768
- registerKey: (payload) => registerEncryptionKey(client, payload),
1769
- generateEphemeralKeyPair: () => client.createEphemeralKeyPair(),
1770
- deriveSharedSecret: (options) => client.deriveSharedSecret(options),
1771
- encryptCipherEnvelope: (options) => client.buildCipherEnvelope(options),
1772
- decryptCipherEnvelope: (options) => client.openCipherEnvelope(options),
1773
- ensureAgentKey: (options) => ensureAgentEncryptionKey(client, options)
1774
- };
1775
- }
1776
- async function bootstrapEncryptionOptions(client, options) {
1777
- if (!options?.autoRegister || options.autoRegister.enabled === false) {
1778
- return null;
1779
- }
1780
- return autoRegisterEncryptionKey(client, options.autoRegister);
1781
- }
1782
- async function generateEncryptionKeyPair(client, options = {}) {
1783
- client.assertNodeRuntime("generateEncryptionKeyPair");
1784
- const keyType = options.keyType ?? "secp256k1";
1785
- if (keyType !== "secp256k1") {
1786
- throw new Error("Only secp256k1 key generation is supported currently");
1787
- }
1788
- const privateKeyBytes = randomBytes(32);
1789
- const privateKey = Buffer2.from(privateKeyBytes).toString("hex");
1790
- const publicKeyBytes = secp256k1.getPublicKey(privateKeyBytes, true);
1791
- const publicKey = Buffer2.from(publicKeyBytes).toString("hex");
1792
- const envVar = options.envVar ?? "RB_ENCRYPTION_PRIVATE_KEY";
1793
- const resolvedPath = options.envPath ? path.resolve(options.envPath) : void 0;
1794
- if (resolvedPath) {
1795
- const fsModule = await getFs();
1796
- if (!fsModule) {
1797
- throw new Error(
1798
- "File system module is not available; cannot write encryption key env file"
1799
- );
1800
- }
1801
- const envLine = `${envVar}=${privateKey}`;
1802
- if (fsModule.existsSync(resolvedPath)) {
1803
- const content = fsModule.readFileSync(resolvedPath, "utf-8");
1804
- const lineRegex = new RegExp(`^${envVar}=.*$`, "m");
1805
- if (lineRegex.test(content)) {
1806
- if (!options.overwrite) {
1807
- throw new Error(
1808
- `${envVar} already exists in ${resolvedPath}; set overwrite=true to replace it`
1809
- );
1810
- }
1811
- const updated = content.replace(lineRegex, envLine);
1812
- fsModule.writeFileSync(resolvedPath, updated);
1813
- } else {
1814
- const needsNewline = !content.endsWith("\n");
1815
- fsModule.appendFileSync(
1816
- resolvedPath,
1817
- `${needsNewline ? "\n" : ""}${envLine}
1818
- `
1819
- );
1820
- }
1821
- } else {
1822
- fsModule.writeFileSync(resolvedPath, `${envLine}
1823
- `);
1824
- }
1825
- }
1826
- return {
1827
- privateKey,
1828
- publicKey,
1829
- envPath: resolvedPath,
1830
- envVar
1831
- };
1832
- }
1833
-
1834
- // ../../src/services/registry-broker/client/utils.ts
1835
- var DEFAULT_USER_AGENT = "@hol-org/rb-client";
1836
- var DEFAULT_PROGRESS_INTERVAL_MS = 1500;
1837
- var DEFAULT_PROGRESS_TIMEOUT_MS = 5 * 60 * 1e3;
1838
- var DEFAULT_BASE_URL = "https://hol.org/registry/api/v1";
1839
- var JSON_CONTENT_TYPE = /application\/json/i;
1840
- var DEFAULT_HISTORY_TOP_UP_HBAR = 0.25;
1841
- var MINIMUM_REGISTRATION_AUTO_TOP_UP_CREDITS = 1;
1842
- var stripTrailingSlashes = (value) => {
1843
- let end = value.length;
1844
- while (end > 0 && value.charCodeAt(end - 1) === 47) {
1845
- end -= 1;
1846
- }
1847
- return end === value.length ? value : value.slice(0, end);
1848
- };
1849
- var createAbortError = () => typeof DOMException === "function" ? new DOMException("Aborted", "AbortError") : new Error("The operation was aborted");
1850
- var normaliseHeaderName = (name) => name.trim().toLowerCase();
1851
- var isBrowserRuntime = () => typeof window !== "undefined" && typeof window.fetch === "function";
1852
- var toJsonValue = (value) => {
1853
- if (value === null) {
1854
- return null;
1855
- }
1856
- if (value instanceof Date) {
1857
- return value.toISOString();
1858
- }
1859
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
1860
- return value;
1861
- }
1862
- if (Array.isArray(value)) {
1863
- return value.map((item) => item === void 0 ? null : toJsonValue(item));
1804
+ if (Array.isArray(value)) {
1805
+ return value.map((item) => item === void 0 ? null : toJsonValue(item));
1864
1806
  }
1865
1807
  if (typeof value === "object") {
1866
1808
  const result = {};
@@ -2054,1926 +1996,2090 @@ function buildSearchQuery(params) {
2054
1996
  return queryString.length > 0 ? `?${queryString}` : "";
2055
1997
  }
2056
1998
 
2057
- // ../../src/services/registry-broker/client/errors.ts
2058
- var RegistryBrokerError = class extends Error {
2059
- constructor(message, details) {
2060
- super(message);
2061
- this.status = details.status;
2062
- this.statusText = details.statusText;
2063
- this.body = details.body;
2064
- }
2065
- };
2066
- var RegistryBrokerParseError = class extends Error {
2067
- constructor(message, cause, rawValue) {
2068
- super(message);
2069
- this.cause = cause;
2070
- this.rawValue = rawValue;
1999
+ // ../../src/services/registry-broker/client/encrypted-chat-manager.ts
2000
+ var EncryptionUnavailableError = class extends Error {
2001
+ constructor(sessionId, summary) {
2002
+ super("Encryption is not enabled for this session");
2003
+ this.sessionId = sessionId;
2004
+ this.summary = summary;
2071
2005
  }
2072
2006
  };
2073
-
2074
- // ../../src/services/registry-broker/client/search.ts
2075
- function buildVectorFallbackSearchParams(request) {
2076
- const params = {
2077
- q: request.query
2078
- };
2079
- let effectiveLimit;
2080
- if (typeof request.limit === "number" && Number.isFinite(request.limit)) {
2081
- effectiveLimit = request.limit;
2082
- params.limit = request.limit;
2083
- }
2084
- if (typeof request.offset === "number" && Number.isFinite(request.offset) && request.offset > 0) {
2085
- const limit = effectiveLimit && effectiveLimit > 0 ? effectiveLimit : 20;
2086
- params.limit = limit;
2087
- params.page = Math.floor(request.offset / limit) + 1;
2088
- }
2089
- if (request.filter?.registry) {
2090
- params.registry = request.filter.registry;
2007
+ var EncryptedChatManager = class {
2008
+ constructor(client) {
2009
+ this.client = client;
2091
2010
  }
2092
- if (request.filter?.protocols?.length) {
2093
- params.protocols = [...request.filter.protocols];
2011
+ registerConversationContext(context) {
2012
+ this.client.registerConversationContextForEncryption(context);
2094
2013
  }
2095
- if (request.filter?.adapter?.length) {
2096
- params.adapters = [...request.filter.adapter];
2014
+ async startSession(options) {
2015
+ await this.client.encryptionReady();
2016
+ const session = await this.client.chat.createSession({
2017
+ uaid: options.uaid,
2018
+ senderUaid: options.senderUaid,
2019
+ encryptionRequested: true,
2020
+ historyTtlSeconds: options.historyTtlSeconds,
2021
+ auth: options.auth
2022
+ });
2023
+ options.onSessionCreated?.(session.sessionId);
2024
+ const summary = session.encryption;
2025
+ if (!summary?.enabled) {
2026
+ throw new EncryptionUnavailableError(
2027
+ session.sessionId,
2028
+ session.encryption ?? null
2029
+ );
2030
+ }
2031
+ const handle = await this.establishRequesterContext({
2032
+ sessionId: session.sessionId,
2033
+ summary,
2034
+ senderUaid: options.senderUaid,
2035
+ handshakeTimeoutMs: options.handshakeTimeoutMs,
2036
+ pollIntervalMs: options.pollIntervalMs
2037
+ });
2038
+ return handle;
2097
2039
  }
2098
- if (request.filter?.capabilities?.length) {
2099
- params.capabilities = request.filter.capabilities.map(
2100
- (value) => typeof value === "number" ? value.toString(10) : value
2040
+ async acceptSession(options) {
2041
+ await this.client.encryptionReady();
2042
+ const summary = await this.waitForEncryptionSummary(
2043
+ options.sessionId,
2044
+ options.handshakeTimeoutMs,
2045
+ options.pollIntervalMs
2101
2046
  );
2047
+ const handle = await this.establishResponderContext({
2048
+ sessionId: options.sessionId,
2049
+ summary,
2050
+ responderUaid: options.responderUaid,
2051
+ handshakeTimeoutMs: options.handshakeTimeoutMs,
2052
+ pollIntervalMs: options.pollIntervalMs
2053
+ });
2054
+ return handle;
2102
2055
  }
2103
- if (request.filter?.type) {
2104
- params.type = request.filter.type;
2105
- }
2106
- return params;
2107
- }
2108
- function convertSearchResultToVectorResponse(result) {
2109
- const hits = result.hits.map((agent) => ({
2110
- agent,
2111
- score: 0,
2112
- highlights: {}
2113
- }));
2114
- const total = result.total;
2115
- const limit = result.limit;
2116
- const page = result.page;
2117
- const totalVisible = page * limit;
2118
- const limited = total > totalVisible || page > 1;
2119
- return {
2120
- hits,
2121
- total,
2122
- took: 0,
2123
- totalAvailable: total,
2124
- visible: hits.length,
2125
- limited,
2126
- credits_used: 0
2127
- };
2128
- }
2129
- async function search(client, params = {}) {
2130
- const query = buildSearchQuery(params);
2131
- const raw = await client.requestJson(`/search${query}`, {
2132
- method: "GET"
2133
- });
2134
- return client.parseWithSchema(raw, searchResponseSchema, "search response");
2135
- }
2136
- async function delegate(client, request) {
2137
- const raw = await client.requestJson("/delegate", {
2138
- method: "POST",
2139
- body: request,
2140
- headers: { "content-type": "application/json" }
2141
- });
2142
- return client.parseWithSchema(
2143
- raw,
2144
- delegationPlanResponseSchema,
2145
- "delegate response"
2146
- );
2147
- }
2148
- async function stats(client) {
2149
- const raw = await client.requestJson("/stats", { method: "GET" });
2150
- return client.parseWithSchema(raw, statsResponseSchema, "stats response");
2151
- }
2152
- async function registries(client) {
2153
- const raw = await client.requestJson("/registries", {
2154
- method: "GET"
2155
- });
2156
- return client.parseWithSchema(
2157
- raw,
2158
- registriesResponseSchema,
2159
- "registries response"
2160
- );
2161
- }
2162
- async function getAdditionalRegistries(client) {
2163
- const raw = await client.requestJson(
2164
- "/register/additional-registries",
2165
- {
2166
- method: "GET"
2056
+ async establishRequesterContext(params) {
2057
+ const keyPair = this.client.encryption.generateEphemeralKeyPair();
2058
+ await this.client.chat.submitEncryptionHandshake(params.sessionId, {
2059
+ role: "requester",
2060
+ keyType: "secp256k1",
2061
+ ephemeralPublicKey: keyPair.publicKey,
2062
+ uaid: params.senderUaid ?? params.summary.requester?.uaid ?? void 0
2063
+ });
2064
+ const { summary, record } = await this.waitForHandshakeCompletion(
2065
+ params.sessionId,
2066
+ params.handshakeTimeoutMs,
2067
+ params.pollIntervalMs
2068
+ );
2069
+ const responderKey = record.responder?.ephemeralPublicKey;
2070
+ if (!responderKey) {
2071
+ throw new Error("Responder handshake was not completed in time");
2167
2072
  }
2168
- );
2169
- return client.parseWithSchema(
2170
- raw,
2171
- additionalRegistryCatalogResponseSchema,
2172
- "additional registry catalog response"
2173
- );
2174
- }
2175
- async function popularSearches(client) {
2176
- const raw = await client.requestJson("/popular", {
2177
- method: "GET"
2178
- });
2179
- return client.parseWithSchema(
2180
- raw,
2181
- popularResponseSchema,
2182
- "popular searches response"
2183
- );
2184
- }
2185
- async function listProtocols(client) {
2186
- const raw = await client.requestJson("/protocols", {
2187
- method: "GET"
2188
- });
2189
- return client.parseWithSchema(
2190
- raw,
2191
- protocolsResponseSchema,
2192
- "protocols response"
2193
- );
2194
- }
2195
- async function detectProtocol(client, message) {
2196
- const raw = await client.requestJson("/detect-protocol", {
2197
- method: "POST",
2198
- body: { message },
2199
- headers: { "content-type": "application/json" }
2200
- });
2201
- return client.parseWithSchema(
2202
- raw,
2203
- detectProtocolResponseSchema,
2204
- "detect protocol response"
2205
- );
2206
- }
2207
- async function registrySearchByNamespace(client, registry, query) {
2208
- const params = new URLSearchParams();
2209
- if (query) {
2210
- params.set("q", query);
2073
+ const sharedSecret = this.client.encryption.deriveSharedSecret({
2074
+ privateKey: keyPair.privateKey,
2075
+ peerPublicKey: responderKey
2076
+ }).subarray();
2077
+ const recipients = this.buildRecipients(summary);
2078
+ return this.createHandle({
2079
+ sessionId: params.sessionId,
2080
+ sharedSecret,
2081
+ summary,
2082
+ recipients,
2083
+ identity: summary.requester ?? void 0
2084
+ });
2211
2085
  }
2212
- const suffix = params.size > 0 ? `?${params.toString()}` : "";
2213
- const raw = await client.requestJson(
2214
- `/registries/${encodeURIComponent(registry)}/search${suffix}`,
2215
- {
2216
- method: "GET"
2086
+ async establishResponderContext(params) {
2087
+ const keyPair = this.client.encryption.generateEphemeralKeyPair();
2088
+ await this.client.chat.submitEncryptionHandshake(params.sessionId, {
2089
+ role: "responder",
2090
+ keyType: "secp256k1",
2091
+ ephemeralPublicKey: keyPair.publicKey,
2092
+ uaid: params.responderUaid ?? params.summary.responder?.uaid ?? void 0
2093
+ });
2094
+ const { summary, record } = await this.waitForHandshakeCompletion(
2095
+ params.sessionId,
2096
+ params.handshakeTimeoutMs,
2097
+ params.pollIntervalMs
2098
+ );
2099
+ const requesterKey = record.requester?.ephemeralPublicKey;
2100
+ if (!requesterKey) {
2101
+ throw new Error("Requester handshake was not detected in time");
2217
2102
  }
2218
- );
2219
- return client.parseWithSchema(
2220
- raw,
2221
- registrySearchByNamespaceSchema,
2222
- "registry search response"
2223
- );
2103
+ const sharedSecret = this.client.encryption.deriveSharedSecret({
2104
+ privateKey: keyPair.privateKey,
2105
+ peerPublicKey: requesterKey
2106
+ }).subarray();
2107
+ const recipients = this.buildRecipients(summary);
2108
+ return this.createHandle({
2109
+ sessionId: params.sessionId,
2110
+ sharedSecret,
2111
+ summary,
2112
+ recipients,
2113
+ identity: summary.responder ?? void 0
2114
+ });
2115
+ }
2116
+ async waitForHandshakeCompletion(sessionId, timeoutMs = 3e4, pollIntervalMs = 1e3) {
2117
+ const deadline = Date.now() + timeoutMs;
2118
+ while (true) {
2119
+ const status = await this.client.chat.getEncryptionStatus(sessionId);
2120
+ const summary = status.encryption;
2121
+ const record = summary?.handshake;
2122
+ if (summary && record && record.status === "complete") {
2123
+ return { summary, record };
2124
+ }
2125
+ if (Date.now() >= deadline) {
2126
+ throw new Error("Timed out waiting for encrypted handshake completion");
2127
+ }
2128
+ await this.delay(pollIntervalMs);
2129
+ }
2130
+ }
2131
+ async waitForEncryptionSummary(sessionId, _timeoutMs = 3e4, _pollIntervalMs = 1e3) {
2132
+ const status = await this.client.chat.getEncryptionStatus(sessionId);
2133
+ if (!status.encryption?.enabled) {
2134
+ throw new EncryptionUnavailableError(
2135
+ sessionId,
2136
+ status.encryption ?? null
2137
+ );
2138
+ }
2139
+ return status.encryption;
2140
+ }
2141
+ buildRecipients(summary) {
2142
+ const candidates = [summary.requester, summary.responder].filter(Boolean);
2143
+ const normalized = candidates.map((candidate) => {
2144
+ if (!candidate) {
2145
+ return null;
2146
+ }
2147
+ const recipient = {};
2148
+ if (candidate.uaid) {
2149
+ recipient.uaid = candidate.uaid;
2150
+ }
2151
+ if (candidate.ledgerAccountId) {
2152
+ recipient.ledgerAccountId = candidate.ledgerAccountId;
2153
+ }
2154
+ if (candidate.userId) {
2155
+ recipient.userId = candidate.userId;
2156
+ }
2157
+ if (candidate.email) {
2158
+ recipient.email = candidate.email;
2159
+ }
2160
+ return recipient;
2161
+ }).filter(
2162
+ (entry) => Boolean(
2163
+ entry?.uaid || entry?.ledgerAccountId || entry?.userId || entry?.email
2164
+ )
2165
+ );
2166
+ if (normalized.length > 0) {
2167
+ return normalized;
2168
+ }
2169
+ if (summary.responder?.uaid) {
2170
+ return [{ uaid: summary.responder.uaid }];
2171
+ }
2172
+ return [];
2173
+ }
2174
+ createHandle(context) {
2175
+ const sharedSecret = context.sharedSecret;
2176
+ const uaid = context.summary.requester?.uaid ?? context.summary.responder?.uaid ?? context.identity?.uaid;
2177
+ const decryptHistoryEntry = (entry) => this.decryptEntry(entry, context.identity, sharedSecret);
2178
+ const fetchHistory = async (options) => {
2179
+ const snapshot = await this.client.fetchHistorySnapshot(
2180
+ context.sessionId,
2181
+ options
2182
+ );
2183
+ if (snapshot.decryptedHistory) {
2184
+ return snapshot.decryptedHistory;
2185
+ }
2186
+ return snapshot.history.map((entry) => ({
2187
+ entry,
2188
+ plaintext: decryptHistoryEntry(entry)
2189
+ }));
2190
+ };
2191
+ const handle = {
2192
+ sessionId: context.sessionId,
2193
+ mode: "encrypted",
2194
+ summary: context.summary,
2195
+ send: async (options) => {
2196
+ const recipients = options.recipients ?? context.recipients;
2197
+ return this.client.chat.sendMessage({
2198
+ sessionId: context.sessionId,
2199
+ message: options.message ?? "[ciphertext omitted]",
2200
+ streaming: options.streaming,
2201
+ auth: options.auth,
2202
+ uaid,
2203
+ encryption: {
2204
+ plaintext: options.plaintext,
2205
+ sharedSecret: Buffer.from(sharedSecret),
2206
+ recipients
2207
+ }
2208
+ });
2209
+ },
2210
+ decryptHistoryEntry,
2211
+ fetchHistory
2212
+ };
2213
+ this.registerConversationContext({
2214
+ sessionId: context.sessionId,
2215
+ sharedSecret,
2216
+ identity: context.identity
2217
+ });
2218
+ return handle;
2219
+ }
2220
+ decryptEntry(entry, identity, fallbackSecret) {
2221
+ const envelope = entry.cipherEnvelope;
2222
+ if (!envelope) {
2223
+ return null;
2224
+ }
2225
+ const secret = Buffer.from(fallbackSecret);
2226
+ try {
2227
+ return this.client.encryption.decryptCipherEnvelope({
2228
+ envelope,
2229
+ sharedSecret: secret
2230
+ });
2231
+ } catch (_error) {
2232
+ return null;
2233
+ }
2234
+ }
2235
+ recipientMatches(candidate, target) {
2236
+ if (target.uaid && candidate.uaid?.toLowerCase() === target.uaid.toLowerCase()) {
2237
+ return true;
2238
+ }
2239
+ if (target.ledgerAccountId && candidate.ledgerAccountId?.toLowerCase() === target.ledgerAccountId.toLowerCase()) {
2240
+ return true;
2241
+ }
2242
+ if (target.userId && candidate.userId === target.userId) {
2243
+ return true;
2244
+ }
2245
+ if (target.email && candidate.email?.toLowerCase() === target.email.toLowerCase()) {
2246
+ return true;
2247
+ }
2248
+ return false;
2249
+ }
2250
+ async delay(ms) {
2251
+ if (ms <= 0) {
2252
+ return;
2253
+ }
2254
+ await new Promise((resolve) => setTimeout(resolve, ms));
2255
+ }
2256
+ };
2257
+
2258
+ // ../../src/services/registry-broker/client/chat.ts
2259
+ function createChatApi(client, encryptedManager) {
2260
+ return {
2261
+ start: (options) => client.startChat(options),
2262
+ createSession: (payload) => client.createSession(payload),
2263
+ sendMessage: (payload) => client.sendMessage(payload),
2264
+ endSession: (sessionId) => client.endSession(sessionId),
2265
+ getHistory: (sessionId, options) => client.fetchHistorySnapshot(sessionId, options),
2266
+ compactHistory: (payload) => client.compactHistory(payload),
2267
+ getEncryptionStatus: (sessionId) => client.fetchEncryptionStatus(sessionId),
2268
+ submitEncryptionHandshake: (sessionId, payload) => client.postEncryptionHandshake(sessionId, payload),
2269
+ startConversation: (options) => client.startConversation(options),
2270
+ acceptConversation: (options) => client.acceptConversation(options),
2271
+ createEncryptedSession: (options) => encryptedManager.startSession(options),
2272
+ acceptEncryptedSession: (options) => encryptedManager.acceptSession(options)
2273
+ };
2224
2274
  }
2225
- async function vectorSearch(client, request) {
2275
+ async function createSession(client, payload, allowHistoryAutoTopUp = true) {
2276
+ const body = {};
2277
+ if ("uaid" in payload && payload.uaid) {
2278
+ body.uaid = payload.uaid;
2279
+ }
2280
+ if ("agentUrl" in payload && payload.agentUrl) {
2281
+ body.agentUrl = payload.agentUrl;
2282
+ }
2283
+ if (payload.auth) {
2284
+ body.auth = serialiseAuthConfig(payload.auth);
2285
+ }
2286
+ if (payload.historyTtlSeconds !== void 0) {
2287
+ body.historyTtlSeconds = payload.historyTtlSeconds;
2288
+ }
2289
+ if (payload.encryptionRequested !== void 0) {
2290
+ body.encryptionRequested = payload.encryptionRequested;
2291
+ }
2292
+ if (payload.senderUaid) {
2293
+ body.senderUaid = payload.senderUaid;
2294
+ }
2226
2295
  try {
2227
- const raw = await client.requestJson("/search", {
2296
+ const raw = await client.requestJson("/chat/session", {
2228
2297
  method: "POST",
2229
- body: request,
2298
+ body,
2230
2299
  headers: { "content-type": "application/json" }
2231
2300
  });
2232
2301
  return client.parseWithSchema(
2233
2302
  raw,
2234
- vectorSearchResponseSchema,
2235
- "vector search response"
2303
+ createSessionResponseSchema,
2304
+ "chat session response"
2305
+ );
2306
+ } catch (error) {
2307
+ const maybeError = error instanceof Error ? error : null;
2308
+ if (allowHistoryAutoTopUp && client.shouldAutoTopUpHistory(payload, maybeError)) {
2309
+ await client.executeHistoryAutoTopUp("chat.session");
2310
+ return createSession(client, payload, false);
2311
+ }
2312
+ throw error;
2313
+ }
2314
+ }
2315
+ async function startChat(client, encryptedManager, options) {
2316
+ if ("uaid" in options && options.uaid) {
2317
+ return startConversation(client, encryptedManager, {
2318
+ uaid: options.uaid,
2319
+ senderUaid: options.senderUaid,
2320
+ historyTtlSeconds: options.historyTtlSeconds,
2321
+ auth: options.auth,
2322
+ encryption: options.encryption,
2323
+ onSessionCreated: options.onSessionCreated
2324
+ });
2325
+ }
2326
+ if ("agentUrl" in options && options.agentUrl) {
2327
+ const session = await createSession(client, {
2328
+ agentUrl: options.agentUrl,
2329
+ auth: options.auth,
2330
+ historyTtlSeconds: options.historyTtlSeconds,
2331
+ senderUaid: options.senderUaid
2332
+ });
2333
+ options.onSessionCreated?.(session.sessionId);
2334
+ return createPlaintextConversationHandle(
2335
+ client,
2336
+ session.sessionId,
2337
+ session.encryption ?? null,
2338
+ options.auth,
2339
+ { agentUrl: options.agentUrl, uaid: options.uaid }
2340
+ );
2341
+ }
2342
+ throw new Error("startChat requires either uaid or agentUrl");
2343
+ }
2344
+ async function startConversation(client, encryptedManager, options) {
2345
+ const preference = options.encryption?.preference ?? "preferred";
2346
+ const requestEncryption = preference !== "disabled";
2347
+ if (!requestEncryption) {
2348
+ const session = await createSession(client, {
2349
+ uaid: options.uaid,
2350
+ auth: options.auth,
2351
+ historyTtlSeconds: options.historyTtlSeconds,
2352
+ senderUaid: options.senderUaid,
2353
+ encryptionRequested: false
2354
+ });
2355
+ options.onSessionCreated?.(session.sessionId);
2356
+ return createPlaintextConversationHandle(
2357
+ client,
2358
+ session.sessionId,
2359
+ session.encryption ?? null,
2360
+ options.auth,
2361
+ { uaid: options.uaid }
2236
2362
  );
2363
+ }
2364
+ try {
2365
+ const handle = await encryptedManager.startSession({
2366
+ uaid: options.uaid,
2367
+ senderUaid: options.senderUaid,
2368
+ historyTtlSeconds: options.historyTtlSeconds,
2369
+ handshakeTimeoutMs: options.encryption?.handshakeTimeoutMs,
2370
+ pollIntervalMs: options.encryption?.pollIntervalMs,
2371
+ onSessionCreated: (sessionId) => {
2372
+ options.onSessionCreated?.(sessionId);
2373
+ },
2374
+ auth: options.auth
2375
+ });
2376
+ return handle;
2377
+ } catch (error) {
2378
+ if (error instanceof EncryptionUnavailableError) {
2379
+ if (preference === "required") {
2380
+ throw error;
2381
+ }
2382
+ return createPlaintextConversationHandle(
2383
+ client,
2384
+ error.sessionId,
2385
+ error.summary ?? null,
2386
+ options.auth,
2387
+ { uaid: options.uaid }
2388
+ );
2389
+ }
2390
+ throw error;
2391
+ }
2392
+ }
2393
+ async function acceptConversation(client, encryptedManager, options) {
2394
+ const preference = options.encryption?.preference ?? "preferred";
2395
+ if (preference === "disabled") {
2396
+ return createPlaintextConversationHandle(client, options.sessionId, null);
2397
+ }
2398
+ try {
2399
+ const handle = await encryptedManager.acceptSession({
2400
+ sessionId: options.sessionId,
2401
+ responderUaid: options.responderUaid,
2402
+ handshakeTimeoutMs: options.encryption?.handshakeTimeoutMs,
2403
+ pollIntervalMs: options.encryption?.pollIntervalMs
2404
+ });
2405
+ return handle;
2237
2406
  } catch (error) {
2238
- if (error instanceof RegistryBrokerError && error.status === 501) {
2239
- const fallback = await search(
2407
+ if (error instanceof EncryptionUnavailableError && preference !== "required") {
2408
+ return createPlaintextConversationHandle(
2240
2409
  client,
2241
- buildVectorFallbackSearchParams(request)
2410
+ options.sessionId,
2411
+ null,
2412
+ void 0,
2413
+ { uaid: options.responderUaid }
2242
2414
  );
2243
- return convertSearchResultToVectorResponse(fallback);
2244
2415
  }
2245
2416
  throw error;
2246
2417
  }
2247
2418
  }
2248
- async function searchStatus(client) {
2249
- const raw = await client.requestJson("/search/status", {
2250
- method: "GET"
2251
- });
2252
- return client.parseWithSchema(
2253
- raw,
2254
- searchStatusResponseSchema,
2255
- "search status response"
2256
- );
2419
+ function createPlaintextConversationHandle(client, sessionId, summary, defaultAuth, context) {
2420
+ const uaid = context?.uaid?.trim();
2421
+ const agentUrl = context?.agentUrl?.trim();
2422
+ const fetchHistory = async (options) => {
2423
+ const snapshot = await client.fetchHistorySnapshot(sessionId, options);
2424
+ if (snapshot.decryptedHistory) {
2425
+ return snapshot.decryptedHistory;
2426
+ }
2427
+ return snapshot.history.map((entry) => ({
2428
+ entry,
2429
+ plaintext: entry.content
2430
+ }));
2431
+ };
2432
+ return {
2433
+ sessionId,
2434
+ mode: "plaintext",
2435
+ summary: summary ?? null,
2436
+ send: async (options) => {
2437
+ const plaintext = options.plaintext;
2438
+ if (!plaintext || plaintext.trim().length === 0) {
2439
+ throw new Error("plaintext is required for chat messages");
2440
+ }
2441
+ const message = options.message ?? plaintext;
2442
+ return sendMessage(client, {
2443
+ sessionId,
2444
+ message,
2445
+ streaming: options.streaming,
2446
+ auth: options.auth ?? defaultAuth,
2447
+ uaid,
2448
+ agentUrl
2449
+ });
2450
+ },
2451
+ decryptHistoryEntry: (entry) => entry.content,
2452
+ fetchHistory
2453
+ };
2257
2454
  }
2258
- async function websocketStats(client) {
2259
- const raw = await client.requestJson("/websocket/stats", {
2260
- method: "GET"
2261
- });
2262
- return client.parseWithSchema(
2263
- raw,
2264
- websocketStatsResponseSchema,
2265
- "websocket stats response"
2455
+ async function compactHistory(client, payload) {
2456
+ if (!payload.sessionId || payload.sessionId.trim().length === 0) {
2457
+ throw new Error("sessionId is required to compact chat history");
2458
+ }
2459
+ const body = {};
2460
+ if (typeof payload.preserveEntries === "number" && Number.isFinite(payload.preserveEntries) && payload.preserveEntries >= 0) {
2461
+ body.preserveEntries = Math.floor(payload.preserveEntries);
2462
+ }
2463
+ const raw = await client.requestJson(
2464
+ `/chat/session/${encodeURIComponent(payload.sessionId)}/compact`,
2465
+ {
2466
+ method: "POST",
2467
+ headers: { "content-type": "application/json" },
2468
+ body
2469
+ }
2266
2470
  );
2267
- }
2268
- async function metricsSummary(client) {
2269
- const raw = await client.requestJson("/metrics", {
2270
- method: "GET"
2271
- });
2272
2471
  return client.parseWithSchema(
2273
2472
  raw,
2274
- metricsSummaryResponseSchema,
2275
- "metrics summary response"
2473
+ chatHistoryCompactionResponseSchema,
2474
+ "chat history compaction response"
2276
2475
  );
2277
2476
  }
2278
- async function facets(client, adapter) {
2279
- const params = new URLSearchParams();
2280
- if (adapter) {
2281
- params.set("adapter", adapter);
2477
+ async function fetchEncryptionStatus(client, sessionId) {
2478
+ if (!sessionId || sessionId.trim().length === 0) {
2479
+ throw new Error("sessionId is required for encryption status");
2282
2480
  }
2283
- const suffix = params.size > 0 ? `?${params.toString()}` : "";
2284
- const raw = await client.requestJson(`/search/facets${suffix}`, {
2285
- method: "GET"
2286
- });
2287
- return client.parseWithSchema(
2288
- raw,
2289
- searchFacetsResponseSchema,
2290
- "search facets response"
2291
- );
2292
- }
2293
-
2294
- // ../../src/services/registry-broker/client/adapters.ts
2295
- async function adapters(client) {
2296
- const raw = await client.requestJson("/adapters", {
2297
- method: "GET"
2298
- });
2299
- return client.parseWithSchema(
2300
- raw,
2301
- adaptersResponseSchema,
2302
- "adapters response"
2481
+ const raw = await client.requestJson(
2482
+ `/chat/session/${encodeURIComponent(sessionId)}/encryption`,
2483
+ {
2484
+ method: "GET"
2485
+ }
2303
2486
  );
2304
- }
2305
- async function adaptersDetailed(client) {
2306
- const raw = await client.requestJson("/adapters/details", {
2307
- method: "GET"
2308
- });
2309
2487
  return client.parseWithSchema(
2310
2488
  raw,
2311
- adapterDetailsResponseSchema,
2312
- "adapter details response"
2489
+ sessionEncryptionStatusResponseSchema,
2490
+ "session encryption status response"
2313
2491
  );
2314
2492
  }
2315
- async function adapterRegistryCategories(client) {
2493
+ async function postEncryptionHandshake(client, sessionId, payload) {
2494
+ if (!sessionId || sessionId.trim().length === 0) {
2495
+ throw new Error("sessionId is required for encryption handshake");
2496
+ }
2316
2497
  const raw = await client.requestJson(
2317
- "/adapters/registry/categories",
2498
+ `/chat/session/${encodeURIComponent(sessionId)}/encryption-handshake`,
2318
2499
  {
2319
- method: "GET"
2500
+ method: "POST",
2501
+ headers: { "content-type": "application/json" },
2502
+ body: {
2503
+ role: payload.role,
2504
+ keyType: payload.keyType,
2505
+ ephemeralPublicKey: payload.ephemeralPublicKey,
2506
+ longTermPublicKey: payload.longTermPublicKey,
2507
+ signature: payload.signature,
2508
+ uaid: payload.uaid,
2509
+ userId: payload.userId,
2510
+ ledgerAccountId: payload.ledgerAccountId,
2511
+ metadata: payload.metadata
2512
+ }
2320
2513
  }
2321
2514
  );
2322
- return client.parseWithSchema(
2515
+ const response = client.parseWithSchema(
2323
2516
  raw,
2324
- adapterRegistryCategoriesResponseSchema,
2325
- "adapter registry categories response"
2517
+ encryptionHandshakeResponseSchema,
2518
+ "encryption handshake response"
2326
2519
  );
2520
+ return response.handshake;
2327
2521
  }
2328
- async function adapterRegistryAdapters(client, filters = {}) {
2329
- const params = new URLSearchParams();
2330
- if (filters.category) {
2331
- params.set("category", filters.category);
2332
- }
2333
- if (filters.entity) {
2334
- params.set("entity", filters.entity);
2522
+ async function sendMessage(client, payload) {
2523
+ const body = {
2524
+ message: payload.message
2525
+ };
2526
+ if (payload.streaming !== void 0) {
2527
+ body.streaming = payload.streaming;
2335
2528
  }
2336
- if (filters.keywords?.length) {
2337
- params.set("keywords", filters.keywords.join(","));
2529
+ if (payload.auth) {
2530
+ body.auth = serialiseAuthConfig(payload.auth);
2338
2531
  }
2339
- if (filters.query) {
2340
- params.set("query", filters.query);
2532
+ if ("uaid" in payload) {
2533
+ body.uaid = payload.uaid;
2341
2534
  }
2342
- if (typeof filters.limit === "number") {
2343
- params.set("limit", String(filters.limit));
2535
+ if ("sessionId" in payload && payload.sessionId) {
2536
+ body.sessionId = payload.sessionId;
2344
2537
  }
2345
- if (typeof filters.offset === "number") {
2346
- params.set("offset", String(filters.offset));
2538
+ if ("agentUrl" in payload && payload.agentUrl) {
2539
+ body.agentUrl = payload.agentUrl;
2347
2540
  }
2348
- const suffix = params.size > 0 ? `?${params.toString()}` : "";
2349
- const raw = await client.requestJson(
2350
- `/adapters/registry/adapters${suffix}`,
2351
- {
2352
- method: "GET"
2541
+ let cipherEnvelope = payload.cipherEnvelope ?? null;
2542
+ if (payload.encryption) {
2543
+ const sessionIdForEncryption = payload.encryption.sessionId ?? (typeof body.sessionId === "string" ? body.sessionId : void 0);
2544
+ if (!sessionIdForEncryption) {
2545
+ throw new Error(
2546
+ "sessionId is required when using encrypted chat payloads"
2547
+ );
2353
2548
  }
2354
- );
2549
+ if (!payload.encryption.recipients?.length) {
2550
+ throw new Error("recipients are required for encrypted chat payloads");
2551
+ }
2552
+ cipherEnvelope = client.encryption.encryptCipherEnvelope({
2553
+ ...payload.encryption,
2554
+ sessionId: sessionIdForEncryption
2555
+ });
2556
+ }
2557
+ if (cipherEnvelope) {
2558
+ body.cipherEnvelope = toJsonObject(cipherEnvelope);
2559
+ }
2560
+ const raw = await client.requestJson("/chat/message", {
2561
+ method: "POST",
2562
+ body,
2563
+ headers: { "content-type": "application/json" }
2564
+ });
2355
2565
  return client.parseWithSchema(
2356
2566
  raw,
2357
- adapterRegistryAdaptersResponseSchema,
2358
- "adapter registry adapters response"
2567
+ sendMessageResponseSchema,
2568
+ "chat message response"
2359
2569
  );
2360
2570
  }
2361
- async function createAdapterRegistryCategory(client, payload) {
2362
- const raw = await client.requestJson(
2363
- "/adapters/registry/categories",
2364
- {
2365
- method: "POST",
2366
- headers: { "content-type": "application/json" },
2367
- body: toJsonObject(payload)
2368
- }
2369
- );
2370
- const parsed = client.parseWithSchema(
2371
- raw,
2372
- adapterRegistryCreateCategoryResponseSchema,
2373
- "adapter registry create category response"
2374
- );
2375
- return parsed.category;
2571
+ async function endSession(client, sessionId) {
2572
+ await client.request(`/chat/session/${encodeURIComponent(sessionId)}`, {
2573
+ method: "DELETE"
2574
+ });
2376
2575
  }
2377
- async function submitAdapterRegistryAdapter(client, payload) {
2378
- const raw = await client.requestJson(
2379
- "/adapters/registry/adapters",
2380
- {
2381
- method: "POST",
2382
- headers: { "content-type": "application/json" },
2383
- body: toJsonObject(payload)
2576
+
2577
+ // ../../src/services/registry-broker/client/encryption.ts
2578
+ import { Buffer as Buffer3 } from "buffer";
2579
+ import { secp256k1 } from "@noble/curves/secp256k1.js";
2580
+
2581
+ // ../../src/utils/is-browser.ts
2582
+ var isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined";
2583
+
2584
+ // ../../src/utils/dynamic-import.ts
2585
+ var nodeRequire;
2586
+ var isNodeRuntime = () => typeof process !== "undefined" && Boolean(process.versions?.node);
2587
+ function getNodeRequireSync() {
2588
+ try {
2589
+ const moduleNamespace = process.getBuiltinModule?.("module");
2590
+ if (typeof moduleNamespace?.createRequire === "function") {
2591
+ const requireFromModule = moduleNamespace.createRequire(import.meta.url);
2592
+ if (typeof requireFromModule.resolve === "function") {
2593
+ return requireFromModule;
2594
+ }
2384
2595
  }
2385
- );
2386
- return client.parseWithSchema(
2387
- raw,
2388
- adapterRegistrySubmitAdapterAcceptedResponseSchema,
2389
- "adapter registry submit adapter response"
2390
- );
2596
+ const globalObject = typeof global !== "undefined" ? global : globalThis;
2597
+ const runtimeRequire = globalObject.process?.mainModule?.require ?? globalObject.require ?? Function('return typeof require === "function" ? require : undefined;')();
2598
+ if (typeof runtimeRequire === "function" && typeof runtimeRequire.resolve === "function") {
2599
+ return runtimeRequire;
2600
+ }
2601
+ } catch {
2602
+ return null;
2603
+ }
2604
+ return null;
2391
2605
  }
2392
- async function adapterRegistrySubmissionStatus(client, submissionId) {
2393
- const raw = await client.requestJson(
2394
- `/adapters/registry/submissions/${encodeURIComponent(submissionId)}`,
2395
- {
2396
- method: "GET"
2606
+ function isModuleNotFound(specifier, error) {
2607
+ if (!error || typeof error !== "object") {
2608
+ return false;
2609
+ }
2610
+ const code = Reflect.get(error, "code");
2611
+ const message = Reflect.get(error, "message");
2612
+ const messageText = typeof message === "string" ? message : "";
2613
+ if (typeof code === "string" && code.includes("MODULE_NOT_FOUND")) {
2614
+ return messageText.includes(specifier);
2615
+ }
2616
+ if (messageText) {
2617
+ const lowered = messageText.toLowerCase();
2618
+ if (lowered.includes("cannot find module") || lowered.includes("module not found") || lowered.includes("cannot find package")) {
2619
+ return lowered.includes(specifier.toLowerCase());
2397
2620
  }
2398
- );
2399
- return client.parseWithSchema(
2400
- raw,
2401
- adapterRegistrySubmissionStatusResponseSchema,
2402
- "adapter registry submission status response"
2403
- );
2621
+ }
2622
+ return false;
2404
2623
  }
2405
-
2406
- // ../../src/services/registry-broker/client/credits.ts
2407
- async function loadX402Dependencies(client) {
2408
- const [{ default: axios }, x402Axios, x402Types] = await Promise.all([
2409
- import("axios"),
2410
- optionalImport("x402-axios"),
2411
- optionalImport("x402/types")
2412
- ]);
2413
- if (!x402Axios || !x402Types) {
2414
- throw new Error(
2415
- "x402-axios and x402/types are required for X402 flows. Install them to enable ledger payments."
2624
+ async function resolveNodeRequire() {
2625
+ if (nodeRequire !== void 0) {
2626
+ return nodeRequire;
2627
+ }
2628
+ if (isBrowser && !isNodeRuntime()) {
2629
+ nodeRequire = null;
2630
+ return nodeRequire;
2631
+ }
2632
+ try {
2633
+ nodeRequire = getNodeRequireSync();
2634
+ } catch {
2635
+ nodeRequire = null;
2636
+ }
2637
+ return nodeRequire;
2638
+ }
2639
+ async function dynamicImport(specifier) {
2640
+ try {
2641
+ return await import(
2642
+ /* webpackIgnore: true */
2643
+ specifier
2416
2644
  );
2645
+ } catch (error) {
2646
+ if (isModuleNotFound(specifier, error)) {
2647
+ return null;
2648
+ }
2649
+ throw error;
2417
2650
  }
2418
- const withPaymentInterceptor = x402Axios.withPaymentInterceptor;
2419
- const decodePaymentResponse = x402Axios.decodeXPaymentResponse;
2420
- const createX402Signer = x402Types.createSigner;
2421
- const createPaymentClient = (walletClient) => {
2422
- const axiosClient = axios.create({
2423
- baseURL: client.baseUrl,
2424
- headers: {
2425
- ...client.getDefaultHeaders(),
2426
- "content-type": "application/json"
2651
+ }
2652
+ async function optionalImport(specifier, options = {}) {
2653
+ if (isBrowser && !isNodeRuntime()) {
2654
+ return dynamicImport(specifier);
2655
+ }
2656
+ if (!options.preferImport) {
2657
+ const requireFn = await resolveNodeRequire();
2658
+ if (requireFn) {
2659
+ try {
2660
+ return requireFn(specifier);
2661
+ } catch (error) {
2662
+ if (!isModuleNotFound(specifier, error)) {
2663
+ throw error;
2664
+ }
2427
2665
  }
2428
- });
2429
- const paymentClient = withPaymentInterceptor(axiosClient, walletClient);
2430
- return paymentClient;
2431
- };
2432
- return { createPaymentClient, decodePaymentResponse, createX402Signer };
2666
+ }
2667
+ }
2668
+ return dynamicImport(specifier);
2433
2669
  }
2434
- function calculateHbarAmountParam(hbarAmount) {
2435
- const tinybars = Math.ceil(hbarAmount * 1e8);
2436
- if (tinybars <= 0) {
2437
- throw new Error("Calculated purchase amount must be positive");
2670
+ function optionalImportSync(specifier) {
2671
+ if (isBrowser && !isNodeRuntime()) {
2672
+ return null;
2438
2673
  }
2439
- return tinybars / 1e8;
2674
+ try {
2675
+ const requireFn = getNodeRequireSync();
2676
+ if (requireFn) {
2677
+ return requireFn(specifier);
2678
+ }
2679
+ } catch (error) {
2680
+ if (!isModuleNotFound(specifier, error)) {
2681
+ throw error;
2682
+ }
2683
+ }
2684
+ return null;
2440
2685
  }
2441
- async function purchaseCreditsWithHbar(client, params) {
2442
- const body = {
2443
- accountId: params.accountId,
2444
- payerKey: params.privateKey,
2445
- hbarAmount: calculateHbarAmountParam(params.hbarAmount)
2446
- };
2447
- if (params.memo) {
2448
- body.memo = params.memo;
2686
+
2687
+ // ../../src/services/registry-broker/client/encryption.ts
2688
+ var getFs = async () => {
2689
+ const fsModule = await optionalImport("node:fs") ?? await optionalImport("fs");
2690
+ if (fsModule && typeof fsModule.existsSync === "function" && typeof fsModule.readFileSync === "function" && typeof fsModule.writeFileSync === "function" && typeof fsModule.appendFileSync === "function") {
2691
+ return fsModule;
2449
2692
  }
2450
- if (params.metadata) {
2451
- body.metadata = params.metadata;
2693
+ return null;
2694
+ };
2695
+ var getNodePath = async () => {
2696
+ const pathModule = await optionalImport("node:path") ?? await optionalImport("path");
2697
+ if (pathModule && typeof pathModule.resolve === "function") {
2698
+ return pathModule;
2452
2699
  }
2453
- const raw = await client.requestJson("/credits/purchase", {
2700
+ return null;
2701
+ };
2702
+ var getNodeCrypto = async () => {
2703
+ const cryptoModule = await optionalImport("node:crypto") ?? await optionalImport("crypto");
2704
+ if (cryptoModule && typeof cryptoModule.randomBytes === "function") {
2705
+ return cryptoModule;
2706
+ }
2707
+ return null;
2708
+ };
2709
+ async function registerEncryptionKey(client, payload) {
2710
+ const raw = await client.requestJson("/encryption/keys", {
2454
2711
  method: "POST",
2455
2712
  headers: { "content-type": "application/json" },
2456
- body
2713
+ body: payload
2457
2714
  });
2458
2715
  return client.parseWithSchema(
2459
2716
  raw,
2460
- creditPurchaseResponseSchema,
2461
- "credit purchase response"
2462
- );
2463
- }
2464
- async function getX402Minimums(client) {
2465
- const raw = await client.requestJson(
2466
- "/credits/purchase/x402/minimums",
2467
- { method: "GET" }
2468
- );
2469
- return client.parseWithSchema(
2470
- raw,
2471
- x402MinimumsResponseSchema,
2472
- "x402 minimums response"
2717
+ registerEncryptionKeyResponseSchema,
2718
+ "register encryption key response"
2473
2719
  );
2474
2720
  }
2475
- async function purchaseCreditsWithX402(client, params) {
2476
- const { createPaymentClient, decodePaymentResponse } = await loadX402Dependencies(client);
2477
- if (!Number.isFinite(params.credits) || params.credits <= 0) {
2478
- throw new Error("credits must be a positive number");
2721
+ function normalizeAutoRegisterIdentity(config) {
2722
+ const identity = {};
2723
+ if (config.uaid) {
2724
+ identity.uaid = config.uaid;
2479
2725
  }
2480
- if (params.usdAmount !== void 0 && (!Number.isFinite(params.usdAmount) || params.usdAmount <= 0)) {
2481
- throw new Error("usdAmount must be a positive number when provided");
2726
+ if (config.ledgerAccountId) {
2727
+ identity.ledgerAccountId = config.ledgerAccountId;
2728
+ if (config.ledgerNetwork) {
2729
+ identity.ledgerNetwork = config.ledgerNetwork;
2730
+ }
2482
2731
  }
2483
- const body = {
2484
- accountId: params.accountId,
2485
- credits: params.credits
2486
- };
2487
- if (params.usdAmount !== void 0) {
2488
- body.usdAmount = params.usdAmount;
2732
+ if (config.email) {
2733
+ identity.email = config.email;
2489
2734
  }
2490
- if (params.description) {
2491
- body.description = params.description;
2735
+ if (identity.uaid || identity.ledgerAccountId || identity.email) {
2736
+ return identity;
2492
2737
  }
2493
- if (params.metadata) {
2494
- body.metadata = params.metadata;
2738
+ return null;
2739
+ }
2740
+ function derivePublicKeyFromPrivateKey(client, privateKey) {
2741
+ const normalized = client.hexToBuffer(privateKey);
2742
+ const publicKey = secp256k1.getPublicKey(normalized, true);
2743
+ return Buffer3.from(publicKey).toString("hex");
2744
+ }
2745
+ async function resolveAutoRegisterKeyMaterial(client, config) {
2746
+ if (config.publicKey?.trim()) {
2747
+ return { publicKey: config.publicKey.trim() };
2495
2748
  }
2496
- const paymentClient = createPaymentClient(params.walletClient);
2497
- const response = await paymentClient.post("/credits/purchase/x402", body);
2498
- const parsed = client.parseWithSchema(
2499
- response.data,
2500
- x402CreditPurchaseResponseSchema,
2501
- "x402 credit purchase response"
2502
- );
2503
- const responseHeaders = response.headers ?? {};
2504
- const paymentHeader = typeof responseHeaders["x-payment-response"] === "string" ? responseHeaders["x-payment-response"] : void 0;
2505
- const decodedPayment = paymentHeader !== void 0 ? decodePaymentResponse(paymentHeader) : void 0;
2506
- return {
2507
- ...parsed,
2508
- paymentResponseHeader: paymentHeader,
2509
- paymentResponse: decodedPayment
2510
- };
2749
+ let privateKey = config.privateKey?.trim();
2750
+ const envVar = config.envVar ?? "RB_ENCRYPTION_PRIVATE_KEY";
2751
+ if (!privateKey && envVar && process?.env?.[envVar]?.trim()) {
2752
+ privateKey = process.env[envVar]?.trim();
2753
+ }
2754
+ if (!privateKey && config.generateIfMissing) {
2755
+ const pair = await client.generateEncryptionKeyPair({
2756
+ keyType: config.keyType ?? "secp256k1",
2757
+ envVar,
2758
+ envPath: config.envPath,
2759
+ overwrite: config.overwriteEnv
2760
+ });
2761
+ return { publicKey: pair.publicKey, privateKey: pair.privateKey };
2762
+ }
2763
+ if (privateKey) {
2764
+ const publicKey = derivePublicKeyFromPrivateKey(client, privateKey);
2765
+ return { publicKey, privateKey };
2766
+ }
2767
+ return null;
2511
2768
  }
2512
- async function buyCreditsWithX402(client, params) {
2513
- const network = params.network ?? "base";
2514
- const { createX402Signer } = await loadX402Dependencies(client);
2515
- const normalizedKey = normalizeHexPrivateKey(params.evmPrivateKey);
2516
- const walletClient = await createX402Signer(network, normalizedKey);
2517
- return purchaseCreditsWithX402(client, {
2518
- accountId: params.accountId,
2519
- credits: params.credits,
2520
- usdAmount: params.usdAmount,
2521
- description: params.description,
2522
- metadata: params.metadata,
2523
- walletClient
2769
+ async function autoRegisterEncryptionKey(client, config) {
2770
+ const identity = normalizeAutoRegisterIdentity(config);
2771
+ if (!identity) {
2772
+ throw new Error(
2773
+ "Auto-registration requires uaid, ledgerAccountId, or email"
2774
+ );
2775
+ }
2776
+ const material = await resolveAutoRegisterKeyMaterial(client, config);
2777
+ if (!material) {
2778
+ throw new Error(
2779
+ "Unable to resolve encryption public key for auto-registration"
2780
+ );
2781
+ }
2782
+ await registerEncryptionKey(client, {
2783
+ keyType: config.keyType ?? "secp256k1",
2784
+ publicKey: material.publicKey,
2785
+ ...identity
2524
2786
  });
2787
+ return material;
2525
2788
  }
2526
-
2527
- // ../../src/services/registry-broker/client/agents.ts
2528
- async function performRegisterAgent(client, payload) {
2529
- const raw = await client.requestJson("/register", {
2530
- method: "POST",
2531
- body: serialiseAgentRegistrationRequest(payload),
2532
- headers: { "content-type": "application/json" }
2789
+ async function ensureAgentEncryptionKey(client, options) {
2790
+ return autoRegisterEncryptionKey(client, {
2791
+ ...options,
2792
+ uaid: options.uaid,
2793
+ enabled: true
2533
2794
  });
2534
- return client.parseWithSchema(
2535
- raw,
2536
- registerAgentResponseSchema,
2537
- "register agent response"
2538
- );
2539
2795
  }
2540
- function calculateHbarAmount(creditsToPurchase, creditsPerHbar) {
2541
- if (creditsPerHbar <= 0) {
2542
- throw new Error("creditsPerHbar must be positive");
2543
- }
2544
- if (creditsToPurchase <= 0) {
2545
- throw new Error("creditsToPurchase must be positive");
2546
- }
2547
- const rawHbar = creditsToPurchase / creditsPerHbar;
2548
- const tinybars = Math.ceil(rawHbar * 1e8);
2549
- return tinybars / 1e8;
2796
+ function createEncryptionApi(client) {
2797
+ return {
2798
+ registerKey: (payload) => registerEncryptionKey(client, payload),
2799
+ generateEphemeralKeyPair: () => client.createEphemeralKeyPair(),
2800
+ deriveSharedSecret: (options) => client.deriveSharedSecret(options),
2801
+ encryptCipherEnvelope: (options) => client.buildCipherEnvelope(options),
2802
+ decryptCipherEnvelope: (options) => client.openCipherEnvelope(options),
2803
+ ensureAgentKey: (options) => ensureAgentEncryptionKey(client, options)
2804
+ };
2550
2805
  }
2551
- function resolveCreditsToPurchase(shortfallCredits) {
2552
- if (!Number.isFinite(shortfallCredits) || shortfallCredits <= 0) {
2553
- return 0;
2806
+ async function bootstrapEncryptionOptions(client, options) {
2807
+ if (!options?.autoRegister || options.autoRegister.enabled === false) {
2808
+ return null;
2554
2809
  }
2555
- return Math.max(
2556
- Math.ceil(shortfallCredits),
2557
- MINIMUM_REGISTRATION_AUTO_TOP_UP_CREDITS
2558
- );
2810
+ return autoRegisterEncryptionKey(client, options.autoRegister);
2559
2811
  }
2560
- async function ensureCreditsForRegistration(client, payload, autoTopUp) {
2561
- const details = autoTopUp ?? null;
2562
- if (!details) {
2563
- return;
2812
+ async function generateEncryptionKeyPair(client, options = {}) {
2813
+ client.assertNodeRuntime("generateEncryptionKeyPair");
2814
+ const keyType = options.keyType ?? "secp256k1";
2815
+ if (keyType !== "secp256k1") {
2816
+ throw new Error("Only secp256k1 key generation is supported currently");
2564
2817
  }
2565
- if (!details.accountId || !details.accountId.trim()) {
2566
- throw new Error("autoTopUp.accountId is required");
2818
+ const cryptoModule = await getNodeCrypto();
2819
+ if (!cryptoModule) {
2820
+ throw new Error(
2821
+ "Node.js crypto module is not available; cannot generate encryption key pair"
2822
+ );
2567
2823
  }
2568
- if (!details.privateKey || !details.privateKey.trim()) {
2569
- throw new Error("autoTopUp.privateKey is required");
2824
+ const privateKeyBytes = cryptoModule.randomBytes(32);
2825
+ const privateKey = Buffer3.from(privateKeyBytes).toString("hex");
2826
+ const publicKeyBytes = secp256k1.getPublicKey(privateKeyBytes, true);
2827
+ const publicKey = Buffer3.from(publicKeyBytes).toString("hex");
2828
+ const envVar = options.envVar ?? "RB_ENCRYPTION_PRIVATE_KEY";
2829
+ const pathModule = options.envPath ? await getNodePath() : null;
2830
+ const resolvedPath = options.envPath && pathModule ? pathModule.resolve(options.envPath) : void 0;
2831
+ if (options.envPath && !resolvedPath) {
2832
+ throw new Error(
2833
+ "Node.js path module is not available; cannot resolve encryption key env path"
2834
+ );
2570
2835
  }
2571
- for (let attempt = 0; attempt < 3; attempt += 1) {
2572
- const quote = await getRegistrationQuote(client, payload);
2573
- const shortfall = quote.shortfallCredits ?? 0;
2574
- if (shortfall <= 0) {
2575
- return;
2576
- }
2577
- const creditsToPurchase = resolveCreditsToPurchase(shortfall);
2578
- if (creditsToPurchase <= 0) {
2579
- return;
2580
- }
2581
- const creditsPerHbar = quote.creditsPerHbar ?? null;
2582
- if (!creditsPerHbar || creditsPerHbar <= 0) {
2583
- throw new Error("Unable to determine credits per HBAR for auto top-up");
2836
+ if (resolvedPath) {
2837
+ const fsModule = await getFs();
2838
+ if (!fsModule) {
2839
+ throw new Error(
2840
+ "File system module is not available; cannot write encryption key env file"
2841
+ );
2584
2842
  }
2585
- const hbarAmount = calculateHbarAmount(creditsToPurchase, creditsPerHbar);
2586
- await purchaseCreditsWithHbar(client, {
2587
- accountId: details.accountId.trim(),
2588
- privateKey: details.privateKey.trim(),
2589
- hbarAmount,
2590
- memo: details.memo ?? "Registry Broker auto top-up",
2591
- metadata: {
2592
- shortfallCredits: shortfall,
2593
- requiredCredits: quote.requiredCredits,
2594
- purchasedCredits: creditsToPurchase
2843
+ const envLine = `${envVar}=${privateKey}`;
2844
+ if (fsModule.existsSync(resolvedPath)) {
2845
+ const content = fsModule.readFileSync(resolvedPath, "utf-8");
2846
+ const lineRegex = new RegExp(`^${envVar}=.*$`, "m");
2847
+ if (lineRegex.test(content)) {
2848
+ if (!options.overwrite) {
2849
+ throw new Error(
2850
+ `${envVar} already exists in ${resolvedPath}; set overwrite=true to replace it`
2851
+ );
2852
+ }
2853
+ const updated = content.replace(lineRegex, envLine);
2854
+ fsModule.writeFileSync(resolvedPath, updated);
2855
+ } else {
2856
+ const needsNewline = !content.endsWith("\n");
2857
+ fsModule.appendFileSync(
2858
+ resolvedPath,
2859
+ `${needsNewline ? "\n" : ""}${envLine}
2860
+ `
2861
+ );
2595
2862
  }
2596
- });
2597
- }
2598
- const finalQuote = await getRegistrationQuote(client, payload);
2599
- if ((finalQuote.shortfallCredits ?? 0) > 0) {
2600
- throw new Error("Unable to purchase sufficient credits for registration");
2863
+ } else {
2864
+ fsModule.writeFileSync(resolvedPath, `${envLine}
2865
+ `);
2866
+ }
2601
2867
  }
2868
+ return {
2869
+ privateKey,
2870
+ publicKey,
2871
+ envPath: resolvedPath,
2872
+ envVar
2873
+ };
2602
2874
  }
2603
- async function resolveUaid(client, uaid) {
2604
- const raw = await client.requestJson(
2605
- `/resolve/${encodeURIComponent(uaid)}`,
2606
- {
2607
- method: "GET"
2608
- }
2609
- );
2875
+
2876
+ // ../../src/services/registry-broker/client/adapters.ts
2877
+ async function adapters(client) {
2878
+ const raw = await client.requestJson("/adapters", {
2879
+ method: "GET"
2880
+ });
2610
2881
  return client.parseWithSchema(
2611
2882
  raw,
2612
- resolveResponseSchema,
2613
- "resolve UAID response"
2883
+ adaptersResponseSchema,
2884
+ "adapters response"
2614
2885
  );
2615
2886
  }
2616
- async function registerAgent(client, payload, options) {
2617
- const autoTopUp = options?.autoTopUp ?? client.registrationAutoTopUp;
2618
- if (!autoTopUp) {
2619
- return performRegisterAgent(client, payload);
2620
- }
2621
- await ensureCreditsForRegistration(client, payload, autoTopUp);
2622
- let retried = false;
2623
- while (true) {
2624
- try {
2625
- return await performRegisterAgent(client, payload);
2626
- } catch (error) {
2627
- const shortfall = client.extractInsufficientCreditsDetails(error);
2628
- if (shortfall && !retried) {
2629
- await ensureCreditsForRegistration(client, payload, autoTopUp);
2630
- retried = true;
2631
- continue;
2632
- }
2633
- throw error;
2634
- }
2635
- }
2636
- }
2637
- async function getRegistrationQuote(client, payload) {
2638
- const raw = await client.requestJson("/register/quote", {
2639
- method: "POST",
2640
- body: serialiseAgentRegistrationRequest(payload),
2641
- headers: { "content-type": "application/json" }
2887
+ async function adaptersDetailed(client) {
2888
+ const raw = await client.requestJson("/adapters/details", {
2889
+ method: "GET"
2642
2890
  });
2643
2891
  return client.parseWithSchema(
2644
2892
  raw,
2645
- registrationQuoteResponseSchema,
2646
- "registration quote response"
2893
+ adapterDetailsResponseSchema,
2894
+ "adapter details response"
2647
2895
  );
2648
2896
  }
2649
- async function updateAgent(client, uaid, payload) {
2897
+ async function adapterRegistryCategories(client) {
2650
2898
  const raw = await client.requestJson(
2651
- `/register/${encodeURIComponent(uaid)}`,
2899
+ "/adapters/registry/categories",
2652
2900
  {
2653
- method: "PUT",
2654
- body: serialiseAgentRegistrationRequest(payload),
2655
- headers: { "content-type": "application/json" }
2901
+ method: "GET"
2656
2902
  }
2657
2903
  );
2658
2904
  return client.parseWithSchema(
2659
2905
  raw,
2660
- registerAgentResponseSchema,
2661
- "update agent response"
2662
- );
2663
- }
2664
- async function getRegistrationProgress(client, attemptId) {
2665
- const normalisedAttemptId = attemptId.trim();
2666
- if (!normalisedAttemptId) {
2667
- throw new Error("attemptId is required");
2668
- }
2669
- try {
2670
- const raw = await client.requestJson(
2671
- `/register/progress/${encodeURIComponent(normalisedAttemptId)}`,
2672
- { method: "GET" }
2673
- );
2674
- const parsed = client.parseWithSchema(
2675
- raw,
2676
- registrationProgressResponseSchema,
2677
- "registration progress response"
2678
- );
2679
- return parsed.progress;
2680
- } catch (error) {
2681
- if (error instanceof RegistryBrokerError && error.status === 404) {
2682
- return null;
2683
- }
2684
- throw error;
2685
- }
2686
- }
2687
- async function waitForRegistrationCompletion(client, attemptId, options = {}) {
2688
- const normalisedAttemptId = attemptId.trim();
2689
- if (!normalisedAttemptId) {
2690
- throw new Error("attemptId is required");
2691
- }
2692
- const interval = Math.max(
2693
- 250,
2694
- options.intervalMs ?? DEFAULT_PROGRESS_INTERVAL_MS
2906
+ adapterRegistryCategoriesResponseSchema,
2907
+ "adapter registry categories response"
2695
2908
  );
2696
- const timeoutMs = options.timeoutMs ?? DEFAULT_PROGRESS_TIMEOUT_MS;
2697
- const throwOnFailure = options.throwOnFailure ?? true;
2698
- const signal = options.signal;
2699
- const startedAt = Date.now();
2700
- while (true) {
2701
- if (signal?.aborted) {
2702
- throw createAbortError();
2703
- }
2704
- const progress = await client.getRegistrationProgress(normalisedAttemptId);
2705
- if (progress) {
2706
- options.onProgress?.(progress);
2707
- if (progress.status === "completed") {
2708
- return progress;
2709
- }
2710
- if (progress.status === "partial" || progress.status === "failed") {
2711
- if (throwOnFailure) {
2712
- throw new RegistryBrokerError(
2713
- "Registration did not complete successfully",
2714
- {
2715
- status: 409,
2716
- statusText: progress.status,
2717
- body: progress
2718
- }
2719
- );
2720
- }
2721
- return progress;
2722
- }
2909
+ }
2910
+ async function adapterRegistryAdapters(client, filters = {}) {
2911
+ const params = new URLSearchParams();
2912
+ if (filters.category) {
2913
+ params.set("category", filters.category);
2914
+ }
2915
+ if (filters.entity) {
2916
+ params.set("entity", filters.entity);
2917
+ }
2918
+ if (filters.keywords?.length) {
2919
+ params.set("keywords", filters.keywords.join(","));
2920
+ }
2921
+ if (filters.query) {
2922
+ params.set("query", filters.query);
2923
+ }
2924
+ if (typeof filters.limit === "number") {
2925
+ params.set("limit", String(filters.limit));
2926
+ }
2927
+ if (typeof filters.offset === "number") {
2928
+ params.set("offset", String(filters.offset));
2929
+ }
2930
+ const suffix = params.size > 0 ? `?${params.toString()}` : "";
2931
+ const raw = await client.requestJson(
2932
+ `/adapters/registry/adapters${suffix}`,
2933
+ {
2934
+ method: "GET"
2723
2935
  }
2724
- if (Date.now() - startedAt >= timeoutMs) {
2725
- throw new Error(
2726
- `Registration progress polling timed out after ${timeoutMs}ms`
2727
- );
2936
+ );
2937
+ return client.parseWithSchema(
2938
+ raw,
2939
+ adapterRegistryAdaptersResponseSchema,
2940
+ "adapter registry adapters response"
2941
+ );
2942
+ }
2943
+ async function createAdapterRegistryCategory(client, payload) {
2944
+ const raw = await client.requestJson(
2945
+ "/adapters/registry/categories",
2946
+ {
2947
+ method: "POST",
2948
+ headers: { "content-type": "application/json" },
2949
+ body: toJsonObject(payload)
2728
2950
  }
2729
- await client.delay(interval, signal);
2730
- }
2951
+ );
2952
+ const parsed = client.parseWithSchema(
2953
+ raw,
2954
+ adapterRegistryCreateCategoryResponseSchema,
2955
+ "adapter registry create category response"
2956
+ );
2957
+ return parsed.category;
2731
2958
  }
2732
- async function validateUaid(client, uaid) {
2959
+ async function submitAdapterRegistryAdapter(client, payload) {
2733
2960
  const raw = await client.requestJson(
2734
- `/uaids/validate/${encodeURIComponent(uaid)}`,
2961
+ "/adapters/registry/adapters",
2735
2962
  {
2736
- method: "GET"
2963
+ method: "POST",
2964
+ headers: { "content-type": "application/json" },
2965
+ body: toJsonObject(payload)
2737
2966
  }
2738
2967
  );
2739
2968
  return client.parseWithSchema(
2740
2969
  raw,
2741
- uaidValidationResponseSchema,
2742
- "UAID validation response"
2970
+ adapterRegistrySubmitAdapterAcceptedResponseSchema,
2971
+ "adapter registry submit adapter response"
2743
2972
  );
2744
2973
  }
2745
- async function getUaidConnectionStatus(client, uaid) {
2974
+ async function adapterRegistrySubmissionStatus(client, submissionId) {
2746
2975
  const raw = await client.requestJson(
2747
- `/uaids/connections/${encodeURIComponent(uaid)}/status`,
2976
+ `/adapters/registry/submissions/${encodeURIComponent(submissionId)}`,
2748
2977
  {
2749
2978
  method: "GET"
2750
2979
  }
2751
2980
  );
2752
2981
  return client.parseWithSchema(
2753
2982
  raw,
2754
- uaidConnectionStatusSchema,
2755
- "UAID connection status"
2983
+ adapterRegistrySubmissionStatusResponseSchema,
2984
+ "adapter registry submission status response"
2756
2985
  );
2757
2986
  }
2758
- async function closeUaidConnection(client, uaid) {
2759
- await client.request(`/uaids/connections/${encodeURIComponent(uaid)}`, {
2760
- method: "DELETE"
2761
- });
2987
+
2988
+ // ../../src/services/registry-broker/client/credits.ts
2989
+ async function loadX402Dependencies(client) {
2990
+ const [{ default: axios }, x402Axios, x402Types] = await Promise.all([
2991
+ import("axios"),
2992
+ optionalImport("x402-axios"),
2993
+ optionalImport("x402/types")
2994
+ ]);
2995
+ if (!x402Axios || !x402Types) {
2996
+ throw new Error(
2997
+ "x402-axios and x402/types are required for X402 flows. Install them to enable ledger payments."
2998
+ );
2999
+ }
3000
+ const withPaymentInterceptor = x402Axios.withPaymentInterceptor;
3001
+ const decodePaymentResponse = x402Axios.decodeXPaymentResponse;
3002
+ const createX402Signer = x402Types.createSigner;
3003
+ const createPaymentClient = (walletClient) => {
3004
+ const axiosClient = axios.create({
3005
+ baseURL: client.baseUrl,
3006
+ headers: {
3007
+ ...client.getDefaultHeaders(),
3008
+ "content-type": "application/json"
3009
+ }
3010
+ });
3011
+ const paymentClient = withPaymentInterceptor(axiosClient, walletClient);
3012
+ return paymentClient;
3013
+ };
3014
+ return { createPaymentClient, decodePaymentResponse, createX402Signer };
2762
3015
  }
2763
- async function dashboardStats(client) {
2764
- const raw = await client.requestJson("/dashboard/stats", {
2765
- method: "GET"
3016
+ function calculateHbarAmountParam(hbarAmount) {
3017
+ const tinybars = Math.ceil(hbarAmount * 1e8);
3018
+ if (tinybars <= 0) {
3019
+ throw new Error("Calculated purchase amount must be positive");
3020
+ }
3021
+ return tinybars / 1e8;
3022
+ }
3023
+ async function purchaseCreditsWithHbar(client, params) {
3024
+ const body = {
3025
+ accountId: params.accountId,
3026
+ payerKey: params.privateKey,
3027
+ hbarAmount: calculateHbarAmountParam(params.hbarAmount)
3028
+ };
3029
+ if (params.memo) {
3030
+ body.memo = params.memo;
3031
+ }
3032
+ if (params.metadata) {
3033
+ body.metadata = params.metadata;
3034
+ }
3035
+ const raw = await client.requestJson("/credits/purchase", {
3036
+ method: "POST",
3037
+ headers: { "content-type": "application/json" },
3038
+ body
2766
3039
  });
2767
3040
  return client.parseWithSchema(
2768
3041
  raw,
2769
- dashboardStatsResponseSchema,
2770
- "dashboard stats response"
3042
+ creditPurchaseResponseSchema,
3043
+ "credit purchase response"
2771
3044
  );
2772
3045
  }
2773
-
2774
- // ../../src/services/registry-broker/client/ledger-auth.ts
2775
- import { Buffer as Buffer3 } from "buffer";
2776
-
2777
- // ../../src/services/registry-broker/ledger-network.ts
2778
- var normalise = (value) => value.trim().toLowerCase();
2779
- var HEDERA_NETWORK_ALIASES = /* @__PURE__ */ new Map([
2780
- ["hedera:mainnet", { canonical: "hedera:mainnet", hederaNetwork: "mainnet" }],
2781
- ["mainnet", { canonical: "hedera:mainnet", hederaNetwork: "mainnet" }],
2782
- ["hedera-mainnet", { canonical: "hedera:mainnet", hederaNetwork: "mainnet" }],
2783
- ["hedera_mainnet", { canonical: "hedera:mainnet", hederaNetwork: "mainnet" }],
2784
- ["hedera:testnet", { canonical: "hedera:testnet", hederaNetwork: "testnet" }],
2785
- ["testnet", { canonical: "hedera:testnet", hederaNetwork: "testnet" }],
2786
- ["hedera-testnet", { canonical: "hedera:testnet", hederaNetwork: "testnet" }],
2787
- ["hedera_testnet", { canonical: "hedera:testnet", hederaNetwork: "testnet" }]
2788
- ]);
2789
- var EVM_NETWORK_CHAIN_IDS = {
2790
- abstract: 2741,
2791
- "abstract-testnet": 11124,
2792
- base: 8453,
2793
- "base-sepolia": 84532,
2794
- avalanche: 43114,
2795
- "avalanche-fuji": 43113,
2796
- iotex: 4689,
2797
- sei: 1329,
2798
- "sei-testnet": 1328,
2799
- polygon: 137,
2800
- "polygon-amoy": 80002,
2801
- peaq: 3338
2802
- };
2803
- var CHAIN_ID_TO_ALIAS = new Map(
2804
- Object.entries(EVM_NETWORK_CHAIN_IDS).map(([alias, id]) => [id, alias])
2805
- );
2806
- var parseChainId = (value) => {
2807
- if (/^eip155:\d+$/i.test(value)) {
2808
- return Number.parseInt(value.split(":")[1], 10);
3046
+ async function getX402Minimums(client) {
3047
+ const raw = await client.requestJson(
3048
+ "/credits/purchase/x402/minimums",
3049
+ { method: "GET" }
3050
+ );
3051
+ return client.parseWithSchema(
3052
+ raw,
3053
+ x402MinimumsResponseSchema,
3054
+ "x402 minimums response"
3055
+ );
3056
+ }
3057
+ async function purchaseCreditsWithX402(client, params) {
3058
+ const { createPaymentClient, decodePaymentResponse } = await loadX402Dependencies(client);
3059
+ if (!Number.isFinite(params.credits) || params.credits <= 0) {
3060
+ throw new Error("credits must be a positive number");
2809
3061
  }
2810
- if (/^\d+$/.test(value)) {
2811
- return Number.parseInt(value, 10);
3062
+ if (params.usdAmount !== void 0 && (!Number.isFinite(params.usdAmount) || params.usdAmount <= 0)) {
3063
+ throw new Error("usdAmount must be a positive number when provided");
2812
3064
  }
2813
- return void 0;
2814
- };
2815
- var normaliseEvmNetwork = (value) => {
2816
- const trimmed = normalise(value);
2817
- let chainId = parseChainId(trimmed);
2818
- let alias;
2819
- if (chainId === void 0) {
2820
- const mapped = EVM_NETWORK_CHAIN_IDS[trimmed];
2821
- if (mapped !== void 0) {
2822
- chainId = mapped;
2823
- alias = trimmed;
2824
- }
2825
- } else if (CHAIN_ID_TO_ALIAS.has(chainId)) {
2826
- alias = CHAIN_ID_TO_ALIAS.get(chainId);
3065
+ const body = {
3066
+ accountId: params.accountId,
3067
+ credits: params.credits
3068
+ };
3069
+ if (params.usdAmount !== void 0) {
3070
+ body.usdAmount = params.usdAmount;
2827
3071
  }
2828
- if (chainId === void 0) {
2829
- throw new Error(
2830
- 'Unsupported EVM ledger network. Provide an alias like "base-sepolia" or a canonical eip155:<chainId> string.'
2831
- );
3072
+ if (params.description) {
3073
+ body.description = params.description;
2832
3074
  }
3075
+ if (params.metadata) {
3076
+ body.metadata = params.metadata;
3077
+ }
3078
+ const paymentClient = createPaymentClient(params.walletClient);
3079
+ const response = await paymentClient.post("/credits/purchase/x402", body);
3080
+ const parsed = client.parseWithSchema(
3081
+ response.data,
3082
+ x402CreditPurchaseResponseSchema,
3083
+ "x402 credit purchase response"
3084
+ );
3085
+ const responseHeaders = response.headers ?? {};
3086
+ const paymentHeader = typeof responseHeaders["x-payment-response"] === "string" ? responseHeaders["x-payment-response"] : void 0;
3087
+ const decodedPayment = paymentHeader !== void 0 ? decodePaymentResponse(paymentHeader) : void 0;
2833
3088
  return {
2834
- canonical: `eip155:${chainId}`,
2835
- kind: "evm",
2836
- chainId,
2837
- legacyName: alias
3089
+ ...parsed,
3090
+ paymentResponseHeader: paymentHeader,
3091
+ paymentResponse: decodedPayment
2838
3092
  };
2839
- };
2840
- var normaliseHederaNetwork = (value) => {
2841
- const trimmed = normalise(value);
2842
- const mapping = HEDERA_NETWORK_ALIASES.get(trimmed);
2843
- if (!mapping) {
2844
- throw new Error(
2845
- 'Unsupported Hedera network. Use hedera:mainnet or hedera:testnet (legacy "mainnet"/"testnet" also accepted).'
2846
- );
3093
+ }
3094
+ async function buyCreditsWithX402(client, params) {
3095
+ const network = params.network ?? "base";
3096
+ const { createX402Signer } = await loadX402Dependencies(client);
3097
+ const normalizedKey = normalizeHexPrivateKey(params.evmPrivateKey);
3098
+ const walletClient = await createX402Signer(network, normalizedKey);
3099
+ return purchaseCreditsWithX402(client, {
3100
+ accountId: params.accountId,
3101
+ credits: params.credits,
3102
+ usdAmount: params.usdAmount,
3103
+ description: params.description,
3104
+ metadata: params.metadata,
3105
+ walletClient
3106
+ });
3107
+ }
3108
+
3109
+ // ../../src/services/registry-broker/client/errors.ts
3110
+ var RegistryBrokerError = class extends Error {
3111
+ constructor(message, details) {
3112
+ super(message);
3113
+ this.status = details.status;
3114
+ this.statusText = details.statusText;
3115
+ this.body = details.body;
2847
3116
  }
2848
- return {
2849
- canonical: mapping.canonical,
2850
- kind: "hedera",
2851
- hederaNetwork: mapping.hederaNetwork
2852
- };
2853
3117
  };
2854
- var canonicalizeLedgerNetwork = (network) => {
2855
- if (typeof network !== "string" || network.trim().length === 0) {
2856
- throw new Error("Ledger network is required.");
2857
- }
2858
- const trimmed = normalise(network);
2859
- if (trimmed.startsWith("hedera:") || trimmed.includes("hedera-") || trimmed.includes("hedera_") || trimmed === "mainnet" || trimmed === "testnet") {
2860
- return normaliseHederaNetwork(trimmed);
3118
+ var RegistryBrokerParseError = class extends Error {
3119
+ constructor(message, cause, rawValue) {
3120
+ super(message);
3121
+ this.cause = cause;
3122
+ this.rawValue = rawValue;
2861
3123
  }
2862
- return normaliseEvmNetwork(trimmed);
2863
3124
  };
2864
3125
 
2865
- // ../../src/services/registry-broker/private-key-signer.ts
2866
- var unsupported = (method) => new Error(`${method} is not supported by the in-memory signer`);
2867
- var cachedSdk = null;
2868
- var loadHashgraphSdk = () => {
2869
- if (cachedSdk) {
2870
- return cachedSdk;
3126
+ // ../../src/services/registry-broker/client/agents.ts
3127
+ async function performRegisterAgent(client, payload) {
3128
+ const raw = await client.requestJson("/register", {
3129
+ method: "POST",
3130
+ body: serialiseAgentRegistrationRequest(payload),
3131
+ headers: { "content-type": "application/json" }
3132
+ });
3133
+ return client.parseWithSchema(
3134
+ raw,
3135
+ registerAgentResponseSchema,
3136
+ "register agent response"
3137
+ );
3138
+ }
3139
+ function calculateHbarAmount(creditsToPurchase, creditsPerHbar) {
3140
+ if (creditsPerHbar <= 0) {
3141
+ throw new Error("creditsPerHbar must be positive");
2871
3142
  }
2872
- const resolved = optionalImportSync("@hashgraph/sdk");
2873
- if (resolved) {
2874
- cachedSdk = resolved;
2875
- return resolved;
3143
+ if (creditsToPurchase <= 0) {
3144
+ throw new Error("creditsToPurchase must be positive");
2876
3145
  }
2877
- const message = "@hashgraph/sdk is required for ledger signing. Install it as a dependency to enable createPrivateKeySigner.";
2878
- throw new Error(message);
2879
- };
2880
- var loadHashgraphSdkAsync = async () => {
2881
- if (cachedSdk) {
2882
- return cachedSdk;
3146
+ const rawHbar = creditsToPurchase / creditsPerHbar;
3147
+ const tinybars = Math.ceil(rawHbar * 1e8);
3148
+ return tinybars / 1e8;
3149
+ }
3150
+ function resolveCreditsToPurchase(shortfallCredits) {
3151
+ if (!Number.isFinite(shortfallCredits) || shortfallCredits <= 0) {
3152
+ return 0;
2883
3153
  }
2884
- const resolved = await optionalImport("@hashgraph/sdk");
2885
- if (resolved) {
2886
- cachedSdk = resolved;
2887
- return resolved;
3154
+ return Math.max(
3155
+ Math.ceil(shortfallCredits),
3156
+ MINIMUM_REGISTRATION_AUTO_TOP_UP_CREDITS
3157
+ );
3158
+ }
3159
+ async function ensureCreditsForRegistration(client, payload, autoTopUp) {
3160
+ const details = autoTopUp ?? null;
3161
+ if (!details) {
3162
+ return;
2888
3163
  }
2889
- const message = "@hashgraph/sdk is required for ledger signing. Install it as a dependency to enable createPrivateKeySigner.";
2890
- throw new Error(message);
2891
- };
2892
- var buildSigner = (sdk, options) => {
2893
- const { AccountId, LedgerId, PrivateKey, SignerSignature } = sdk;
2894
- if (!options.privateKey) {
2895
- throw new Error("privateKey is required to create a ledger signer.");
3164
+ if (!details.accountId || !details.accountId.trim()) {
3165
+ throw new Error("autoTopUp.accountId is required");
2896
3166
  }
2897
- if (!options.accountId) {
2898
- throw new Error("accountId is required to create a ledger signer.");
3167
+ if (!details.privateKey || !details.privateKey.trim()) {
3168
+ throw new Error("autoTopUp.privateKey is required");
2899
3169
  }
2900
- const accountId = AccountId.fromString(options.accountId);
2901
- const privateKey = PrivateKey.fromString(options.privateKey);
2902
- const ledgerId = LedgerId.fromString(options.network);
2903
- return {
2904
- getLedgerId: () => ledgerId,
2905
- getAccountId: () => accountId,
2906
- getAccountKey: () => privateKey.publicKey,
2907
- getNetwork: () => ({}),
2908
- getMirrorNetwork: () => [],
2909
- sign: async (messages) => Promise.all(
2910
- messages.map(async (message) => {
2911
- const signature = await privateKey.sign(message);
2912
- return new SignerSignature({
2913
- publicKey: privateKey.publicKey,
2914
- signature,
2915
- accountId
2916
- });
2917
- })
2918
- ),
2919
- getAccountBalance: async () => {
2920
- throw unsupported("getAccountBalance");
2921
- },
2922
- getAccountInfo: async () => {
2923
- throw unsupported("getAccountInfo");
2924
- },
2925
- getAccountRecords: async () => {
2926
- throw unsupported("getAccountRecords");
2927
- },
2928
- signTransaction: async (_) => {
2929
- throw unsupported("signTransaction");
2930
- },
2931
- checkTransaction: async (_) => {
2932
- throw unsupported("checkTransaction");
2933
- },
2934
- populateTransaction: async (_) => {
2935
- throw unsupported("populateTransaction");
2936
- },
2937
- call: async (_request) => {
2938
- throw unsupported("call");
3170
+ for (let attempt = 0; attempt < 3; attempt += 1) {
3171
+ const quote = await getRegistrationQuote(client, payload);
3172
+ const shortfall = quote.shortfallCredits ?? 0;
3173
+ if (shortfall <= 0) {
3174
+ return;
2939
3175
  }
2940
- };
2941
- };
2942
- var createPrivateKeySigner = (options) => buildSigner(loadHashgraphSdk(), options);
2943
- var createPrivateKeySignerAsync = async (options) => buildSigner(await loadHashgraphSdkAsync(), options);
2944
-
2945
- // ../../src/services/registry-broker/client/ledger-auth.ts
2946
- async function loadViemAccount(privateKey) {
2947
- try {
2948
- const viem = await import("viem/accounts");
2949
- return viem.privateKeyToAccount(privateKey);
2950
- } catch (error) {
2951
- const err = new Error(
2952
- 'EVM ledger authentication requires the optional dependency "viem". Install it to use evmPrivateKey flows.'
2953
- );
2954
- err.cause = error;
2955
- throw err;
2956
- }
2957
- }
2958
- async function resolveLedgerAuthSignature(message, options) {
2959
- if (typeof options.sign === "function") {
2960
- const result = await options.sign(message);
2961
- if (!result || typeof result.signature !== "string" || result.signature.length === 0) {
2962
- throw new Error("Custom ledger signer failed to produce a signature.");
3176
+ const creditsToPurchase = resolveCreditsToPurchase(shortfall);
3177
+ if (creditsToPurchase <= 0) {
3178
+ return;
2963
3179
  }
2964
- return result;
3180
+ const creditsPerHbar = quote.creditsPerHbar ?? null;
3181
+ if (!creditsPerHbar || creditsPerHbar <= 0) {
3182
+ throw new Error("Unable to determine credits per HBAR for auto top-up");
3183
+ }
3184
+ const hbarAmount = calculateHbarAmount(creditsToPurchase, creditsPerHbar);
3185
+ await purchaseCreditsWithHbar(client, {
3186
+ accountId: details.accountId.trim(),
3187
+ privateKey: details.privateKey.trim(),
3188
+ hbarAmount,
3189
+ memo: details.memo ?? "Registry Broker auto top-up",
3190
+ metadata: {
3191
+ shortfallCredits: shortfall,
3192
+ requiredCredits: quote.requiredCredits,
3193
+ purchasedCredits: creditsToPurchase
3194
+ }
3195
+ });
2965
3196
  }
2966
- if (!options.signer || typeof options.signer.sign !== "function") {
2967
- throw new Error(
2968
- "Ledger authentication requires a Hedera Signer or custom sign function."
2969
- );
3197
+ const finalQuote = await getRegistrationQuote(client, payload);
3198
+ if ((finalQuote.shortfallCredits ?? 0) > 0) {
3199
+ throw new Error("Unable to purchase sufficient credits for registration");
2970
3200
  }
2971
- const payload = Buffer3.from(message, "utf8");
2972
- const signatures = await options.signer.sign([payload]);
2973
- const signatureEntry = signatures?.[0];
2974
- if (!signatureEntry) {
2975
- throw new Error("Signer did not return any signatures.");
3201
+ }
3202
+ async function resolveUaid(client, uaid) {
3203
+ const raw = await client.requestJson(
3204
+ `/resolve/${encodeURIComponent(uaid)}`,
3205
+ {
3206
+ method: "GET"
3207
+ }
3208
+ );
3209
+ return client.parseWithSchema(
3210
+ raw,
3211
+ resolveResponseSchema,
3212
+ "resolve UAID response"
3213
+ );
3214
+ }
3215
+ async function registerAgent(client, payload, options) {
3216
+ const autoTopUp = options?.autoTopUp ?? client.registrationAutoTopUp;
3217
+ if (!autoTopUp) {
3218
+ return performRegisterAgent(client, payload);
2976
3219
  }
2977
- let derivedPublicKey;
2978
- if (signatureEntry.publicKey) {
2979
- derivedPublicKey = signatureEntry.publicKey.toString();
2980
- } else if (typeof options.signer.getAccountKey === "function") {
2981
- const accountKey = await options.signer.getAccountKey();
2982
- if (accountKey && typeof accountKey.toString === "function") {
2983
- derivedPublicKey = accountKey.toString();
3220
+ await ensureCreditsForRegistration(client, payload, autoTopUp);
3221
+ let retried = false;
3222
+ while (true) {
3223
+ try {
3224
+ return await performRegisterAgent(client, payload);
3225
+ } catch (error) {
3226
+ const shortfall = client.extractInsufficientCreditsDetails(error);
3227
+ if (shortfall && !retried) {
3228
+ await ensureCreditsForRegistration(client, payload, autoTopUp);
3229
+ retried = true;
3230
+ continue;
3231
+ }
3232
+ throw error;
2984
3233
  }
2985
3234
  }
2986
- return {
2987
- signature: Buffer3.from(signatureEntry.signature).toString("base64"),
2988
- signatureKind: "raw",
2989
- publicKey: derivedPublicKey
2990
- };
2991
3235
  }
2992
- async function createLedgerChallenge(client, payload) {
2993
- const resolvedNetwork = canonicalizeLedgerNetwork(payload.network);
2994
- const network = resolvedNetwork.kind === "hedera" ? resolvedNetwork.hederaNetwork ?? resolvedNetwork.canonical : resolvedNetwork.canonical;
2995
- const raw = await client.requestJson("/auth/ledger/challenge", {
3236
+ async function getRegistrationQuote(client, payload) {
3237
+ const raw = await client.requestJson("/register/quote", {
2996
3238
  method: "POST",
2997
- headers: { "content-type": "application/json" },
2998
- body: {
2999
- accountId: payload.accountId,
3000
- network
3239
+ body: serialiseAgentRegistrationRequest(payload),
3240
+ headers: { "content-type": "application/json" }
3241
+ });
3242
+ return client.parseWithSchema(
3243
+ raw,
3244
+ registrationQuoteResponseSchema,
3245
+ "registration quote response"
3246
+ );
3247
+ }
3248
+ async function updateAgent(client, uaid, payload) {
3249
+ const raw = await client.requestJson(
3250
+ `/register/${encodeURIComponent(uaid)}`,
3251
+ {
3252
+ method: "PUT",
3253
+ body: serialiseAgentRegistrationRequest(payload),
3254
+ headers: { "content-type": "application/json" }
3001
3255
  }
3002
- });
3256
+ );
3003
3257
  return client.parseWithSchema(
3004
3258
  raw,
3005
- ledgerChallengeResponseSchema,
3006
- "ledger challenge response"
3259
+ registerAgentResponseSchema,
3260
+ "update agent response"
3007
3261
  );
3008
3262
  }
3009
- async function verifyLedgerChallenge(client, payload) {
3010
- const resolvedNetwork = canonicalizeLedgerNetwork(payload.network);
3011
- const network = resolvedNetwork.kind === "hedera" ? resolvedNetwork.hederaNetwork ?? resolvedNetwork.canonical : resolvedNetwork.canonical;
3012
- const body = {
3013
- challengeId: payload.challengeId,
3014
- accountId: payload.accountId,
3015
- network,
3016
- signature: payload.signature
3017
- };
3018
- if (payload.signatureKind) {
3019
- body.signatureKind = payload.signatureKind;
3263
+ async function getRegistrationProgress(client, attemptId) {
3264
+ const normalisedAttemptId = attemptId.trim();
3265
+ if (!normalisedAttemptId) {
3266
+ throw new Error("attemptId is required");
3020
3267
  }
3021
- if (payload.publicKey) {
3022
- body.publicKey = payload.publicKey;
3268
+ try {
3269
+ const raw = await client.requestJson(
3270
+ `/register/progress/${encodeURIComponent(normalisedAttemptId)}`,
3271
+ { method: "GET" }
3272
+ );
3273
+ const parsed = client.parseWithSchema(
3274
+ raw,
3275
+ registrationProgressResponseSchema,
3276
+ "registration progress response"
3277
+ );
3278
+ return parsed.progress;
3279
+ } catch (error) {
3280
+ if (error instanceof RegistryBrokerError && error.status === 404) {
3281
+ return null;
3282
+ }
3283
+ throw error;
3023
3284
  }
3024
- if (typeof payload.expiresInMinutes === "number") {
3025
- body.expiresInMinutes = payload.expiresInMinutes;
3285
+ }
3286
+ async function waitForRegistrationCompletion(client, attemptId, options = {}) {
3287
+ const normalisedAttemptId = attemptId.trim();
3288
+ if (!normalisedAttemptId) {
3289
+ throw new Error("attemptId is required");
3026
3290
  }
3027
- const raw = await client.requestJson("/auth/ledger/verify", {
3028
- method: "POST",
3029
- headers: { "content-type": "application/json" },
3030
- body
3031
- });
3032
- const result = client.parseWithSchema(
3033
- raw,
3034
- ledgerVerifyResponseSchema,
3035
- "ledger verification response"
3291
+ const interval = Math.max(
3292
+ 250,
3293
+ options.intervalMs ?? DEFAULT_PROGRESS_INTERVAL_MS
3036
3294
  );
3037
- client.setLedgerApiKey(result.key);
3038
- return result;
3039
- }
3040
- async function authenticateWithLedger(client, options) {
3041
- const challenge = await client.createLedgerChallenge({
3042
- accountId: options.accountId,
3043
- network: options.network
3044
- });
3045
- const signed = await resolveLedgerAuthSignature(challenge.message, options);
3046
- const verification = await client.verifyLedgerChallenge({
3047
- challengeId: challenge.challengeId,
3048
- accountId: options.accountId,
3049
- network: options.network,
3050
- signature: signed.signature,
3051
- signatureKind: signed.signatureKind,
3052
- publicKey: signed.publicKey,
3053
- expiresInMinutes: options.expiresInMinutes
3054
- });
3055
- return verification;
3056
- }
3057
- async function authenticateWithLedgerCredentials(client, options) {
3058
- const {
3059
- accountId,
3060
- network,
3061
- signer,
3062
- sign,
3063
- hederaPrivateKey,
3064
- evmPrivateKey,
3065
- expiresInMinutes,
3066
- setAccountHeader = true,
3067
- label,
3068
- logger
3069
- } = options;
3070
- const resolvedNetwork = canonicalizeLedgerNetwork(network);
3071
- const labelSuffix = label ? ` for ${label}` : "";
3072
- const networkPayload = resolvedNetwork.canonical;
3073
- const authOptions = {
3074
- accountId,
3075
- network: networkPayload,
3076
- expiresInMinutes
3077
- };
3078
- if (sign) {
3079
- authOptions.sign = sign;
3080
- } else if (signer) {
3081
- authOptions.signer = signer;
3082
- } else if (hederaPrivateKey) {
3083
- if (resolvedNetwork.kind !== "hedera" || !resolvedNetwork.hederaNetwork) {
3084
- throw new Error(
3085
- "hederaPrivateKey can only be used with hedera:mainnet or hedera:testnet networks."
3086
- );
3295
+ const timeoutMs = options.timeoutMs ?? DEFAULT_PROGRESS_TIMEOUT_MS;
3296
+ const throwOnFailure = options.throwOnFailure ?? true;
3297
+ const signal = options.signal;
3298
+ const startedAt = Date.now();
3299
+ while (true) {
3300
+ if (signal?.aborted) {
3301
+ throw createAbortError();
3087
3302
  }
3088
- authOptions.signer = await createPrivateKeySignerAsync({
3089
- accountId,
3090
- privateKey: hederaPrivateKey,
3091
- network: resolvedNetwork.hederaNetwork
3092
- });
3093
- } else if (evmPrivateKey) {
3094
- if (resolvedNetwork.kind !== "evm") {
3303
+ const progress = await client.getRegistrationProgress(normalisedAttemptId);
3304
+ if (progress) {
3305
+ options.onProgress?.(progress);
3306
+ if (progress.status === "completed") {
3307
+ return progress;
3308
+ }
3309
+ if (progress.status === "partial" || progress.status === "failed") {
3310
+ if (throwOnFailure) {
3311
+ throw new RegistryBrokerError(
3312
+ "Registration did not complete successfully",
3313
+ {
3314
+ status: 409,
3315
+ statusText: progress.status,
3316
+ body: progress
3317
+ }
3318
+ );
3319
+ }
3320
+ return progress;
3321
+ }
3322
+ }
3323
+ if (Date.now() - startedAt >= timeoutMs) {
3095
3324
  throw new Error(
3096
- "evmPrivateKey can only be used with CAIP-2 EVM networks (eip155:<chainId>)."
3325
+ `Registration progress polling timed out after ${timeoutMs}ms`
3097
3326
  );
3098
3327
  }
3099
- const formattedKey = evmPrivateKey.startsWith("0x") ? evmPrivateKey : `0x${evmPrivateKey}`;
3100
- const account = await loadViemAccount(formattedKey);
3101
- authOptions.sign = async (message) => ({
3102
- signature: await account.signMessage({ message }),
3103
- signatureKind: "evm",
3104
- publicKey: account.publicKey
3105
- });
3106
- } else {
3107
- throw new Error(
3108
- "Provide a signer, sign function, hederaPrivateKey, or evmPrivateKey to authenticate with the ledger."
3109
- );
3328
+ await client.delay(interval, signal);
3110
3329
  }
3111
- logger?.info?.(
3112
- `Authenticating ledger account ${accountId} (${resolvedNetwork.canonical})${labelSuffix}...`
3330
+ }
3331
+ async function validateUaid(client, uaid) {
3332
+ const raw = await client.requestJson(
3333
+ `/uaids/validate/${encodeURIComponent(uaid)}`,
3334
+ {
3335
+ method: "GET"
3336
+ }
3113
3337
  );
3114
- const verification = await client.authenticateWithLedger(authOptions);
3115
- if (setAccountHeader) {
3116
- client.setDefaultHeader("x-account-id", verification.accountId);
3117
- }
3118
- logger?.info?.(
3119
- `Ledger authentication complete${labelSuffix}. Issued key prefix: ${verification.apiKey.prefix}\u2026${verification.apiKey.lastFour}`
3338
+ return client.parseWithSchema(
3339
+ raw,
3340
+ uaidValidationResponseSchema,
3341
+ "UAID validation response"
3120
3342
  );
3121
- return verification;
3122
- }
3123
-
3124
- // ../../src/services/registry-broker/client/chat-history.ts
3125
- import { Buffer as Buffer4 } from "buffer";
3126
- function identitiesMatch(a, b) {
3127
- if (!a && !b) {
3128
- return true;
3129
- }
3130
- if (!a || !b) {
3131
- return false;
3132
- }
3133
- if (a.uaid && b.uaid && a.uaid.toLowerCase() === b.uaid.toLowerCase()) {
3134
- return true;
3135
- }
3136
- if (a.ledgerAccountId && b.ledgerAccountId && a.ledgerAccountId.toLowerCase() === b.ledgerAccountId.toLowerCase()) {
3137
- return true;
3138
- }
3139
- if (a.userId && b.userId && a.userId === b.userId) {
3140
- return true;
3141
- }
3142
- if (a.email && b.email && a.email.toLowerCase() === b.email.toLowerCase()) {
3143
- return true;
3144
- }
3145
- return false;
3146
3343
  }
3147
- async function fetchHistorySnapshot(conversationContexts, client, sessionId, options) {
3148
- if (!sessionId || sessionId.trim().length === 0) {
3149
- throw new Error("sessionId is required to fetch chat history");
3150
- }
3344
+ async function getUaidConnectionStatus(client, uaid) {
3151
3345
  const raw = await client.requestJson(
3152
- `/chat/session/${encodeURIComponent(sessionId)}/history`,
3346
+ `/uaids/connections/${encodeURIComponent(uaid)}/status`,
3153
3347
  {
3154
3348
  method: "GET"
3155
3349
  }
3156
3350
  );
3157
- const snapshot = client.parseWithSchema(
3351
+ return client.parseWithSchema(
3158
3352
  raw,
3159
- chatHistorySnapshotResponseSchema,
3160
- "chat history snapshot response"
3353
+ uaidConnectionStatusSchema,
3354
+ "UAID connection status"
3161
3355
  );
3162
- return attachDecryptedHistory(
3163
- conversationContexts,
3164
- client,
3165
- sessionId,
3166
- snapshot,
3167
- options
3356
+ }
3357
+ async function closeUaidConnection(client, uaid) {
3358
+ await client.request(`/uaids/connections/${encodeURIComponent(uaid)}`, {
3359
+ method: "DELETE"
3360
+ });
3361
+ }
3362
+ async function dashboardStats(client) {
3363
+ const raw = await client.requestJson("/dashboard/stats", {
3364
+ method: "GET"
3365
+ });
3366
+ return client.parseWithSchema(
3367
+ raw,
3368
+ dashboardStatsResponseSchema,
3369
+ "dashboard stats response"
3168
3370
  );
3169
3371
  }
3170
- function attachDecryptedHistory(conversationContexts, client, sessionId, snapshot, options) {
3171
- const shouldDecrypt = options?.decrypt !== void 0 ? options.decrypt : client.encryptionOptions?.autoDecryptHistory === true;
3172
- if (!shouldDecrypt) {
3173
- return snapshot;
3174
- }
3175
- const requiresContext = snapshot.history.some(
3176
- (entry) => Boolean(entry.cipherEnvelope)
3372
+
3373
+ // ../../src/services/registry-broker/client/verification.ts
3374
+ async function getVerificationStatus(client, uaid) {
3375
+ const raw = await client.requestJson(
3376
+ `/verification/status/${encodeURIComponent(uaid)}`,
3377
+ { method: "GET" }
3378
+ );
3379
+ return client.parseWithSchema(
3380
+ raw,
3381
+ verificationStatusResponseSchema,
3382
+ "verification status response"
3177
3383
  );
3178
- if (!requiresContext) {
3179
- return {
3180
- ...snapshot,
3181
- decryptedHistory: snapshot.history.map((entry) => ({
3182
- entry,
3183
- plaintext: entry.content
3184
- }))
3185
- };
3186
- }
3187
- const context = resolveDecryptionContext(
3188
- conversationContexts,
3189
- client,
3190
- sessionId,
3191
- options
3384
+ }
3385
+ async function createVerificationChallenge(client, uaid) {
3386
+ const raw = await client.requestJson("/verification/challenge", {
3387
+ method: "POST",
3388
+ headers: { "content-type": "application/json" },
3389
+ body: { uaid }
3390
+ });
3391
+ return client.parseWithSchema(
3392
+ raw,
3393
+ verificationChallengeResponseSchema,
3394
+ "verification challenge response"
3192
3395
  );
3193
- if (!context) {
3194
- throw new Error(
3195
- "Unable to decrypt chat history: encryption context unavailable"
3196
- );
3197
- }
3198
- const decryptedHistory = snapshot.history.map((entry) => ({
3199
- entry,
3200
- plaintext: decryptHistoryEntryFromContext(client, entry, context)
3201
- }));
3202
- return { ...snapshot, decryptedHistory };
3203
3396
  }
3204
- function registerConversationContextForEncryption(conversationContexts, context) {
3205
- const normalized = {
3206
- sessionId: context.sessionId,
3207
- sharedSecret: Buffer4.from(context.sharedSecret),
3208
- identity: context.identity ? { ...context.identity } : void 0
3209
- };
3210
- const entries = conversationContexts.get(context.sessionId) ?? [];
3211
- const existingIndex = entries.findIndex(
3212
- (existing) => identitiesMatch(existing.identity, normalized.identity)
3397
+ async function getVerificationChallenge(client, challengeId) {
3398
+ const raw = await client.requestJson(
3399
+ `/verification/challenge/${encodeURIComponent(challengeId)}`,
3400
+ { method: "GET" }
3401
+ );
3402
+ return client.parseWithSchema(
3403
+ raw,
3404
+ verificationChallengeDetailsResponseSchema,
3405
+ "verification challenge details response"
3213
3406
  );
3214
- if (existingIndex >= 0) {
3215
- entries[existingIndex] = normalized;
3216
- } else {
3217
- entries.push(normalized);
3218
- }
3219
- conversationContexts.set(context.sessionId, entries);
3220
3407
  }
3221
- function resolveDecryptionContext(conversationContexts, client, sessionId, options) {
3222
- if (options?.sharedSecret) {
3223
- return {
3224
- sessionId,
3225
- sharedSecret: client.normalizeSharedSecret(options.sharedSecret),
3226
- identity: options.identity
3227
- };
3228
- }
3229
- const contexts = conversationContexts.get(sessionId);
3230
- if (!contexts || contexts.length === 0) {
3231
- return null;
3232
- }
3233
- if (options?.identity) {
3234
- const match = contexts.find(
3235
- (context) => identitiesMatch(context.identity, options.identity)
3236
- );
3237
- if (match) {
3238
- return match;
3408
+ async function verifyVerificationChallenge(client, params) {
3409
+ const raw = await client.requestJson("/verification/verify", {
3410
+ method: "POST",
3411
+ headers: { "content-type": "application/json" },
3412
+ body: {
3413
+ challengeId: params.challengeId,
3414
+ method: params.method ?? "moltbook-post"
3239
3415
  }
3240
- }
3241
- return contexts[0];
3416
+ });
3417
+ return client.parseWithSchema(
3418
+ raw,
3419
+ verificationVerifyResponseSchema,
3420
+ "verification verify response"
3421
+ );
3242
3422
  }
3243
- function decryptHistoryEntryFromContext(client, entry, context) {
3244
- const envelope = entry.cipherEnvelope;
3245
- if (!envelope) {
3246
- return entry.content;
3247
- }
3248
- const secret = Buffer4.from(context.sharedSecret);
3249
- try {
3250
- return client.encryption.decryptCipherEnvelope({
3251
- envelope,
3252
- sharedSecret: secret
3253
- });
3254
- } catch (_error) {
3255
- return null;
3256
- }
3423
+ async function getVerificationOwnership(client, uaid) {
3424
+ const raw = await client.requestJson(
3425
+ `/verification/ownership/${encodeURIComponent(uaid)}`,
3426
+ { method: "GET" }
3427
+ );
3428
+ return client.parseWithSchema(
3429
+ raw,
3430
+ verificationOwnershipResponseSchema,
3431
+ "verification ownership response"
3432
+ );
3257
3433
  }
3258
-
3259
- // ../../src/services/registry-broker/client/encrypted-chat-manager.ts
3260
- var EncryptionUnavailableError = class extends Error {
3261
- constructor(sessionId, summary) {
3262
- super("Encryption is not enabled for this session");
3263
- this.sessionId = sessionId;
3264
- this.summary = summary;
3265
- }
3266
- };
3267
- var EncryptedChatManager = class {
3268
- constructor(client) {
3269
- this.client = client;
3270
- }
3271
- registerConversationContext(context) {
3272
- this.client.registerConversationContextForEncryption(context);
3273
- }
3274
- async startSession(options) {
3275
- await this.client.encryptionReady();
3276
- const session = await this.client.chat.createSession({
3277
- uaid: options.uaid,
3278
- senderUaid: options.senderUaid,
3279
- encryptionRequested: true,
3280
- historyTtlSeconds: options.historyTtlSeconds,
3281
- auth: options.auth
3282
- });
3283
- options.onSessionCreated?.(session.sessionId);
3284
- const summary = session.encryption;
3285
- if (!summary?.enabled) {
3286
- throw new EncryptionUnavailableError(
3287
- session.sessionId,
3288
- session.encryption ?? null
3289
- );
3290
- }
3291
- const handle = await this.establishRequesterContext({
3292
- sessionId: session.sessionId,
3293
- summary,
3294
- senderUaid: options.senderUaid,
3295
- handshakeTimeoutMs: options.handshakeTimeoutMs,
3296
- pollIntervalMs: options.pollIntervalMs
3297
- });
3298
- return handle;
3299
- }
3300
- async acceptSession(options) {
3301
- await this.client.encryptionReady();
3302
- const summary = await this.waitForEncryptionSummary(
3303
- options.sessionId,
3304
- options.handshakeTimeoutMs,
3305
- options.pollIntervalMs
3306
- );
3307
- const handle = await this.establishResponderContext({
3308
- sessionId: options.sessionId,
3309
- summary,
3310
- responderUaid: options.responderUaid,
3311
- handshakeTimeoutMs: options.handshakeTimeoutMs,
3312
- pollIntervalMs: options.pollIntervalMs
3313
- });
3314
- return handle;
3315
- }
3316
- async establishRequesterContext(params) {
3317
- const keyPair = this.client.encryption.generateEphemeralKeyPair();
3318
- await this.client.chat.submitEncryptionHandshake(params.sessionId, {
3319
- role: "requester",
3320
- keyType: "secp256k1",
3321
- ephemeralPublicKey: keyPair.publicKey,
3322
- uaid: params.senderUaid ?? params.summary.requester?.uaid ?? void 0
3323
- });
3324
- const { summary, record } = await this.waitForHandshakeCompletion(
3325
- params.sessionId,
3326
- params.handshakeTimeoutMs,
3327
- params.pollIntervalMs
3328
- );
3329
- const responderKey = record.responder?.ephemeralPublicKey;
3330
- if (!responderKey) {
3331
- throw new Error("Responder handshake was not completed in time");
3332
- }
3333
- const sharedSecret = this.client.encryption.deriveSharedSecret({
3334
- privateKey: keyPair.privateKey,
3335
- peerPublicKey: responderKey
3336
- }).subarray();
3337
- const recipients = this.buildRecipients(summary);
3338
- return this.createHandle({
3339
- sessionId: params.sessionId,
3340
- sharedSecret,
3341
- summary,
3342
- recipients,
3343
- identity: summary.requester ?? void 0
3344
- });
3345
- }
3346
- async establishResponderContext(params) {
3347
- const keyPair = this.client.encryption.generateEphemeralKeyPair();
3348
- await this.client.chat.submitEncryptionHandshake(params.sessionId, {
3349
- role: "responder",
3350
- keyType: "secp256k1",
3351
- ephemeralPublicKey: keyPair.publicKey,
3352
- uaid: params.responderUaid ?? params.summary.responder?.uaid ?? void 0
3353
- });
3354
- const { summary, record } = await this.waitForHandshakeCompletion(
3355
- params.sessionId,
3356
- params.handshakeTimeoutMs,
3357
- params.pollIntervalMs
3358
- );
3359
- const requesterKey = record.requester?.ephemeralPublicKey;
3360
- if (!requesterKey) {
3361
- throw new Error("Requester handshake was not detected in time");
3434
+ async function verifySenderOwnership(client, uaid) {
3435
+ const raw = await client.requestJson(
3436
+ "/verification/verify-sender",
3437
+ {
3438
+ method: "POST",
3439
+ headers: { "content-type": "application/json" },
3440
+ body: { uaid }
3362
3441
  }
3363
- const sharedSecret = this.client.encryption.deriveSharedSecret({
3364
- privateKey: keyPair.privateKey,
3365
- peerPublicKey: requesterKey
3366
- }).subarray();
3367
- const recipients = this.buildRecipients(summary);
3368
- return this.createHandle({
3369
- sessionId: params.sessionId,
3370
- sharedSecret,
3371
- summary,
3372
- recipients,
3373
- identity: summary.responder ?? void 0
3374
- });
3375
- }
3376
- async waitForHandshakeCompletion(sessionId, timeoutMs = 3e4, pollIntervalMs = 1e3) {
3377
- const deadline = Date.now() + timeoutMs;
3378
- while (true) {
3379
- const status = await this.client.chat.getEncryptionStatus(sessionId);
3380
- const summary = status.encryption;
3381
- const record = summary?.handshake;
3382
- if (summary && record && record.status === "complete") {
3383
- return { summary, record };
3384
- }
3385
- if (Date.now() >= deadline) {
3386
- throw new Error("Timed out waiting for encrypted handshake completion");
3387
- }
3388
- await this.delay(pollIntervalMs);
3442
+ );
3443
+ return client.parseWithSchema(
3444
+ raw,
3445
+ verificationVerifySenderResponseSchema,
3446
+ "verification sender response"
3447
+ );
3448
+ }
3449
+ async function verifyUaidDnsTxt(client, payload) {
3450
+ const raw = await client.requestJson("/verification/dns/verify", {
3451
+ method: "POST",
3452
+ headers: { "content-type": "application/json" },
3453
+ body: {
3454
+ uaid: payload.uaid,
3455
+ ...payload.persist !== void 0 ? { persist: payload.persist } : {}
3389
3456
  }
3457
+ });
3458
+ return client.parseWithSchema(
3459
+ raw,
3460
+ verificationDnsStatusResponseSchema,
3461
+ "verification dns verify response"
3462
+ );
3463
+ }
3464
+ async function getVerificationDnsStatus(client, uaid, query) {
3465
+ const params = new URLSearchParams();
3466
+ if (query?.refresh !== void 0) {
3467
+ params.set("refresh", String(query.refresh));
3390
3468
  }
3391
- async waitForEncryptionSummary(sessionId, _timeoutMs = 3e4, _pollIntervalMs = 1e3) {
3392
- const status = await this.client.chat.getEncryptionStatus(sessionId);
3393
- if (!status.encryption?.enabled) {
3394
- throw new EncryptionUnavailableError(
3395
- sessionId,
3396
- status.encryption ?? null
3397
- );
3398
- }
3399
- return status.encryption;
3469
+ if (query?.persist !== void 0) {
3470
+ params.set("persist", String(query.persist));
3400
3471
  }
3401
- buildRecipients(summary) {
3402
- const candidates = [summary.requester, summary.responder].filter(Boolean);
3403
- const normalized = candidates.map((candidate) => {
3404
- if (!candidate) {
3405
- return null;
3406
- }
3407
- const recipient = {};
3408
- if (candidate.uaid) {
3409
- recipient.uaid = candidate.uaid;
3410
- }
3411
- if (candidate.ledgerAccountId) {
3412
- recipient.ledgerAccountId = candidate.ledgerAccountId;
3413
- }
3414
- if (candidate.userId) {
3415
- recipient.userId = candidate.userId;
3416
- }
3417
- if (candidate.email) {
3418
- recipient.email = candidate.email;
3472
+ const queryString = params.toString();
3473
+ const path = `/verification/dns/status/${encodeURIComponent(uaid)}${queryString ? `?${queryString}` : ""}`;
3474
+ const raw = await client.requestJson(path, {
3475
+ method: "GET"
3476
+ });
3477
+ return client.parseWithSchema(
3478
+ raw,
3479
+ verificationDnsStatusResponseSchema,
3480
+ "verification dns status response"
3481
+ );
3482
+ }
3483
+ async function getRegisterStatus(client, uaid) {
3484
+ const raw = await client.requestJson(
3485
+ `/register/status/${encodeURIComponent(uaid)}`,
3486
+ { method: "GET" }
3487
+ );
3488
+ return client.parseWithSchema(
3489
+ raw,
3490
+ registerStatusResponseSchema,
3491
+ "register status response"
3492
+ );
3493
+ }
3494
+ async function registerOwnedMoltbookAgent(client, uaid, request) {
3495
+ const raw = await client.requestJson(
3496
+ `/register/${encodeURIComponent(uaid)}`,
3497
+ {
3498
+ method: "PUT",
3499
+ headers: { "content-type": "application/json" },
3500
+ body: {
3501
+ registered: request.registered ?? true,
3502
+ ...request.name ? { name: request.name } : {},
3503
+ ...request.description ? { description: request.description } : {},
3504
+ ...request.endpoint ? { endpoint: request.endpoint } : {},
3505
+ ...request.metadata ? { metadata: request.metadata } : {}
3419
3506
  }
3420
- return recipient;
3421
- }).filter(
3422
- (entry) => Boolean(
3423
- entry?.uaid || entry?.ledgerAccountId || entry?.userId || entry?.email
3424
- )
3425
- );
3426
- if (normalized.length > 0) {
3427
- return normalized;
3428
- }
3429
- if (summary.responder?.uaid) {
3430
- return [{ uaid: summary.responder.uaid }];
3431
3507
  }
3432
- return [];
3508
+ );
3509
+ return client.parseWithSchema(
3510
+ raw,
3511
+ moltbookOwnerRegistrationUpdateResponseSchema,
3512
+ "moltbook owner registration update response"
3513
+ );
3514
+ }
3515
+
3516
+ // ../../src/services/registry-broker/client/ledger-auth.ts
3517
+ import { Buffer as Buffer4 } from "buffer";
3518
+
3519
+ // ../../src/services/registry-broker/ledger-network.ts
3520
+ var normalise = (value) => value.trim().toLowerCase();
3521
+ var HEDERA_NETWORK_ALIASES = /* @__PURE__ */ new Map([
3522
+ ["hedera:mainnet", { canonical: "hedera:mainnet", hederaNetwork: "mainnet" }],
3523
+ ["mainnet", { canonical: "hedera:mainnet", hederaNetwork: "mainnet" }],
3524
+ ["hedera-mainnet", { canonical: "hedera:mainnet", hederaNetwork: "mainnet" }],
3525
+ ["hedera_mainnet", { canonical: "hedera:mainnet", hederaNetwork: "mainnet" }],
3526
+ ["hedera:testnet", { canonical: "hedera:testnet", hederaNetwork: "testnet" }],
3527
+ ["testnet", { canonical: "hedera:testnet", hederaNetwork: "testnet" }],
3528
+ ["hedera-testnet", { canonical: "hedera:testnet", hederaNetwork: "testnet" }],
3529
+ ["hedera_testnet", { canonical: "hedera:testnet", hederaNetwork: "testnet" }]
3530
+ ]);
3531
+ var EVM_NETWORK_CHAIN_IDS = {
3532
+ abstract: 2741,
3533
+ "abstract-testnet": 11124,
3534
+ base: 8453,
3535
+ "base-sepolia": 84532,
3536
+ avalanche: 43114,
3537
+ "avalanche-fuji": 43113,
3538
+ iotex: 4689,
3539
+ sei: 1329,
3540
+ "sei-testnet": 1328,
3541
+ polygon: 137,
3542
+ "polygon-amoy": 80002,
3543
+ peaq: 3338
3544
+ };
3545
+ var CHAIN_ID_TO_ALIAS = new Map(
3546
+ Object.entries(EVM_NETWORK_CHAIN_IDS).map(([alias, id]) => [id, alias])
3547
+ );
3548
+ var parseChainId = (value) => {
3549
+ if (/^eip155:\d+$/i.test(value)) {
3550
+ return Number.parseInt(value.split(":")[1], 10);
3433
3551
  }
3434
- createHandle(context) {
3435
- const sharedSecret = context.sharedSecret;
3436
- const uaid = context.summary.requester?.uaid ?? context.summary.responder?.uaid ?? context.identity?.uaid;
3437
- const decryptHistoryEntry = (entry) => this.decryptEntry(entry, context.identity, sharedSecret);
3438
- const fetchHistory = async (options) => {
3439
- const snapshot = await this.client.fetchHistorySnapshot(
3440
- context.sessionId,
3441
- options
3442
- );
3443
- if (snapshot.decryptedHistory) {
3444
- return snapshot.decryptedHistory;
3445
- }
3446
- return snapshot.history.map((entry) => ({
3447
- entry,
3448
- plaintext: decryptHistoryEntry(entry)
3449
- }));
3450
- };
3451
- const handle = {
3452
- sessionId: context.sessionId,
3453
- mode: "encrypted",
3454
- summary: context.summary,
3455
- send: async (options) => {
3456
- const recipients = options.recipients ?? context.recipients;
3457
- return this.client.chat.sendMessage({
3458
- sessionId: context.sessionId,
3459
- message: options.message ?? "[ciphertext omitted]",
3460
- streaming: options.streaming,
3461
- auth: options.auth,
3462
- uaid,
3463
- encryption: {
3464
- plaintext: options.plaintext,
3465
- sharedSecret: Buffer.from(sharedSecret),
3466
- recipients
3467
- }
3468
- });
3469
- },
3470
- decryptHistoryEntry,
3471
- fetchHistory
3472
- };
3473
- this.registerConversationContext({
3474
- sessionId: context.sessionId,
3475
- sharedSecret,
3476
- identity: context.identity
3477
- });
3478
- return handle;
3552
+ if (/^\d+$/.test(value)) {
3553
+ return Number.parseInt(value, 10);
3479
3554
  }
3480
- decryptEntry(entry, identity, fallbackSecret) {
3481
- const envelope = entry.cipherEnvelope;
3482
- if (!envelope) {
3483
- return null;
3484
- }
3485
- const secret = Buffer.from(fallbackSecret);
3486
- try {
3487
- return this.client.encryption.decryptCipherEnvelope({
3488
- envelope,
3489
- sharedSecret: secret
3490
- });
3491
- } catch (_error) {
3492
- return null;
3555
+ return void 0;
3556
+ };
3557
+ var normaliseEvmNetwork = (value) => {
3558
+ const trimmed = normalise(value);
3559
+ let chainId = parseChainId(trimmed);
3560
+ let alias;
3561
+ if (chainId === void 0) {
3562
+ const mapped = EVM_NETWORK_CHAIN_IDS[trimmed];
3563
+ if (mapped !== void 0) {
3564
+ chainId = mapped;
3565
+ alias = trimmed;
3493
3566
  }
3567
+ } else if (CHAIN_ID_TO_ALIAS.has(chainId)) {
3568
+ alias = CHAIN_ID_TO_ALIAS.get(chainId);
3494
3569
  }
3495
- recipientMatches(candidate, target) {
3496
- if (target.uaid && candidate.uaid?.toLowerCase() === target.uaid.toLowerCase()) {
3497
- return true;
3498
- }
3499
- if (target.ledgerAccountId && candidate.ledgerAccountId?.toLowerCase() === target.ledgerAccountId.toLowerCase()) {
3500
- return true;
3501
- }
3502
- if (target.userId && candidate.userId === target.userId) {
3503
- return true;
3504
- }
3505
- if (target.email && candidate.email?.toLowerCase() === target.email.toLowerCase()) {
3506
- return true;
3507
- }
3508
- return false;
3570
+ if (chainId === void 0) {
3571
+ throw new Error(
3572
+ 'Unsupported EVM ledger network. Provide an alias like "base-sepolia" or a canonical eip155:<chainId> string.'
3573
+ );
3509
3574
  }
3510
- async delay(ms) {
3511
- if (ms <= 0) {
3512
- return;
3513
- }
3514
- await new Promise((resolve2) => setTimeout(resolve2, ms));
3575
+ return {
3576
+ canonical: `eip155:${chainId}`,
3577
+ kind: "evm",
3578
+ chainId,
3579
+ legacyName: alias
3580
+ };
3581
+ };
3582
+ var normaliseHederaNetwork = (value) => {
3583
+ const trimmed = normalise(value);
3584
+ const mapping = HEDERA_NETWORK_ALIASES.get(trimmed);
3585
+ if (!mapping) {
3586
+ throw new Error(
3587
+ 'Unsupported Hedera network. Use hedera:mainnet or hedera:testnet (legacy "mainnet"/"testnet" also accepted).'
3588
+ );
3589
+ }
3590
+ return {
3591
+ canonical: mapping.canonical,
3592
+ kind: "hedera",
3593
+ hederaNetwork: mapping.hederaNetwork
3594
+ };
3595
+ };
3596
+ var canonicalizeLedgerNetwork = (network) => {
3597
+ if (typeof network !== "string" || network.trim().length === 0) {
3598
+ throw new Error("Ledger network is required.");
3599
+ }
3600
+ const trimmed = normalise(network);
3601
+ if (trimmed.startsWith("hedera:") || trimmed.includes("hedera-") || trimmed.includes("hedera_") || trimmed === "mainnet" || trimmed === "testnet") {
3602
+ return normaliseHederaNetwork(trimmed);
3515
3603
  }
3604
+ return normaliseEvmNetwork(trimmed);
3516
3605
  };
3517
3606
 
3518
- // ../../src/services/registry-broker/client/chat.ts
3519
- function createChatApi(client, encryptedManager) {
3520
- return {
3521
- start: (options) => client.startChat(options),
3522
- createSession: (payload) => client.createSession(payload),
3523
- sendMessage: (payload) => client.sendMessage(payload),
3524
- endSession: (sessionId) => client.endSession(sessionId),
3525
- getHistory: (sessionId, options) => client.fetchHistorySnapshot(sessionId, options),
3526
- compactHistory: (payload) => client.compactHistory(payload),
3527
- getEncryptionStatus: (sessionId) => client.fetchEncryptionStatus(sessionId),
3528
- submitEncryptionHandshake: (sessionId, payload) => client.postEncryptionHandshake(sessionId, payload),
3529
- startConversation: (options) => client.startConversation(options),
3530
- acceptConversation: (options) => client.acceptConversation(options),
3531
- createEncryptedSession: (options) => encryptedManager.startSession(options),
3532
- acceptEncryptedSession: (options) => encryptedManager.acceptSession(options)
3533
- };
3534
- }
3535
- async function createSession(client, payload, allowHistoryAutoTopUp = true) {
3536
- const body = {};
3537
- if ("uaid" in payload && payload.uaid) {
3538
- body.uaid = payload.uaid;
3607
+ // ../../src/services/registry-broker/private-key-signer.ts
3608
+ var unsupported = (method) => new Error(`${method} is not supported by the in-memory signer`);
3609
+ var cachedSdk = null;
3610
+ var loadHashgraphSdk = () => {
3611
+ if (cachedSdk) {
3612
+ return cachedSdk;
3539
3613
  }
3540
- if ("agentUrl" in payload && payload.agentUrl) {
3541
- body.agentUrl = payload.agentUrl;
3614
+ const resolved = optionalImportSync("@hashgraph/sdk");
3615
+ if (resolved) {
3616
+ cachedSdk = resolved;
3617
+ return resolved;
3542
3618
  }
3543
- if (payload.auth) {
3544
- body.auth = serialiseAuthConfig(payload.auth);
3619
+ const message = "@hashgraph/sdk is required for ledger signing. Install it as a dependency to enable createPrivateKeySigner.";
3620
+ throw new Error(message);
3621
+ };
3622
+ var loadHashgraphSdkAsync = async () => {
3623
+ if (cachedSdk) {
3624
+ return cachedSdk;
3545
3625
  }
3546
- if (payload.historyTtlSeconds !== void 0) {
3547
- body.historyTtlSeconds = payload.historyTtlSeconds;
3626
+ const resolved = await optionalImport("@hashgraph/sdk");
3627
+ if (resolved) {
3628
+ cachedSdk = resolved;
3629
+ return resolved;
3548
3630
  }
3549
- if (payload.encryptionRequested !== void 0) {
3550
- body.encryptionRequested = payload.encryptionRequested;
3631
+ const message = "@hashgraph/sdk is required for ledger signing. Install it as a dependency to enable createPrivateKeySigner.";
3632
+ throw new Error(message);
3633
+ };
3634
+ var buildSigner = (sdk, options) => {
3635
+ const { AccountId, LedgerId, PrivateKey, SignerSignature } = sdk;
3636
+ if (!options.privateKey) {
3637
+ throw new Error("privateKey is required to create a ledger signer.");
3551
3638
  }
3552
- if (payload.senderUaid) {
3553
- body.senderUaid = payload.senderUaid;
3639
+ if (!options.accountId) {
3640
+ throw new Error("accountId is required to create a ledger signer.");
3554
3641
  }
3642
+ const accountId = AccountId.fromString(options.accountId);
3643
+ const privateKey = PrivateKey.fromString(options.privateKey);
3644
+ const ledgerId = LedgerId.fromString(options.network);
3645
+ return {
3646
+ getLedgerId: () => ledgerId,
3647
+ getAccountId: () => accountId,
3648
+ getAccountKey: () => privateKey.publicKey,
3649
+ getNetwork: () => ({}),
3650
+ getMirrorNetwork: () => [],
3651
+ sign: async (messages) => Promise.all(
3652
+ messages.map(async (message) => {
3653
+ const signature = await privateKey.sign(message);
3654
+ return new SignerSignature({
3655
+ publicKey: privateKey.publicKey,
3656
+ signature,
3657
+ accountId
3658
+ });
3659
+ })
3660
+ ),
3661
+ getAccountBalance: async () => {
3662
+ throw unsupported("getAccountBalance");
3663
+ },
3664
+ getAccountInfo: async () => {
3665
+ throw unsupported("getAccountInfo");
3666
+ },
3667
+ getAccountRecords: async () => {
3668
+ throw unsupported("getAccountRecords");
3669
+ },
3670
+ signTransaction: async (_) => {
3671
+ throw unsupported("signTransaction");
3672
+ },
3673
+ checkTransaction: async (_) => {
3674
+ throw unsupported("checkTransaction");
3675
+ },
3676
+ populateTransaction: async (_) => {
3677
+ throw unsupported("populateTransaction");
3678
+ },
3679
+ call: async (_request) => {
3680
+ throw unsupported("call");
3681
+ }
3682
+ };
3683
+ };
3684
+ var createPrivateKeySigner = (options) => buildSigner(loadHashgraphSdk(), options);
3685
+ var createPrivateKeySignerAsync = async (options) => buildSigner(await loadHashgraphSdkAsync(), options);
3686
+
3687
+ // ../../src/services/registry-broker/client/ledger-auth.ts
3688
+ async function loadViemAccount(privateKey) {
3555
3689
  try {
3556
- const raw = await client.requestJson("/chat/session", {
3557
- method: "POST",
3558
- body,
3559
- headers: { "content-type": "application/json" }
3560
- });
3561
- return client.parseWithSchema(
3562
- raw,
3563
- createSessionResponseSchema,
3564
- "chat session response"
3565
- );
3690
+ const viem = await import("viem/accounts");
3691
+ return viem.privateKeyToAccount(privateKey);
3566
3692
  } catch (error) {
3567
- const maybeError = error instanceof Error ? error : null;
3568
- if (allowHistoryAutoTopUp && client.shouldAutoTopUpHistory(payload, maybeError)) {
3569
- await client.executeHistoryAutoTopUp("chat.session");
3570
- return createSession(client, payload, false);
3571
- }
3572
- throw error;
3573
- }
3574
- }
3575
- async function startChat(client, encryptedManager, options) {
3576
- if ("uaid" in options && options.uaid) {
3577
- return startConversation(client, encryptedManager, {
3578
- uaid: options.uaid,
3579
- senderUaid: options.senderUaid,
3580
- historyTtlSeconds: options.historyTtlSeconds,
3581
- auth: options.auth,
3582
- encryption: options.encryption,
3583
- onSessionCreated: options.onSessionCreated
3584
- });
3585
- }
3586
- if ("agentUrl" in options && options.agentUrl) {
3587
- const session = await createSession(client, {
3588
- agentUrl: options.agentUrl,
3589
- auth: options.auth,
3590
- historyTtlSeconds: options.historyTtlSeconds,
3591
- senderUaid: options.senderUaid
3592
- });
3593
- options.onSessionCreated?.(session.sessionId);
3594
- return createPlaintextConversationHandle(
3595
- client,
3596
- session.sessionId,
3597
- session.encryption ?? null,
3598
- options.auth,
3599
- { agentUrl: options.agentUrl, uaid: options.uaid }
3693
+ const err = new Error(
3694
+ 'EVM ledger authentication requires the optional dependency "viem". Install it to use evmPrivateKey flows.'
3600
3695
  );
3696
+ err.cause = error;
3697
+ throw err;
3601
3698
  }
3602
- throw new Error("startChat requires either uaid or agentUrl");
3603
3699
  }
3604
- async function startConversation(client, encryptedManager, options) {
3605
- const preference = options.encryption?.preference ?? "preferred";
3606
- const requestEncryption = preference !== "disabled";
3607
- if (!requestEncryption) {
3608
- const session = await createSession(client, {
3609
- uaid: options.uaid,
3610
- auth: options.auth,
3611
- historyTtlSeconds: options.historyTtlSeconds,
3612
- senderUaid: options.senderUaid,
3613
- encryptionRequested: false
3614
- });
3615
- options.onSessionCreated?.(session.sessionId);
3616
- return createPlaintextConversationHandle(
3617
- client,
3618
- session.sessionId,
3619
- session.encryption ?? null,
3620
- options.auth,
3621
- { uaid: options.uaid }
3622
- );
3623
- }
3624
- try {
3625
- const handle = await encryptedManager.startSession({
3626
- uaid: options.uaid,
3627
- senderUaid: options.senderUaid,
3628
- historyTtlSeconds: options.historyTtlSeconds,
3629
- handshakeTimeoutMs: options.encryption?.handshakeTimeoutMs,
3630
- pollIntervalMs: options.encryption?.pollIntervalMs,
3631
- onSessionCreated: (sessionId) => {
3632
- options.onSessionCreated?.(sessionId);
3633
- },
3634
- auth: options.auth
3635
- });
3636
- return handle;
3637
- } catch (error) {
3638
- if (error instanceof EncryptionUnavailableError) {
3639
- if (preference === "required") {
3640
- throw error;
3641
- }
3642
- return createPlaintextConversationHandle(
3643
- client,
3644
- error.sessionId,
3645
- error.summary ?? null,
3646
- options.auth,
3647
- { uaid: options.uaid }
3648
- );
3700
+ async function resolveLedgerAuthSignature(message, options) {
3701
+ if (typeof options.sign === "function") {
3702
+ const result = await options.sign(message);
3703
+ if (!result || typeof result.signature !== "string" || result.signature.length === 0) {
3704
+ throw new Error("Custom ledger signer failed to produce a signature.");
3649
3705
  }
3650
- throw error;
3706
+ return result;
3651
3707
  }
3652
- }
3653
- async function acceptConversation(client, encryptedManager, options) {
3654
- const preference = options.encryption?.preference ?? "preferred";
3655
- if (preference === "disabled") {
3656
- return createPlaintextConversationHandle(client, options.sessionId, null);
3708
+ if (!options.signer || typeof options.signer.sign !== "function") {
3709
+ throw new Error(
3710
+ "Ledger authentication requires a Hedera Signer or custom sign function."
3711
+ );
3657
3712
  }
3658
- try {
3659
- const handle = await encryptedManager.acceptSession({
3660
- sessionId: options.sessionId,
3661
- responderUaid: options.responderUaid,
3662
- handshakeTimeoutMs: options.encryption?.handshakeTimeoutMs,
3663
- pollIntervalMs: options.encryption?.pollIntervalMs
3664
- });
3665
- return handle;
3666
- } catch (error) {
3667
- if (error instanceof EncryptionUnavailableError && preference !== "required") {
3668
- return createPlaintextConversationHandle(
3669
- client,
3670
- options.sessionId,
3671
- null,
3672
- void 0,
3673
- { uaid: options.responderUaid }
3674
- );
3675
- }
3676
- throw error;
3713
+ const payload = Buffer4.from(message, "utf8");
3714
+ const signatures = await options.signer.sign([payload]);
3715
+ const signatureEntry = signatures?.[0];
3716
+ if (!signatureEntry) {
3717
+ throw new Error("Signer did not return any signatures.");
3677
3718
  }
3678
- }
3679
- function createPlaintextConversationHandle(client, sessionId, summary, defaultAuth, context) {
3680
- const uaid = context?.uaid?.trim();
3681
- const agentUrl = context?.agentUrl?.trim();
3682
- const fetchHistory = async (options) => {
3683
- const snapshot = await client.fetchHistorySnapshot(sessionId, options);
3684
- if (snapshot.decryptedHistory) {
3685
- return snapshot.decryptedHistory;
3719
+ let derivedPublicKey;
3720
+ if (signatureEntry.publicKey) {
3721
+ derivedPublicKey = signatureEntry.publicKey.toString();
3722
+ } else if (typeof options.signer.getAccountKey === "function") {
3723
+ const accountKey = await options.signer.getAccountKey();
3724
+ if (accountKey && typeof accountKey.toString === "function") {
3725
+ derivedPublicKey = accountKey.toString();
3686
3726
  }
3687
- return snapshot.history.map((entry) => ({
3688
- entry,
3689
- plaintext: entry.content
3690
- }));
3691
- };
3727
+ }
3692
3728
  return {
3693
- sessionId,
3694
- mode: "plaintext",
3695
- summary: summary ?? null,
3696
- send: async (options) => {
3697
- const plaintext = options.plaintext;
3698
- if (!plaintext || plaintext.trim().length === 0) {
3699
- throw new Error("plaintext is required for chat messages");
3700
- }
3701
- const message = options.message ?? plaintext;
3702
- return sendMessage(client, {
3703
- sessionId,
3704
- message,
3705
- streaming: options.streaming,
3706
- auth: options.auth ?? defaultAuth,
3707
- uaid,
3708
- agentUrl
3709
- });
3710
- },
3711
- decryptHistoryEntry: (entry) => entry.content,
3712
- fetchHistory
3729
+ signature: Buffer4.from(signatureEntry.signature).toString("base64"),
3730
+ signatureKind: "raw",
3731
+ publicKey: derivedPublicKey
3713
3732
  };
3714
3733
  }
3715
- async function compactHistory(client, payload) {
3716
- if (!payload.sessionId || payload.sessionId.trim().length === 0) {
3717
- throw new Error("sessionId is required to compact chat history");
3718
- }
3719
- const body = {};
3720
- if (typeof payload.preserveEntries === "number" && Number.isFinite(payload.preserveEntries) && payload.preserveEntries >= 0) {
3721
- body.preserveEntries = Math.floor(payload.preserveEntries);
3722
- }
3723
- const raw = await client.requestJson(
3724
- `/chat/session/${encodeURIComponent(payload.sessionId)}/compact`,
3725
- {
3726
- method: "POST",
3727
- headers: { "content-type": "application/json" },
3728
- body
3734
+ async function createLedgerChallenge(client, payload) {
3735
+ const resolvedNetwork = canonicalizeLedgerNetwork(payload.network);
3736
+ const network = resolvedNetwork.kind === "hedera" ? resolvedNetwork.hederaNetwork ?? resolvedNetwork.canonical : resolvedNetwork.canonical;
3737
+ const raw = await client.requestJson("/auth/ledger/challenge", {
3738
+ method: "POST",
3739
+ headers: { "content-type": "application/json" },
3740
+ body: {
3741
+ accountId: payload.accountId,
3742
+ network
3729
3743
  }
3730
- );
3744
+ });
3731
3745
  return client.parseWithSchema(
3732
3746
  raw,
3733
- chatHistoryCompactionResponseSchema,
3734
- "chat history compaction response"
3747
+ ledgerChallengeResponseSchema,
3748
+ "ledger challenge response"
3735
3749
  );
3736
3750
  }
3737
- async function fetchEncryptionStatus(client, sessionId) {
3738
- if (!sessionId || sessionId.trim().length === 0) {
3739
- throw new Error("sessionId is required for encryption status");
3751
+ async function verifyLedgerChallenge(client, payload) {
3752
+ const resolvedNetwork = canonicalizeLedgerNetwork(payload.network);
3753
+ const network = resolvedNetwork.kind === "hedera" ? resolvedNetwork.hederaNetwork ?? resolvedNetwork.canonical : resolvedNetwork.canonical;
3754
+ const body = {
3755
+ challengeId: payload.challengeId,
3756
+ accountId: payload.accountId,
3757
+ network,
3758
+ signature: payload.signature
3759
+ };
3760
+ if (payload.signatureKind) {
3761
+ body.signatureKind = payload.signatureKind;
3740
3762
  }
3741
- const raw = await client.requestJson(
3742
- `/chat/session/${encodeURIComponent(sessionId)}/encryption`,
3743
- {
3744
- method: "GET"
3745
- }
3746
- );
3747
- return client.parseWithSchema(
3763
+ if (payload.publicKey) {
3764
+ body.publicKey = payload.publicKey;
3765
+ }
3766
+ if (typeof payload.expiresInMinutes === "number") {
3767
+ body.expiresInMinutes = payload.expiresInMinutes;
3768
+ }
3769
+ const raw = await client.requestJson("/auth/ledger/verify", {
3770
+ method: "POST",
3771
+ headers: { "content-type": "application/json" },
3772
+ body
3773
+ });
3774
+ const result = client.parseWithSchema(
3748
3775
  raw,
3749
- sessionEncryptionStatusResponseSchema,
3750
- "session encryption status response"
3776
+ ledgerVerifyResponseSchema,
3777
+ "ledger verification response"
3751
3778
  );
3779
+ client.setLedgerApiKey(result.key);
3780
+ return result;
3752
3781
  }
3753
- async function postEncryptionHandshake(client, sessionId, payload) {
3754
- if (!sessionId || sessionId.trim().length === 0) {
3755
- throw new Error("sessionId is required for encryption handshake");
3756
- }
3757
- const raw = await client.requestJson(
3758
- `/chat/session/${encodeURIComponent(sessionId)}/encryption-handshake`,
3759
- {
3760
- method: "POST",
3761
- headers: { "content-type": "application/json" },
3762
- body: {
3763
- role: payload.role,
3764
- keyType: payload.keyType,
3765
- ephemeralPublicKey: payload.ephemeralPublicKey,
3766
- longTermPublicKey: payload.longTermPublicKey,
3767
- signature: payload.signature,
3768
- uaid: payload.uaid,
3769
- userId: payload.userId,
3770
- ledgerAccountId: payload.ledgerAccountId,
3771
- metadata: payload.metadata
3772
- }
3782
+ async function authenticateWithLedger(client, options) {
3783
+ const challenge = await client.createLedgerChallenge({
3784
+ accountId: options.accountId,
3785
+ network: options.network
3786
+ });
3787
+ const signed = await resolveLedgerAuthSignature(challenge.message, options);
3788
+ const verification = await client.verifyLedgerChallenge({
3789
+ challengeId: challenge.challengeId,
3790
+ accountId: options.accountId,
3791
+ network: options.network,
3792
+ signature: signed.signature,
3793
+ signatureKind: signed.signatureKind,
3794
+ publicKey: signed.publicKey,
3795
+ expiresInMinutes: options.expiresInMinutes
3796
+ });
3797
+ return verification;
3798
+ }
3799
+ async function authenticateWithLedgerCredentials(client, options) {
3800
+ const {
3801
+ accountId,
3802
+ network,
3803
+ signer,
3804
+ sign,
3805
+ hederaPrivateKey,
3806
+ evmPrivateKey,
3807
+ expiresInMinutes,
3808
+ setAccountHeader = true,
3809
+ label,
3810
+ logger
3811
+ } = options;
3812
+ const resolvedNetwork = canonicalizeLedgerNetwork(network);
3813
+ const labelSuffix = label ? ` for ${label}` : "";
3814
+ const networkPayload = resolvedNetwork.canonical;
3815
+ const authOptions = {
3816
+ accountId,
3817
+ network: networkPayload,
3818
+ expiresInMinutes
3819
+ };
3820
+ if (sign) {
3821
+ authOptions.sign = sign;
3822
+ } else if (signer) {
3823
+ authOptions.signer = signer;
3824
+ } else if (hederaPrivateKey) {
3825
+ if (resolvedNetwork.kind !== "hedera" || !resolvedNetwork.hederaNetwork) {
3826
+ throw new Error(
3827
+ "hederaPrivateKey can only be used with hedera:mainnet or hedera:testnet networks."
3828
+ );
3829
+ }
3830
+ authOptions.signer = await createPrivateKeySignerAsync({
3831
+ accountId,
3832
+ privateKey: hederaPrivateKey,
3833
+ network: resolvedNetwork.hederaNetwork
3834
+ });
3835
+ } else if (evmPrivateKey) {
3836
+ if (resolvedNetwork.kind !== "evm") {
3837
+ throw new Error(
3838
+ "evmPrivateKey can only be used with CAIP-2 EVM networks (eip155:<chainId>)."
3839
+ );
3773
3840
  }
3841
+ const formattedKey = evmPrivateKey.startsWith("0x") ? evmPrivateKey : `0x${evmPrivateKey}`;
3842
+ const account = await loadViemAccount(formattedKey);
3843
+ authOptions.sign = async (message) => ({
3844
+ signature: await account.signMessage({ message }),
3845
+ signatureKind: "evm",
3846
+ publicKey: account.publicKey
3847
+ });
3848
+ } else {
3849
+ throw new Error(
3850
+ "Provide a signer, sign function, hederaPrivateKey, or evmPrivateKey to authenticate with the ledger."
3851
+ );
3852
+ }
3853
+ logger?.info?.(
3854
+ `Authenticating ledger account ${accountId} (${resolvedNetwork.canonical})${labelSuffix}...`
3774
3855
  );
3775
- const response = client.parseWithSchema(
3776
- raw,
3777
- encryptionHandshakeResponseSchema,
3778
- "encryption handshake response"
3856
+ const verification = await client.authenticateWithLedger(authOptions);
3857
+ if (setAccountHeader) {
3858
+ client.setDefaultHeader("x-account-id", verification.accountId);
3859
+ }
3860
+ logger?.info?.(
3861
+ `Ledger authentication complete${labelSuffix}. Issued key prefix: ${verification.apiKey.prefix}\u2026${verification.apiKey.lastFour}`
3779
3862
  );
3780
- return response.handshake;
3863
+ return verification;
3781
3864
  }
3782
- async function sendMessage(client, payload) {
3783
- const body = {
3784
- message: payload.message
3865
+
3866
+ // ../../src/services/registry-broker/client/search.ts
3867
+ function buildVectorFallbackSearchParams(request) {
3868
+ const params = {
3869
+ q: request.query
3785
3870
  };
3786
- if (payload.streaming !== void 0) {
3787
- body.streaming = payload.streaming;
3871
+ let effectiveLimit;
3872
+ if (typeof request.limit === "number" && Number.isFinite(request.limit)) {
3873
+ effectiveLimit = request.limit;
3874
+ params.limit = request.limit;
3788
3875
  }
3789
- if (payload.auth) {
3790
- body.auth = serialiseAuthConfig(payload.auth);
3876
+ if (typeof request.offset === "number" && Number.isFinite(request.offset) && request.offset > 0) {
3877
+ const limit = effectiveLimit && effectiveLimit > 0 ? effectiveLimit : 20;
3878
+ params.limit = limit;
3879
+ params.page = Math.floor(request.offset / limit) + 1;
3791
3880
  }
3792
- if ("uaid" in payload) {
3793
- body.uaid = payload.uaid;
3881
+ if (request.filter?.registry) {
3882
+ params.registry = request.filter.registry;
3794
3883
  }
3795
- if ("sessionId" in payload && payload.sessionId) {
3796
- body.sessionId = payload.sessionId;
3884
+ if (request.filter?.protocols?.length) {
3885
+ params.protocols = [...request.filter.protocols];
3797
3886
  }
3798
- if ("agentUrl" in payload && payload.agentUrl) {
3799
- body.agentUrl = payload.agentUrl;
3887
+ if (request.filter?.adapter?.length) {
3888
+ params.adapters = [...request.filter.adapter];
3800
3889
  }
3801
- let cipherEnvelope = payload.cipherEnvelope ?? null;
3802
- if (payload.encryption) {
3803
- const sessionIdForEncryption = payload.encryption.sessionId ?? (typeof body.sessionId === "string" ? body.sessionId : void 0);
3804
- if (!sessionIdForEncryption) {
3805
- throw new Error(
3806
- "sessionId is required when using encrypted chat payloads"
3807
- );
3808
- }
3809
- if (!payload.encryption.recipients?.length) {
3810
- throw new Error("recipients are required for encrypted chat payloads");
3811
- }
3812
- cipherEnvelope = client.encryption.encryptCipherEnvelope({
3813
- ...payload.encryption,
3814
- sessionId: sessionIdForEncryption
3815
- });
3890
+ if (request.filter?.capabilities?.length) {
3891
+ params.capabilities = request.filter.capabilities.map(
3892
+ (value) => typeof value === "number" ? value.toString(10) : value
3893
+ );
3816
3894
  }
3817
- if (cipherEnvelope) {
3818
- body.cipherEnvelope = toJsonObject(cipherEnvelope);
3895
+ if (request.filter?.type) {
3896
+ params.type = request.filter.type;
3819
3897
  }
3820
- const raw = await client.requestJson("/chat/message", {
3898
+ return params;
3899
+ }
3900
+ function convertSearchResultToVectorResponse(result) {
3901
+ const hits = result.hits.map((agent) => ({
3902
+ agent,
3903
+ score: 0,
3904
+ highlights: {}
3905
+ }));
3906
+ const total = result.total;
3907
+ const limit = result.limit;
3908
+ const page = result.page;
3909
+ const totalVisible = page * limit;
3910
+ const limited = total > totalVisible || page > 1;
3911
+ return {
3912
+ hits,
3913
+ total,
3914
+ took: 0,
3915
+ totalAvailable: total,
3916
+ visible: hits.length,
3917
+ limited,
3918
+ credits_used: 0
3919
+ };
3920
+ }
3921
+ async function search(client, params = {}) {
3922
+ const query = buildSearchQuery(params);
3923
+ const raw = await client.requestJson(`/search${query}`, {
3924
+ method: "GET"
3925
+ });
3926
+ return client.parseWithSchema(raw, searchResponseSchema, "search response");
3927
+ }
3928
+ async function delegate(client, request) {
3929
+ const raw = await client.requestJson("/delegate", {
3821
3930
  method: "POST",
3822
- body,
3931
+ body: request,
3823
3932
  headers: { "content-type": "application/json" }
3824
3933
  });
3825
3934
  return client.parseWithSchema(
3826
3935
  raw,
3827
- sendMessageResponseSchema,
3828
- "chat message response"
3936
+ delegationPlanResponseSchema,
3937
+ "delegate response"
3829
3938
  );
3830
3939
  }
3831
- async function endSession(client, sessionId) {
3832
- await client.request(`/chat/session/${encodeURIComponent(sessionId)}`, {
3833
- method: "DELETE"
3940
+ async function stats(client) {
3941
+ const raw = await client.requestJson("/stats", { method: "GET" });
3942
+ return client.parseWithSchema(raw, statsResponseSchema, "stats response");
3943
+ }
3944
+ async function registries(client) {
3945
+ const raw = await client.requestJson("/registries", {
3946
+ method: "GET"
3834
3947
  });
3948
+ return client.parseWithSchema(
3949
+ raw,
3950
+ registriesResponseSchema,
3951
+ "registries response"
3952
+ );
3835
3953
  }
3836
-
3837
- // ../../src/services/registry-broker/client/verification.ts
3838
- async function getVerificationStatus(client, uaid) {
3954
+ async function getAdditionalRegistries(client) {
3839
3955
  const raw = await client.requestJson(
3840
- `/verification/status/${encodeURIComponent(uaid)}`,
3841
- { method: "GET" }
3956
+ "/register/additional-registries",
3957
+ {
3958
+ method: "GET"
3959
+ }
3842
3960
  );
3843
3961
  return client.parseWithSchema(
3844
3962
  raw,
3845
- verificationStatusResponseSchema,
3846
- "verification status response"
3963
+ additionalRegistryCatalogResponseSchema,
3964
+ "additional registry catalog response"
3847
3965
  );
3848
3966
  }
3849
- async function createVerificationChallenge(client, uaid) {
3850
- const raw = await client.requestJson("/verification/challenge", {
3851
- method: "POST",
3852
- headers: { "content-type": "application/json" },
3853
- body: { uaid }
3967
+ async function popularSearches(client) {
3968
+ const raw = await client.requestJson("/popular", {
3969
+ method: "GET"
3854
3970
  });
3855
3971
  return client.parseWithSchema(
3856
3972
  raw,
3857
- verificationChallengeResponseSchema,
3858
- "verification challenge response"
3973
+ popularResponseSchema,
3974
+ "popular searches response"
3859
3975
  );
3860
3976
  }
3861
- async function getVerificationChallenge(client, challengeId) {
3862
- const raw = await client.requestJson(
3863
- `/verification/challenge/${encodeURIComponent(challengeId)}`,
3864
- { method: "GET" }
3865
- );
3977
+ async function listProtocols(client) {
3978
+ const raw = await client.requestJson("/protocols", {
3979
+ method: "GET"
3980
+ });
3866
3981
  return client.parseWithSchema(
3867
3982
  raw,
3868
- verificationChallengeDetailsResponseSchema,
3869
- "verification challenge details response"
3983
+ protocolsResponseSchema,
3984
+ "protocols response"
3870
3985
  );
3871
3986
  }
3872
- async function verifyVerificationChallenge(client, params) {
3873
- const raw = await client.requestJson("/verification/verify", {
3987
+ async function detectProtocol(client, message) {
3988
+ const raw = await client.requestJson("/detect-protocol", {
3874
3989
  method: "POST",
3875
- headers: { "content-type": "application/json" },
3876
- body: {
3877
- challengeId: params.challengeId,
3878
- method: params.method ?? "moltbook-post"
3879
- }
3990
+ body: { message },
3991
+ headers: { "content-type": "application/json" }
3880
3992
  });
3881
3993
  return client.parseWithSchema(
3882
3994
  raw,
3883
- verificationVerifyResponseSchema,
3884
- "verification verify response"
3885
- );
3886
- }
3887
- async function getVerificationOwnership(client, uaid) {
3888
- const raw = await client.requestJson(
3889
- `/verification/ownership/${encodeURIComponent(uaid)}`,
3890
- { method: "GET" }
3891
- );
3892
- return client.parseWithSchema(
3893
- raw,
3894
- verificationOwnershipResponseSchema,
3895
- "verification ownership response"
3995
+ detectProtocolResponseSchema,
3996
+ "detect protocol response"
3896
3997
  );
3897
3998
  }
3898
- async function verifySenderOwnership(client, uaid) {
3999
+ async function registrySearchByNamespace(client, registry, query) {
4000
+ const params = new URLSearchParams();
4001
+ if (query) {
4002
+ params.set("q", query);
4003
+ }
4004
+ const suffix = params.size > 0 ? `?${params.toString()}` : "";
3899
4005
  const raw = await client.requestJson(
3900
- "/verification/verify-sender",
4006
+ `/registries/${encodeURIComponent(registry)}/search${suffix}`,
3901
4007
  {
3902
- method: "POST",
3903
- headers: { "content-type": "application/json" },
3904
- body: { uaid }
4008
+ method: "GET"
3905
4009
  }
3906
4010
  );
3907
4011
  return client.parseWithSchema(
3908
4012
  raw,
3909
- verificationVerifySenderResponseSchema,
3910
- "verification sender response"
4013
+ registrySearchByNamespaceSchema,
4014
+ "registry search response"
3911
4015
  );
3912
4016
  }
3913
- async function verifyUaidDnsTxt(client, payload) {
3914
- const raw = await client.requestJson("/verification/dns/verify", {
3915
- method: "POST",
3916
- headers: { "content-type": "application/json" },
3917
- body: {
3918
- uaid: payload.uaid,
3919
- ...payload.persist !== void 0 ? { persist: payload.persist } : {}
4017
+ async function vectorSearch(client, request) {
4018
+ try {
4019
+ const raw = await client.requestJson("/search", {
4020
+ method: "POST",
4021
+ body: request,
4022
+ headers: { "content-type": "application/json" }
4023
+ });
4024
+ return client.parseWithSchema(
4025
+ raw,
4026
+ vectorSearchResponseSchema,
4027
+ "vector search response"
4028
+ );
4029
+ } catch (error) {
4030
+ if (error instanceof RegistryBrokerError && error.status === 501) {
4031
+ const fallback = await search(
4032
+ client,
4033
+ buildVectorFallbackSearchParams(request)
4034
+ );
4035
+ return convertSearchResultToVectorResponse(fallback);
3920
4036
  }
4037
+ throw error;
4038
+ }
4039
+ }
4040
+ async function searchStatus(client) {
4041
+ const raw = await client.requestJson("/search/status", {
4042
+ method: "GET"
3921
4043
  });
3922
4044
  return client.parseWithSchema(
3923
4045
  raw,
3924
- verificationDnsStatusResponseSchema,
3925
- "verification dns verify response"
4046
+ searchStatusResponseSchema,
4047
+ "search status response"
3926
4048
  );
3927
4049
  }
3928
- async function getVerificationDnsStatus(client, uaid, query) {
3929
- const params = new URLSearchParams();
3930
- if (query?.refresh !== void 0) {
3931
- params.set("refresh", String(query.refresh));
3932
- }
3933
- if (query?.persist !== void 0) {
3934
- params.set("persist", String(query.persist));
3935
- }
3936
- const queryString = params.toString();
3937
- const path2 = `/verification/dns/status/${encodeURIComponent(uaid)}${queryString ? `?${queryString}` : ""}`;
3938
- const raw = await client.requestJson(path2, {
4050
+ async function websocketStats(client) {
4051
+ const raw = await client.requestJson("/websocket/stats", {
3939
4052
  method: "GET"
3940
4053
  });
3941
4054
  return client.parseWithSchema(
3942
4055
  raw,
3943
- verificationDnsStatusResponseSchema,
3944
- "verification dns status response"
4056
+ websocketStatsResponseSchema,
4057
+ "websocket stats response"
3945
4058
  );
3946
4059
  }
3947
- async function getRegisterStatus(client, uaid) {
3948
- const raw = await client.requestJson(
3949
- `/register/status/${encodeURIComponent(uaid)}`,
3950
- { method: "GET" }
3951
- );
4060
+ async function metricsSummary(client) {
4061
+ const raw = await client.requestJson("/metrics", {
4062
+ method: "GET"
4063
+ });
3952
4064
  return client.parseWithSchema(
3953
4065
  raw,
3954
- registerStatusResponseSchema,
3955
- "register status response"
4066
+ metricsSummaryResponseSchema,
4067
+ "metrics summary response"
3956
4068
  );
3957
4069
  }
3958
- async function registerOwnedMoltbookAgent(client, uaid, request) {
3959
- const raw = await client.requestJson(
3960
- `/register/${encodeURIComponent(uaid)}`,
3961
- {
3962
- method: "PUT",
3963
- headers: { "content-type": "application/json" },
3964
- body: {
3965
- registered: request.registered ?? true,
3966
- ...request.name ? { name: request.name } : {},
3967
- ...request.description ? { description: request.description } : {},
3968
- ...request.endpoint ? { endpoint: request.endpoint } : {},
3969
- ...request.metadata ? { metadata: request.metadata } : {}
3970
- }
3971
- }
3972
- );
4070
+ async function facets(client, adapter) {
4071
+ const params = new URLSearchParams();
4072
+ if (adapter) {
4073
+ params.set("adapter", adapter);
4074
+ }
4075
+ const suffix = params.size > 0 ? `?${params.toString()}` : "";
4076
+ const raw = await client.requestJson(`/search/facets${suffix}`, {
4077
+ method: "GET"
4078
+ });
3973
4079
  return client.parseWithSchema(
3974
4080
  raw,
3975
- moltbookOwnerRegistrationUpdateResponseSchema,
3976
- "moltbook owner registration update response"
4081
+ searchFacetsResponseSchema,
4082
+ "search facets response"
3977
4083
  );
3978
4084
  }
3979
4085
 
@@ -3988,6 +4094,28 @@ async function skillsConfig(client) {
3988
4094
  "skill registry config response"
3989
4095
  );
3990
4096
  }
4097
+ async function getSkillStatus(client, params) {
4098
+ const normalizedName = params.name.trim();
4099
+ if (!normalizedName) {
4100
+ throw new Error("name is required");
4101
+ }
4102
+ const query = new URLSearchParams();
4103
+ query.set("name", normalizedName);
4104
+ if (params.version?.trim()) {
4105
+ query.set("version", params.version.trim());
4106
+ }
4107
+ const raw = await client.requestJson(
4108
+ `/skills/status?${query.toString()}`,
4109
+ {
4110
+ method: "GET"
4111
+ }
4112
+ );
4113
+ return client.parseWithSchema(
4114
+ raw,
4115
+ skillStatusResponseSchema,
4116
+ "skill status response"
4117
+ );
4118
+ }
3991
4119
  async function listSkills(client, params = {}) {
3992
4120
  const query = new URLSearchParams();
3993
4121
  if (params.name) {
@@ -4503,15 +4631,6 @@ async function verifySkillDomainProof(client, payload) {
4503
4631
  }
4504
4632
 
4505
4633
  // ../../src/services/registry-broker/client/base-client.ts
4506
- import { Buffer as Buffer5 } from "buffer";
4507
- import {
4508
- createCipheriv,
4509
- createDecipheriv,
4510
- createHash,
4511
- randomBytes as randomBytes2
4512
- } from "crypto";
4513
- import { secp256k1 as secp256k12 } from "@noble/curves/secp256k1.js";
4514
- import { ZodError } from "zod";
4515
4634
  var RegistryBrokerClient = class _RegistryBrokerClient {
4516
4635
  constructor(options = {}) {
4517
4636
  this.encryptionBootstrapPromise = null;
@@ -4628,11 +4747,11 @@ var RegistryBrokerClient = class _RegistryBrokerClient {
4628
4747
  }
4629
4748
  await this.encryptionBootstrapPromise;
4630
4749
  }
4631
- buildUrl(path2) {
4632
- const normalisedPath = path2.startsWith("/") ? path2 : `/${path2}`;
4750
+ buildUrl(path) {
4751
+ const normalisedPath = path.startsWith("/") ? path : `/${path}`;
4633
4752
  return `${this.baseUrl}${normalisedPath}`;
4634
4753
  }
4635
- async request(path2, config) {
4754
+ async request(path, config) {
4636
4755
  const headers = new Headers();
4637
4756
  Object.entries(this.defaultHeaders).forEach(([key, value]) => {
4638
4757
  headers.set(key, value);
@@ -4658,7 +4777,7 @@ var RegistryBrokerClient = class _RegistryBrokerClient {
4658
4777
  headers.set("content-type", "application/json");
4659
4778
  }
4660
4779
  }
4661
- const response = await this.fetchImpl(this.buildUrl(path2), init);
4780
+ const response = await this.fetchImpl(this.buildUrl(path), init);
4662
4781
  if (response.ok) {
4663
4782
  return response;
4664
4783
  }
@@ -4669,8 +4788,8 @@ var RegistryBrokerClient = class _RegistryBrokerClient {
4669
4788
  body: errorBody
4670
4789
  });
4671
4790
  }
4672
- async requestJson(path2, config) {
4673
- const response = await this.request(path2, config);
4791
+ async requestJson(path, config) {
4792
+ const response = await this.request(path, config);
4674
4793
  const contentType = response.headers?.get("content-type") ?? "";
4675
4794
  if (!JSON_CONTENT_TYPE.test(contentType)) {
4676
4795
  const body = await response.text();
@@ -4849,6 +4968,9 @@ var RegistryBrokerClient = class _RegistryBrokerClient {
4849
4968
  async skillsConfig() {
4850
4969
  return skillsConfig(this);
4851
4970
  }
4971
+ async getSkillStatus(params) {
4972
+ return getSkillStatus(this, params);
4973
+ }
4852
4974
  async listSkills(options) {
4853
4975
  return listSkills(this, options);
4854
4976
  }
@@ -5240,12 +5362,12 @@ var RegistryBrokerClient = class _RegistryBrokerClient {
5240
5362
  }
5241
5363
  return;
5242
5364
  }
5243
- await new Promise((resolve2, reject) => {
5365
+ await new Promise((resolve, reject) => {
5244
5366
  const timer = setTimeout(() => {
5245
5367
  if (signal) {
5246
5368
  signal.removeEventListener("abort", onAbort);
5247
5369
  }
5248
- resolve2();
5370
+ resolve();
5249
5371
  }, ms);
5250
5372
  const onAbort = () => {
5251
5373
  clearTimeout(timer);
@@ -5267,9 +5389,17 @@ var RegistryBrokerClient = class _RegistryBrokerClient {
5267
5389
  throw new Error(`${feature} is only available in Node.js environments`);
5268
5390
  }
5269
5391
  }
5392
+ getNodeCrypto(feature) {
5393
+ this.assertNodeRuntime(feature);
5394
+ const nodeCrypto = optionalImportSync("node:crypto") ?? optionalImportSync("crypto");
5395
+ if (!nodeCrypto) {
5396
+ throw new Error(`${feature} requires the Node.js crypto module`);
5397
+ }
5398
+ return nodeCrypto;
5399
+ }
5270
5400
  createEphemeralKeyPair() {
5271
- this.assertNodeRuntime("generateEphemeralKeyPair");
5272
- const privateKeyBytes = randomBytes2(32);
5401
+ const { randomBytes } = this.getNodeCrypto("generateEphemeralKeyPair");
5402
+ const privateKeyBytes = randomBytes(32);
5273
5403
  const publicKey = secp256k12.getPublicKey(privateKeyBytes, true);
5274
5404
  return {
5275
5405
  privateKey: Buffer5.from(privateKeyBytes).toString("hex"),
@@ -5277,16 +5407,18 @@ var RegistryBrokerClient = class _RegistryBrokerClient {
5277
5407
  };
5278
5408
  }
5279
5409
  deriveSharedSecret(options) {
5280
- this.assertNodeRuntime("deriveSharedSecret");
5410
+ const { createHash } = this.getNodeCrypto("deriveSharedSecret");
5281
5411
  const privateKey = this.hexToBuffer(options.privateKey);
5282
5412
  const peerPublicKey = this.hexToBuffer(options.peerPublicKey);
5283
5413
  const shared = secp256k12.getSharedSecret(privateKey, peerPublicKey, true);
5284
5414
  return createHash("sha256").update(Buffer5.from(shared)).digest();
5285
5415
  }
5286
5416
  buildCipherEnvelope(options) {
5287
- this.assertNodeRuntime("encryptCipherEnvelope");
5417
+ const { createCipheriv, randomBytes } = this.getNodeCrypto(
5418
+ "encryptCipherEnvelope"
5419
+ );
5288
5420
  const sharedSecret = this.normalizeSharedSecret(options.sharedSecret);
5289
- const iv = randomBytes2(12);
5421
+ const iv = randomBytes(12);
5290
5422
  const cipher = createCipheriv("aes-256-gcm", sharedSecret, iv);
5291
5423
  const aadSource = options.associatedData ?? options.sessionId;
5292
5424
  const associatedDataEncoded = aadSource ? Buffer5.from(aadSource, "utf8").toString("base64") : void 0;
@@ -5315,7 +5447,7 @@ var RegistryBrokerClient = class _RegistryBrokerClient {
5315
5447
  };
5316
5448
  }
5317
5449
  openCipherEnvelope(options) {
5318
- this.assertNodeRuntime("decryptCipherEnvelope");
5450
+ const { createDecipheriv } = this.getNodeCrypto("decryptCipherEnvelope");
5319
5451
  const sharedSecret = this.normalizeSharedSecret(options.sharedSecret);
5320
5452
  const payload = Buffer5.from(options.envelope.ciphertext, "base64");
5321
5453
  const nonce = Buffer5.from(options.envelope.nonce, "base64");