@hai.ai/jacs 0.6.0 → 0.8.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 +336 -52
- package/client.d.ts +96 -0
- package/client.js +560 -0
- package/express.d.ts +69 -0
- package/express.js +130 -0
- package/express.js.map +1 -0
- package/index.d.ts +117 -96
- package/index.js +19 -17
- 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/koa.d.ts +59 -0
- package/koa.js +124 -0
- package/koa.js.map +1 -0
- package/langchain.d.ts +97 -0
- package/langchain.js +439 -0
- package/langchain.js.map +1 -0
- package/mcp.d.ts +75 -42
- package/mcp.js +449 -422
- package/mcp.js.map +1 -1
- package/package.json +91 -7
- package/scripts/install-cli.js +125 -0
- package/simple.d.ts +92 -430
- package/simple.js +507 -524
- package/src/a2a.js +2 -2
- package/testing.d.ts +39 -0
- package/testing.js +49 -0
- package/vercel-ai.d.ts +54 -0
- package/vercel-ai.js +162 -0
- package/vercel-ai.js.map +1 -0
- package/mcp.ts +0 -521
package/client.js
ADDED
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* JACS Instance-Based Client API
|
|
4
|
+
*
|
|
5
|
+
* v0.7.0: Async-first API. All methods that call native JACS operations
|
|
6
|
+
* return Promises by default. Use `*Sync` variants for synchronous execution.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { JacsClient } from '@hai.ai/jacs/client';
|
|
11
|
+
*
|
|
12
|
+
* const client = await JacsClient.quickstart({ algorithm: 'ring-Ed25519' });
|
|
13
|
+
* const signed = await client.signMessage({ action: 'approve' });
|
|
14
|
+
* const result = await client.verify(signed.raw);
|
|
15
|
+
* console.log(`Valid: ${result.valid}`);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
21
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
22
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
23
|
+
}
|
|
24
|
+
Object.defineProperty(o, k2, desc);
|
|
25
|
+
}) : (function(o, m, k, k2) {
|
|
26
|
+
if (k2 === undefined) k2 = k;
|
|
27
|
+
o[k2] = m[k];
|
|
28
|
+
}));
|
|
29
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
30
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
31
|
+
}) : function(o, v) {
|
|
32
|
+
o["default"] = v;
|
|
33
|
+
});
|
|
34
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
35
|
+
var ownKeys = function(o) {
|
|
36
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
37
|
+
var ar = [];
|
|
38
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
39
|
+
return ar;
|
|
40
|
+
};
|
|
41
|
+
return ownKeys(o);
|
|
42
|
+
};
|
|
43
|
+
return function (mod) {
|
|
44
|
+
if (mod && mod.__esModule) return mod;
|
|
45
|
+
var result = {};
|
|
46
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
47
|
+
__setModuleDefault(result, mod);
|
|
48
|
+
return result;
|
|
49
|
+
};
|
|
50
|
+
})();
|
|
51
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
52
|
+
exports.JacsClient = exports.MAX_VERIFY_DOCUMENT_BYTES = exports.MAX_VERIFY_URL_LEN = exports.generateVerifyLink = exports.createConfig = exports.hashString = void 0;
|
|
53
|
+
const index_1 = require("./index");
|
|
54
|
+
Object.defineProperty(exports, "hashString", { enumerable: true, get: function () { return index_1.hashString; } });
|
|
55
|
+
Object.defineProperty(exports, "createConfig", { enumerable: true, get: function () { return index_1.createConfig; } });
|
|
56
|
+
const fs = __importStar(require("fs"));
|
|
57
|
+
const path = __importStar(require("path"));
|
|
58
|
+
const simple_1 = require("./simple");
|
|
59
|
+
Object.defineProperty(exports, "generateVerifyLink", { enumerable: true, get: function () { return simple_1.generateVerifyLink; } });
|
|
60
|
+
Object.defineProperty(exports, "MAX_VERIFY_URL_LEN", { enumerable: true, get: function () { return simple_1.MAX_VERIFY_URL_LEN; } });
|
|
61
|
+
Object.defineProperty(exports, "MAX_VERIFY_DOCUMENT_BYTES", { enumerable: true, get: function () { return simple_1.MAX_VERIFY_DOCUMENT_BYTES; } });
|
|
62
|
+
// =============================================================================
|
|
63
|
+
// Helpers
|
|
64
|
+
// =============================================================================
|
|
65
|
+
function resolveStrict(explicit) {
|
|
66
|
+
if (explicit !== undefined) {
|
|
67
|
+
return explicit;
|
|
68
|
+
}
|
|
69
|
+
const envStrict = process.env.JACS_STRICT_MODE;
|
|
70
|
+
return envStrict === 'true' || envStrict === '1';
|
|
71
|
+
}
|
|
72
|
+
function resolveConfigRelativePath(configPath, candidate) {
|
|
73
|
+
if (path.isAbsolute(candidate)) {
|
|
74
|
+
return candidate;
|
|
75
|
+
}
|
|
76
|
+
return path.resolve(path.dirname(configPath), candidate);
|
|
77
|
+
}
|
|
78
|
+
function normalizeDocumentInput(document) {
|
|
79
|
+
if (typeof document === 'string') {
|
|
80
|
+
return document;
|
|
81
|
+
}
|
|
82
|
+
if (document && typeof document === 'object') {
|
|
83
|
+
if (typeof document.raw === 'string') {
|
|
84
|
+
return document.raw;
|
|
85
|
+
}
|
|
86
|
+
if (typeof document.raw_json === 'string') {
|
|
87
|
+
return document.raw_json;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return JSON.stringify(document);
|
|
91
|
+
}
|
|
92
|
+
function extractAgentInfo(resolvedConfigPath) {
|
|
93
|
+
const config = JSON.parse(fs.readFileSync(resolvedConfigPath, 'utf8'));
|
|
94
|
+
const agentIdVersion = config.jacs_agent_id_and_version || '';
|
|
95
|
+
const [agentId] = agentIdVersion.split(':');
|
|
96
|
+
const keyDir = resolveConfigRelativePath(resolvedConfigPath, config.jacs_key_directory || './jacs_keys');
|
|
97
|
+
return {
|
|
98
|
+
agentId: agentId || '',
|
|
99
|
+
name: config.name || '',
|
|
100
|
+
publicKeyPath: path.join(keyDir, 'jacs.public.pem'),
|
|
101
|
+
configPath: resolvedConfigPath,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function parseSignedResult(result) {
|
|
105
|
+
const doc = JSON.parse(result);
|
|
106
|
+
return {
|
|
107
|
+
raw: result,
|
|
108
|
+
documentId: doc.jacsId || '',
|
|
109
|
+
agentId: doc.jacsSignature?.agentID || '',
|
|
110
|
+
timestamp: doc.jacsSignature?.date || '',
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function ensurePassword() {
|
|
114
|
+
let password = process.env.JACS_PRIVATE_KEY_PASSWORD || '';
|
|
115
|
+
if (!password) {
|
|
116
|
+
const crypto = require('crypto');
|
|
117
|
+
const upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
118
|
+
const lower = 'abcdefghijklmnopqrstuvwxyz';
|
|
119
|
+
const digits = '0123456789';
|
|
120
|
+
const special = '!@#$%^&*()-_=+';
|
|
121
|
+
const all = upper + lower + digits + special;
|
|
122
|
+
password =
|
|
123
|
+
upper[crypto.randomInt(upper.length)] +
|
|
124
|
+
lower[crypto.randomInt(lower.length)] +
|
|
125
|
+
digits[crypto.randomInt(digits.length)] +
|
|
126
|
+
special[crypto.randomInt(special.length)];
|
|
127
|
+
for (let i = 4; i < 32; i++) {
|
|
128
|
+
password += all[crypto.randomInt(all.length)];
|
|
129
|
+
}
|
|
130
|
+
const keysDir = './jacs_keys';
|
|
131
|
+
fs.mkdirSync(keysDir, { recursive: true });
|
|
132
|
+
const pwPath = path.join(keysDir, '.jacs_password');
|
|
133
|
+
fs.writeFileSync(pwPath, password, { mode: 0o600 });
|
|
134
|
+
process.env.JACS_PRIVATE_KEY_PASSWORD = password;
|
|
135
|
+
}
|
|
136
|
+
return password;
|
|
137
|
+
}
|
|
138
|
+
// =============================================================================
|
|
139
|
+
// JacsClient
|
|
140
|
+
// =============================================================================
|
|
141
|
+
class JacsClient {
|
|
142
|
+
constructor(options) {
|
|
143
|
+
this.agent = null;
|
|
144
|
+
this.info = null;
|
|
145
|
+
this._strict = false;
|
|
146
|
+
this._strict = resolveStrict(options?.strict);
|
|
147
|
+
}
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
// Static factories (async)
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
/**
|
|
152
|
+
* Zero-config factory: loads or creates a persistent agent.
|
|
153
|
+
*/
|
|
154
|
+
static async quickstart(options) {
|
|
155
|
+
const client = new JacsClient({ strict: options?.strict });
|
|
156
|
+
const configPath = options?.configPath || './jacs.config.json';
|
|
157
|
+
if (fs.existsSync(configPath)) {
|
|
158
|
+
await client.load(configPath);
|
|
159
|
+
return client;
|
|
160
|
+
}
|
|
161
|
+
const password = ensurePassword();
|
|
162
|
+
const algo = options?.algorithm || 'pq2025';
|
|
163
|
+
await client.create({ name: 'jacs-agent', password, algorithm: algo, configPath });
|
|
164
|
+
return client;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Zero-config factory (sync variant).
|
|
168
|
+
*/
|
|
169
|
+
static quickstartSync(options) {
|
|
170
|
+
const client = new JacsClient({ strict: options?.strict });
|
|
171
|
+
const configPath = options?.configPath || './jacs.config.json';
|
|
172
|
+
if (fs.existsSync(configPath)) {
|
|
173
|
+
client.loadSync(configPath);
|
|
174
|
+
return client;
|
|
175
|
+
}
|
|
176
|
+
const password = ensurePassword();
|
|
177
|
+
const algo = options?.algorithm || 'pq2025';
|
|
178
|
+
client.createSync({ name: 'jacs-agent', password, algorithm: algo, configPath });
|
|
179
|
+
return client;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Create an ephemeral in-memory client for testing.
|
|
183
|
+
*/
|
|
184
|
+
static async ephemeral(algorithm) {
|
|
185
|
+
const client = new JacsClient();
|
|
186
|
+
const nativeAgent = new index_1.JacsAgent();
|
|
187
|
+
const resultJson = await nativeAgent.ephemeral(algorithm ?? null);
|
|
188
|
+
const result = JSON.parse(resultJson);
|
|
189
|
+
client.agent = nativeAgent;
|
|
190
|
+
client.info = {
|
|
191
|
+
agentId: result.agent_id || '',
|
|
192
|
+
name: result.name || 'ephemeral',
|
|
193
|
+
publicKeyPath: '',
|
|
194
|
+
configPath: '',
|
|
195
|
+
};
|
|
196
|
+
return client;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Create an ephemeral in-memory client (sync variant).
|
|
200
|
+
*/
|
|
201
|
+
static ephemeralSync(algorithm) {
|
|
202
|
+
const client = new JacsClient();
|
|
203
|
+
const nativeAgent = new index_1.JacsAgent();
|
|
204
|
+
const resultJson = nativeAgent.ephemeralSync(algorithm ?? null);
|
|
205
|
+
const result = JSON.parse(resultJson);
|
|
206
|
+
client.agent = nativeAgent;
|
|
207
|
+
client.info = {
|
|
208
|
+
agentId: result.agent_id || '',
|
|
209
|
+
name: result.name || 'ephemeral',
|
|
210
|
+
publicKeyPath: '',
|
|
211
|
+
configPath: '',
|
|
212
|
+
};
|
|
213
|
+
return client;
|
|
214
|
+
}
|
|
215
|
+
// ---------------------------------------------------------------------------
|
|
216
|
+
// Lifecycle
|
|
217
|
+
// ---------------------------------------------------------------------------
|
|
218
|
+
async load(configPath, options) {
|
|
219
|
+
if (options?.strict !== undefined) {
|
|
220
|
+
this._strict = options.strict;
|
|
221
|
+
}
|
|
222
|
+
const requestedPath = configPath || './jacs.config.json';
|
|
223
|
+
const resolvedConfigPath = path.resolve(requestedPath);
|
|
224
|
+
if (!fs.existsSync(resolvedConfigPath)) {
|
|
225
|
+
throw new Error(`Config file not found: ${requestedPath}\nRun 'jacs create' to create a new agent.`);
|
|
226
|
+
}
|
|
227
|
+
this.agent = new index_1.JacsAgent();
|
|
228
|
+
await this.agent.load(resolvedConfigPath);
|
|
229
|
+
this.info = extractAgentInfo(resolvedConfigPath);
|
|
230
|
+
return this.info;
|
|
231
|
+
}
|
|
232
|
+
loadSync(configPath, options) {
|
|
233
|
+
if (options?.strict !== undefined) {
|
|
234
|
+
this._strict = options.strict;
|
|
235
|
+
}
|
|
236
|
+
const requestedPath = configPath || './jacs.config.json';
|
|
237
|
+
const resolvedConfigPath = path.resolve(requestedPath);
|
|
238
|
+
if (!fs.existsSync(resolvedConfigPath)) {
|
|
239
|
+
throw new Error(`Config file not found: ${requestedPath}\nRun 'jacs create' to create a new agent.`);
|
|
240
|
+
}
|
|
241
|
+
this.agent = new index_1.JacsAgent();
|
|
242
|
+
this.agent.loadSync(resolvedConfigPath);
|
|
243
|
+
this.info = extractAgentInfo(resolvedConfigPath);
|
|
244
|
+
return this.info;
|
|
245
|
+
}
|
|
246
|
+
async create(options) {
|
|
247
|
+
const resolvedPassword = options.password ?? process.env.JACS_PRIVATE_KEY_PASSWORD ?? '';
|
|
248
|
+
if (!resolvedPassword) {
|
|
249
|
+
throw new Error('Missing private key password. Pass options.password or set JACS_PRIVATE_KEY_PASSWORD.');
|
|
250
|
+
}
|
|
251
|
+
const resultJson = await (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);
|
|
252
|
+
const result = JSON.parse(resultJson);
|
|
253
|
+
const cfgPath = result.config_path || options.configPath || './jacs.config.json';
|
|
254
|
+
this.info = {
|
|
255
|
+
agentId: result.agent_id || '',
|
|
256
|
+
name: result.name || options.name,
|
|
257
|
+
publicKeyPath: result.public_key_path || `${options.keyDirectory || './jacs_keys'}/jacs.public.pem`,
|
|
258
|
+
configPath: cfgPath,
|
|
259
|
+
};
|
|
260
|
+
this.agent = new index_1.JacsAgent();
|
|
261
|
+
await this.agent.load(path.resolve(cfgPath));
|
|
262
|
+
return this.info;
|
|
263
|
+
}
|
|
264
|
+
createSync(options) {
|
|
265
|
+
const resolvedPassword = options.password ?? process.env.JACS_PRIVATE_KEY_PASSWORD ?? '';
|
|
266
|
+
if (!resolvedPassword) {
|
|
267
|
+
throw new Error('Missing private key password. Pass options.password or set JACS_PRIVATE_KEY_PASSWORD.');
|
|
268
|
+
}
|
|
269
|
+
const resultJson = (0, index_1.createAgentSync)(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);
|
|
270
|
+
const result = JSON.parse(resultJson);
|
|
271
|
+
const cfgPath = result.config_path || options.configPath || './jacs.config.json';
|
|
272
|
+
this.info = {
|
|
273
|
+
agentId: result.agent_id || '',
|
|
274
|
+
name: result.name || options.name,
|
|
275
|
+
publicKeyPath: result.public_key_path || `${options.keyDirectory || './jacs_keys'}/jacs.public.pem`,
|
|
276
|
+
configPath: cfgPath,
|
|
277
|
+
};
|
|
278
|
+
this.agent = new index_1.JacsAgent();
|
|
279
|
+
this.agent.loadSync(path.resolve(cfgPath));
|
|
280
|
+
return this.info;
|
|
281
|
+
}
|
|
282
|
+
reset() {
|
|
283
|
+
this.agent = null;
|
|
284
|
+
this.info = null;
|
|
285
|
+
this._strict = false;
|
|
286
|
+
}
|
|
287
|
+
dispose() {
|
|
288
|
+
this.reset();
|
|
289
|
+
}
|
|
290
|
+
[Symbol.dispose]() {
|
|
291
|
+
this.reset();
|
|
292
|
+
}
|
|
293
|
+
// ---------------------------------------------------------------------------
|
|
294
|
+
// Getters
|
|
295
|
+
// ---------------------------------------------------------------------------
|
|
296
|
+
get agentId() {
|
|
297
|
+
return this.info?.agentId || '';
|
|
298
|
+
}
|
|
299
|
+
get name() {
|
|
300
|
+
return this.info?.name || '';
|
|
301
|
+
}
|
|
302
|
+
get strict() {
|
|
303
|
+
return this._strict;
|
|
304
|
+
}
|
|
305
|
+
// ---------------------------------------------------------------------------
|
|
306
|
+
// Signing & Verification
|
|
307
|
+
// ---------------------------------------------------------------------------
|
|
308
|
+
requireAgent() {
|
|
309
|
+
if (!this.agent) {
|
|
310
|
+
throw new Error('No agent loaded. Call quickstart(), ephemeral(), load(), or create() first.');
|
|
311
|
+
}
|
|
312
|
+
return this.agent;
|
|
313
|
+
}
|
|
314
|
+
async signMessage(data) {
|
|
315
|
+
const agent = this.requireAgent();
|
|
316
|
+
const docContent = { jacsType: 'message', jacsLevel: 'raw', content: data };
|
|
317
|
+
const result = await agent.createDocument(JSON.stringify(docContent), null, null, true, null, null);
|
|
318
|
+
return parseSignedResult(result);
|
|
319
|
+
}
|
|
320
|
+
signMessageSync(data) {
|
|
321
|
+
const agent = this.requireAgent();
|
|
322
|
+
const docContent = { jacsType: 'message', jacsLevel: 'raw', content: data };
|
|
323
|
+
const result = agent.createDocumentSync(JSON.stringify(docContent), null, null, true, null, null);
|
|
324
|
+
return parseSignedResult(result);
|
|
325
|
+
}
|
|
326
|
+
async verify(signedDocument) {
|
|
327
|
+
const agent = this.requireAgent();
|
|
328
|
+
const trimmed = signedDocument.trim();
|
|
329
|
+
if (trimmed.length > 0 && !trimmed.startsWith('{') && !trimmed.startsWith('[')) {
|
|
330
|
+
return { valid: false, signerId: '', timestamp: '', attachments: [], errors: [`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 ? '...' : ''}'`] };
|
|
331
|
+
}
|
|
332
|
+
let doc;
|
|
333
|
+
try {
|
|
334
|
+
doc = JSON.parse(signedDocument);
|
|
335
|
+
}
|
|
336
|
+
catch (e) {
|
|
337
|
+
return { valid: false, signerId: '', timestamp: '', attachments: [], errors: [`Invalid JSON: ${e}`] };
|
|
338
|
+
}
|
|
339
|
+
try {
|
|
340
|
+
await agent.verifyDocument(signedDocument);
|
|
341
|
+
const attachments = (doc.jacsFiles || []).map((f) => ({
|
|
342
|
+
filename: f.path || '', mimeType: f.mimetype || 'application/octet-stream',
|
|
343
|
+
hash: f.sha256 || '', embedded: f.embed || false,
|
|
344
|
+
content: f.contents ? Buffer.from(f.contents, 'base64') : undefined,
|
|
345
|
+
}));
|
|
346
|
+
return { valid: true, data: doc.content, signerId: doc.jacsSignature?.agentID || '', timestamp: doc.jacsSignature?.date || '', attachments, errors: [] };
|
|
347
|
+
}
|
|
348
|
+
catch (e) {
|
|
349
|
+
if (this._strict)
|
|
350
|
+
throw new Error(`Verification failed (strict mode): ${e}`);
|
|
351
|
+
return { valid: false, signerId: doc.jacsSignature?.agentID || '', timestamp: doc.jacsSignature?.date || '', attachments: [], errors: [String(e)] };
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
verifySync(signedDocument) {
|
|
355
|
+
const agent = this.requireAgent();
|
|
356
|
+
const trimmed = signedDocument.trim();
|
|
357
|
+
if (trimmed.length > 0 && !trimmed.startsWith('{') && !trimmed.startsWith('[')) {
|
|
358
|
+
return { valid: false, signerId: '', timestamp: '', attachments: [], errors: [`Input does not appear to be a JSON document.`] };
|
|
359
|
+
}
|
|
360
|
+
let doc;
|
|
361
|
+
try {
|
|
362
|
+
doc = JSON.parse(signedDocument);
|
|
363
|
+
}
|
|
364
|
+
catch (e) {
|
|
365
|
+
return { valid: false, signerId: '', timestamp: '', attachments: [], errors: [`Invalid JSON: ${e}`] };
|
|
366
|
+
}
|
|
367
|
+
try {
|
|
368
|
+
agent.verifyDocumentSync(signedDocument);
|
|
369
|
+
const attachments = (doc.jacsFiles || []).map((f) => ({
|
|
370
|
+
filename: f.path || '', mimeType: f.mimetype || 'application/octet-stream',
|
|
371
|
+
hash: f.sha256 || '', embedded: f.embed || false,
|
|
372
|
+
content: f.contents ? Buffer.from(f.contents, 'base64') : undefined,
|
|
373
|
+
}));
|
|
374
|
+
return { valid: true, data: doc.content, signerId: doc.jacsSignature?.agentID || '', timestamp: doc.jacsSignature?.date || '', attachments, errors: [] };
|
|
375
|
+
}
|
|
376
|
+
catch (e) {
|
|
377
|
+
if (this._strict)
|
|
378
|
+
throw new Error(`Verification failed (strict mode): ${e}`);
|
|
379
|
+
return { valid: false, signerId: doc.jacsSignature?.agentID || '', timestamp: doc.jacsSignature?.date || '', attachments: [], errors: [String(e)] };
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
async verifySelf() {
|
|
383
|
+
const agent = this.requireAgent();
|
|
384
|
+
try {
|
|
385
|
+
await agent.verifyAgent();
|
|
386
|
+
return { valid: true, signerId: this.info?.agentId || '', timestamp: '', attachments: [], errors: [] };
|
|
387
|
+
}
|
|
388
|
+
catch (e) {
|
|
389
|
+
if (this._strict)
|
|
390
|
+
throw new Error(`Self-verification failed (strict mode): ${e}`);
|
|
391
|
+
return { valid: false, signerId: '', timestamp: '', attachments: [], errors: [String(e)] };
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
verifySelfSync() {
|
|
395
|
+
const agent = this.requireAgent();
|
|
396
|
+
try {
|
|
397
|
+
agent.verifyAgentSync();
|
|
398
|
+
return { valid: true, signerId: this.info?.agentId || '', timestamp: '', attachments: [], errors: [] };
|
|
399
|
+
}
|
|
400
|
+
catch (e) {
|
|
401
|
+
if (this._strict)
|
|
402
|
+
throw new Error(`Self-verification failed (strict mode): ${e}`);
|
|
403
|
+
return { valid: false, signerId: '', timestamp: '', attachments: [], errors: [String(e)] };
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
async verifyById(documentId) {
|
|
407
|
+
const agent = this.requireAgent();
|
|
408
|
+
if (!documentId.includes(':')) {
|
|
409
|
+
return { valid: false, signerId: '', timestamp: '', attachments: [], errors: [`Document ID must be in 'uuid:version' format, got '${documentId}'.`] };
|
|
410
|
+
}
|
|
411
|
+
try {
|
|
412
|
+
await agent.verifyDocumentById(documentId);
|
|
413
|
+
return { valid: true, signerId: '', timestamp: '', attachments: [], errors: [] };
|
|
414
|
+
}
|
|
415
|
+
catch (e) {
|
|
416
|
+
if (this._strict)
|
|
417
|
+
throw new Error(`Verification failed (strict mode): ${e}`);
|
|
418
|
+
return { valid: false, signerId: '', timestamp: '', attachments: [], errors: [String(e)] };
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
verifyByIdSync(documentId) {
|
|
422
|
+
const agent = this.requireAgent();
|
|
423
|
+
if (!documentId.includes(':')) {
|
|
424
|
+
return { valid: false, signerId: '', timestamp: '', attachments: [], errors: [`Document ID must be in 'uuid:version' format, got '${documentId}'.`] };
|
|
425
|
+
}
|
|
426
|
+
try {
|
|
427
|
+
agent.verifyDocumentByIdSync(documentId);
|
|
428
|
+
return { valid: true, signerId: '', timestamp: '', attachments: [], errors: [] };
|
|
429
|
+
}
|
|
430
|
+
catch (e) {
|
|
431
|
+
if (this._strict)
|
|
432
|
+
throw new Error(`Verification failed (strict mode): ${e}`);
|
|
433
|
+
return { valid: false, signerId: '', timestamp: '', attachments: [], errors: [String(e)] };
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
// ---------------------------------------------------------------------------
|
|
437
|
+
// Files
|
|
438
|
+
// ---------------------------------------------------------------------------
|
|
439
|
+
async signFile(filePath, embed = false) {
|
|
440
|
+
const agent = this.requireAgent();
|
|
441
|
+
if (!fs.existsSync(filePath))
|
|
442
|
+
throw new Error(`File not found: ${filePath}`);
|
|
443
|
+
const docContent = { jacsType: 'file', jacsLevel: 'raw', filename: path.basename(filePath) };
|
|
444
|
+
const result = await agent.createDocument(JSON.stringify(docContent), null, null, true, filePath, embed);
|
|
445
|
+
return parseSignedResult(result);
|
|
446
|
+
}
|
|
447
|
+
signFileSync(filePath, embed = false) {
|
|
448
|
+
const agent = this.requireAgent();
|
|
449
|
+
if (!fs.existsSync(filePath))
|
|
450
|
+
throw new Error(`File not found: ${filePath}`);
|
|
451
|
+
const docContent = { jacsType: 'file', jacsLevel: 'raw', filename: path.basename(filePath) };
|
|
452
|
+
const result = agent.createDocumentSync(JSON.stringify(docContent), null, null, true, filePath, embed);
|
|
453
|
+
return parseSignedResult(result);
|
|
454
|
+
}
|
|
455
|
+
// ---------------------------------------------------------------------------
|
|
456
|
+
// Agreements
|
|
457
|
+
// ---------------------------------------------------------------------------
|
|
458
|
+
async createAgreement(document, agentIds, options) {
|
|
459
|
+
const agent = this.requireAgent();
|
|
460
|
+
const docString = normalizeDocumentInput(document);
|
|
461
|
+
const hasExtended = options?.timeout || options?.quorum !== undefined || options?.requiredAlgorithms || options?.minimumStrength;
|
|
462
|
+
let result;
|
|
463
|
+
if (hasExtended) {
|
|
464
|
+
result = await agent.createAgreementWithOptions(docString, agentIds, options?.question || null, options?.context || null, options?.fieldName || null, options?.timeout || null, options?.quorum ?? null, options?.requiredAlgorithms || null, options?.minimumStrength || null);
|
|
465
|
+
}
|
|
466
|
+
else {
|
|
467
|
+
result = await agent.createAgreement(docString, agentIds, options?.question || null, options?.context || null, options?.fieldName || null);
|
|
468
|
+
}
|
|
469
|
+
return parseSignedResult(result);
|
|
470
|
+
}
|
|
471
|
+
createAgreementSync(document, agentIds, options) {
|
|
472
|
+
const agent = this.requireAgent();
|
|
473
|
+
const docString = normalizeDocumentInput(document);
|
|
474
|
+
const hasExtended = options?.timeout || options?.quorum !== undefined || options?.requiredAlgorithms || options?.minimumStrength;
|
|
475
|
+
let result;
|
|
476
|
+
if (hasExtended) {
|
|
477
|
+
result = agent.createAgreementWithOptionsSync(docString, agentIds, options?.question || null, options?.context || null, options?.fieldName || null, options?.timeout || null, options?.quorum ?? null, options?.requiredAlgorithms || null, options?.minimumStrength || null);
|
|
478
|
+
}
|
|
479
|
+
else {
|
|
480
|
+
result = agent.createAgreementSync(docString, agentIds, options?.question || null, options?.context || null, options?.fieldName || null);
|
|
481
|
+
}
|
|
482
|
+
return parseSignedResult(result);
|
|
483
|
+
}
|
|
484
|
+
async signAgreement(document, fieldName) {
|
|
485
|
+
const agent = this.requireAgent();
|
|
486
|
+
const docString = normalizeDocumentInput(document);
|
|
487
|
+
const result = await agent.signAgreement(docString, fieldName || null);
|
|
488
|
+
return parseSignedResult(result);
|
|
489
|
+
}
|
|
490
|
+
signAgreementSync(document, fieldName) {
|
|
491
|
+
const agent = this.requireAgent();
|
|
492
|
+
const docString = normalizeDocumentInput(document);
|
|
493
|
+
const result = agent.signAgreementSync(docString, fieldName || null);
|
|
494
|
+
return parseSignedResult(result);
|
|
495
|
+
}
|
|
496
|
+
async checkAgreement(document, fieldName) {
|
|
497
|
+
const agent = this.requireAgent();
|
|
498
|
+
const docString = normalizeDocumentInput(document);
|
|
499
|
+
const result = await agent.checkAgreement(docString, fieldName || null);
|
|
500
|
+
return JSON.parse(result);
|
|
501
|
+
}
|
|
502
|
+
checkAgreementSync(document, fieldName) {
|
|
503
|
+
const agent = this.requireAgent();
|
|
504
|
+
const docString = normalizeDocumentInput(document);
|
|
505
|
+
const result = agent.checkAgreementSync(docString, fieldName || null);
|
|
506
|
+
return JSON.parse(result);
|
|
507
|
+
}
|
|
508
|
+
// ---------------------------------------------------------------------------
|
|
509
|
+
// Agent management
|
|
510
|
+
// ---------------------------------------------------------------------------
|
|
511
|
+
async updateAgent(newAgentData) {
|
|
512
|
+
const agent = this.requireAgent();
|
|
513
|
+
const dataString = typeof newAgentData === 'string' ? newAgentData : JSON.stringify(newAgentData);
|
|
514
|
+
return agent.updateAgent(dataString);
|
|
515
|
+
}
|
|
516
|
+
updateAgentSync(newAgentData) {
|
|
517
|
+
const agent = this.requireAgent();
|
|
518
|
+
const dataString = typeof newAgentData === 'string' ? newAgentData : JSON.stringify(newAgentData);
|
|
519
|
+
return agent.updateAgentSync(dataString);
|
|
520
|
+
}
|
|
521
|
+
async updateDocument(documentId, newDocumentData, attachments, embed) {
|
|
522
|
+
const agent = this.requireAgent();
|
|
523
|
+
const dataString = typeof newDocumentData === 'string' ? newDocumentData : JSON.stringify(newDocumentData);
|
|
524
|
+
const result = await agent.updateDocument(documentId, dataString, attachments || null, embed ?? null);
|
|
525
|
+
return parseSignedResult(result);
|
|
526
|
+
}
|
|
527
|
+
updateDocumentSync(documentId, newDocumentData, attachments, embed) {
|
|
528
|
+
const agent = this.requireAgent();
|
|
529
|
+
const dataString = typeof newDocumentData === 'string' ? newDocumentData : JSON.stringify(newDocumentData);
|
|
530
|
+
const result = agent.updateDocumentSync(documentId, dataString, attachments || null, embed ?? null);
|
|
531
|
+
return parseSignedResult(result);
|
|
532
|
+
}
|
|
533
|
+
// ---------------------------------------------------------------------------
|
|
534
|
+
// Trust Store (sync-only)
|
|
535
|
+
// ---------------------------------------------------------------------------
|
|
536
|
+
trustAgent(agentJson) { return (0, index_1.trustAgent)(agentJson); }
|
|
537
|
+
listTrustedAgents() { return (0, index_1.listTrustedAgents)(); }
|
|
538
|
+
untrustAgent(agentId) { (0, index_1.untrustAgent)(agentId); }
|
|
539
|
+
isTrusted(agentId) { return (0, index_1.isTrusted)(agentId); }
|
|
540
|
+
getTrustedAgent(agentId) { return (0, index_1.getTrustedAgent)(agentId); }
|
|
541
|
+
// ---------------------------------------------------------------------------
|
|
542
|
+
// Audit
|
|
543
|
+
// ---------------------------------------------------------------------------
|
|
544
|
+
async audit(options) {
|
|
545
|
+
const json = await (0, index_1.audit)(options?.configPath ?? undefined, options?.recentN ?? undefined);
|
|
546
|
+
return JSON.parse(json);
|
|
547
|
+
}
|
|
548
|
+
auditSync(options) {
|
|
549
|
+
const json = (0, index_1.auditSync)(options?.configPath ?? undefined, options?.recentN ?? undefined);
|
|
550
|
+
return JSON.parse(json);
|
|
551
|
+
}
|
|
552
|
+
// ---------------------------------------------------------------------------
|
|
553
|
+
// Verify Link
|
|
554
|
+
// ---------------------------------------------------------------------------
|
|
555
|
+
generateVerifyLink(document, baseUrl) {
|
|
556
|
+
return (0, simple_1.generateVerifyLink)(document, baseUrl);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
exports.JacsClient = JacsClient;
|
|
560
|
+
//# sourceMappingURL=client.js.map
|
package/express.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JACS Express Middleware
|
|
3
|
+
*
|
|
4
|
+
* Factory-based middleware for Express v4/v5 that verifies incoming
|
|
5
|
+
* JACS-signed request bodies and optionally auto-signs JSON responses.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import express from 'express';
|
|
10
|
+
* import { JacsClient } from './client';
|
|
11
|
+
* import { jacsMiddleware } from './express';
|
|
12
|
+
*
|
|
13
|
+
* const client = await JacsClient.quickstart();
|
|
14
|
+
* const app = express();
|
|
15
|
+
* app.use(express.text({ type: 'application/json' }));
|
|
16
|
+
* app.use(jacsMiddleware({ client, verify: true }));
|
|
17
|
+
*
|
|
18
|
+
* app.post('/api/data', (req, res) => {
|
|
19
|
+
* console.log(req.jacsPayload); // verified payload
|
|
20
|
+
* res.json({ status: 'ok' });
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
import type { JacsClient } from './client.js';
|
|
25
|
+
/** Minimal Express-like request shape. */
|
|
26
|
+
export interface ExpressRequest {
|
|
27
|
+
method: string;
|
|
28
|
+
body?: any;
|
|
29
|
+
headers: Record<string, any>;
|
|
30
|
+
[key: string]: any;
|
|
31
|
+
}
|
|
32
|
+
/** Minimal Express-like response shape. */
|
|
33
|
+
export interface ExpressResponse {
|
|
34
|
+
status(code: number): ExpressResponse;
|
|
35
|
+
json(body: any): ExpressResponse;
|
|
36
|
+
send(body: any): ExpressResponse;
|
|
37
|
+
type(val: string): ExpressResponse;
|
|
38
|
+
headersSent: boolean;
|
|
39
|
+
[key: string]: any;
|
|
40
|
+
}
|
|
41
|
+
/** Express next function. */
|
|
42
|
+
export type ExpressNextFunction = (err?: any) => void;
|
|
43
|
+
export interface JacsMiddlewareOptions {
|
|
44
|
+
/** Pre-initialized JacsClient instance (preferred). */
|
|
45
|
+
client?: JacsClient;
|
|
46
|
+
/** Path to jacs config file. Used only if `client` is not provided. */
|
|
47
|
+
configPath?: string;
|
|
48
|
+
/** Auto-sign JSON responses via res.json() interception. Default: false (opt-in). */
|
|
49
|
+
sign?: boolean;
|
|
50
|
+
/** Verify incoming POST/PUT/PATCH bodies as JACS documents. Default: true. */
|
|
51
|
+
verify?: boolean;
|
|
52
|
+
/** Allow unsigned/invalid requests to pass through instead of returning 401. Default: false. */
|
|
53
|
+
optional?: boolean;
|
|
54
|
+
}
|
|
55
|
+
export interface JacsRequest extends ExpressRequest {
|
|
56
|
+
/** Verified JACS payload content (set when verify succeeds). */
|
|
57
|
+
jacsPayload?: any;
|
|
58
|
+
/** JacsClient instance for manual sign/verify in route handlers. */
|
|
59
|
+
jacsClient?: JacsClient;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Create JACS Express middleware.
|
|
63
|
+
*
|
|
64
|
+
* The returned middleware attaches `req.jacsClient` on every request.
|
|
65
|
+
* When `verify` is true (default), POST/PUT/PATCH bodies are verified as
|
|
66
|
+
* JACS-signed documents and the extracted payload is set on `req.jacsPayload`.
|
|
67
|
+
* When `sign` is true, `res.json()` is intercepted to auto-sign the response.
|
|
68
|
+
*/
|
|
69
|
+
export declare function jacsMiddleware(options?: JacsMiddlewareOptions): (req: JacsRequest, res: ExpressResponse, next: ExpressNextFunction) => Promise<void>;
|