diff --git a/README.md b/README.md index 0833e31..bf506b0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# @elydora/sdk +# Elydora Node SDK -Node.js/TypeScript SDK for the Elydora tamper-evident audit platform. +Official Node.js/TypeScript SDK for the [Elydora](https://elydora.com) tamper-evident audit platform. Build cryptographically verifiable audit trails for AI agent operations. ## Installation @@ -15,10 +15,10 @@ Requires Node.js 18+ (uses built-in `crypto` module with Ed25519 support). ```typescript import { ElydoraClient } from '@elydora/sdk'; -// 1. Authenticate +// Authenticate const auth = await ElydoraClient.login('https://api.elydora.com', 'user@example.com', 'password'); -// 2. Create client +// Create client const client = new ElydoraClient({ orgId: auth.user.org_id, agentId: 'my-agent-id', @@ -27,7 +27,7 @@ const client = new ElydoraClient({ }); client.setToken(auth.token); -// 3. Create and submit an operation +// Create and submit an operation const eor = client.createOperation({ operationType: 'data.access', subject: { user_id: 'u-123', resource: 'patient-record' }, @@ -39,48 +39,180 @@ const { receipt } = await client.submitOperation(eor); console.log('Operation submitted:', receipt.operation_id); ``` +## CLI + +The SDK includes a CLI for installing audit hooks into AI coding agents. + +```bash +npx elydora install \ + --agent claudecode \ + --org_id org-123 \ + --agent_id agent-456 \ + --private_key \ + --kid agent-456-key-v1 +``` + +### Commands + +| Command | Description | +|---------|-------------| +| `elydora install` | Install Elydora audit hook for a coding agent | +| `elydora uninstall` | Remove Elydora audit hook for a coding agent | +| `elydora status` | Show installation status for all agents | +| `elydora agents` | List supported coding agents | + +### Supported Agents + +| Agent | Key | +|-------|-----| +| Claude Code | `claudecode` | +| Cursor | `cursor` | +| Gemini CLI | `gemini` | +| Augment Code | `augment` | +| Kiro | `kiro` | +| OpenCode | `opencode` | + ## API Reference -### Static Methods +### Configuration -- `ElydoraClient.register(baseUrl, email, password, displayName?, orgName?)` — Register a new user and organization -- `ElydoraClient.login(baseUrl, email, password)` — Authenticate and receive a JWT +```typescript +const client = new ElydoraClient({ + orgId: string, // Organization ID + agentId: string, // Agent ID + privateKey: string, // Base64url-encoded Ed25519 seed + baseUrl?: string, // API base URL (default: https://api.elydora.com) + ttlMs?: number, // Operation TTL in ms (default: 30000) + maxRetries?: number, // Max retries on transient failures (default: 3) + kid?: string, // Key ID (default: {agentId}-key-v1) +}); +``` -### Instance Methods +### Authentication -#### Agent Management -- `registerAgent(request)` — Register a new agent with public keys -- `getAgent(agentId)` — Retrieve agent details -- `freezeAgent(agentId, reason)` — Freeze an agent -- `revokeKey(agentId, kid, reason)` — Revoke an agent key +```typescript +// Register a new user and organization +const reg = await ElydoraClient.register(baseUrl, email, password, displayName?, orgName?); -#### Operations -- `createOperation(params)` — Construct and sign an EOR locally (synchronous) -- `submitOperation(eor)` — Submit a signed EOR to the API -- `getOperation(operationId)` — Retrieve an operation -- `verifyOperation(operationId)` — Verify operation integrity +// Login and receive a JWT +const auth = await ElydoraClient.login(baseUrl, email, password); -#### Audit -- `queryAudit(params)` — Query the audit log +// Set token on client +client.setToken(auth.token); +``` -#### Epochs -- `listEpochs()` — List all epochs -- `getEpoch(epochId)` — Retrieve an epoch +### Operations -#### Exports -- `createExport(params)` — Create a compliance export -- `listExports()` — List all exports -- `getExport(exportId)` — Retrieve export status +```typescript +// Create a signed EOR locally (synchronous, no network call) +const eor = client.createOperation({ + operationType: 'inference', + subject: { model: 'gpt-4' }, + action: { type: 'completion' }, + payload: { prompt: 'Hello' }, +}); -#### JWKS -- `getJWKS()` — Retrieve platform public keys +// Submit to API +const { receipt } = await client.submitOperation(eor); -## Cryptographic Details +// Retrieve an operation +const op = await client.getOperation(operationId); -- **Ed25519**: Signs operations using Node.js built-in `crypto` module -- **Chain hashing**: `SHA-256(prev_chain_hash | payload_hash | operation_id | issued_at)` -- **JCS**: RFC 8785 JSON Canonicalization Scheme for deterministic serialization -- **Base64url**: RFC 4648 section 5, no padding +// Verify integrity (signature, chain, receipt, merkle) +const result = await client.verifyOperation(operationId); +``` + +### Agent Management + +```typescript +// Register a new agent +const agent = await client.registerAgent({ + agent_id: 'my-agent', + display_name: 'My Agent', + responsible_entity: 'team@example.com', + keys: [{ kid: 'key-v1', public_key: '', algorithm: 'ed25519' }], +}); + +// Get agent details +const details = await client.getAgent(agentId); + +// Freeze an agent +await client.freezeAgent(agentId, 'security review'); + +// Revoke a key +await client.revokeKey(agentId, kid, 'key rotation'); +``` + +### Audit + +```typescript +const results = await client.queryAudit({ + agent_id: 'agent-123', + operation_type: 'inference', + start_time: Date.now() - 86400000, + end_time: Date.now(), + limit: 50, +}); +``` + +### Epochs + +```typescript +const { epochs } = await client.listEpochs(); +const { epoch } = await client.getEpoch(epochId); +``` + +### Exports + +```typescript +const { export: exp } = await client.createExport({ + start_time: Date.now() - 86400000, + end_time: Date.now(), + format: 'json', +}); + +const { exports } = await client.listExports(); +const { export: detail, download_url } = await client.getExport(exportId); +``` + +### JWKS + +```typescript +const { keys } = await client.getJWKS(); +``` + +### Crypto Utilities + +The SDK exports low-level cryptographic primitives for advanced use: + +```typescript +import { + jcsCanonicalise, // RFC 8785 JSON Canonicalization + sha256Base64url, // SHA-256 hash as base64url + computeChainHash, // Chain hash computation + computePayloadHash, // Payload hash computation + signEd25519, // Ed25519 signing + derivePublicKey, // Derive public key from private seed + ZERO_CHAIN_HASH, // Genesis chain hash constant +} from '@elydora/sdk'; +``` + +## Error Handling + +```typescript +import { ElydoraError } from '@elydora/sdk'; + +try { + await client.submitOperation(eor); +} catch (err) { + if (err instanceof ElydoraError) { + console.error(err.code); // e.g. 'INVALID_SIGNATURE' + console.error(err.message); // Human-readable message + console.error(err.statusCode); // HTTP status code + console.error(err.requestId); // Request ID for support + } +} +``` ## License