@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 CHANGED
@@ -1,6 +1,10 @@
1
1
  # JACS for Node.js
2
2
 
3
- Node.js bindings for JACS (JSON Agent Communication Standard) -- an open data provenance toolkit for signing and verifying AI agent communications. JACS works standalone with no server required; optionally register with [HAI.ai](https://hai.ai) for cross-organization key discovery.
3
+ **Sign it. Prove it.**
4
+
5
+ Cryptographic signatures for AI agent outputs -- so anyone can verify who said what and whether it was changed. No server. Three lines of code. Optionally register with [HAI.ai](https://hai.ai) for cross-organization key discovery.
6
+
7
+ [Which integration should I use?](https://humanassisted.github.io/JACS/getting-started/decision-tree.html) | [Full documentation](https://humanassisted.github.io/JACS/)
4
8
 
5
9
  **Dependencies**: The `overrides` in `package.json` for `body-parser` and `qs` are for security (CVE-2024-45590). Do not remove them without re-auditing.
6
10
 
@@ -12,53 +16,91 @@ npm install @hai.ai/jacs
12
16
 
13
17
  The npm package ships prebuilt native bindings for supported targets and does not compile Rust during `npm install`.
14
18
 
19
+ ## v0.8.0: Framework Adapters
20
+
21
+ New in v0.8.0: first-class adapters for **Vercel AI SDK**, **Express**, **Koa**, **LangChain.js**, and a full **MCP tool suite**. All framework dependencies are optional peer deps — install only what you use.
22
+
23
+ ### Async-First API
24
+
25
+ All NAPI operations return Promises by default. Sync variants are available with a `Sync` suffix, following the Node.js convention (like `fs.readFile` vs `fs.readFileSync`).
26
+
27
+ ```javascript
28
+ // Async (default, recommended -- does not block the event loop)
29
+ const signed = await jacs.signMessage({ action: 'approve' });
30
+
31
+ // Sync (blocks event loop, use in scripts or CLI tools)
32
+ const signed = jacs.signMessageSync({ action: 'approve' });
33
+ ```
34
+
15
35
  ## Quick Start
16
36
 
37
+ Zero-config -- one call to start signing:
38
+
17
39
  ```javascript
18
40
  const jacs = require('@hai.ai/jacs/simple');
19
41
 
20
- // Load your agent (run `jacs create` first if needed)
21
- const agent = jacs.load('./jacs.config.json');
42
+ await jacs.quickstart();
43
+ const signed = await jacs.signMessage({ action: 'approve', amount: 100 });
44
+ const result = await jacs.verify(signed.raw);
45
+ console.log(`Valid: ${result.valid}, Signer: ${result.signerId}`);
46
+ ```
22
47
 
23
- // Sign a message
24
- const signed = jacs.signMessage({
25
- action: 'approve',
26
- amount: 100
27
- });
48
+ `quickstart()` creates a persistent agent with keys on disk. If `./jacs.config.json` already exists, it loads it; otherwise it creates a new agent. Agent, keys, and config are saved to `./jacs_data`, `./jacs_keys`, and `./jacs.config.json`. If `JACS_PRIVATE_KEY_PASSWORD` is not set, a secure password is auto-generated and saved to `./jacs_keys/.jacs_password`. Pass `{ algorithm: 'ring-Ed25519' }` to override the default (`pq2025`).
28
49
 
29
- // Verify it
30
- const result = jacs.verify(signed.raw);
31
- console.log(`Valid: ${result.valid}`);
32
- console.log(`Signer: ${result.signerId}`);
50
+ **Signed your first document?** Next: [Verify it standalone](#standalone-verification-no-agent-required) | [Add framework adapters](#framework-adapters) | [Multi-agent agreements](#multi-party-agreements) | [Full docs](https://humanassisted.github.io/JACS/getting-started/quick-start.html)
51
+
52
+ ### Advanced: Loading an existing agent
53
+
54
+ If you already have an agent (e.g., created by a previous `quickstart()` call), load it explicitly:
55
+
56
+ ```javascript
57
+ const jacs = require('@hai.ai/jacs/simple');
58
+
59
+ await jacs.load('./jacs.config.json');
60
+
61
+ const signed = await jacs.signMessage({ action: 'approve', amount: 100 });
62
+ const result = await jacs.verify(signed.raw);
63
+ console.log(`Valid: ${result.valid}, Signer: ${result.signerId}`);
33
64
  ```
34
65
 
35
66
  ## Core API
36
67
 
68
+ Every function that calls into NAPI has both async (default) and sync variants:
69
+
70
+ | Function | Sync Variant | Description |
71
+ |----------|-------------|-------------|
72
+ | `quickstart(options?)` | `quickstartSync(options?)` | Create a persistent agent with keys on disk |
73
+ | `create(options)` | `createSync(options)` | Create a new agent programmatically |
74
+ | `load(configPath)` | `loadSync(configPath)` | Load agent from config file |
75
+ | `verifySelf()` | `verifySelfSync()` | Verify agent's own integrity |
76
+ | `updateAgent(data)` | `updateAgentSync(data)` | Update agent document |
77
+ | `updateDocument(id, data)` | `updateDocumentSync(id, data)` | Update existing document |
78
+ | `signMessage(data)` | `signMessageSync(data)` | Sign any JSON data |
79
+ | `signFile(path, embed)` | `signFileSync(path, embed)` | Sign a file |
80
+ | `verify(doc)` | `verifySync(doc)` | Verify signed document |
81
+ | `verifyById(id)` | `verifyByIdSync(id)` | Verify by storage ID |
82
+ | `reencryptKey(old, new)` | `reencryptKeySync(old, new)` | Re-encrypt private key |
83
+ | `getSetupInstructions(domain)` | `getSetupInstructionsSync(domain)` | Get DNS/well-known setup |
84
+ | `createAgreement(doc, ids, ...)` | `createAgreementSync(doc, ids, ...)` | Create multi-party agreement |
85
+ | `signAgreement(doc)` | `signAgreementSync(doc)` | Sign an agreement |
86
+ | `checkAgreement(doc)` | `checkAgreementSync(doc)` | Check agreement status |
87
+ | `audit(options?)` | `auditSync(options?)` | Run a security audit |
88
+
89
+ Pure sync functions (no NAPI call, no suffix needed):
90
+
37
91
  | Function | Description |
38
92
  |----------|-------------|
39
- | `create(options)` | Create a new agent programmatically (non-interactive) |
40
- | `load(configPath)` | Load agent from config file |
41
- | `verifySelf()` | Verify agent's own integrity |
42
- | `updateAgent(data)` | Update agent document with new data |
43
- | `updateDocument(id, data)` | Update existing document with new data |
44
- | `signMessage(data)` | Sign any JSON data |
45
- | `signFile(path, embed)` | Sign a file |
46
- | `verify(doc)` | Verify signed document (JSON string) |
47
- | `verifyStandalone(doc, opts?)` | Verify without loading an agent (one-off) |
48
- | `verifyById(id)` | Verify a document by storage ID (`uuid:version`) |
49
- | `registerWithHai(opts?)` | Register the loaded agent with HAI.ai |
50
- | `getDnsRecord(domain, ttl?)` | Get DNS TXT record line for the agent |
51
- | `getWellKnownJson()` | Get well-known JSON for `/.well-known/jacs-pubkey.json` |
52
- | `reencryptKey(oldPw, newPw)` | Re-encrypt private key with new password |
53
- | `getPublicKey()` | Get public key for sharing |
93
+ | `verifyStandalone(doc, opts?)` | Verify without loading an agent |
94
+ | `getPublicKey()` | Get public key |
54
95
  | `isLoaded()` | Check if agent is loaded |
55
- | `trustAgent(json)` | Add an agent to the local trust store |
56
- | `listTrustedAgents()` | List all trusted agent IDs |
57
- | `untrustAgent(id)` | Remove an agent from the trust store |
58
- | `isTrusted(id)` | Check if an agent is trusted |
59
- | `getTrustedAgent(id)` | Get a trusted agent's JSON document |
60
- | `audit(options?)` | Run a read-only security audit; optional `configPath`, `recentN` |
61
- | `generateVerifyLink(doc, baseUrl?)` | Generate a shareable hai.ai verification URL for a signed document |
96
+ | `getDnsRecord(domain, ttl?)` | Get DNS TXT record |
97
+ | `getWellKnownJson()` | Get well-known JSON |
98
+ | `trustAgent(json)` | Add agent to trust store |
99
+ | `listTrustedAgents()` | List trusted agent IDs |
100
+ | `untrustAgent(id)` | Remove from trust store |
101
+ | `isTrusted(id)` | Check if agent is trusted |
102
+ | `getTrustedAgent(id)` | Get trusted agent's JSON |
103
+ | `generateVerifyLink(doc, baseUrl?)` | Generate verification URL |
62
104
 
63
105
  ## Types
64
106
 
@@ -85,7 +127,7 @@ interface VerificationResult {
85
127
  ```typescript
86
128
  const jacs = require('@hai.ai/jacs/simple');
87
129
 
88
- const agent = jacs.create({
130
+ const agent = await jacs.create({
89
131
  name: 'my-agent',
90
132
  password: process.env.JACS_PRIVATE_KEY_PASSWORD, // required
91
133
  algorithm: 'pq2025', // default; also: "ring-Ed25519", "RSA-PSS"
@@ -95,17 +137,39 @@ const agent = jacs.create({
95
137
  console.log(`Created: ${agent.agentId}`);
96
138
  ```
97
139
 
140
+ ### Standalone Verification (No Agent Required)
141
+
142
+ Verify a signed document without loading an agent. Useful for one-off verification, CI/CD pipelines, or services that only need to verify, not sign.
143
+
144
+ ```typescript
145
+ import { verifyStandalone, generateVerifyLink } from '@hai.ai/jacs/simple';
146
+
147
+ const result = verifyStandalone(signedJson, {
148
+ keyResolution: 'local',
149
+ keyDirectory: './trusted-keys/',
150
+ });
151
+ if (result.valid) {
152
+ console.log(`Signed by: ${result.signerId}`);
153
+ }
154
+
155
+ // Generate a shareable verification link
156
+ const url = generateVerifyLink(signed.raw);
157
+ // https://hai.ai/jacs/verify?s=<base64url-encoded-document>
158
+ ```
159
+
160
+ Documents signed by Rust or Python agents verify identically in Node.js -- cross-language interop is tested on every commit with Ed25519 and pq2025 (ML-DSA-87). See the full [Verification Guide](https://humanassisted.github.io/JACS/getting-started/verification.html) for CLI, DNS, and cross-language examples.
161
+
98
162
  ### Verify by Document ID
99
163
 
100
164
  ```javascript
101
- const result = jacs.verifyById('550e8400-e29b-41d4-a716-446655440000:1');
165
+ const result = await jacs.verifyById('550e8400-e29b-41d4-a716-446655440000:1');
102
166
  console.log(`Valid: ${result.valid}`);
103
167
  ```
104
168
 
105
169
  ### Re-encrypt Private Key
106
170
 
107
171
  ```javascript
108
- jacs.reencryptKey('old-password-123!', 'new-Str0ng-P@ss!');
172
+ await jacs.reencryptKey('old-password-123!', 'new-Str0ng-P@ss!');
109
173
  ```
110
174
 
111
175
  ### Password Requirements
@@ -123,17 +187,17 @@ The `pq-dilithium` algorithm is deprecated. Use `pq2025` (ML-DSA-87, FIPS-204) i
123
187
  ```javascript
124
188
  const jacs = require('@hai.ai/jacs/simple');
125
189
 
126
- jacs.load('./jacs.config.json');
190
+ await jacs.load('./jacs.config.json');
127
191
 
128
192
  // Sign data
129
- const signed = jacs.signMessage({
193
+ const signed = await jacs.signMessage({
130
194
  action: 'transfer',
131
195
  amount: 500,
132
196
  to: 'agent-123'
133
197
  });
134
198
 
135
199
  // Later, verify received data
136
- const result = jacs.verify(receivedJson);
200
+ const result = await jacs.verify(receivedJson);
137
201
  if (result.valid) {
138
202
  console.log(`Signed by: ${result.signerId}`);
139
203
  console.log(`Data: ${JSON.stringify(result.data)}`);
@@ -146,7 +210,7 @@ if (result.valid) {
146
210
  // Get current agent, modify, and update
147
211
  const agentDoc = JSON.parse(jacs.exportAgent());
148
212
  agentDoc.jacsAgentType = 'updated-service';
149
- const updated = jacs.updateAgent(agentDoc);
213
+ const updated = await jacs.updateAgent(agentDoc);
150
214
  console.log('Agent updated with new version');
151
215
  ```
152
216
 
@@ -154,12 +218,12 @@ console.log('Agent updated with new version');
154
218
 
155
219
  ```javascript
156
220
  // Create a document
157
- const signed = jacs.signMessage({ status: 'pending', amount: 100 });
221
+ const signed = await jacs.signMessage({ status: 'pending', amount: 100 });
158
222
 
159
223
  // Later, update it
160
224
  const doc = JSON.parse(signed.raw);
161
225
  doc.content.status = 'approved';
162
- const updated = jacs.updateDocument(signed.documentId, doc);
226
+ const updated = await jacs.updateDocument(signed.documentId, doc);
163
227
  console.log('Document updated with new version');
164
228
  ```
165
229
 
@@ -167,28 +231,247 @@ console.log('Document updated with new version');
167
231
 
168
232
  ```javascript
169
233
  // Reference only (stores hash)
170
- const signed = jacs.signFile('contract.pdf', false);
234
+ const signed = await jacs.signFile('contract.pdf', false);
171
235
 
172
236
  // Embed content (portable document)
173
- const embedded = jacs.signFile('contract.pdf', true);
237
+ const embedded = await jacs.signFile('contract.pdf', true);
174
238
  ```
175
239
 
176
- ### MCP Integration
240
+ ## Framework Adapters
177
241
 
178
- JACS provides a transport proxy that wraps any MCP transport with automatic signing and verification at the network boundary:
242
+ ### Vercel AI SDK (`@hai.ai/jacs/vercel-ai`)
179
243
 
180
- ```javascript
244
+ Sign AI model outputs with cryptographic provenance using the AI SDK's middleware pattern:
245
+
246
+ ```typescript
247
+ import { JacsClient } from '@hai.ai/jacs/client';
248
+ import { withProvenance } from '@hai.ai/jacs/vercel-ai';
249
+ import { openai } from '@ai-sdk/openai';
250
+ import { generateText } from 'ai';
251
+
252
+ const client = await JacsClient.quickstart();
253
+ const model = withProvenance(openai('gpt-4o'), { client });
254
+
255
+ const { text, providerMetadata } = await generateText({ model, prompt: 'Hello!' });
256
+ console.log(providerMetadata?.jacs?.text?.documentId); // signed proof
257
+ ```
258
+
259
+ Works with `generateText`, `streamText` (signs after stream completes), and tool calls. Compose with other middleware via `jacsProvenance()`.
260
+
261
+ **Peer deps**: `npm install ai @ai-sdk/provider`
262
+
263
+ ### Express Middleware (`@hai.ai/jacs/express`)
264
+
265
+ Verify incoming signed requests, optionally auto-sign responses:
266
+
267
+ ```typescript
268
+ import express from 'express';
269
+ import { JacsClient } from '@hai.ai/jacs/client';
270
+ import { jacsMiddleware } from '@hai.ai/jacs/express';
271
+
272
+ const client = await JacsClient.quickstart();
273
+ const app = express();
274
+ app.use(express.text({ type: 'application/json' }));
275
+ app.use(jacsMiddleware({ client, verify: true }));
276
+
277
+ app.post('/api/data', (req, res) => {
278
+ console.log(req.jacsPayload); // verified payload
279
+ // Manual signing via req.jacsClient:
280
+ req.jacsClient.signMessage({ status: 'ok' }).then(signed => {
281
+ res.type('text/plain').send(signed.raw);
282
+ });
283
+ });
284
+ ```
285
+
286
+ Options: `client`, `configPath`, `sign` (auto-sign, default false), `verify` (default true), `optional` (allow unsigned, default false). Supports Express v4 + v5.
287
+
288
+ **Peer dep**: `npm install express`
289
+
290
+ ### Koa Middleware (`@hai.ai/jacs/koa`)
291
+
292
+ ```typescript
293
+ import Koa from 'koa';
294
+ import { jacsKoaMiddleware } from '@hai.ai/jacs/koa';
295
+
296
+ const app = new Koa();
297
+ app.use(jacsKoaMiddleware({ client, verify: true, sign: true }));
298
+ app.use(async (ctx) => {
299
+ console.log(ctx.state.jacsPayload); // verified
300
+ ctx.body = { status: 'ok' }; // auto-signed when sign: true
301
+ });
302
+ ```
303
+
304
+ **Peer dep**: `npm install koa`
305
+
306
+ ### LangChain.js (`@hai.ai/jacs/langchain`)
307
+
308
+ Two integration patterns — full toolkit or auto-signing wrappers:
309
+
310
+ **Full toolkit** — give your LangChain agent access to all JACS operations (sign, verify, agreements, trust, audit):
311
+
312
+ ```typescript
313
+ import { JacsClient } from '@hai.ai/jacs/client';
314
+ import { createJacsTools } from '@hai.ai/jacs/langchain';
315
+
316
+ const client = await JacsClient.quickstart();
317
+ const jacsTools = createJacsTools({ client });
318
+
319
+ // Bind to your LLM — agent can now sign, verify, create agreements, etc.
320
+ const llm = model.bindTools([...myTools, ...jacsTools]);
321
+ ```
322
+
323
+ Returns 11 tools: `jacs_sign`, `jacs_verify`, `jacs_create_agreement`, `jacs_sign_agreement`, `jacs_check_agreement`, `jacs_verify_self`, `jacs_trust_agent`, `jacs_list_trusted`, `jacs_is_trusted`, `jacs_audit`, `jacs_agent_info`.
324
+
325
+ **Auto-signing wrappers** — transparently sign existing tool outputs:
326
+
327
+ ```typescript
328
+ import { signedTool, jacsToolNode } from '@hai.ai/jacs/langchain';
329
+
330
+ // Wrap a single tool
331
+ const signed = signedTool(myTool, { client });
332
+
333
+ // Or wrap all tools in a ToolNode (LangGraph)
334
+ const node = jacsToolNode([tool1, tool2], { client });
335
+ ```
336
+
337
+ **Peer deps**: `npm install @langchain/core` (and optionally `@langchain/langgraph` for `jacsToolNode`)
338
+
339
+ ### MCP (`@hai.ai/jacs/mcp`)
340
+
341
+ Two integration patterns — transport proxy or full tool registration:
342
+
343
+ **Transport proxy** — wrap any MCP transport with signing/verification:
344
+
345
+ ```typescript
346
+ import { JacsClient } from '@hai.ai/jacs/client';
181
347
  import { createJACSTransportProxy } from '@hai.ai/jacs/mcp';
182
348
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
183
349
 
184
- // Wrap any MCP transport with JACS signing
350
+ const client = await JacsClient.quickstart();
185
351
  const baseTransport = new StdioServerTransport();
186
- const jacsTransport = createJACSTransportProxy(
187
- baseTransport, './jacs.config.json', 'server'
352
+ const secureTransport = createJACSTransportProxy(baseTransport, client, 'server');
353
+ ```
354
+
355
+ **MCP tool registration** — add all JACS tools to your MCP server (mirrors the Rust `jacs-mcp` server):
356
+
357
+ ```typescript
358
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
359
+ import { JacsClient } from '@hai.ai/jacs/client';
360
+ import { registerJacsTools } from '@hai.ai/jacs/mcp';
361
+
362
+ const server = new Server({ name: 'my-server', version: '1.0.0' }, { capabilities: { tools: {} } });
363
+ const client = await JacsClient.quickstart();
364
+ registerJacsTools(server, client);
365
+ ```
366
+
367
+ Registers 17 tools: signing, verification, agreements, trust store, audit, HAI integration, file signing, and more. Use `getJacsMcpToolDefinitions()` and `handleJacsMcpToolCall()` for custom integration.
368
+
369
+ **Peer dep**: `npm install @modelcontextprotocol/sdk`
370
+
371
+ ### Legacy: `@hai.ai/jacs/http`
372
+
373
+ The old `JACSExpressMiddleware` and `JACSKoaMiddleware` are still available from `@hai.ai/jacs/http` for backward compatibility. New code should use `@hai.ai/jacs/express` and `@hai.ai/jacs/koa`.
374
+
375
+ ## JacsClient (Instance-Based API)
376
+
377
+ `JacsClient` is the recommended API for new code. Each instance owns its own agent, so multiple clients can coexist in the same process without shared global state.
378
+
379
+ ```typescript
380
+ import { JacsClient } from '@hai.ai/jacs/client';
381
+
382
+ // Zero-config: loads or creates a persistent agent
383
+ const client = await JacsClient.quickstart({ algorithm: 'ring-Ed25519' });
384
+
385
+ const signed = await client.signMessage({ action: 'approve', amount: 100 });
386
+ const result = await client.verify(signed.raw);
387
+ console.log(`Valid: ${result.valid}, Signer: ${result.signerId}`);
388
+ ```
389
+
390
+ ### Ephemeral Clients
391
+
392
+ For testing or throwaway use, create an in-memory client with no files or env vars:
393
+
394
+ ```typescript
395
+ const client = await JacsClient.ephemeral('ring-Ed25519');
396
+ const signed = await client.signMessage({ hello: 'world' });
397
+ const result = await client.verify(signed.raw);
398
+ ```
399
+
400
+ Sync variants are also available:
401
+
402
+ ```typescript
403
+ const client = JacsClient.ephemeralSync('ring-Ed25519');
404
+ const signed = client.signMessageSync({ hello: 'world' });
405
+ const result = client.verifySync(signed.raw);
406
+ ```
407
+
408
+ ### Multi-Party Agreements
409
+
410
+ Create agreements that require signatures from multiple agents, with optional constraints:
411
+
412
+ ```typescript
413
+ const agreement = await client.createAgreement(
414
+ { action: 'deploy', version: '2.0' },
415
+ [agentA.agentId, agentB.agentId],
416
+ {
417
+ question: 'Approve deployment?',
418
+ timeout: '2026-03-01T00:00:00Z', // ISO 8601 deadline
419
+ quorum: 2, // M-of-N signatures required
420
+ requiredAlgorithms: ['ring-Ed25519'], // restrict signing algorithms
421
+ minimumStrength: 'classical', // "classical" or "post-quantum"
422
+ },
188
423
  );
424
+
425
+ // Other agents sign the agreement
426
+ const signed = await agentB.signAgreement(agreement.raw);
427
+
428
+ // Check agreement status
429
+ const status = await client.checkAgreement(signed.raw);
430
+ console.log(`Complete: ${status.complete}, Signatures: ${status.signedCount}/${status.totalRequired}`);
189
431
  ```
190
432
 
191
- See `examples/mcp.simple.server.js` for a complete MCP server example with JACS-signed tools.
433
+ ### JacsClient API
434
+
435
+ All instance methods have async (default) and sync variants:
436
+
437
+ | Method | Sync Variant | Description |
438
+ |--------|-------------|-------------|
439
+ | `JacsClient.quickstart(options?)` | `JacsClient.quickstartSync(options?)` | Load or create a persistent agent |
440
+ | `JacsClient.ephemeral(algorithm?)` | `JacsClient.ephemeralSync(algorithm?)` | Create an in-memory agent |
441
+ | `client.load(configPath?)` | `client.loadSync(configPath?)` | Load agent from config file |
442
+ | `client.create(options)` | `client.createSync(options)` | Create a new agent |
443
+ | `client.signMessage(data)` | `client.signMessageSync(data)` | Sign any JSON data |
444
+ | `client.verify(doc)` | `client.verifySync(doc)` | Verify a signed document |
445
+ | `client.verifySelf()` | `client.verifySelfSync()` | Verify agent's own integrity |
446
+ | `client.verifyById(id)` | `client.verifyByIdSync(id)` | Verify by storage ID |
447
+ | `client.signFile(path, embed?)` | `client.signFileSync(path, embed?)` | Sign a file |
448
+ | `client.createAgreement(...)` | `client.createAgreementSync(...)` | Create multi-party agreement |
449
+ | `client.signAgreement(...)` | `client.signAgreementSync(...)` | Sign an agreement |
450
+ | `client.checkAgreement(...)` | `client.checkAgreementSync(...)` | Check agreement status |
451
+ | `client.updateAgent(data)` | `client.updateAgentSync(data)` | Update agent document |
452
+ | `client.updateDocument(id, data)` | `client.updateDocumentSync(id, data)` | Update a document |
453
+
454
+ See [`examples/multi_agent_agreement.ts`](./examples/multi_agent_agreement.ts) for a complete multi-agent agreement demo.
455
+
456
+ ## Testing
457
+
458
+ The `@hai.ai/jacs/testing` module provides zero-setup test helpers:
459
+
460
+ ```typescript
461
+ import { createTestClient, createTestClientSync } from '@hai.ai/jacs/testing';
462
+
463
+ // Async (preferred)
464
+ const client = await createTestClient('ring-Ed25519');
465
+ const signed = await client.signMessage({ hello: 'test' });
466
+ const result = await client.verify(signed.raw);
467
+ assert(result.valid);
468
+
469
+ // Sync
470
+ const client2 = createTestClientSync('ring-Ed25519');
471
+ const signed2 = client2.signMessageSync({ hello: 'test' });
472
+ const result2 = client2.verifySync(signed2.raw);
473
+ assert(result2.valid);
474
+ ```
192
475
 
193
476
  ## HAI Integration
194
477
 
@@ -232,6 +515,7 @@ interface RemotePublicKeyInfo {
232
515
 
233
516
  - [JACS Book](https://humanassisted.github.io/JACS/) - Full documentation (published book)
234
517
  - [Quick Start](https://humanassisted.github.io/JACS/getting-started/quick-start.html)
518
+ - [Verification Guide](https://humanassisted.github.io/JACS/getting-started/verification.html) - CLI, standalone, DNS verification
235
519
  - [Source](https://github.com/HumanAssisted/JACS) - GitHub repository
236
520
  - [HAI Developer Portal](https://hai.ai/dev)
237
521
  - [Examples](./examples/)
package/client.d.ts ADDED
@@ -0,0 +1,96 @@
1
+ /**
2
+ * JACS Instance-Based Client API
3
+ *
4
+ * v0.7.0: Async-first API. All methods that call native JACS operations
5
+ * return Promises by default. Use `*Sync` variants for synchronous execution.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { JacsClient } from '@hai.ai/jacs/client';
10
+ *
11
+ * const client = await JacsClient.quickstart({ algorithm: 'ring-Ed25519' });
12
+ * const signed = await client.signMessage({ action: 'approve' });
13
+ * const result = await client.verify(signed.raw);
14
+ * console.log(`Valid: ${result.valid}`);
15
+ * ```
16
+ */
17
+ import { hashString, createConfig } from './index';
18
+ import { generateVerifyLink, MAX_VERIFY_URL_LEN, MAX_VERIFY_DOCUMENT_BYTES } from './simple';
19
+ import type { AgentInfo, SignedDocument, VerificationResult, Attachment, AgreementStatus, AuditOptions, QuickstartOptions, QuickstartInfo, CreateAgentOptions, LoadOptions } from './simple';
20
+ export type { AgentInfo, SignedDocument, VerificationResult, Attachment, AgreementStatus, AuditOptions, QuickstartOptions, QuickstartInfo, CreateAgentOptions, LoadOptions, };
21
+ export { hashString, createConfig, generateVerifyLink, MAX_VERIFY_URL_LEN, MAX_VERIFY_DOCUMENT_BYTES };
22
+ export interface AgreementOptions {
23
+ question?: string;
24
+ context?: string;
25
+ fieldName?: string;
26
+ timeout?: string;
27
+ quorum?: number;
28
+ requiredAlgorithms?: string[];
29
+ minimumStrength?: string;
30
+ }
31
+ export interface JacsClientOptions {
32
+ configPath?: string;
33
+ algorithm?: string;
34
+ strict?: boolean;
35
+ }
36
+ export declare class JacsClient {
37
+ private agent;
38
+ private info;
39
+ private _strict;
40
+ constructor(options?: JacsClientOptions);
41
+ /**
42
+ * Zero-config factory: loads or creates a persistent agent.
43
+ */
44
+ static quickstart(options?: QuickstartOptions): Promise<JacsClient>;
45
+ /**
46
+ * Zero-config factory (sync variant).
47
+ */
48
+ static quickstartSync(options?: QuickstartOptions): JacsClient;
49
+ /**
50
+ * Create an ephemeral in-memory client for testing.
51
+ */
52
+ static ephemeral(algorithm?: string): Promise<JacsClient>;
53
+ /**
54
+ * Create an ephemeral in-memory client (sync variant).
55
+ */
56
+ static ephemeralSync(algorithm?: string): JacsClient;
57
+ load(configPath?: string, options?: LoadOptions): Promise<AgentInfo>;
58
+ loadSync(configPath?: string, options?: LoadOptions): AgentInfo;
59
+ create(options: CreateAgentOptions): Promise<AgentInfo>;
60
+ createSync(options: CreateAgentOptions): AgentInfo;
61
+ reset(): void;
62
+ dispose(): void;
63
+ [Symbol.dispose](): void;
64
+ get agentId(): string;
65
+ get name(): string;
66
+ get strict(): boolean;
67
+ private requireAgent;
68
+ signMessage(data: any): Promise<SignedDocument>;
69
+ signMessageSync(data: any): SignedDocument;
70
+ verify(signedDocument: string): Promise<VerificationResult>;
71
+ verifySync(signedDocument: string): VerificationResult;
72
+ verifySelf(): Promise<VerificationResult>;
73
+ verifySelfSync(): VerificationResult;
74
+ verifyById(documentId: string): Promise<VerificationResult>;
75
+ verifyByIdSync(documentId: string): VerificationResult;
76
+ signFile(filePath: string, embed?: boolean): Promise<SignedDocument>;
77
+ signFileSync(filePath: string, embed?: boolean): SignedDocument;
78
+ createAgreement(document: any, agentIds: string[], options?: AgreementOptions): Promise<SignedDocument>;
79
+ createAgreementSync(document: any, agentIds: string[], options?: AgreementOptions): SignedDocument;
80
+ signAgreement(document: any, fieldName?: string): Promise<SignedDocument>;
81
+ signAgreementSync(document: any, fieldName?: string): SignedDocument;
82
+ checkAgreement(document: any, fieldName?: string): Promise<AgreementStatus>;
83
+ checkAgreementSync(document: any, fieldName?: string): AgreementStatus;
84
+ updateAgent(newAgentData: any): Promise<string>;
85
+ updateAgentSync(newAgentData: any): string;
86
+ updateDocument(documentId: string, newDocumentData: any, attachments?: string[], embed?: boolean): Promise<SignedDocument>;
87
+ updateDocumentSync(documentId: string, newDocumentData: any, attachments?: string[], embed?: boolean): SignedDocument;
88
+ trustAgent(agentJson: string): string;
89
+ listTrustedAgents(): string[];
90
+ untrustAgent(agentId: string): void;
91
+ isTrusted(agentId: string): boolean;
92
+ getTrustedAgent(agentId: string): string;
93
+ audit(options?: AuditOptions): Promise<Record<string, unknown>>;
94
+ auditSync(options?: AuditOptions): Record<string, unknown>;
95
+ generateVerifyLink(document: string, baseUrl?: string): string;
96
+ }