@nekzus/liop 2.4.0-alpha.7 → 2.4.0-alpha.8
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/NOTICE +19 -0
- package/README.md +36 -17
- package/dist/bin/agent.js +674 -82
- package/dist/bin/agent.js.map +1 -1
- package/dist/bridge.d.ts +2 -2
- package/dist/bridge.js +3 -3
- package/dist/{chunk-T5IUZF47.js → chunk-3L2O2XKG.js} +12 -5
- package/dist/chunk-3L2O2XKG.js.map +1 -0
- package/dist/{chunk-SONUORBT.js → chunk-7BSCUYUE.js} +2 -2
- package/dist/chunk-7BSCUYUE.js.map +1 -0
- package/dist/{chunk-QLCOEP5J.js → chunk-7PITYWOV.js} +2 -2
- package/dist/chunk-7PITYWOV.js.map +1 -0
- package/dist/{chunk-74CISO2I.js → chunk-7RXOIDXP.js} +28 -4
- package/dist/chunk-7RXOIDXP.js.map +1 -0
- package/dist/{chunk-GA3Q2S7O.js → chunk-BOISQ45Z.js} +5 -5
- package/dist/chunk-BOISQ45Z.js.map +1 -0
- package/dist/{chunk-547TYL27.js → chunk-DZ2FQGJD.js} +26 -1423
- package/dist/chunk-DZ2FQGJD.js.map +1 -0
- package/dist/{chunk-PYKRQAER.js → chunk-EG46XMJT.js} +2 -2
- package/dist/chunk-EG46XMJT.js.map +1 -0
- package/dist/chunk-ESRXG36Y.js +115 -0
- package/dist/chunk-ESRXG36Y.js.map +1 -0
- package/dist/chunk-FTF6AMF6.js +3 -0
- package/dist/{chunk-RWRRBYG4.js.map → chunk-FTF6AMF6.js.map} +1 -1
- package/dist/{chunk-72MNYFR6.js → chunk-HA6YZ42O.js} +2 -2
- package/dist/chunk-HA6YZ42O.js.map +1 -0
- package/dist/{chunk-WCCGE4QR.js → chunk-HD2N3IJX.js} +144 -30
- package/dist/chunk-HD2N3IJX.js.map +1 -0
- package/dist/{chunk-OUUTDSOW.js → chunk-IK7CGWAZ.js} +3 -3
- package/dist/chunk-IK7CGWAZ.js.map +1 -0
- package/dist/chunk-L6J72C5X.js +1477 -0
- package/dist/chunk-L6J72C5X.js.map +1 -0
- package/dist/{chunk-U5BZ66VX.js → chunk-PAICJCKJ.js} +60 -175
- package/dist/chunk-PAICJCKJ.js.map +1 -0
- package/dist/{chunk-32ADSAJS.js → chunk-PEN3KFLF.js} +14 -4
- package/dist/chunk-PEN3KFLF.js.map +1 -0
- package/dist/{chunk-CRZBVFDV.js → chunk-T7R5HUFD.js} +225 -66
- package/dist/chunk-T7R5HUFD.js.map +1 -0
- package/dist/{chunk-WSW6YJNY.js → chunk-TKRX6CFI.js} +3 -3
- package/dist/chunk-TKRX6CFI.js.map +1 -0
- package/dist/chunk-UCVP3XAL.js +279 -0
- package/dist/chunk-UCVP3XAL.js.map +1 -0
- package/dist/chunk-VH4K4U45.js +180 -0
- package/dist/chunk-VH4K4U45.js.map +1 -0
- package/dist/{chunk-JIJPZFR2.js → chunk-Y62GORQF.js} +2 -2
- package/dist/chunk-Y62GORQF.js.map +1 -0
- package/dist/chunk-ZP3VVXOI.js +66 -0
- package/dist/chunk-ZP3VVXOI.js.map +1 -0
- package/dist/client.d.ts +2 -2
- package/dist/client.js +11 -8
- package/dist/gateway.d.ts +3 -3
- package/dist/gateway.js +11 -9
- package/dist/{hybrid-CF__0YnC.d.ts → hybrid-CrKB50nh.d.ts} +2 -2
- package/dist/{index-cMV0_yD9.d.ts → index-CX43dvMs.d.ts} +2 -32
- package/dist/{index-BW95kAL4.d.ts → index-DoW2gzBZ.d.ts} +3 -21
- package/dist/index.d.ts +170 -46
- package/dist/index.js +20 -15
- package/dist/index.js.map +1 -1
- package/dist/kyber-CGOA7Q6A.js +3 -0
- package/dist/{kyber-3ULIJSE3.js.map → kyber-CGOA7Q6A.js.map} +1 -1
- package/dist/mesh.d.ts +27 -143
- package/dist/mesh.js +4 -3
- package/dist/node-B0b2vUFS.d.ts +164 -0
- package/dist/protocol/liop_core.proto +3 -0
- package/dist/server.d.ts +2 -2
- package/dist/server.js +7 -6
- package/dist/types.js +1 -1
- package/dist/verifier-HRFXBKT5.js +6 -0
- package/dist/{verifier-3FAKCFNN.js.map → verifier-HRFXBKT5.js.map} +1 -1
- package/dist/workers/logic-execution.js +3 -3
- package/dist/workers/logic-execution.js.map +1 -1
- package/dist/workers/zk-verifier.js +1 -1
- package/dist/workers/zk-verifier.js.map +1 -1
- package/package.json +8 -2
- package/dist/chunk-32ADSAJS.js.map +0 -1
- package/dist/chunk-547TYL27.js.map +0 -1
- package/dist/chunk-72MNYFR6.js.map +0 -1
- package/dist/chunk-74CISO2I.js.map +0 -1
- package/dist/chunk-CRZBVFDV.js.map +0 -1
- package/dist/chunk-GA3Q2S7O.js.map +0 -1
- package/dist/chunk-JIJPZFR2.js.map +0 -1
- package/dist/chunk-OUUTDSOW.js.map +0 -1
- package/dist/chunk-PYKRQAER.js.map +0 -1
- package/dist/chunk-QLCOEP5J.js.map +0 -1
- package/dist/chunk-RWRRBYG4.js +0 -3
- package/dist/chunk-SONUORBT.js.map +0 -1
- package/dist/chunk-T5IUZF47.js.map +0 -1
- package/dist/chunk-U5BZ66VX.js.map +0 -1
- package/dist/chunk-WCCGE4QR.js.map +0 -1
- package/dist/chunk-WSW6YJNY.js.map +0 -1
- package/dist/kyber-3ULIJSE3.js +0 -3
- package/dist/verifier-3FAKCFNN.js +0 -5
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { deriveLogicImageDigest } from './chunk-
|
|
2
|
-
import {
|
|
1
|
+
import { deriveLogicImageDigest } from './chunk-IK7CGWAZ.js';
|
|
2
|
+
import { zkVerificationDurationMs } from './chunk-PAICJCKJ.js';
|
|
3
|
+
import { log } from './chunk-HA6YZ42O.js';
|
|
3
4
|
import * as fs from 'fs';
|
|
4
5
|
import { createRequire } from 'module';
|
|
5
6
|
import path from 'path';
|
|
@@ -61,6 +62,7 @@ var LiopVerifier = class _LiopVerifier {
|
|
|
61
62
|
async verifyZkReceipt(logicPayload, remoteImageIdHex, zkReceipt, sessionSecret, expectedOutput) {
|
|
62
63
|
const pool = this.getZkPool();
|
|
63
64
|
if (!pool) throw new Error("Worker pool initialization failed");
|
|
65
|
+
const startTime = performance.now();
|
|
64
66
|
const result = await pool.run({
|
|
65
67
|
action: "verify_receipt",
|
|
66
68
|
logicPayload: new Uint8Array(logicPayload),
|
|
@@ -69,6 +71,14 @@ var LiopVerifier = class _LiopVerifier {
|
|
|
69
71
|
sessionSecret: sessionSecret ? new Uint8Array(sessionSecret) : void 0,
|
|
70
72
|
expectedOutput
|
|
71
73
|
});
|
|
74
|
+
const durationMs = performance.now() - startTime;
|
|
75
|
+
try {
|
|
76
|
+
zkVerificationDurationMs.observe(
|
|
77
|
+
{ status: result.verified ? "verified" : "failed" },
|
|
78
|
+
durationMs
|
|
79
|
+
);
|
|
80
|
+
} catch {
|
|
81
|
+
}
|
|
72
82
|
if (result.verified) {
|
|
73
83
|
log.info(`[LiopVerifier] ${result.message}`);
|
|
74
84
|
return true;
|
|
@@ -100,5 +110,5 @@ var LiopVerifier = class _LiopVerifier {
|
|
|
100
110
|
};
|
|
101
111
|
|
|
102
112
|
export { LiopVerifier };
|
|
103
|
-
//# sourceMappingURL=chunk-
|
|
104
|
-
//# sourceMappingURL=chunk-
|
|
113
|
+
//# sourceMappingURL=chunk-PEN3KFLF.js.map
|
|
114
|
+
//# sourceMappingURL=chunk-PEN3KFLF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/crypto/verifier.ts"],"names":["__filename","__dirname"],"mappings":"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","file":"chunk-PEN3KFLF.js","sourcesContent":["// Copyright 2026 Nekzus Solutions and contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport path from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport { Piscina } from \"piscina\";\nimport { zkVerificationDurationMs } from \"../observability/metrics.js\";\nimport { log } from \"../utils/logger.js\";\nimport { deriveLogicImageDigest } from \"./logic-image-id.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n/**\n * LIOP Tier-0 Industrial Verifier\n *\n * This engine is responsible for the trustless verification of remote logic execution.\n * It validates both the integrity of the code (ZkImageID) and the mathematical proof\n * of its execution (ZkSeal), as well as hardware-level attestation (TEE).\n */\nexport class LiopVerifier {\n\t// Singleton Worker Pool for heavy ZK verification\n\tprivate static zkWorkerPool: Piscina | null = null;\n\n\tprivate getZkPool() {\n\t\tif (!LiopVerifier.zkWorkerPool) {\n\t\t\tconst isTS = import.meta.url.endsWith(\".ts\");\n\t\t\tconst workerExt = isTS ? \".ts\" : \".js\";\n\n\t\t\tlet execArgv: string[] = [];\n\t\t\tif (isTS) {\n\t\t\t\ttry {\n\t\t\t\t\tconst req = createRequire(import.meta.url);\n\t\t\t\t\tconst tsxPkg = req.resolve(\"tsx/package.json\");\n\t\t\t\t\tconst absoluteTsx = pathToFileURL(\n\t\t\t\t\t\tpath.join(path.dirname(tsxPkg), \"dist\", \"loader.mjs\"),\n\t\t\t\t\t).href;\n\t\t\t\t\texecArgv = [\"--import\", absoluteTsx];\n\t\t\t\t} catch (_e) {\n\t\t\t\t\texecArgv = [\"--import\", \"tsx\"];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Support both flat dist/ and original src/ structure\n\t\t\tconst workerPaths = [\n\t\t\t\tpath.resolve(__dirname, `./workers/zk-verifier${workerExt}`), // Flat dist/ (tsup)\n\t\t\t\tpath.resolve(__dirname, `../workers/zk-verifier${workerExt}`), // Original src/\n\t\t\t];\n\n\t\t\tconst workerFilename =\n\t\t\t\tworkerPaths.find((p) => fs.existsSync(p)) || workerPaths[1];\n\n\t\t\tLiopVerifier.zkWorkerPool = new Piscina({\n\t\t\t\tfilename: workerFilename,\n\t\t\t\tminThreads: 1,\n\t\t\t\tmaxThreads: 2, // Minimal footprint since verification is fast compared to generation\n\t\t\t\tidleTimeout: 30000,\n\t\t\t\texecArgv,\n\t\t\t});\n\n\t\t\t// Pre-warm the verification worker\n\t\t\tLiopVerifier.zkWorkerPool.run({ action: \"warmup\" }).catch((err) => {\n\t\t\t\tlog.debug(\n\t\t\t\t\t`[LiopVerifier] Verification pool warm-up ping failed: ${err.message}`,\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t\treturn LiopVerifier.zkWorkerPool;\n\t}\n\n\t/**\n\t * Verifies a Zero-Knowledge Receipt from a remote LIOP node via Worker Pool.\n\t *\n\t * @param logicPayload The raw WASM or JS logic that was sent to the provider.\n\t * @param remoteImageIdHex The ImageID reported by the provider (must match our local calculation).\n\t * @param zkReceipt The mathematical proof (Seal + Journal) from the zkVM.\n\t */\n\tpublic async verifyZkReceipt(\n\t\tlogicPayload: Buffer,\n\t\tremoteImageIdHex: string,\n\t\tzkReceipt: Buffer,\n\t\tsessionSecret?: Buffer,\n\t\texpectedOutput?: unknown,\n\t): Promise<boolean> {\n\t\tconst pool = this.getZkPool();\n\t\tif (!pool) throw new Error(\"Worker pool initialization failed\");\n\t\tconst startTime = performance.now();\n\t\tconst result = await pool.run({\n\t\t\taction: \"verify_receipt\",\n\t\t\tlogicPayload: new Uint8Array(logicPayload),\n\t\t\tremoteImageIdHex,\n\t\t\tzkReceipt: new Uint8Array(zkReceipt),\n\t\t\tsessionSecret: sessionSecret ? new Uint8Array(sessionSecret) : undefined,\n\t\t\texpectedOutput,\n\t\t});\n\t\tconst durationMs = performance.now() - startTime;\n\n\t\ttry {\n\t\t\tzkVerificationDurationMs.observe(\n\t\t\t\t{ status: result.verified ? \"verified\" : \"failed\" },\n\t\t\t\tdurationMs,\n\t\t\t);\n\t\t} catch {\n\t\t\t// Metrics observation failure must never disrupt cryptographic verification\n\t\t}\n\n\t\tif (result.verified) {\n\t\t\tlog.info(`[LiopVerifier] ${result.message}`);\n\t\t\treturn true;\n\t\t}\n\n\t\tlog.error(`[LiopVerifier] FAILED: ${result.message}`);\n\t\treturn false;\n\t}\n\n\t/**\n\t * Verifies if a node is running inside an authenticated TEE (e.g. AWS Nitro).\n\t *\n\t * @param attestationReport The COSE-signed attestation document from the hardware.\n\t */\n\tpublic async verifyTeeAttestation(\n\t\tattestationReport: Buffer,\n\t): Promise<boolean> {\n\t\tif (attestationReport.length === 0) return true; // Optional in Mesh Alpha\n\n\t\ttry {\n\t\t\t// Architecture for AWS Nitro Enclaves:\n\t\t\t// 1. Decode CBOR/COSE\n\t\t\t// 2. Verify Signature against AWS Nitro Root CA\n\t\t\t// 3. Compare PCRs\n\t\t\tlog.info(\"[LiopVerifier] TEE Attestation: Not configured (no-op).\");\n\t\t\treturn true;\n\t\t} catch (err) {\n\t\t\tlog.error(\"[LiopVerifier] TEE Verification Failed:\", err);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Derives the ImageID of a logic payload following the LIOP v1 Standard.\n\t */\n\tpublic deriveImageId(logicPayload: Buffer): Buffer {\n\t\treturn deriveLogicImageDigest(logicPayload);\n\t}\n}\n"]}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { TokenManager } from './chunk-ESRXG36Y.js';
|
|
2
|
+
import { TokenTelemetryEngine } from './chunk-DZ2FQGJD.js';
|
|
3
|
+
import { LiopVerifier } from './chunk-PEN3KFLF.js';
|
|
4
|
+
import { Kyber768Wrapper } from './chunk-7PITYWOV.js';
|
|
5
|
+
import { createChannelCredentials, liopV1, GRPC_CHANNEL_OPTIONS } from './chunk-TKRX6CFI.js';
|
|
6
|
+
import { pqcHandshakesTotal, pqcHandshakeDurationMs, zkVerificationsTotal, toolCallErrorsTotal, wireEgressBytesTotal } from './chunk-PAICJCKJ.js';
|
|
7
|
+
import { MCP_PROTOCOL_VERSION, MCP_LEGACY_SUPPORT_ENABLED, MCP_PROTOCOL_VERSION_LEGACY } from './chunk-EG46XMJT.js';
|
|
8
|
+
import { MeshNode } from './chunk-7RXOIDXP.js';
|
|
9
|
+
import { log } from './chunk-HA6YZ42O.js';
|
|
7
10
|
import * as grpc from '@grpc/grpc-js';
|
|
8
11
|
import { createDecipheriv, randomBytes, createCipheriv } from 'crypto';
|
|
9
12
|
|
|
@@ -11,6 +14,7 @@ var LiopRpcClient = class {
|
|
|
11
14
|
// biome-ignore lint/suspicious/noExplicitAny: internal gRPC client type
|
|
12
15
|
client;
|
|
13
16
|
token;
|
|
17
|
+
lastResolvedToken;
|
|
14
18
|
address;
|
|
15
19
|
constructor(address, tls, token) {
|
|
16
20
|
const credentials = createChannelCredentials(tls);
|
|
@@ -20,17 +24,35 @@ var LiopRpcClient = class {
|
|
|
20
24
|
GRPC_CHANNEL_OPTIONS
|
|
21
25
|
);
|
|
22
26
|
this.token = token;
|
|
27
|
+
if (typeof token === "string") {
|
|
28
|
+
this.lastResolvedToken = token;
|
|
29
|
+
}
|
|
23
30
|
this.address = address;
|
|
24
31
|
}
|
|
32
|
+
setToken(token) {
|
|
33
|
+
this.token = token;
|
|
34
|
+
if (typeof token === "string") {
|
|
35
|
+
this.lastResolvedToken = token;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async resolveToken() {
|
|
39
|
+
if (typeof this.token === "function") {
|
|
40
|
+
this.lastResolvedToken = await this.token();
|
|
41
|
+
return this.lastResolvedToken;
|
|
42
|
+
}
|
|
43
|
+
this.lastResolvedToken = this.token;
|
|
44
|
+
return this.token;
|
|
45
|
+
}
|
|
25
46
|
/**
|
|
26
47
|
* Negotiates intent with the remote host.
|
|
27
48
|
* Returns the ephemeral Kyber public key for payload encryption.
|
|
28
49
|
*/
|
|
29
50
|
async negotiateIntent(request) {
|
|
51
|
+
const activeToken = await this.resolveToken();
|
|
30
52
|
return new Promise((resolve, reject) => {
|
|
31
53
|
const metadata = new grpc.Metadata();
|
|
32
|
-
if (
|
|
33
|
-
metadata.add("authorization", `Bearer ${
|
|
54
|
+
if (activeToken) {
|
|
55
|
+
metadata.add("authorization", `Bearer ${activeToken}`);
|
|
34
56
|
}
|
|
35
57
|
this.client.NegotiateIntent(
|
|
36
58
|
request,
|
|
@@ -51,8 +73,9 @@ var LiopRpcClient = class {
|
|
|
51
73
|
*/
|
|
52
74
|
executeLogic(request) {
|
|
53
75
|
const metadata = new grpc.Metadata();
|
|
54
|
-
|
|
55
|
-
|
|
76
|
+
const activeToken = this.lastResolvedToken || (typeof this.token === "string" ? this.token : void 0);
|
|
77
|
+
if (activeToken) {
|
|
78
|
+
metadata.add("authorization", `Bearer ${activeToken}`);
|
|
56
79
|
}
|
|
57
80
|
return this.client.ExecuteLogic(request, metadata);
|
|
58
81
|
}
|
|
@@ -108,6 +131,7 @@ var LiopClient = class {
|
|
|
108
131
|
serverInfo;
|
|
109
132
|
verifier = new LiopVerifier();
|
|
110
133
|
oauthToken;
|
|
134
|
+
tokenManager;
|
|
111
135
|
/** Protocol negotiation era */
|
|
112
136
|
era = "modern";
|
|
113
137
|
/** Negotiated protocol version */
|
|
@@ -115,40 +139,6 @@ var LiopClient = class {
|
|
|
115
139
|
constructor(tls) {
|
|
116
140
|
this.tlsOptions = tls;
|
|
117
141
|
}
|
|
118
|
-
/**
|
|
119
|
-
* Requests an M2M access token from the Nexus Authorization Server using Client Credentials.
|
|
120
|
-
*/
|
|
121
|
-
async acquireM2MToken(authOpts) {
|
|
122
|
-
const baseUrl = authOpts.nexusUrl.endsWith("/oidc") ? authOpts.nexusUrl : `${authOpts.nexusUrl}/oidc`;
|
|
123
|
-
const tokenUrl = `${baseUrl}/token`;
|
|
124
|
-
log.info(`[LiopClient] Requesting M2M Token from Nexus AS: ${tokenUrl}`);
|
|
125
|
-
const params = new URLSearchParams({
|
|
126
|
-
grant_type: "client_credentials",
|
|
127
|
-
scope: authOpts.scope || "liop:tools:call liop:tools:list liop:resources:read liop:schema:read liop:mesh:query",
|
|
128
|
-
resource: authOpts.audience,
|
|
129
|
-
client_id: authOpts.clientId,
|
|
130
|
-
client_secret: authOpts.clientSecret
|
|
131
|
-
});
|
|
132
|
-
const response = await fetch(tokenUrl, {
|
|
133
|
-
method: "POST",
|
|
134
|
-
headers: {
|
|
135
|
-
"Content-Type": "application/x-www-form-urlencoded"
|
|
136
|
-
},
|
|
137
|
-
body: params.toString()
|
|
138
|
-
});
|
|
139
|
-
if (!response.ok) {
|
|
140
|
-
const text = await response.text();
|
|
141
|
-
throw new Error(
|
|
142
|
-
`OAuth token request failed with status ${response.status}: ${text}`
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
const data = await response.json();
|
|
146
|
-
if (!data.access_token) {
|
|
147
|
-
throw new Error("OAuth token response did not contain an access_token.");
|
|
148
|
-
}
|
|
149
|
-
log.info("[LiopClient] M2M Token acquired successfully.");
|
|
150
|
-
return data.access_token;
|
|
151
|
-
}
|
|
152
142
|
/**
|
|
153
143
|
* Discovers and connects to the target server or mesh capability.
|
|
154
144
|
* If address is omitted, it sets up the MeshNode to act purely dynamically.
|
|
@@ -161,14 +151,20 @@ var LiopClient = class {
|
|
|
161
151
|
const scope = options?.auth?.scope || process.env.LIOP_OAUTH_SCOPE || "liop:tools:call liop:tools:list liop:resources:read liop:schema:read liop:mesh:query";
|
|
162
152
|
this.oauthToken = options?.auth?.token || process.env.LIOP_OAUTH_TOKEN || process.env.LIOP_TOKEN;
|
|
163
153
|
if (clientId && clientSecret) {
|
|
154
|
+
const baseUrl = (nexusUrl).endsWith("/oidc") ? nexusUrl : `${nexusUrl}/oidc`;
|
|
155
|
+
const tokenEndpoint = `${baseUrl}/token`;
|
|
156
|
+
this.tokenManager = new TokenManager({
|
|
157
|
+
tokenEndpoint,
|
|
158
|
+
clientId,
|
|
159
|
+
clientSecret,
|
|
160
|
+
audience,
|
|
161
|
+
scopes: scope
|
|
162
|
+
});
|
|
164
163
|
try {
|
|
165
|
-
this.oauthToken = await this.
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
audience,
|
|
170
|
-
scope
|
|
171
|
-
});
|
|
164
|
+
this.oauthToken = await this.tokenManager.getToken();
|
|
165
|
+
log.info(
|
|
166
|
+
"[LiopClient] Dynamic TokenManager configured and initial token acquired."
|
|
167
|
+
);
|
|
172
168
|
} catch (err) {
|
|
173
169
|
log.error(
|
|
174
170
|
`[LiopClient] Failed to acquire OAuth M2M Token: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -181,9 +177,15 @@ var LiopClient = class {
|
|
|
181
177
|
`[LiopClient] Mesh Node synchronized. PeerID: ${this.meshNode.getPeerId()}`
|
|
182
178
|
);
|
|
183
179
|
if (address) {
|
|
180
|
+
const tokenResolver = async () => {
|
|
181
|
+
if (this.tokenManager) {
|
|
182
|
+
return await this.tokenManager.getToken();
|
|
183
|
+
}
|
|
184
|
+
return this.oauthToken;
|
|
185
|
+
};
|
|
184
186
|
this.rpcClients.set(
|
|
185
187
|
"static",
|
|
186
|
-
new LiopRpcClient(address, this.tlsOptions,
|
|
188
|
+
new LiopRpcClient(address, this.tlsOptions, tokenResolver)
|
|
187
189
|
);
|
|
188
190
|
this.serverInfo = { name: `LiopServer (${address})`, version: "1.0.0" };
|
|
189
191
|
log.info(`[LiopClient] Static gRPC configured for: ${address}`);
|
|
@@ -313,6 +315,7 @@ var LiopClient = class {
|
|
|
313
315
|
if (!this.meshNode) {
|
|
314
316
|
throw new Error("Client must be connected before discovering tools.");
|
|
315
317
|
}
|
|
318
|
+
const discoveryStartTime = Date.now();
|
|
316
319
|
log.info(
|
|
317
320
|
`[LiopClient] Discovery started (forceRefresh: ${forceRefresh})...`
|
|
318
321
|
);
|
|
@@ -349,6 +352,19 @@ var LiopClient = class {
|
|
|
349
352
|
log.info(
|
|
350
353
|
`[LiopClient] Discovery finished. Found ${tools.length} unique tools.`
|
|
351
354
|
);
|
|
355
|
+
try {
|
|
356
|
+
const telemetry = TokenTelemetryEngine.getInstance();
|
|
357
|
+
const toolsPayload = JSON.stringify(tools);
|
|
358
|
+
const toolsResponsePayload = JSON.stringify({ tools });
|
|
359
|
+
telemetry.record({
|
|
360
|
+
type: "tools_list",
|
|
361
|
+
method: "discoverTools",
|
|
362
|
+
estimatedInputTokens: telemetry.countTokens(toolsPayload),
|
|
363
|
+
estimatedOutputTokens: telemetry.countTokens(toolsResponsePayload),
|
|
364
|
+
durationMs: Date.now() - discoveryStartTime
|
|
365
|
+
});
|
|
366
|
+
} catch {
|
|
367
|
+
}
|
|
352
368
|
return tools;
|
|
353
369
|
}
|
|
354
370
|
/**
|
|
@@ -358,6 +374,7 @@ var LiopClient = class {
|
|
|
358
374
|
if (!this.meshNode) {
|
|
359
375
|
throw new Error("Client must be connected before calling tools.");
|
|
360
376
|
}
|
|
377
|
+
const callStartTime = Date.now();
|
|
361
378
|
const toolName = request.name;
|
|
362
379
|
log.info(`[LiopClient] Resolving Tool: ${toolName}`);
|
|
363
380
|
let rpcClient = this.rpcClients.get("static");
|
|
@@ -405,13 +422,52 @@ var LiopClient = class {
|
|
|
405
422
|
const agentDid = this.meshNode ? `did:liop:${this.meshNode.getPeerId()}` : "did:liop:ephemeral";
|
|
406
423
|
const intentPayload = Buffer.from(`${toolName}:${Date.now()}`);
|
|
407
424
|
const proofOfIntent = this.meshNode ? await this.meshNode.sign(intentPayload) : intentPayload;
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
425
|
+
let intentResponse;
|
|
426
|
+
try {
|
|
427
|
+
intentResponse = await rpcClient.negotiateIntent({
|
|
428
|
+
agent_did: agentDid,
|
|
429
|
+
capability_hash: toolName,
|
|
430
|
+
proof_of_intent: proofOfIntent
|
|
431
|
+
});
|
|
432
|
+
} catch (err) {
|
|
433
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
434
|
+
if (this.tokenManager && (errMsg.includes("UNAUTHENTICATED") || errMsg.includes("Invalid JWT") || errMsg.includes("timestamp check failed") || errMsg.includes("expired"))) {
|
|
435
|
+
log.warn(
|
|
436
|
+
`[LiopClient] Token expired/unauthenticated for ${toolName}. Preemptively refreshing OAuth token and retrying negotiateIntent...`
|
|
437
|
+
);
|
|
438
|
+
this.tokenManager.invalidate();
|
|
439
|
+
const freshToken = await this.tokenManager.getToken();
|
|
440
|
+
this.oauthToken = freshToken;
|
|
441
|
+
rpcClient.setToken(freshToken);
|
|
442
|
+
intentResponse = await rpcClient.negotiateIntent({
|
|
443
|
+
agent_did: agentDid,
|
|
444
|
+
capability_hash: toolName,
|
|
445
|
+
proof_of_intent: proofOfIntent
|
|
446
|
+
});
|
|
447
|
+
} else {
|
|
448
|
+
throw err;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
413
451
|
if (!intentResponse.accepted) {
|
|
414
|
-
|
|
452
|
+
if (this.tokenManager && (intentResponse.error_message?.includes("token") || intentResponse.error_message?.includes("UNAUTHENTICATED") || intentResponse.error_message?.includes("expired") || intentResponse.error_message?.includes("timestamp check failed"))) {
|
|
453
|
+
log.warn(
|
|
454
|
+
`[LiopClient] Intent rejected with auth error: "${intentResponse.error_message}". Refreshing token and retrying...`
|
|
455
|
+
);
|
|
456
|
+
this.tokenManager.invalidate();
|
|
457
|
+
const freshToken = await this.tokenManager.getToken();
|
|
458
|
+
this.oauthToken = freshToken;
|
|
459
|
+
rpcClient.setToken(freshToken);
|
|
460
|
+
intentResponse = await rpcClient.negotiateIntent({
|
|
461
|
+
agent_did: agentDid,
|
|
462
|
+
capability_hash: toolName,
|
|
463
|
+
proof_of_intent: proofOfIntent
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
if (!intentResponse.accepted) {
|
|
467
|
+
throw new Error(
|
|
468
|
+
`Intent denied by host: ${intentResponse.error_message}`
|
|
469
|
+
);
|
|
470
|
+
}
|
|
415
471
|
}
|
|
416
472
|
const publicKey = intentResponse.kyber_public_key || intentResponse.kyberPublicKey;
|
|
417
473
|
const sessionToken = intentResponse.session_token || intentResponse.sessionToken;
|
|
@@ -420,6 +476,13 @@ var LiopClient = class {
|
|
|
420
476
|
"[LiopClient] Critical Error: Kyber Public Key not found in IntentResponse.",
|
|
421
477
|
intentResponse
|
|
422
478
|
);
|
|
479
|
+
try {
|
|
480
|
+
pqcHandshakesTotal.inc({
|
|
481
|
+
algorithm: "ml-kem-768",
|
|
482
|
+
status: "failure"
|
|
483
|
+
});
|
|
484
|
+
} catch {
|
|
485
|
+
}
|
|
423
486
|
throw new Error(
|
|
424
487
|
"Handshake failed: Remote host did not provide a valid Kyber Public Key."
|
|
425
488
|
);
|
|
@@ -427,7 +490,29 @@ var LiopClient = class {
|
|
|
427
490
|
log.info(
|
|
428
491
|
`[LiopClient] Encapsulating Post-Quantum Shared Secret for ${request.name}...`
|
|
429
492
|
);
|
|
430
|
-
const
|
|
493
|
+
const pqcStart = performance.now();
|
|
494
|
+
let kyberCiphertext;
|
|
495
|
+
let sharedSecret;
|
|
496
|
+
try {
|
|
497
|
+
const res = await Kyber768Wrapper.encapsulateAsymmetric(publicKey);
|
|
498
|
+
kyberCiphertext = res.ciphertext;
|
|
499
|
+
sharedSecret = res.sharedSecret;
|
|
500
|
+
const pqcDuration = performance.now() - pqcStart;
|
|
501
|
+
pqcHandshakeDurationMs.observe({ tool: request.name }, pqcDuration);
|
|
502
|
+
pqcHandshakesTotal.inc({
|
|
503
|
+
algorithm: "ml-kem-768",
|
|
504
|
+
status: "success"
|
|
505
|
+
});
|
|
506
|
+
} catch (encapError) {
|
|
507
|
+
try {
|
|
508
|
+
pqcHandshakesTotal.inc({
|
|
509
|
+
algorithm: "ml-kem-768",
|
|
510
|
+
status: "failure"
|
|
511
|
+
});
|
|
512
|
+
} catch {
|
|
513
|
+
}
|
|
514
|
+
throw encapError;
|
|
515
|
+
}
|
|
431
516
|
log.info(`[LiopClient] Sealing WASM Payload and Inputs...`);
|
|
432
517
|
const _safePayload = _wasmPayload || Buffer.from("");
|
|
433
518
|
const { ciphertext: encryptedWasm, nonce: aesNonce } = AesGcmWrapper.encryptPayload(_safePayload, sharedSecret);
|
|
@@ -475,7 +560,20 @@ var LiopClient = class {
|
|
|
475
560
|
Buffer.from(sharedSecret),
|
|
476
561
|
response.semantic_evidence
|
|
477
562
|
);
|
|
563
|
+
try {
|
|
564
|
+
zkVerificationsTotal.inc({
|
|
565
|
+
status: isValid ? "valid" : "invalid"
|
|
566
|
+
});
|
|
567
|
+
} catch {
|
|
568
|
+
}
|
|
478
569
|
if (!isValid) {
|
|
570
|
+
try {
|
|
571
|
+
toolCallErrorsTotal.inc({
|
|
572
|
+
capability: toolName,
|
|
573
|
+
error_type: "zk_verification_failed"
|
|
574
|
+
});
|
|
575
|
+
} catch {
|
|
576
|
+
}
|
|
479
577
|
reject(
|
|
480
578
|
new Error(
|
|
481
579
|
"PROTOCOL INTEGRITY VIOLATION: ZK-Receipt verification failed."
|
|
@@ -483,8 +581,34 @@ var LiopClient = class {
|
|
|
483
581
|
);
|
|
484
582
|
return;
|
|
485
583
|
}
|
|
584
|
+
} else {
|
|
585
|
+
try {
|
|
586
|
+
toolCallErrorsTotal.inc({
|
|
587
|
+
capability: toolName,
|
|
588
|
+
error_type: "remote_execution_error"
|
|
589
|
+
});
|
|
590
|
+
} catch {
|
|
591
|
+
}
|
|
486
592
|
}
|
|
487
593
|
resultFulfilled = true;
|
|
594
|
+
try {
|
|
595
|
+
const telemetry = TokenTelemetryEngine.getInstance();
|
|
596
|
+
const inputPayload = JSON.stringify(request.arguments ?? {});
|
|
597
|
+
telemetry.record({
|
|
598
|
+
type: "tool_call",
|
|
599
|
+
method: "callTool",
|
|
600
|
+
toolName,
|
|
601
|
+
peerId: targetClientKey !== toolName ? targetClientKey : void 0,
|
|
602
|
+
estimatedInputTokens: telemetry.countTokens(inputPayload),
|
|
603
|
+
estimatedOutputTokens: telemetry.countTokens(
|
|
604
|
+
response.semantic_evidence
|
|
605
|
+
),
|
|
606
|
+
durationMs: Date.now() - callStartTime
|
|
607
|
+
});
|
|
608
|
+
const egressBytes = Buffer.byteLength(response.semantic_evidence || "") + (response.cryptographic_proof ? response.cryptographic_proof.length : 0) + (response.zk_receipt ? response.zk_receipt.length : 0);
|
|
609
|
+
wireEgressBytesTotal.inc({ capability: toolName }, egressBytes);
|
|
610
|
+
} catch {
|
|
611
|
+
}
|
|
488
612
|
resolve({
|
|
489
613
|
content: [
|
|
490
614
|
{
|
|
@@ -495,12 +619,26 @@ var LiopClient = class {
|
|
|
495
619
|
isError: response.is_error
|
|
496
620
|
});
|
|
497
621
|
} catch (err) {
|
|
622
|
+
try {
|
|
623
|
+
toolCallErrorsTotal.inc({
|
|
624
|
+
capability: toolName,
|
|
625
|
+
error_type: "verification_exception"
|
|
626
|
+
});
|
|
627
|
+
} catch {
|
|
628
|
+
}
|
|
498
629
|
reject(err);
|
|
499
630
|
}
|
|
500
631
|
});
|
|
501
632
|
stream.on("error", (err) => {
|
|
502
633
|
this.rpcClients.delete(targetClientKey);
|
|
503
634
|
this.rpcClients.delete(toolName);
|
|
635
|
+
try {
|
|
636
|
+
toolCallErrorsTotal.inc({
|
|
637
|
+
capability: toolName,
|
|
638
|
+
error_type: "stream_error"
|
|
639
|
+
});
|
|
640
|
+
} catch {
|
|
641
|
+
}
|
|
504
642
|
if (resultFulfilled) return;
|
|
505
643
|
log.error("[LiopClient] Stream Error:", err);
|
|
506
644
|
reject(err);
|
|
@@ -515,7 +653,6 @@ var LiopClient = class {
|
|
|
515
653
|
getOrCreateRpcClient(peerId, address) {
|
|
516
654
|
let client = this.rpcClients.get(peerId);
|
|
517
655
|
if (!client) {
|
|
518
|
-
let nodeToken = this.oauthToken;
|
|
519
656
|
let manifest = this.manifests.get(peerId);
|
|
520
657
|
let realPeerId = peerId;
|
|
521
658
|
if (!manifest) {
|
|
@@ -560,9 +697,15 @@ var LiopClient = class {
|
|
|
560
697
|
log.info(
|
|
561
698
|
`[LiopClient] Resolved node-specific token for peer ${realPeerId.slice(-8)} (${providerName || "unknown"})`
|
|
562
699
|
);
|
|
563
|
-
nodeToken = envToken;
|
|
564
700
|
}
|
|
565
|
-
|
|
701
|
+
const tokenResolver = async () => {
|
|
702
|
+
if (envToken) return envToken;
|
|
703
|
+
if (this.tokenManager) {
|
|
704
|
+
return await this.tokenManager.getToken();
|
|
705
|
+
}
|
|
706
|
+
return this.oauthToken;
|
|
707
|
+
};
|
|
708
|
+
client = new LiopRpcClient(address, this.tlsOptions, tokenResolver);
|
|
566
709
|
this.rpcClients.set(peerId, client);
|
|
567
710
|
}
|
|
568
711
|
return client;
|
|
@@ -575,6 +718,7 @@ var LiopClient = class {
|
|
|
575
718
|
if (!this.meshNode) {
|
|
576
719
|
throw new Error("Client must be connected before reading resources.");
|
|
577
720
|
}
|
|
721
|
+
const readStartTime = Date.now();
|
|
578
722
|
log.info(`[LiopClient] Querying Mesh for Resource: ${uri}...`);
|
|
579
723
|
const providers = await this.meshNode.findProviders(uri);
|
|
580
724
|
if (providers.length === 0) {
|
|
@@ -588,7 +732,7 @@ var LiopClient = class {
|
|
|
588
732
|
if (!resourceDef) {
|
|
589
733
|
throw new Error(`Resource ${uri} not listed in remote manifest.`);
|
|
590
734
|
}
|
|
591
|
-
|
|
735
|
+
const result = {
|
|
592
736
|
contents: [
|
|
593
737
|
{
|
|
594
738
|
uri,
|
|
@@ -597,6 +741,21 @@ var LiopClient = class {
|
|
|
597
741
|
}
|
|
598
742
|
]
|
|
599
743
|
};
|
|
744
|
+
try {
|
|
745
|
+
const telemetry = TokenTelemetryEngine.getInstance();
|
|
746
|
+
const outputPayload = JSON.stringify(result);
|
|
747
|
+
telemetry.record({
|
|
748
|
+
type: "resource_read",
|
|
749
|
+
method: "readResource",
|
|
750
|
+
toolName: uri,
|
|
751
|
+
peerId: providers[0],
|
|
752
|
+
estimatedInputTokens: telemetry.countTokens(uri),
|
|
753
|
+
estimatedOutputTokens: telemetry.countTokens(outputPayload),
|
|
754
|
+
durationMs: Date.now() - readStartTime
|
|
755
|
+
});
|
|
756
|
+
} catch {
|
|
757
|
+
}
|
|
758
|
+
return result;
|
|
600
759
|
}
|
|
601
760
|
getServerInfo() {
|
|
602
761
|
return this.serverInfo;
|
|
@@ -611,6 +770,6 @@ var LiopClient = class {
|
|
|
611
770
|
}
|
|
612
771
|
};
|
|
613
772
|
|
|
614
|
-
export { LiopClient, LiopRpcClient };
|
|
615
|
-
//# sourceMappingURL=chunk-
|
|
616
|
-
//# sourceMappingURL=chunk-
|
|
773
|
+
export { AesGcmWrapper, LiopClient, LiopRpcClient };
|
|
774
|
+
//# sourceMappingURL=chunk-T7R5HUFD.js.map
|
|
775
|
+
//# sourceMappingURL=chunk-T7R5HUFD.js.map
|