@hai.ai/jacs 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +237 -0
- package/http.d.ts +13 -0
- package/http.js +154 -0
- package/index.d.ts +178 -0
- package/index.js +343 -0
- package/jacs.darwin-arm64.node +0 -0
- package/jacs.darwin-x64.node +0 -0
- package/jacs.linux-arm-gnueabihf.node +0 -0
- package/jacs.linux-arm-musleabihf.node +0 -0
- package/jacs.linux-arm64-gnu.node +0 -0
- package/jacs.linux-x64-gnu.node +0 -0
- package/jacs.linux-x64-musl.node +0 -0
- package/mcp.d.ts +61 -0
- package/mcp.js +514 -0
- package/mcp.js.map +1 -0
- package/mcp.ts +521 -0
- package/package.json +103 -0
- package/simple.d.ts +573 -0
- package/simple.js +920 -0
- package/src/a2a.d.ts +79 -0
- package/src/a2a.js +617 -0
package/simple.js
ADDED
|
@@ -0,0 +1,920 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* JACS Simplified API for TypeScript/JavaScript
|
|
4
|
+
*
|
|
5
|
+
* A streamlined interface for the most common JACS operations:
|
|
6
|
+
* - load(): Load an existing agent from config
|
|
7
|
+
* - verifySelf(): Verify the loaded agent's integrity
|
|
8
|
+
* - signMessage(): Sign a message or data
|
|
9
|
+
* - verify(): Verify any signed document
|
|
10
|
+
* - signFile(): Sign a file with optional embedding
|
|
11
|
+
* - updateAgent(): Update the agent document with new data
|
|
12
|
+
* - updateDocument(): Update an existing document with new data
|
|
13
|
+
* - createAgreement(): Create a multi-party agreement
|
|
14
|
+
* - signAgreement(): Sign an existing agreement
|
|
15
|
+
* - checkAgreement(): Check agreement status
|
|
16
|
+
* - trustAgent(): Add an agent to the local trust store
|
|
17
|
+
* - listTrustedAgents(): List all trusted agent IDs
|
|
18
|
+
* - untrustAgent(): Remove an agent from the trust store
|
|
19
|
+
* - isTrusted(): Check if an agent is trusted
|
|
20
|
+
* - getTrustedAgent(): Get a trusted agent's JSON
|
|
21
|
+
* - audit(): Run a read-only security audit and health checks
|
|
22
|
+
*
|
|
23
|
+
* Also re-exports for advanced usage:
|
|
24
|
+
* - JacsAgent: Class for direct agent control
|
|
25
|
+
* - hashString: Standalone SHA-256 hashing
|
|
26
|
+
* - verifyString: Verify with external public key
|
|
27
|
+
* - createConfig: Create agent configuration
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* import * as jacs from '@hai.ai/jacs/simple';
|
|
32
|
+
*
|
|
33
|
+
* // Load agent
|
|
34
|
+
* const agent = jacs.load('./jacs.config.json');
|
|
35
|
+
*
|
|
36
|
+
* // Sign a message
|
|
37
|
+
* const signed = jacs.signMessage({ action: 'approve', amount: 100 });
|
|
38
|
+
*
|
|
39
|
+
* // Verify it
|
|
40
|
+
* const result = jacs.verify(signed.raw);
|
|
41
|
+
* console.log(`Valid: ${result.valid}`);
|
|
42
|
+
*
|
|
43
|
+
* // Use standalone hash function
|
|
44
|
+
* const hash = jacs.hashString('data to hash');
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
48
|
+
if (k2 === undefined) k2 = k;
|
|
49
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
50
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
51
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
52
|
+
}
|
|
53
|
+
Object.defineProperty(o, k2, desc);
|
|
54
|
+
}) : (function(o, m, k, k2) {
|
|
55
|
+
if (k2 === undefined) k2 = k;
|
|
56
|
+
o[k2] = m[k];
|
|
57
|
+
}));
|
|
58
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
59
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
60
|
+
}) : function(o, v) {
|
|
61
|
+
o["default"] = v;
|
|
62
|
+
});
|
|
63
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
64
|
+
var ownKeys = function(o) {
|
|
65
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
66
|
+
var ar = [];
|
|
67
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
68
|
+
return ar;
|
|
69
|
+
};
|
|
70
|
+
return ownKeys(o);
|
|
71
|
+
};
|
|
72
|
+
return function (mod) {
|
|
73
|
+
if (mod && mod.__esModule) return mod;
|
|
74
|
+
var result = {};
|
|
75
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
76
|
+
__setModuleDefault(result, mod);
|
|
77
|
+
return result;
|
|
78
|
+
};
|
|
79
|
+
})();
|
|
80
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
81
|
+
exports.MAX_VERIFY_DOCUMENT_BYTES = exports.MAX_VERIFY_URL_LEN = exports.createConfig = exports.verifyString = exports.hashString = exports.JacsAgent = void 0;
|
|
82
|
+
exports.create = create;
|
|
83
|
+
exports.load = load;
|
|
84
|
+
exports.verifySelf = verifySelf;
|
|
85
|
+
exports.signMessage = signMessage;
|
|
86
|
+
exports.updateAgent = updateAgent;
|
|
87
|
+
exports.updateDocument = updateDocument;
|
|
88
|
+
exports.signFile = signFile;
|
|
89
|
+
exports.verify = verify;
|
|
90
|
+
exports.verifyStandalone = verifyStandalone;
|
|
91
|
+
exports.verifyById = verifyById;
|
|
92
|
+
exports.reencryptKey = reencryptKey;
|
|
93
|
+
exports.getPublicKey = getPublicKey;
|
|
94
|
+
exports.exportAgent = exportAgent;
|
|
95
|
+
exports.getAgentInfo = getAgentInfo;
|
|
96
|
+
exports.isLoaded = isLoaded;
|
|
97
|
+
exports.getDnsRecord = getDnsRecord;
|
|
98
|
+
exports.getWellKnownJson = getWellKnownJson;
|
|
99
|
+
exports.registerWithHai = registerWithHai;
|
|
100
|
+
exports.createAgreement = createAgreement;
|
|
101
|
+
exports.signAgreement = signAgreement;
|
|
102
|
+
exports.checkAgreement = checkAgreement;
|
|
103
|
+
exports.trustAgent = trustAgent;
|
|
104
|
+
exports.listTrustedAgents = listTrustedAgents;
|
|
105
|
+
exports.untrustAgent = untrustAgent;
|
|
106
|
+
exports.isTrusted = isTrusted;
|
|
107
|
+
exports.getTrustedAgent = getTrustedAgent;
|
|
108
|
+
exports.audit = audit;
|
|
109
|
+
exports.generateVerifyLink = generateVerifyLink;
|
|
110
|
+
const index_1 = require("./index");
|
|
111
|
+
Object.defineProperty(exports, "JacsAgent", { enumerable: true, get: function () { return index_1.JacsAgent; } });
|
|
112
|
+
Object.defineProperty(exports, "hashString", { enumerable: true, get: function () { return index_1.hashString; } });
|
|
113
|
+
Object.defineProperty(exports, "verifyString", { enumerable: true, get: function () { return index_1.verifyString; } });
|
|
114
|
+
Object.defineProperty(exports, "createConfig", { enumerable: true, get: function () { return index_1.createConfig; } });
|
|
115
|
+
const fs = __importStar(require("fs"));
|
|
116
|
+
const path = __importStar(require("path"));
|
|
117
|
+
// =============================================================================
|
|
118
|
+
// Global State
|
|
119
|
+
// =============================================================================
|
|
120
|
+
let globalAgent = null;
|
|
121
|
+
let agentInfo = null;
|
|
122
|
+
function resolveConfigRelativePath(configPath, candidate) {
|
|
123
|
+
if (path.isAbsolute(candidate)) {
|
|
124
|
+
return candidate;
|
|
125
|
+
}
|
|
126
|
+
return path.resolve(path.dirname(configPath), candidate);
|
|
127
|
+
}
|
|
128
|
+
function normalizeDocumentInput(document) {
|
|
129
|
+
if (typeof document === 'string') {
|
|
130
|
+
return document;
|
|
131
|
+
}
|
|
132
|
+
if (document && typeof document === 'object') {
|
|
133
|
+
if (typeof document.raw === 'string') {
|
|
134
|
+
return document.raw;
|
|
135
|
+
}
|
|
136
|
+
if (typeof document.raw_json === 'string') {
|
|
137
|
+
return document.raw_json;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return JSON.stringify(document);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Creates a new JACS agent with cryptographic keys.
|
|
144
|
+
*
|
|
145
|
+
* This is a fully programmatic API that does not require interactive input.
|
|
146
|
+
* The password must be provided directly or via the JACS_PRIVATE_KEY_PASSWORD
|
|
147
|
+
* environment variable.
|
|
148
|
+
*
|
|
149
|
+
* @param options - Agent creation options
|
|
150
|
+
* @returns AgentInfo containing the agent ID, name, and file paths
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```typescript
|
|
154
|
+
* const agent = jacs.create({
|
|
155
|
+
* name: 'my-agent',
|
|
156
|
+
* password: process.env.JACS_PRIVATE_KEY_PASSWORD,
|
|
157
|
+
* algorithm: 'pq2025',
|
|
158
|
+
* });
|
|
159
|
+
* console.log(`Created: ${agent.agentId}`);
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
function create(options) {
|
|
163
|
+
const resolvedPassword = options.password ?? process.env.JACS_PRIVATE_KEY_PASSWORD ?? '';
|
|
164
|
+
if (!resolvedPassword) {
|
|
165
|
+
throw new Error('Missing private key password. Pass options.password or set JACS_PRIVATE_KEY_PASSWORD.');
|
|
166
|
+
}
|
|
167
|
+
const resultJson = (0, index_1.createAgent)(options.name, resolvedPassword, options.algorithm ?? null, options.dataDirectory ?? null, options.keyDirectory ?? null, options.configPath ?? null, options.agentType ?? null, options.description ?? null, options.domain ?? null, options.defaultStorage ?? null);
|
|
168
|
+
const info = JSON.parse(resultJson);
|
|
169
|
+
return {
|
|
170
|
+
agentId: info.agent_id || '',
|
|
171
|
+
name: info.name || options.name,
|
|
172
|
+
publicKeyPath: info.public_key_path || `${options.keyDirectory || './jacs_keys'}/jacs.public.pem`,
|
|
173
|
+
configPath: info.config_path || options.configPath || './jacs.config.json',
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Loads an existing agent from a configuration file.
|
|
178
|
+
*
|
|
179
|
+
* @param configPath - Path to jacs.config.json (default: "./jacs.config.json")
|
|
180
|
+
* @returns AgentInfo with the loaded agent's details
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* const agent = jacs.load('./jacs.config.json');
|
|
185
|
+
* console.log(`Loaded: ${agent.agentId}`);
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
function load(configPath) {
|
|
189
|
+
const requestedPath = configPath || './jacs.config.json';
|
|
190
|
+
const resolvedConfigPath = path.resolve(requestedPath);
|
|
191
|
+
if (!fs.existsSync(resolvedConfigPath)) {
|
|
192
|
+
throw new Error(`Config file not found: ${requestedPath}\nRun 'jacs create' to create a new agent.`);
|
|
193
|
+
}
|
|
194
|
+
// Create new agent instance
|
|
195
|
+
globalAgent = new index_1.JacsAgent();
|
|
196
|
+
globalAgent.load(resolvedConfigPath);
|
|
197
|
+
// Read config to get agent info
|
|
198
|
+
const config = JSON.parse(fs.readFileSync(resolvedConfigPath, 'utf8'));
|
|
199
|
+
const agentIdVersion = config.jacs_agent_id_and_version || '';
|
|
200
|
+
const [agentId, version] = agentIdVersion.split(':');
|
|
201
|
+
const keyDir = resolveConfigRelativePath(resolvedConfigPath, config.jacs_key_directory || './jacs_keys');
|
|
202
|
+
agentInfo = {
|
|
203
|
+
agentId: agentId || '',
|
|
204
|
+
name: config.name || '',
|
|
205
|
+
publicKeyPath: path.join(keyDir, 'jacs.public.pem'),
|
|
206
|
+
configPath: resolvedConfigPath,
|
|
207
|
+
};
|
|
208
|
+
return agentInfo;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Verifies the currently loaded agent's integrity.
|
|
212
|
+
*
|
|
213
|
+
* @returns VerificationResult indicating if the agent is valid
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```typescript
|
|
217
|
+
* const result = jacs.verifySelf();
|
|
218
|
+
* if (result.valid) {
|
|
219
|
+
* console.log('Agent integrity verified');
|
|
220
|
+
* }
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
function verifySelf() {
|
|
224
|
+
if (!globalAgent) {
|
|
225
|
+
throw new Error('No agent loaded. Call load() first.');
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
globalAgent.verifyAgent();
|
|
229
|
+
return {
|
|
230
|
+
valid: true,
|
|
231
|
+
signerId: agentInfo?.agentId || '',
|
|
232
|
+
timestamp: '',
|
|
233
|
+
attachments: [],
|
|
234
|
+
errors: [],
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
catch (e) {
|
|
238
|
+
return {
|
|
239
|
+
valid: false,
|
|
240
|
+
signerId: '',
|
|
241
|
+
timestamp: '',
|
|
242
|
+
attachments: [],
|
|
243
|
+
errors: [String(e)],
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Signs arbitrary data as a JACS message.
|
|
249
|
+
*
|
|
250
|
+
* @param data - The data to sign (object, string, or any JSON-serializable value)
|
|
251
|
+
* @returns SignedDocument containing the full signed document
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```typescript
|
|
255
|
+
* const signed = jacs.signMessage({ action: 'approve', amount: 100 });
|
|
256
|
+
* console.log(`Document ID: ${signed.documentId}`);
|
|
257
|
+
* ```
|
|
258
|
+
*/
|
|
259
|
+
function signMessage(data) {
|
|
260
|
+
if (!globalAgent) {
|
|
261
|
+
throw new Error('No agent loaded. Call load() first.');
|
|
262
|
+
}
|
|
263
|
+
// Create document structure
|
|
264
|
+
const docContent = {
|
|
265
|
+
jacsType: 'message',
|
|
266
|
+
jacsLevel: 'raw',
|
|
267
|
+
content: data,
|
|
268
|
+
};
|
|
269
|
+
const result = globalAgent.createDocument(JSON.stringify(docContent), null, null, true, // no_save
|
|
270
|
+
null, null);
|
|
271
|
+
// Parse result
|
|
272
|
+
const doc = JSON.parse(result);
|
|
273
|
+
return {
|
|
274
|
+
raw: result,
|
|
275
|
+
documentId: doc.jacsId || '',
|
|
276
|
+
agentId: doc.jacsSignature?.agentID || '',
|
|
277
|
+
timestamp: doc.jacsSignature?.date || '',
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Updates the agent document with new data and re-signs it.
|
|
282
|
+
*
|
|
283
|
+
* This function expects a complete agent document (not partial updates).
|
|
284
|
+
* Use exportAgent() to get the current document, modify it, then pass it here.
|
|
285
|
+
* The function will create a new version, re-sign, and re-hash the document.
|
|
286
|
+
*
|
|
287
|
+
* @param newAgentData - Complete agent document as JSON string or object
|
|
288
|
+
* @returns The updated and re-signed agent document as a JSON string
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* ```typescript
|
|
292
|
+
* // Get current agent, modify, and update
|
|
293
|
+
* const agentDoc = JSON.parse(jacs.exportAgent());
|
|
294
|
+
* agentDoc.jacsAgentType = 'updated-service';
|
|
295
|
+
* const updated = jacs.updateAgent(agentDoc);
|
|
296
|
+
* console.log('Agent updated with new version');
|
|
297
|
+
* ```
|
|
298
|
+
*/
|
|
299
|
+
function updateAgent(newAgentData) {
|
|
300
|
+
if (!globalAgent) {
|
|
301
|
+
throw new Error('No agent loaded. Call load() first.');
|
|
302
|
+
}
|
|
303
|
+
const dataString = typeof newAgentData === 'string'
|
|
304
|
+
? newAgentData
|
|
305
|
+
: JSON.stringify(newAgentData);
|
|
306
|
+
return globalAgent.updateAgent(dataString);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Updates an existing document with new data and re-signs it.
|
|
310
|
+
*
|
|
311
|
+
* Use signMessage() to create a document first, then use this to update it.
|
|
312
|
+
* The function will create a new version, re-sign, and re-hash the document.
|
|
313
|
+
*
|
|
314
|
+
* @param documentId - The document ID (jacsId) to update
|
|
315
|
+
* @param newDocumentData - The updated document as JSON string or object
|
|
316
|
+
* @param attachments - Optional array of file paths to attach
|
|
317
|
+
* @param embed - If true, embed attachment contents
|
|
318
|
+
* @returns SignedDocument with the updated document
|
|
319
|
+
*
|
|
320
|
+
* @example
|
|
321
|
+
* ```typescript
|
|
322
|
+
* // Create a document first
|
|
323
|
+
* const signed = jacs.signMessage({ status: 'pending' });
|
|
324
|
+
*
|
|
325
|
+
* // Later, update it
|
|
326
|
+
* const doc = JSON.parse(signed.raw);
|
|
327
|
+
* doc.content.status = 'approved';
|
|
328
|
+
* const updated = jacs.updateDocument(signed.documentId, doc);
|
|
329
|
+
* console.log('Document updated with new version');
|
|
330
|
+
* ```
|
|
331
|
+
*/
|
|
332
|
+
function updateDocument(documentId, newDocumentData, attachments, embed) {
|
|
333
|
+
if (!globalAgent) {
|
|
334
|
+
throw new Error('No agent loaded. Call load() first.');
|
|
335
|
+
}
|
|
336
|
+
const dataString = typeof newDocumentData === 'string'
|
|
337
|
+
? newDocumentData
|
|
338
|
+
: JSON.stringify(newDocumentData);
|
|
339
|
+
const result = globalAgent.updateDocument(documentId, dataString, attachments || null, embed ?? null);
|
|
340
|
+
const doc = JSON.parse(result);
|
|
341
|
+
return {
|
|
342
|
+
raw: result,
|
|
343
|
+
documentId: doc.jacsId || '',
|
|
344
|
+
agentId: doc.jacsSignature?.agentID || '',
|
|
345
|
+
timestamp: doc.jacsSignature?.date || '',
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Signs a file with optional content embedding.
|
|
350
|
+
*
|
|
351
|
+
* @param filePath - Path to the file to sign
|
|
352
|
+
* @param embed - If true, embed file content in the document
|
|
353
|
+
* @returns SignedDocument with file attachment
|
|
354
|
+
*
|
|
355
|
+
* @example
|
|
356
|
+
* ```typescript
|
|
357
|
+
* const signed = jacs.signFile('contract.pdf', true);
|
|
358
|
+
* console.log(`Signed: ${signed.attachments[0].filename}`);
|
|
359
|
+
* ```
|
|
360
|
+
*/
|
|
361
|
+
function signFile(filePath, embed = false) {
|
|
362
|
+
if (!globalAgent) {
|
|
363
|
+
throw new Error('No agent loaded. Call load() first.');
|
|
364
|
+
}
|
|
365
|
+
if (!fs.existsSync(filePath)) {
|
|
366
|
+
throw new Error(`File not found: ${filePath}`);
|
|
367
|
+
}
|
|
368
|
+
// Create document structure
|
|
369
|
+
const docContent = {
|
|
370
|
+
jacsType: 'file',
|
|
371
|
+
jacsLevel: 'raw',
|
|
372
|
+
filename: path.basename(filePath),
|
|
373
|
+
};
|
|
374
|
+
const result = globalAgent.createDocument(JSON.stringify(docContent), null, null, true, // no_save
|
|
375
|
+
filePath, embed);
|
|
376
|
+
// Parse result
|
|
377
|
+
const doc = JSON.parse(result);
|
|
378
|
+
return {
|
|
379
|
+
raw: result,
|
|
380
|
+
documentId: doc.jacsId || '',
|
|
381
|
+
agentId: doc.jacsSignature?.agentID || '',
|
|
382
|
+
timestamp: doc.jacsSignature?.date || '',
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Verifies a signed document and extracts its content.
|
|
387
|
+
*
|
|
388
|
+
* @param signedDocument - The JSON string of the signed document
|
|
389
|
+
* @returns VerificationResult with the verification status and extracted content
|
|
390
|
+
*
|
|
391
|
+
* @example
|
|
392
|
+
* ```typescript
|
|
393
|
+
* const result = jacs.verify(signedJson);
|
|
394
|
+
* if (result.valid) {
|
|
395
|
+
* console.log(`Signed by: ${result.signerId}`);
|
|
396
|
+
* }
|
|
397
|
+
* ```
|
|
398
|
+
*/
|
|
399
|
+
function verify(signedDocument) {
|
|
400
|
+
if (!globalAgent) {
|
|
401
|
+
throw new Error('No agent loaded. Call load() first.');
|
|
402
|
+
}
|
|
403
|
+
// Detect non-JSON input and provide helpful error
|
|
404
|
+
const trimmed = signedDocument.trim();
|
|
405
|
+
if (trimmed.length > 0 && !trimmed.startsWith('{') && !trimmed.startsWith('[')) {
|
|
406
|
+
return {
|
|
407
|
+
valid: false,
|
|
408
|
+
signerId: '',
|
|
409
|
+
timestamp: '',
|
|
410
|
+
attachments: [],
|
|
411
|
+
errors: [
|
|
412
|
+
`Input does not appear to be a JSON document. If you have a document ID (e.g., 'uuid:version'), use verifyById() instead. Received: '${trimmed.substring(0, 50)}${trimmed.length > 50 ? '...' : ''}'`
|
|
413
|
+
],
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
let doc;
|
|
417
|
+
try {
|
|
418
|
+
doc = JSON.parse(signedDocument);
|
|
419
|
+
}
|
|
420
|
+
catch (e) {
|
|
421
|
+
return {
|
|
422
|
+
valid: false,
|
|
423
|
+
signerId: '',
|
|
424
|
+
timestamp: '',
|
|
425
|
+
attachments: [],
|
|
426
|
+
errors: [`Invalid JSON: ${e}`],
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
try {
|
|
430
|
+
globalAgent.verifyDocument(signedDocument);
|
|
431
|
+
// Extract attachments
|
|
432
|
+
const attachments = (doc.jacsFiles || []).map((f) => ({
|
|
433
|
+
filename: f.path || '',
|
|
434
|
+
mimeType: f.mimetype || 'application/octet-stream',
|
|
435
|
+
hash: f.sha256 || '',
|
|
436
|
+
embedded: f.embed || false,
|
|
437
|
+
content: f.contents ? Buffer.from(f.contents, 'base64') : undefined,
|
|
438
|
+
}));
|
|
439
|
+
return {
|
|
440
|
+
valid: true,
|
|
441
|
+
data: doc.content,
|
|
442
|
+
signerId: doc.jacsSignature?.agentID || '',
|
|
443
|
+
timestamp: doc.jacsSignature?.date || '',
|
|
444
|
+
attachments,
|
|
445
|
+
errors: [],
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
catch (e) {
|
|
449
|
+
return {
|
|
450
|
+
valid: false,
|
|
451
|
+
signerId: doc.jacsSignature?.agentID || '',
|
|
452
|
+
timestamp: doc.jacsSignature?.date || '',
|
|
453
|
+
attachments: [],
|
|
454
|
+
errors: [String(e)],
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Verify a signed JACS document without loading an agent.
|
|
460
|
+
* Uses caller-supplied key resolution and directories; does not use global agent state.
|
|
461
|
+
*
|
|
462
|
+
* @param signedDocument - Full signed JACS document JSON string
|
|
463
|
+
* @param options - Optional keyResolution, dataDirectory, keyDirectory
|
|
464
|
+
* @returns VerificationResult with valid and signerId
|
|
465
|
+
*
|
|
466
|
+
* @example
|
|
467
|
+
* ```typescript
|
|
468
|
+
* const result = jacs.verifyStandalone(signedJson, { keyResolution: 'local', keyDirectory: './keys' });
|
|
469
|
+
* if (result.valid) console.log(`Signed by: ${result.signerId}`);
|
|
470
|
+
* ```
|
|
471
|
+
*/
|
|
472
|
+
function verifyStandalone(signedDocument, options) {
|
|
473
|
+
const doc = typeof signedDocument === 'string' ? signedDocument : JSON.stringify(signedDocument);
|
|
474
|
+
const r = (0, index_1.verifyDocumentStandalone)(doc, options?.keyResolution ?? undefined, options?.dataDirectory ?? undefined, options?.keyDirectory ?? undefined);
|
|
475
|
+
return {
|
|
476
|
+
valid: r.valid,
|
|
477
|
+
signerId: r.signerId,
|
|
478
|
+
timestamp: '',
|
|
479
|
+
attachments: [],
|
|
480
|
+
errors: [],
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Verifies a document by its storage ID.
|
|
485
|
+
*
|
|
486
|
+
* Use this when you have a document ID (e.g., "uuid:version") rather than
|
|
487
|
+
* the full JSON string. The document will be loaded from storage and verified.
|
|
488
|
+
*
|
|
489
|
+
* @param documentId - The document ID in "uuid:version" format
|
|
490
|
+
* @returns VerificationResult with the verification status
|
|
491
|
+
*
|
|
492
|
+
* @example
|
|
493
|
+
* ```typescript
|
|
494
|
+
* const result = jacs.verifyById('550e8400-e29b-41d4-a716-446655440000:1');
|
|
495
|
+
* if (result.valid) {
|
|
496
|
+
* console.log('Document verified');
|
|
497
|
+
* }
|
|
498
|
+
* ```
|
|
499
|
+
*/
|
|
500
|
+
function verifyById(documentId) {
|
|
501
|
+
if (!globalAgent) {
|
|
502
|
+
throw new Error('No agent loaded. Call load() first.');
|
|
503
|
+
}
|
|
504
|
+
if (!documentId.includes(':')) {
|
|
505
|
+
return {
|
|
506
|
+
valid: false,
|
|
507
|
+
signerId: '',
|
|
508
|
+
timestamp: '',
|
|
509
|
+
attachments: [],
|
|
510
|
+
errors: [
|
|
511
|
+
`Document ID must be in 'uuid:version' format, got '${documentId}'. Use verify() with the full JSON string instead.`
|
|
512
|
+
],
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
try {
|
|
516
|
+
globalAgent.verifyDocumentById(documentId);
|
|
517
|
+
return {
|
|
518
|
+
valid: true,
|
|
519
|
+
signerId: '',
|
|
520
|
+
timestamp: '',
|
|
521
|
+
attachments: [],
|
|
522
|
+
errors: [],
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
catch (e) {
|
|
526
|
+
return {
|
|
527
|
+
valid: false,
|
|
528
|
+
signerId: '',
|
|
529
|
+
timestamp: '',
|
|
530
|
+
attachments: [],
|
|
531
|
+
errors: [String(e)],
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Re-encrypt the agent's private key with a new password.
|
|
537
|
+
*
|
|
538
|
+
* @param oldPassword - The current password for the private key
|
|
539
|
+
* @param newPassword - The new password to encrypt with (must meet password requirements)
|
|
540
|
+
*
|
|
541
|
+
* @example
|
|
542
|
+
* ```typescript
|
|
543
|
+
* jacs.reencryptKey('old-password-123!', 'new-Str0ng-P@ss!');
|
|
544
|
+
* console.log('Key re-encrypted successfully');
|
|
545
|
+
* ```
|
|
546
|
+
*/
|
|
547
|
+
function reencryptKey(oldPassword, newPassword) {
|
|
548
|
+
if (!globalAgent) {
|
|
549
|
+
throw new Error('No agent loaded. Call load() first.');
|
|
550
|
+
}
|
|
551
|
+
globalAgent.reencryptKey(oldPassword, newPassword);
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Get the loaded agent's public key in PEM format.
|
|
555
|
+
*
|
|
556
|
+
* @returns The public key as a PEM-encoded string
|
|
557
|
+
*
|
|
558
|
+
* @example
|
|
559
|
+
* ```typescript
|
|
560
|
+
* const pem = jacs.getPublicKey();
|
|
561
|
+
* console.log(pem); // Share with others for verification
|
|
562
|
+
* ```
|
|
563
|
+
*/
|
|
564
|
+
function getPublicKey() {
|
|
565
|
+
if (!agentInfo) {
|
|
566
|
+
throw new Error('No agent loaded. Call load() first.');
|
|
567
|
+
}
|
|
568
|
+
if (!fs.existsSync(agentInfo.publicKeyPath)) {
|
|
569
|
+
throw new Error(`Public key not found: ${agentInfo.publicKeyPath}`);
|
|
570
|
+
}
|
|
571
|
+
return fs.readFileSync(agentInfo.publicKeyPath, 'utf8');
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Export the agent document for sharing.
|
|
575
|
+
*
|
|
576
|
+
* @returns The agent JSON document as a string
|
|
577
|
+
*
|
|
578
|
+
* @example
|
|
579
|
+
* ```typescript
|
|
580
|
+
* const agentDoc = jacs.exportAgent();
|
|
581
|
+
* // Send to another party for trust establishment
|
|
582
|
+
* ```
|
|
583
|
+
*/
|
|
584
|
+
function exportAgent() {
|
|
585
|
+
if (!agentInfo) {
|
|
586
|
+
throw new Error('No agent loaded. Call load() first.');
|
|
587
|
+
}
|
|
588
|
+
// Read agent file
|
|
589
|
+
const configPath = path.resolve(agentInfo.configPath);
|
|
590
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
591
|
+
const dataDir = resolveConfigRelativePath(configPath, config.jacs_data_directory || './jacs_data');
|
|
592
|
+
const agentIdVersion = config.jacs_agent_id_and_version || '';
|
|
593
|
+
const agentPath = path.join(dataDir, 'agent', `${agentIdVersion}.json`);
|
|
594
|
+
if (!fs.existsSync(agentPath)) {
|
|
595
|
+
throw new Error(`Agent file not found: ${agentPath}`);
|
|
596
|
+
}
|
|
597
|
+
return fs.readFileSync(agentPath, 'utf8');
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Get information about the currently loaded agent.
|
|
601
|
+
*
|
|
602
|
+
* @returns AgentInfo if an agent is loaded, null otherwise
|
|
603
|
+
*/
|
|
604
|
+
function getAgentInfo() {
|
|
605
|
+
return agentInfo;
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Check if an agent is currently loaded.
|
|
609
|
+
*
|
|
610
|
+
* @returns true if an agent is loaded, false otherwise
|
|
611
|
+
*/
|
|
612
|
+
function isLoaded() {
|
|
613
|
+
return globalAgent !== null;
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Returns the DNS TXT record line for the loaded agent (for DNS-based discovery).
|
|
617
|
+
* Format: _v1.agent.jacs.{domain}. TTL IN TXT "v=hai.ai; jacs_agent_id=...; alg=SHA-256; enc=base64; jac_public_key_hash=..."
|
|
618
|
+
*/
|
|
619
|
+
function getDnsRecord(domain, ttl = 3600) {
|
|
620
|
+
if (!agentInfo) {
|
|
621
|
+
throw new Error('No agent loaded. Call load() first.');
|
|
622
|
+
}
|
|
623
|
+
const agentDoc = JSON.parse(exportAgent());
|
|
624
|
+
const jacsId = agentDoc.jacsId || agentDoc.agentId || '';
|
|
625
|
+
const publicKeyHash = agentDoc.jacsSignature?.publicKeyHash ||
|
|
626
|
+
agentDoc.jacsSignature?.['publicKeyHash'] ||
|
|
627
|
+
'';
|
|
628
|
+
const d = domain.replace(/\.$/, '');
|
|
629
|
+
const owner = `_v1.agent.jacs.${d}.`;
|
|
630
|
+
const txt = `v=hai.ai; jacs_agent_id=${jacsId}; alg=SHA-256; enc=base64; jac_public_key_hash=${publicKeyHash}`;
|
|
631
|
+
return `${owner} ${ttl} IN TXT "${txt}"`;
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Returns the well-known JSON object for the loaded agent (e.g. for /.well-known/jacs-pubkey.json).
|
|
635
|
+
* Keys: publicKey, publicKeyHash, algorithm, agentId.
|
|
636
|
+
*/
|
|
637
|
+
function getWellKnownJson() {
|
|
638
|
+
if (!agentInfo) {
|
|
639
|
+
throw new Error('No agent loaded. Call load() first.');
|
|
640
|
+
}
|
|
641
|
+
const agentDoc = JSON.parse(exportAgent());
|
|
642
|
+
const jacsId = agentDoc.jacsId || agentDoc.agentId || '';
|
|
643
|
+
const publicKeyHash = agentDoc.jacsSignature?.publicKeyHash ||
|
|
644
|
+
agentDoc.jacsSignature?.['publicKeyHash'] ||
|
|
645
|
+
'';
|
|
646
|
+
let publicKey = '';
|
|
647
|
+
try {
|
|
648
|
+
publicKey = getPublicKey();
|
|
649
|
+
}
|
|
650
|
+
catch {
|
|
651
|
+
// optional if key file missing
|
|
652
|
+
}
|
|
653
|
+
return {
|
|
654
|
+
publicKey,
|
|
655
|
+
publicKeyHash,
|
|
656
|
+
algorithm: 'SHA-256',
|
|
657
|
+
agentId: jacsId,
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Register the loaded agent with HAI.ai.
|
|
662
|
+
* Requires a loaded agent (uses exportAgent() for the payload).
|
|
663
|
+
* Calls POST {haiUrl}/api/v1/agents/register with Bearer token and agent JSON.
|
|
664
|
+
*
|
|
665
|
+
* @param options - apiKey (or HAI_API_KEY env), haiUrl (default "https://hai.ai"), preview
|
|
666
|
+
* @returns HaiRegistrationResult with agentId, jacsId, dnsVerified, signatures
|
|
667
|
+
*/
|
|
668
|
+
async function registerWithHai(options) {
|
|
669
|
+
if (!agentInfo) {
|
|
670
|
+
throw new Error('No agent loaded. Call load() first.');
|
|
671
|
+
}
|
|
672
|
+
const apiKey = options?.apiKey ?? process.env.HAI_API_KEY;
|
|
673
|
+
if (!apiKey) {
|
|
674
|
+
throw new Error('HAI registration requires an API key. Set apiKey in options or HAI_API_KEY env.');
|
|
675
|
+
}
|
|
676
|
+
if (options?.preview) {
|
|
677
|
+
return {
|
|
678
|
+
agentId: agentInfo.agentId,
|
|
679
|
+
jacsId: '',
|
|
680
|
+
dnsVerified: false,
|
|
681
|
+
signatures: [],
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
const baseUrl = (options?.haiUrl ?? 'https://hai.ai').replace(/\/$/, '');
|
|
685
|
+
const agentJson = exportAgent();
|
|
686
|
+
const url = `${baseUrl}/api/v1/agents/register`;
|
|
687
|
+
const res = await fetch(url, {
|
|
688
|
+
method: 'POST',
|
|
689
|
+
headers: {
|
|
690
|
+
Authorization: `Bearer ${apiKey}`,
|
|
691
|
+
'Content-Type': 'application/json',
|
|
692
|
+
},
|
|
693
|
+
body: JSON.stringify({ agent_json: agentJson }),
|
|
694
|
+
});
|
|
695
|
+
if (!res.ok) {
|
|
696
|
+
const text = await res.text();
|
|
697
|
+
throw new Error(`HAI registration failed: ${res.status} ${text}`);
|
|
698
|
+
}
|
|
699
|
+
const data = (await res.json());
|
|
700
|
+
const signatures = (data.signatures ?? []).map((s) => (typeof s === 'string' ? s : s.signature ?? s.key_id ?? ''));
|
|
701
|
+
return {
|
|
702
|
+
agentId: data.agent_id ?? '',
|
|
703
|
+
jacsId: data.jacs_id ?? '',
|
|
704
|
+
dnsVerified: data.dns_verified ?? false,
|
|
705
|
+
signatures,
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Creates a multi-party agreement that requires signatures from multiple agents.
|
|
710
|
+
*
|
|
711
|
+
* @param document - The document to create an agreement on (object or JSON string)
|
|
712
|
+
* @param agentIds - List of agent IDs required to sign
|
|
713
|
+
* @param question - Optional question or purpose of the agreement
|
|
714
|
+
* @param context - Optional additional context for signers
|
|
715
|
+
* @param fieldName - Optional custom field name for the agreement (default: "jacsAgreement")
|
|
716
|
+
* @returns SignedDocument containing the agreement document
|
|
717
|
+
*
|
|
718
|
+
* @example
|
|
719
|
+
* ```typescript
|
|
720
|
+
* const agreement = jacs.createAgreement(
|
|
721
|
+
* { proposal: 'Merge codebase' },
|
|
722
|
+
* ['agent-1-uuid', 'agent-2-uuid'],
|
|
723
|
+
* 'Do you approve this merge?',
|
|
724
|
+
* 'This will combine repositories A and B'
|
|
725
|
+
* );
|
|
726
|
+
* ```
|
|
727
|
+
*/
|
|
728
|
+
function createAgreement(document, agentIds, question, context, fieldName) {
|
|
729
|
+
if (!globalAgent) {
|
|
730
|
+
throw new Error('No agent loaded. Call load() first.');
|
|
731
|
+
}
|
|
732
|
+
const docString = normalizeDocumentInput(document);
|
|
733
|
+
const result = globalAgent.createAgreement(docString, agentIds, question || null, context || null, fieldName || null);
|
|
734
|
+
const doc = JSON.parse(result);
|
|
735
|
+
return {
|
|
736
|
+
raw: result,
|
|
737
|
+
documentId: doc.jacsId || '',
|
|
738
|
+
agentId: doc.jacsSignature?.agentID || '',
|
|
739
|
+
timestamp: doc.jacsSignature?.date || '',
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Signs an existing multi-party agreement.
|
|
744
|
+
*
|
|
745
|
+
* @param document - The agreement document to sign (object or JSON string)
|
|
746
|
+
* @param fieldName - Optional custom field name for the agreement (default: "jacsAgreement")
|
|
747
|
+
* @returns SignedDocument with this agent's signature added
|
|
748
|
+
*
|
|
749
|
+
* @example
|
|
750
|
+
* ```typescript
|
|
751
|
+
* // Receive agreement from another party
|
|
752
|
+
* const signedByMe = jacs.signAgreement(agreementDoc);
|
|
753
|
+
* // Send back to coordinator or next signer
|
|
754
|
+
* ```
|
|
755
|
+
*/
|
|
756
|
+
function signAgreement(document, fieldName) {
|
|
757
|
+
if (!globalAgent) {
|
|
758
|
+
throw new Error('No agent loaded. Call load() first.');
|
|
759
|
+
}
|
|
760
|
+
const docString = normalizeDocumentInput(document);
|
|
761
|
+
const result = globalAgent.signAgreement(docString, fieldName || null);
|
|
762
|
+
const doc = JSON.parse(result);
|
|
763
|
+
return {
|
|
764
|
+
raw: result,
|
|
765
|
+
documentId: doc.jacsId || '',
|
|
766
|
+
agentId: doc.jacsSignature?.agentID || '',
|
|
767
|
+
timestamp: doc.jacsSignature?.date || '',
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Checks the status of a multi-party agreement.
|
|
772
|
+
*
|
|
773
|
+
* @param document - The agreement document to check (object or JSON string)
|
|
774
|
+
* @param fieldName - Optional custom field name for the agreement (default: "jacsAgreement")
|
|
775
|
+
* @returns AgreementStatus with completion status and signer details
|
|
776
|
+
*
|
|
777
|
+
* @example
|
|
778
|
+
* ```typescript
|
|
779
|
+
* const status = jacs.checkAgreement(agreementDoc);
|
|
780
|
+
* if (status.complete) {
|
|
781
|
+
* console.log('All parties have signed!');
|
|
782
|
+
* } else {
|
|
783
|
+
* console.log(`Waiting for: ${status.pending.join(', ')}`);
|
|
784
|
+
* }
|
|
785
|
+
* ```
|
|
786
|
+
*/
|
|
787
|
+
function checkAgreement(document, fieldName) {
|
|
788
|
+
if (!globalAgent) {
|
|
789
|
+
throw new Error('No agent loaded. Call load() first.');
|
|
790
|
+
}
|
|
791
|
+
const docString = normalizeDocumentInput(document);
|
|
792
|
+
const result = globalAgent.checkAgreement(docString, fieldName || null);
|
|
793
|
+
return JSON.parse(result);
|
|
794
|
+
}
|
|
795
|
+
// =============================================================================
|
|
796
|
+
// Trust Store Functions
|
|
797
|
+
// =============================================================================
|
|
798
|
+
/**
|
|
799
|
+
* Add an agent to the local trust store.
|
|
800
|
+
*
|
|
801
|
+
* The trust store is a local list of agents you trust. When verifying
|
|
802
|
+
* documents from known agents, the trust store provides signer names
|
|
803
|
+
* and allows quick lookups.
|
|
804
|
+
*
|
|
805
|
+
* @param agentJson - The agent's JSON document (from their exportAgent())
|
|
806
|
+
* @returns The trusted agent's ID
|
|
807
|
+
*
|
|
808
|
+
* @example
|
|
809
|
+
* ```typescript
|
|
810
|
+
* const trustedId = jacs.trustAgent(partnerAgentJson);
|
|
811
|
+
* console.log(`Trusted agent: ${trustedId}`);
|
|
812
|
+
* ```
|
|
813
|
+
*/
|
|
814
|
+
function trustAgent(agentJson) {
|
|
815
|
+
return (0, index_1.trustAgent)(agentJson);
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* List all trusted agent IDs in the local trust store.
|
|
819
|
+
*
|
|
820
|
+
* @returns Array of trusted agent UUIDs
|
|
821
|
+
*
|
|
822
|
+
* @example
|
|
823
|
+
* ```typescript
|
|
824
|
+
* const trustedIds = jacs.listTrustedAgents();
|
|
825
|
+
* console.log(`${trustedIds.length} trusted agents`);
|
|
826
|
+
* ```
|
|
827
|
+
*/
|
|
828
|
+
function listTrustedAgents() {
|
|
829
|
+
return (0, index_1.listTrustedAgents)();
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Remove an agent from the local trust store.
|
|
833
|
+
*
|
|
834
|
+
* @param agentId - The agent UUID to remove
|
|
835
|
+
*
|
|
836
|
+
* @example
|
|
837
|
+
* ```typescript
|
|
838
|
+
* jacs.untrustAgent('550e8400-e29b-41d4-a716-446655440000');
|
|
839
|
+
* ```
|
|
840
|
+
*/
|
|
841
|
+
function untrustAgent(agentId) {
|
|
842
|
+
(0, index_1.untrustAgent)(agentId);
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Check if an agent is in the local trust store.
|
|
846
|
+
*
|
|
847
|
+
* @param agentId - The agent UUID to check
|
|
848
|
+
* @returns true if the agent is trusted
|
|
849
|
+
*
|
|
850
|
+
* @example
|
|
851
|
+
* ```typescript
|
|
852
|
+
* if (jacs.isTrusted(signerId)) {
|
|
853
|
+
* console.log('Signer is in our trust store');
|
|
854
|
+
* }
|
|
855
|
+
* ```
|
|
856
|
+
*/
|
|
857
|
+
function isTrusted(agentId) {
|
|
858
|
+
return (0, index_1.isTrusted)(agentId);
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* Get a trusted agent's full JSON document from the trust store.
|
|
862
|
+
*
|
|
863
|
+
* @param agentId - The agent UUID to retrieve
|
|
864
|
+
* @returns The agent's JSON document as a string
|
|
865
|
+
*
|
|
866
|
+
* @example
|
|
867
|
+
* ```typescript
|
|
868
|
+
* const agentDoc = JSON.parse(jacs.getTrustedAgent(agentId));
|
|
869
|
+
* console.log(`Agent name: ${agentDoc.jacsAgentName}`);
|
|
870
|
+
* ```
|
|
871
|
+
*/
|
|
872
|
+
function getTrustedAgent(agentId) {
|
|
873
|
+
return (0, index_1.getTrustedAgent)(agentId);
|
|
874
|
+
}
|
|
875
|
+
/**
|
|
876
|
+
* Run a read-only security audit and health checks.
|
|
877
|
+
* Returns an object with risks, health_checks, summary, and related fields.
|
|
878
|
+
*
|
|
879
|
+
* @param options - Optional config path and recent document count
|
|
880
|
+
* @returns Audit result object (risks, health_checks, summary, overall_status)
|
|
881
|
+
*
|
|
882
|
+
* @example
|
|
883
|
+
* ```typescript
|
|
884
|
+
* const result = jacs.audit();
|
|
885
|
+
* console.log(`Risks: ${result.risks.length}, Status: ${result.overall_status}`);
|
|
886
|
+
* ```
|
|
887
|
+
*/
|
|
888
|
+
function audit(options) {
|
|
889
|
+
const json = (0, index_1.audit)(options?.configPath ?? undefined, options?.recentN ?? undefined);
|
|
890
|
+
return JSON.parse(json);
|
|
891
|
+
}
|
|
892
|
+
// =============================================================================
|
|
893
|
+
// Verify link (HAI / public verification URLs)
|
|
894
|
+
// =============================================================================
|
|
895
|
+
/** Max length for a full verify URL (scheme + host + path + ?s=...). */
|
|
896
|
+
exports.MAX_VERIFY_URL_LEN = 2048;
|
|
897
|
+
/** Max UTF-8 byte length of a document that fits in a verify link. */
|
|
898
|
+
exports.MAX_VERIFY_DOCUMENT_BYTES = 1515;
|
|
899
|
+
/**
|
|
900
|
+
* Build a verification URL for a signed JACS document (e.g. https://hai.ai/jacs/verify?s=...).
|
|
901
|
+
* Uses URL-safe base64. Throws if the URL would exceed MAX_VERIFY_URL_LEN.
|
|
902
|
+
*
|
|
903
|
+
* @param document - Full signed JACS document string (JSON)
|
|
904
|
+
* @param baseUrl - Base URL of the verifier (no trailing slash). Default "https://hai.ai"
|
|
905
|
+
* @returns Full URL: {baseUrl}/jacs/verify?s={base64url(document)}
|
|
906
|
+
*/
|
|
907
|
+
function generateVerifyLink(document, baseUrl = 'https://hai.ai') {
|
|
908
|
+
const base = baseUrl.replace(/\/+$/, '');
|
|
909
|
+
const encoded = Buffer.from(document, 'utf8')
|
|
910
|
+
.toString('base64')
|
|
911
|
+
.replace(/\+/g, '-')
|
|
912
|
+
.replace(/\//g, '_')
|
|
913
|
+
.replace(/=+$/g, '');
|
|
914
|
+
const fullUrl = `${base}/jacs/verify?s=${encoded}`;
|
|
915
|
+
if (fullUrl.length > exports.MAX_VERIFY_URL_LEN) {
|
|
916
|
+
throw new Error(`Verify URL would exceed max length (${exports.MAX_VERIFY_URL_LEN}). Document size must be at most ${exports.MAX_VERIFY_DOCUMENT_BYTES} UTF-8 bytes.`);
|
|
917
|
+
}
|
|
918
|
+
return fullUrl;
|
|
919
|
+
}
|
|
920
|
+
//# sourceMappingURL=simple.js.map
|