@vorim/sdk 3.3.2 → 3.4.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/dist/index.cjs CHANGED
@@ -117,7 +117,7 @@ async function prepareReplayContext(inputs) {
117
117
  }
118
118
 
119
119
  // src/index.ts
120
- var SDK_VERSION = true ? "3.3.2" : "0.0.0";
120
+ var SDK_VERSION = true ? "3.4.0" : "0.0.0";
121
121
  var USER_AGENT = `vorim-sdk/${SDK_VERSION}`;
122
122
  function canonicalPayloadV0(event) {
123
123
  return [
@@ -175,7 +175,15 @@ var VorimSDK = class _VorimSDK {
175
175
  this.baseUrl = (config.baseUrl || "https://api.vorim.ai").replace(/\/$/, "") + "/v1";
176
176
  this.timeout = config.timeout || 1e4;
177
177
  this.autoSign = config.autoSign !== false;
178
- this.canonicalForm = config.canonicalForm ?? "v0";
178
+ this.canonicalForm = config.canonicalForm ?? "v1";
179
+ if (config.canonicalForm === "v0") {
180
+ try {
181
+ console.warn(
182
+ '[@vorim/sdk] canonicalForm=v0 is deprecated: it leaves metadata, delegation context, and replayable-evidence fields unsigned. Switch to canonicalForm=v1 (the new default in 3.4.0+) for full tamper coverage. Pass canonicalForm: "v0" explicitly only if you need byte-compat with verifiers older than @vorim/verify 0.2.0.'
183
+ );
184
+ } catch {
185
+ }
186
+ }
179
187
  this.chainEvents = config.chainEvents ?? false;
180
188
  }
181
189
  /**
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/replay.ts"],"sourcesContent":["// ============================================================================\n// VORIM SDK — TypeScript\n// Thin client wrapping the Vorim AI REST API\n// ============================================================================\n\nimport type {\n Agent, AgentRegistrationInput, AgentRegistrationResult,\n TrustRecord, AuditEventInput, PermissionScope, PermissionCheckResult,\n AgentDelegationRecord, DelegationLinkClaims,\n} from './types.js';\nimport { jcsCanonicalise, hashPreviousEvent } from './replay.js';\n\n// __SDK_VERSION__ is replaced at build time (tsup define) with the package.json\n// version, so the User-Agent always matches the published version. Falls back to\n// '0.0.0' when run un-bundled (e.g. ts-node / tests) where the define isn't applied.\ndeclare const __SDK_VERSION__: string | undefined;\nconst SDK_VERSION = typeof __SDK_VERSION__ !== 'undefined' ? __SDK_VERSION__ : '0.0.0';\nconst USER_AGENT = `vorim-sdk/${SDK_VERSION}`;\n\nexport interface VorimConfig {\n apiKey: string;\n baseUrl?: string;\n timeout?: number;\n /**\n * Auto-sign audit events with the agent's private key at emit time.\n * Default true in v3.1+. Set to false to opt out globally.\n * When enabled, the SDK signs the event using whichever private key was\n * stored via {@link VorimSDK.useAgentKey} or returned by\n * {@link VorimSDK.register}. Events for unknown agents pass through unsigned.\n */\n autoSign?: boolean;\n /**\n * Canonical form to use when signing. Default `\"v0\"` for backward-compat\n * with `@vorim/sdk` 3.1.x. Set to `\"v1\"` to sign the full event object\n * via RFC 8785 JCS, covering replayable-evidence fields (model_version,\n * tool_catalogue_hash, system_prompt_hash, prev_event_hash). v1 events\n * carry `canonical_form: \"v1\"` on the wire so the server can dispatch\n * verification correctly.\n */\n canonicalForm?: 'v0' | 'v1';\n /**\n * Hash-chain events per agent so deletion of a single audit row\n * becomes detectable. Default `false` (no chaining). When enabled,\n * the SDK sets `prev_event_hash` on each event to SHA-256 of the\n * previous event's canonical bytes for the same agent. The first\n * event after enable / process restart has `prev_event_hash = null`,\n * which the verifier reports as `chain_restart` (informational, not\n * a failure). Chain integrity is checked by `@vorim/verify`.\n */\n chainEvents?: boolean;\n}\n\n/**\n * VAIP v0 canonical bytes used by Vorim's per-event signing.\n *\n * Pipe-joined content fields with empty-string substitution for missing values.\n * This is intentionally duplicated from `@vorim/shared-types` so the published\n * SDK ships with zero runtime dependencies. A parity test in this package\n * imports both definitions and asserts byte-exact equality across a fixture\n * matrix, so they cannot drift silently.\n *\n * To upgrade the format, version the function (`canonicalPayloadV1`) — never\n * edit this one. Old signatures must remain verifiable.\n */\nexport function canonicalPayloadV0(event: AuditEventInput): string {\n return [\n event.event_type,\n event.action,\n event.resource ?? '',\n event.input_hash ?? '',\n event.output_hash ?? '',\n event.result,\n ].join('|');\n}\n\n/**\n * VAIP v1 canonical bytes for audit-event signing (RFC 8785 JCS).\n *\n * Signs the full event object excluding `signature` (the field being\n * computed) and `canonical_form` (metadata about the recipe). Unlike v0,\n * v1 covers the replayable-evidence fields and the metadata field.\n *\n * Re-exports `jcsCanonicalise` from `./replay.js` which is the byte-exact\n * twin of `@vorim/shared-types`' implementation. The cross-language parity\n * script enforces equivalence with the Python SDK.\n */\nexport function canonicalPayloadV1(event: AuditEventInput): string {\n // Strip the fields that are out of scope for v1 signing.\n const { signature: _sig, canonical_form: _cf, ...rest } = event as Record<string, unknown> & AuditEventInput;\n return jcsCanonicalise(rest);\n}\n\nexport class VorimSDK {\n private apiKey: string;\n private baseUrl: string;\n private timeout: number;\n private autoSign: boolean;\n private canonicalForm: 'v0' | 'v1';\n private chainEvents: boolean;\n /**\n * In-memory keyring mapping agent_id -> PEM-encoded Ed25519 private key.\n * Populated automatically by register() and registerEphemeral(), or\n * explicitly via useAgentKey(). Lost on process restart by design; the\n * caller is responsible for durable key storage.\n */\n private agentKeys: Map<string, string> = new Map();\n /**\n * Per-agent hash of the last emitted event's canonical bytes. Used to\n * populate prev_event_hash on the next emit when chainEvents is on.\n * Empty string ↔ no previous event (chain restart). Reset by\n * forgetAgentKey() so reusing an agent_id after revocation doesn't\n * link to the old chain.\n */\n private lastEventHash: Map<string, string> = new Map();\n /**\n * Per-agent monotonic counter incremented by `forgetAgentKey`. An\n * emit that started before `forgetAgentKey` ran will read a stale\n * epoch and refuse to repopulate the chain tail, preventing the\n * revoked agent from inheriting a new lastEventHash from the\n * in-flight emit that the lock was holding.\n */\n private agentForgetEpoch: Map<string, number> = new Map();\n /**\n * Per-agent emit promise. Each new emit awaits the previous one so\n * the chain is constructed in order. Concurrent emits to the same\n * agent are serialised (correct); concurrent emits to different\n * agents remain parallel (fast).\n */\n private chainLocks: Map<string, Promise<void>> = new Map();\n\n constructor(config: VorimConfig) {\n this.apiKey = config.apiKey;\n this.baseUrl = (config.baseUrl || 'https://api.vorim.ai').replace(/\\/$/, '') + '/v1';\n this.timeout = config.timeout || 10000;\n this.autoSign = config.autoSign !== false;\n this.canonicalForm = config.canonicalForm ?? 'v0';\n this.chainEvents = config.chainEvents ?? false;\n }\n\n /**\n * Register a previously-issued agent keypair so this SDK instance can\n * auto-sign events for it on emit. Use this when restoring an agent across\n * process restarts: read the agent's private_key from durable storage,\n * call useAgentKey(agentId, privateKey), and emit() will sign automatically.\n */\n useAgentKey(agentId: string, privateKeyPem: string): void {\n this.agentKeys.set(agentId, privateKeyPem);\n }\n\n /**\n * Forget an agent's signing key (e.g. after revocation). Subsequent emit()\n * calls for that agent will pass through unsigned unless a key is provided\n * inline. Also clears the per-agent chain state — re-using the same\n * agent_id after revocation does NOT link to the old chain.\n */\n forgetAgentKey(agentId: string): void {\n this.agentKeys.delete(agentId);\n this.lastEventHash.delete(agentId);\n this.chainLocks.delete(agentId);\n // Bump the per-agent epoch so any in-flight emit that completes\n // after this call refuses to write back a chain tail. Without\n // this, an emit that holds the chain lock can repopulate\n // lastEventHash after forgetAgentKey clears it, defeating the\n // revoked-agent isolation guarantee.\n this.agentForgetEpoch.set(agentId, (this.agentForgetEpoch.get(agentId) ?? 0) + 1);\n }\n\n /**\n * Cap on how many per-agent chain entries the SDK tracks. Set\n * generously — most callers will hold ≤ 1k agent_ids in memory.\n * Long-running processes that cycle through many agent_ids without\n * calling forgetAgentKey (e.g. ephemeral test agents) would\n * otherwise grow chainLocks / agentForgetEpoch / lastEventHash\n * unbounded.\n */\n private static readonly MAX_CHAIN_STATE_ENTRIES = 10_000;\n\n /**\n * Evict the oldest chain state entries when we cross the cap. Called\n * lazily from prepareEventChained — no scheduled task, no background\n * timer; only runs when the cap is breached during a real emit.\n */\n private evictChainStateIfNeeded(): void {\n if (this.chainLocks.size <= VorimSDK.MAX_CHAIN_STATE_ENTRIES) return;\n const toRemove = Math.ceil(this.chainLocks.size * 0.1); // drop oldest 10 %\n let removed = 0;\n for (const agentId of this.chainLocks.keys()) {\n if (removed >= toRemove) break;\n // Skip agents with an active key — they're in use.\n if (this.agentKeys.has(agentId)) continue;\n this.chainLocks.delete(agentId);\n this.lastEventHash.delete(agentId);\n this.agentForgetEpoch.delete(agentId);\n removed++;\n }\n }\n\n // ─── Health Check ────────────────────────────────────────────────\n\n /**\n * Ping the Vorim API to verify connectivity and API key validity.\n * Returns { status, timestamp } on success, throws VorimError on failure.\n */\n async ping(): Promise<{ status: string; timestamp: string }> {\n const response = await fetch(`${this.baseUrl.replace('/v1', '')}/health`, {\n headers: { 'User-Agent': USER_AGENT },\n signal: AbortSignal.timeout(this.timeout),\n });\n if (!response.ok) throw new VorimError(response.status, 'UNREACHABLE', 'Vorim API is not reachable');\n return response.json() as Promise<{ status: string; timestamp: string }>;\n }\n\n // ─── Agent Identity ────────────────────────────────────────────────\n\n /**\n * Register a new agent with Vorim AI.\n * Returns the agent identity and a private key (shown once).\n *\n * Side effect: the returned private_key is cached in this SDK instance's\n * in-memory keyring so subsequent emit() calls for this agent auto-sign.\n * The keyring is process-local; the caller is responsible for persisting\n * the private_key to durable storage if the agent should survive restarts.\n */\n async register(input: AgentRegistrationInput): Promise<AgentRegistrationResult> {\n const result = await this.post('/agents', input) as AgentRegistrationResult;\n if (result?.agent?.agent_id && result?.private_key) {\n this.agentKeys.set(result.agent.agent_id, result.private_key);\n }\n return result;\n }\n\n /**\n * Verify an agent's identity via the public Trust API.\n */\n async verify(agentId: string): Promise<TrustRecord> {\n return this.get(`/trust/verify/${agentId}`);\n }\n\n /**\n * Get agent details.\n */\n async getAgent(agentId: string): Promise<Agent> {\n return this.get(`/agents/${agentId}`);\n }\n\n /**\n * List all agents in the organisation.\n */\n async listAgents(params?: { page?: number; per_page?: number; status?: string }): Promise<{ agents: Agent[]; meta: any }> {\n const qs = new URLSearchParams(params as any).toString();\n return this.get(`/agents${qs ? '?' + qs : ''}`);\n }\n\n /**\n * Update an agent's metadata.\n */\n async updateAgent(agentId: string, updates: Partial<Pick<Agent, 'name' | 'description' | 'status' | 'capabilities'>>): Promise<Agent> {\n return this.patch(`/agents/${agentId}`, updates);\n }\n\n /**\n * Revoke an agent (permanent deactivation).\n */\n async revoke(agentId: string): Promise<void> {\n await this.delete(`/agents/${agentId}`);\n }\n\n // ─── Permissions ──────────────────────────────────────────────────\n\n /**\n * Check if an agent has a specific permission scope.\n * Target: < 5ms response via Redis cache.\n */\n async check(agentId: string, scope: PermissionScope): Promise<PermissionCheckResult> {\n return this.post(`/agents/${agentId}/permissions/verify`, { scope });\n }\n\n /**\n * Grant a permission scope to an agent.\n */\n async grant(agentId: string, scope: PermissionScope, options?: {\n valid_until?: string;\n rate_limit?: { max: number; window: string };\n }): Promise<any> {\n return this.post(`/agents/${agentId}/permissions`, { scope, ...options });\n }\n\n /**\n * List all active permissions for an agent.\n */\n async listPermissions(agentId: string): Promise<any[]> {\n return this.get(`/agents/${agentId}/permissions`);\n }\n\n /**\n * Revoke a specific permission scope from an agent.\n */\n async revokePermission(agentId: string, scope: PermissionScope): Promise<any> {\n return this.delete(`/agents/${agentId}/permissions/${scope}`);\n }\n\n // ─── Agent-to-Agent Identity Delegation (VAIP -02 § 5) ──────────────\n\n /**\n * Delegate the right to act on this agent's behalf to another agent\n * in the same org, with a strict subset of this agent's scopes.\n *\n * Multi-hop chains are supported up to depth 32. Scope subset is\n * enforced at every hop. Audit events emitted by the delegate carry\n * the chain context (`on_behalf_of`, `delegator_agent_id`,\n * `delegation_chain_id`, `delegation_depth`) so a verifier walking\n * the bundle can reconstruct the full chain.\n *\n * @example\n * ```ts\n * const chain = await vorim.delegateToAgent('agid_parent_abc', {\n * delegate_agent_id: 'agid_child_xyz',\n * scopes_delegated: ['agent:read', 'agent:execute'],\n * max_chain_depth: 1, // delegate may make ONE further hop\n * valid_until: '2026-12-31T00:00:00Z',\n * });\n * console.log(chain.public_chain_id); // chain_<hex>\n * ```\n */\n async delegateToAgent(\n delegatorAgentId: string,\n input: {\n delegate_agent_id: string;\n scopes_delegated: PermissionScope[];\n max_chain_depth?: number;\n valid_until?: string;\n /**\n * Optional Ed25519-signed delegation link (VAIP -02 § 5). When\n * provided, the server verifies the signature against the\n * delegator's stored public key, persists alongside the chain\n * row, and exports it in bundle delegation_tokens so the chain\n * is offline-verifiable by `@vorim/verify`. Compute via\n * {@link signDelegationLink} or set manually if signing\n * elsewhere.\n */\n signed_link?: {\n claims: DelegationLinkClaims;\n signature: string;\n };\n },\n ): Promise<AgentDelegationRecord> {\n return this.post(`/agents/${delegatorAgentId}/delegations`, input);\n }\n\n /**\n * Sign a delegation link with the delegator's private key. Returns\n * the signed link in the shape accepted by `delegateToAgent`'s\n * `signed_link` field.\n *\n * The signature is Ed25519 over the RFC 8785 JCS-canonical bytes of\n * the claims object. Same algorithm the server and `@vorim/verify`\n * use for verification.\n *\n * Use this when the delegator's private key is in this SDK's\n * keyring (i.e. set via `register()` or `useAgentKey()`).\n *\n * @example\n * ```ts\n * const signed = await vorim.signDelegationLink({\n * v: 0,\n * type: 'vaip-delegation-link',\n * chain_id: 'chain_abc', // server returns this on first delegation\n * depth: 1,\n * delegator: 'agid_parent',\n * delegate: 'agid_child',\n * scopes: ['agent:read', 'agent:execute'],\n * max_chain_depth: 1,\n * valid_from: new Date().toISOString(),\n * valid_until: null,\n * parent_link_hash: null,\n * });\n * ```\n */\n async signDelegationLink(\n claims: DelegationLinkClaims,\n ): Promise<{ claims: DelegationLinkClaims; signature: string }> {\n const key = this.agentKeys.get(claims.delegator);\n if (!key) {\n throw new VorimError(\n 400,\n 'NO_AGENT_KEY',\n `SDK has no private key for delegator ${claims.delegator}`,\n );\n }\n // Sign using the SDK's local JCS. Byte-equivalent to shared-types\n // and the server (enforced by scripts/check-replay-parity.sh).\n const bytes = jcsCanonicalise(claims as unknown as Record<string, unknown>);\n const signature = await this.sign(bytes, key);\n return { claims, signature };\n }\n\n /**\n * List active identity-chain entries this agent participates in\n * (either as delegator or delegate). Useful for showing the current\n * delegation graph in an admin UI.\n */\n async listAgentDelegations(agentId: string): Promise<AgentDelegationRecord[]> {\n return this.get(`/agents/${agentId}/delegations`);\n }\n\n /**\n * Walk a delegation chain by its public id. Returns the full chain\n * in depth order.\n */\n async getDelegationChain(\n agentId: string,\n chainId: string,\n ): Promise<AgentDelegationRecord[]> {\n return this.get(`/agents/${agentId}/delegation-chain/${chainId}`);\n }\n\n /**\n * Revoke this agent's delegation in a given chain. Cascades to all\n * descendants beneath this agent's depth in the chain.\n */\n async revokeAgentDelegation(\n agentId: string,\n chainId: string,\n ): Promise<{ revoked: number }> {\n return this.delete(`/agents/${agentId}/delegations/${chainId}`);\n }\n\n // ─── Audit ────────────────────────────────────────────────────────\n\n /**\n * Emit an audit event for an agent action.\n *\n * By default (autoSign=true on the SDK), the event is signed with the\n * agent's private key before it leaves the process. Set options.sign=false\n * to skip signing (e.g. for testing). If the SDK has no private key for the\n * event's agent_id, the event is sent unsigned and a warning is not\n * raised — callers that require signing should check event.signature on\n * the returned event after a round-trip, or use a server-side enforcement\n * flag (VORIM_VERIFY_AUDIT_SIGNATURES).\n */\n async emit(event: AuditEventInput, options?: { sign?: boolean }): Promise<{ ingested: number }> {\n const prepared = await this.prepareEvent(event, options?.sign);\n const result = await this.post('/audit/events', { events: [prepared] }) as { ingested: number };\n this.warnOnPartialIngest(1, result?.ingested ?? 0);\n return result;\n }\n\n /**\n * Emit a batch of audit events (up to 1,000). Each event is signed\n * independently using its agent_id to look up the signing key. See\n * {@link VorimSDK.emit} for signing behaviour and opt-out.\n *\n * When the server returns `ingested < events.length` (e.g. one event\n * referenced an unknown agent_id), a `console.warn` is emitted so\n * operators don't silently lose audit rows. The result is returned\n * unchanged so callers can inspect / act on it.\n */\n async emitBatch(events: AuditEventInput[], options?: { sign?: boolean }): Promise<{ ingested: number }> {\n const prepared = await Promise.all(events.map(e => this.prepareEvent(e, options?.sign)));\n const result = await this.post('/audit/events', { events: prepared }) as { ingested: number };\n this.warnOnPartialIngest(events.length, result?.ingested ?? 0);\n return result;\n }\n\n private warnOnPartialIngest(submitted: number, ingested: number): void {\n if (ingested < submitted) {\n try {\n // eslint-disable-next-line no-console\n console.warn(\n `[@vorim/sdk] partial ingest: server stored ${ingested}/${submitted} events. ` +\n `Common causes: unknown agent_id (cross-org or typo), invalid signature when strict ` +\n `verification is enabled.`,\n );\n } catch {\n /* ignore logger errors */\n }\n }\n }\n\n /**\n * Internal: prepare an event for transmission. Auto-signs if the SDK has a\n * key for this agent and signing isn't explicitly opted out. Pre-existing\n * signatures on the event are respected (caller-signed events are not\n * re-signed). Per-agent failure is non-fatal: if signing throws, the event\n * still sends unsigned so a single bad key doesn't break a batch.\n *\n * Canonical-form dispatch:\n * - If the event already carries `canonical_form`, that wins (caller\n * opted in/out for this specific event).\n * - Otherwise the SDK-level `canonicalForm` (config) applies.\n * - v0 signs the pipe-joined 6 fields. v1 signs the RFC 8785 JCS\n * bytes over the full event minus signature and canonical_form,\n * and the event goes on the wire with `canonical_form: \"v1\"`.\n *\n * Chain construction:\n * - When chainEvents is on, the event gets `prev_event_hash` set to\n * the SHA-256 of the previous event's canonical bytes for the\n * same agent, set BEFORE the signature is computed (so v1\n * signatures cover the chain link).\n * - Chain ops are serialised per-agent via `chainLocks` so\n * concurrent emits to the same agent build a deterministic chain.\n */\n private async prepareEvent(\n event: AuditEventInput,\n signOverride?: boolean\n ): Promise<AuditEventInput> {\n const shouldSign = signOverride ?? this.autoSign;\n if (!shouldSign && !this.chainEvents) return event;\n // Even unsigned events participate in the chain if chaining is on.\n if (this.chainEvents) {\n return this.prepareEventChained(event, shouldSign);\n }\n if (!shouldSign) return event;\n if (event.signature) return event;\n return this.signEventNow(event, shouldSign);\n }\n\n /** Serialise per-agent and apply chain hash + sign. */\n private async prepareEventChained(\n event: AuditEventInput,\n shouldSign: boolean,\n ): Promise<AuditEventInput> {\n const agentId = event.agent_id;\n this.evictChainStateIfNeeded();\n const prior = this.chainLocks.get(agentId) ?? Promise.resolve();\n let release!: () => void;\n const next = new Promise<void>(r => { release = r; });\n this.chainLocks.set(agentId, prior.then(() => next));\n await prior;\n // Snapshot the forget-epoch BEFORE doing any chain work. If the\n // epoch advances while we're in flight, forgetAgentKey() ran and\n // we must not write back the chain tail.\n const startEpoch = this.agentForgetEpoch.get(agentId) ?? 0;\n try {\n // Insert prev_event_hash if we have a previous bytes-hash for this\n // agent. First event after enable / process restart has none.\n const prev = this.lastEventHash.get(agentId);\n const eventWithPrev: AuditEventInput = prev\n ? { ...event, prev_event_hash: prev }\n : event;\n\n // Sign (or pass through unsigned if signing not requested / no\n // key). If forgetAgentKey runs between the lock acquisition and\n // the sign call, skip signing — the key has been revoked and\n // we must not use it. The event still ships unsigned, which the\n // caller can detect via the missing `signature` field.\n const epochBeforeSign = this.agentForgetEpoch.get(agentId) ?? 0;\n const keyStillPresent = this.agentKeys.has(agentId);\n const prepared = shouldSign && !eventWithPrev.signature && keyStillPresent && epochBeforeSign === startEpoch\n ? await this.signEventNow(eventWithPrev, shouldSign)\n : eventWithPrev;\n\n // Record this event's canonical bytes hash as the chain's new tail.\n // Use the v1 form for v1 events (matches what the signature covered);\n // v0 form for v0 events.\n const wireForm = (prepared.canonical_form as 'v0' | 'v1' | undefined) ?? 'v0';\n const bytes = wireForm === 'v1' ? canonicalPayloadV1(prepared) : canonicalPayloadV0(prepared);\n try {\n const tail = await hashPreviousEvent(bytes);\n // Only commit the tail if forgetAgentKey didn't run while we\n // were in flight. Without this guard the revoked agent\n // silently inherits a new chain tail from the in-flight emit.\n if ((this.agentForgetEpoch.get(agentId) ?? 0) === startEpoch) {\n this.lastEventHash.set(agentId, tail);\n }\n } catch {\n // hashing failure (extreme edge) is non-fatal; chain restarts next time\n this.lastEventHash.delete(agentId);\n }\n return prepared;\n } finally {\n release();\n }\n }\n\n /** Sign an event right now, no chain handling.\n *\n * On signing failure (malformed key, Web Crypto unavailable, etc.)\n * the event ships with its requested `canonical_form` preserved and\n * a one-line warning is logged via `console.warn`. The previous\n * behaviour silently dropped both the signature AND the\n * canonical_form marker, which caused the event to be classified\n * server-side as a v0 `signature_missing` instead of a v1 attempt\n * that failed — making the breakage invisible to operators. */\n private async signEventNow(\n event: AuditEventInput,\n _shouldSign: boolean,\n ): Promise<AuditEventInput> {\n const key = this.agentKeys.get(event.agent_id);\n if (!key) return event;\n const form: 'v0' | 'v1' = (event.canonical_form as 'v0' | 'v1' | undefined) ?? this.canonicalForm;\n const withForm: AuditEventInput = form === 'v0'\n ? event\n : { ...event, canonical_form: 'v1' };\n try {\n const payload = form === 'v1' ? canonicalPayloadV1(withForm) : canonicalPayloadV0(withForm);\n const signature = await this.sign(payload, key);\n return { ...withForm, signature };\n } catch (err) {\n // Surface the failure rather than silently dropping the signature.\n // Operators need a signal to detect broken signing at the SDK\n // boundary; verifiers will otherwise misattribute the cause.\n try {\n // eslint-disable-next-line no-console\n console.warn(\n // Don't echo agent_id verbatim — emit a short prefix for\n // correlation while keeping log-sink content lower-cardinality\n // and avoiding accidental leakage of org-identifiable ids.\n `[@vorim/sdk] signing failed for agent_id=${(event.agent_id ?? '').slice(0, 12)}... form=${form}: ${(err as Error)?.message ?? err}. ` +\n `Event will be emitted unsigned with canonical_form retained.`,\n );\n } catch {\n /* ignore logger errors */\n }\n // Preserve canonical_form so the event is still classified as a\n // v1 attempt server-side, just without a signature. This makes\n // the breakage detectable via the signature_missing + v1 form\n // pair instead of looking like a legacy v0 unsigned event.\n return withForm;\n }\n }\n\n /**\n * Export a signed audit bundle for a date range.\n */\n async exportAudit(from: string, to: string, format: string = 'json'): Promise<any> {\n return this.post('/audit/export', { from, to, format });\n }\n\n // ─── API Keys ──────────────────────────────────────────────────────\n\n /**\n * List all API keys for the organisation.\n */\n async listApiKeys(): Promise<any[]> {\n return this.get('/api-keys');\n }\n\n /**\n * Create a new API key.\n */\n async createApiKey(name: string, options?: { scopes?: string[]; expires_at?: string }): Promise<any> {\n return this.post('/api-keys', { name, ...options });\n }\n\n /**\n * Revoke an API key.\n */\n async deleteApiKey(keyId: string): Promise<{ revoked: boolean }> {\n return this.delete(`/api-keys/${keyId}`);\n }\n\n // ─── Ephemeral Agents ──────────────────────────────────────────────\n\n /**\n * Register an ephemeral agent with W3C did:key identity.\n * The agent auto-expires after the specified TTL.\n *\n * Side effect: the returned private_key is cached in this SDK instance's\n * in-memory keyring (matching register()).\n */\n async registerEphemeral(input: {\n capabilities: string[];\n scopes: string[];\n ttl_seconds?: number;\n }): Promise<any> {\n const result = await this.post('/agents/ephemeral', input);\n const agentId: string | undefined = result?.agent?.agent_id ?? result?.did_key;\n if (agentId && result?.private_key) {\n this.agentKeys.set(agentId, result.private_key);\n }\n return result;\n }\n\n // ─── Credential Delegation ──────────────────────────────────────────\n\n /**\n * Register an OAuth provider for credential delegation.\n */\n async registerProvider(input: {\n provider_key: string;\n display_name?: string;\n client_id: string;\n client_secret: string;\n auth_url: string;\n token_url: string;\n revoke_url?: string;\n scopes_available?: string[];\n }): Promise<any> {\n return this.post('/credentials/providers', input);\n }\n\n /**\n * List registered OAuth providers.\n */\n async listProviders(): Promise<any[]> {\n return this.get('/credentials/providers');\n }\n\n /**\n * Store an OAuth connection (user's authorized tokens).\n */\n async storeConnection(input: {\n provider_id: string;\n refresh_token: string;\n scopes_granted: string[];\n external_account_id?: string;\n }): Promise<any> {\n return this.post('/credentials/connections', input);\n }\n\n /**\n * List OAuth connections.\n */\n async listConnections(): Promise<any[]> {\n return this.get('/credentials/connections');\n }\n\n /**\n * Delegate a credential to an agent.\n * The agent will be able to request short-lived access tokens\n * for the delegated scopes without ever seeing the refresh token.\n */\n async delegateCredential(input: {\n connection_id: string;\n agent_id: string;\n scopes_delegated: string[];\n max_requests_per_hr?: number;\n valid_until?: string;\n }): Promise<any> {\n return this.post('/credentials/delegations', input);\n }\n\n /**\n * List credential delegations for the organisation or a specific agent.\n */\n async listDelegations(agentId?: string): Promise<any[]> {\n const params = agentId ? `?agent_id=${agentId}` : '';\n return this.get(`/credentials/delegations${params}`);\n }\n\n /**\n * Revoke a credential delegation (cascades to delegation chains).\n */\n async revokeDelegation(delegationId: string): Promise<{ revoked: boolean }> {\n return this.delete(`/credentials/delegations/${delegationId}`);\n }\n\n /**\n * Request a short-lived access token for an agent.\n * The agent must have an active credential delegation.\n * The refresh token is never exposed — the platform proxies the request.\n */\n async requestToken(input: {\n agent_id: string;\n scope: string;\n provider_id?: string;\n }): Promise<{\n access_token: string;\n token_type: string;\n expires_in: number;\n scope: string;\n delegation_id: string;\n }> {\n return this.post('/credentials/token', input);\n }\n\n // ─── Signing ──────────────────────────────────────────────────────\n\n /**\n * Sign a payload with an Ed25519 private key (client-side).\n * Uses the Web Crypto API or Node.js crypto.\n */\n async sign(payload: string, privateKeyPem: string): Promise<string> {\n if (typeof globalThis.crypto?.subtle !== 'undefined') {\n // Web Crypto API\n const keyData = this.pemToArrayBuffer(privateKeyPem);\n const key = await globalThis.crypto.subtle.importKey(\n 'pkcs8', keyData, { name: 'Ed25519' }, false, ['sign']\n );\n const signature = await globalThis.crypto.subtle.sign(\n 'Ed25519', key, new TextEncoder().encode(payload)\n );\n return `ed25519:${this.arrayBufferToBase64(signature)}`;\n } else {\n // Node.js crypto fallback\n const crypto = await import('node:crypto');\n const sign = crypto.sign(null, Buffer.from(payload), privateKeyPem);\n return `ed25519:${sign.toString('base64')}`;\n }\n }\n\n // ─── HTTP Client ──────────────────────────────────────────────────\n\n private async get(path: string): Promise<any> {\n return this.request('GET', path);\n }\n\n private async post(path: string, body: any): Promise<any> {\n return this.request('POST', path, body);\n }\n\n private async patch(path: string, body: any): Promise<any> {\n return this.request('PATCH', path, body);\n }\n\n private async delete(path: string): Promise<any> {\n return this.request('DELETE', path);\n }\n\n private async request(method: string, path: string, body?: any): Promise<any> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(`${this.baseUrl}${path}`, {\n method,\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n 'User-Agent': USER_AGENT,\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const errBody = await response.json().catch(() => ({})) as Record<string, any>;\n throw new VorimError(\n response.status,\n errBody.error?.code || 'UNKNOWN_ERROR',\n errBody.error?.message || `HTTP ${response.status}`,\n errBody.error?.details\n );\n }\n\n const json = await response.json() as Record<string, any>;\n return json.data;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n private pemToArrayBuffer(pem: string): ArrayBuffer {\n const b64 = pem.replace(/-----[^-]+-----/g, '').replace(/\\s/g, '');\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n }\n\n private arrayBufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = '';\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary);\n }\n}\n\nexport class VorimError extends Error {\n constructor(\n public status: number,\n public code: string,\n message: string,\n public details?: Record<string, unknown>\n ) {\n super(message);\n this.name = 'VorimError';\n }\n}\n\n// ─── Convenience export ──────────────────────────────────────────────\n\nexport default function createVorim(config: VorimConfig): VorimSDK {\n return new VorimSDK(config);\n}\n\n// Re-export types for consumers\nexport type {\n Agent, AgentRegistrationInput, AgentRegistrationResult,\n TrustRecord, AuditEventInput, AuditEventType, AuditResult,\n PermissionScope, PermissionCheckResult, AgentStatus,\n AgentDelegationRecord, DelegationLinkClaims,\n} from './types.js';\n\n// Re-export replayable evidence helpers (VAIP -02 schema field hashing)\nexport {\n hashTool, hashToolCatalogue, hashSystemPrompt, hashPreviousEvent,\n jcsCanonicalise, prepareReplayContext, CANONICAL_TOOL_CATALOGUE_VERSION,\n} from './replay.js';\nexport type { CatalogueTool, ReplayInputs, ReplayContext } from './replay.js';\n","/**\n * Replayable agent decision evidence helpers.\n *\n * Canonical-form hashing for the VAIP -02 schema fields that the SDK\n * attaches to audit events. The hashes recorded in audit_events.tool_catalogue_hash\n * and audit_events.system_prompt_hash use these functions, so the bytes\n * an auditor or counterparty reconstructs must match what the SDK produced.\n *\n * These helpers are intentionally separate from the signing path. The\n * v0 canonical signature form (event_type|action|resource|input_hash|\n * output_hash|result) does NOT cover model_version, tool_catalogue_hash,\n * or system_prompt_hash. They will enter the canonical bytes in v1\n * (RFC 8785 JCS) in a follow-up release.\n *\n * Stable across SDK versions: the canonical-form version is documented\n * in CANONICAL_TOOL_CATALOGUE_VERSION. Future changes get a v2 etc;\n * never edit the existing v1 logic, or already-recorded hashes lose\n * their meaning.\n */\n\n// ─── Versioning ───────────────────────────────────────────────────────────\n\n/**\n * Canonical-form version for tool catalogue hashes produced by this SDK.\n * Recorded in tool_catalogue_canon_version on the event metadata (when\n * the metadata field is used) so verifiers know which hash recipe to\n * reproduce. Increment ONLY if the algorithm changes in a way that\n * would change the hash for the same logical catalogue.\n */\nexport const CANONICAL_TOOL_CATALOGUE_VERSION = 'v1' as const;\n\n// ─── Types ────────────────────────────────────────────────────────────────\n\n/**\n * Minimum shape a tool needs for catalogue hashing. The framework\n * integrations adapt their native tool objects to this shape before\n * calling hashToolCatalogue.\n */\nexport interface CatalogueTool {\n /** The name the model sees and calls. Required. */\n name: string;\n /** Human-readable description shown to the model. Optional; absent ↔ empty string. */\n description?: string;\n /**\n * JSON Schema describing the tool's input parameters. Optional;\n * absent ↔ empty object `{}`. The schema gets RFC 8785 JCS-canonicalised\n * before hashing so semantically-equivalent variations (key order,\n * whitespace) produce the same hash.\n */\n schema?: Record<string, unknown> | null;\n}\n\n// ─── RFC 8785 JCS subset ──────────────────────────────────────────────────\n\n/**\n * RFC 8785 JSON Canonicalization Scheme, sufficient subset for tool\n * catalogue values.\n *\n * Rules:\n * - Object keys sorted lexicographically by UTF-16 code units (which\n * is what JS string comparison does naturally).\n * - No whitespace between tokens.\n * - Numbers: integers as integers, finite floats per ECMAScript\n * Number.prototype.toString. JCS forbids NaN and Infinity.\n * - Strings: JSON-escape using minimal set per RFC 8259 § 7.\n * - null, true, false, arrays: as JSON.stringify produces them, since\n * JSON.stringify already produces the canonical form for these.\n *\n * Not vendoring a full library because tool schemas don't carry\n * non-integer numbers in practice and the JS spec for Number.toString\n * happens to coincide with JCS § 3.2.2.2 for the integer case.\n */\nexport function jcsCanonicalise(value: unknown): string {\n if (value === null) return 'null';\n if (value === true) return 'true';\n if (value === false) return 'false';\n\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) {\n throw new Error('jcsCanonicalise: NaN and Infinity are not JCS-valid');\n }\n // For integers in safe range, .toString() matches JCS. For\n // non-integer floats, .toString() also matches in modern JS\n // engines (V8, JavaScriptCore, SpiderMonkey all use the shortest\n // round-trip representation, which is what JCS § 3.2.2.2 requires).\n return value.toString();\n }\n\n if (typeof value === 'string') {\n return JSON.stringify(value);\n }\n\n if (Array.isArray(value)) {\n return '[' + value.map(jcsCanonicalise).join(',') + ']';\n }\n\n if (typeof value === 'object') {\n const keys = Object.keys(value as Record<string, unknown>).sort();\n const parts = keys.map(k => {\n return JSON.stringify(k) + ':' + jcsCanonicalise((value as Record<string, unknown>)[k]);\n });\n return '{' + parts.join(',') + '}';\n }\n\n // undefined, function, symbol, bigint — not JSON-representable\n throw new Error(`jcsCanonicalise: unsupported value type: ${typeof value}`);\n}\n\n// ─── SHA-256 ──────────────────────────────────────────────────────────────\n\nasync function sha256Hex(input: string | Uint8Array): Promise<string> {\n const bytes = typeof input === 'string' ? new TextEncoder().encode(input) : input;\n\n // Node.js Web Crypto (Node 18+) supports digest. Browser Web Crypto does too.\n // Fall back to node:crypto if Web Crypto is unavailable.\n const subtle = (globalThis as any).crypto?.subtle;\n if (subtle) {\n const buf = await subtle.digest('SHA-256', bytes);\n return Array.from(new Uint8Array(buf))\n .map(b => b.toString(16).padStart(2, '0'))\n .join('');\n }\n\n // Node fallback\n const nodeCrypto = await import('node:crypto');\n return nodeCrypto.createHash('sha256').update(bytes).digest('hex');\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────\n\n/**\n * Hash a single tool definition. Returns `sha256:<hex>`.\n *\n * Canonical form (v1):\n * JCS-canonicalised JSON of `{name, description, schema}` where\n * absent fields substitute `description: \"\"` and `schema: {}`.\n */\nexport async function hashTool(tool: CatalogueTool): Promise<string> {\n const normalised = {\n name: tool.name,\n description: tool.description ?? '',\n schema: tool.schema ?? {},\n };\n const hex = await sha256Hex(jcsCanonicalise(normalised));\n return `sha256:${hex}`;\n}\n\n/**\n * Hash an entire tool catalogue. Returns `sha256:<hex>`.\n *\n * Reordering tools does NOT change the hash (tool hashes sorted\n * lexicographically before concatenation). Adding, removing, or\n * modifying a tool DOES change the hash.\n *\n * Per-tool hashing first means a verifier comparing two catalogue\n * hashes that differ can also be given the per-tool hashes to\n * identify which specific tool changed.\n */\nexport async function hashToolCatalogue(tools: CatalogueTool[]): Promise<string> {\n if (tools.length === 0) {\n // Empty catalogue has a deterministic, stable hash distinct from \"no field\"\n return `sha256:${await sha256Hex('[]')}`;\n }\n const perTool = await Promise.all(tools.map(hashTool));\n perTool.sort();\n const hex = await sha256Hex(perTool.join(''));\n return `sha256:${hex}`;\n}\n\n/**\n * Hash a system prompt. Returns `sha256:<hex>`.\n *\n * The prompt is UTF-8 encoded and hashed verbatim — no normalisation.\n * If a caller wants to ignore whitespace or comment differences, they\n * should normalise before calling. The intent here is deterministic\n * reproducibility, not semantic equivalence.\n */\nexport async function hashSystemPrompt(prompt: string): Promise<string> {\n const hex = await sha256Hex(prompt);\n return `sha256:${hex}`;\n}\n\n/**\n * Convenience: hash the previous event's canonical bytes for use in\n * the prev_event_hash field of hash-chained ingest. Caller provides\n * the canonical bytes (use canonicalPayloadV0 from the main module).\n */\nexport async function hashPreviousEvent(canonicalBytes: string): Promise<string> {\n const hex = await sha256Hex(canonicalBytes);\n return `sha256:${hex}`;\n}\n\n// ─── Replay context — framework integration helper ────────────────────────\n\n/**\n * Raw inputs the integration captures from the framework. Set by the\n * integration's config; turned into hashes by {@link prepareReplayContext}.\n */\nexport interface ReplayInputs {\n /** Stable identifier for the model. E.g. `\"anthropic:claude-opus-4-8\"`. */\n modelVersion?: string;\n /** Tools available to the agent at call time. Hashed via {@link hashToolCatalogue}. */\n tools?: CatalogueTool[];\n /** System prompt active at call time. Hashed via {@link hashSystemPrompt}. */\n systemPrompt?: string;\n}\n\n/**\n * Pre-computed hashes ready to attach to audit events. The three keys\n * match the audit_events column names.\n */\nexport interface ReplayContext {\n model_version?: string;\n tool_catalogue_hash?: string;\n system_prompt_hash?: string;\n}\n\n/**\n * Compute replay context once from raw inputs. Use at integration\n * setup time so each emit can attach the hashes without re-hashing.\n *\n * Returns an object suitable for spreading into an AuditEventInput:\n * `await vorim.emit({ ...event, ...replayContext })`\n *\n * If a field is absent in the inputs, it is absent in the result\n * (not the empty string). That keeps the event lean.\n */\nexport async function prepareReplayContext(\n inputs: ReplayInputs,\n): Promise<ReplayContext> {\n const ctx: ReplayContext = {};\n if (inputs.modelVersion) ctx.model_version = inputs.modelVersion;\n if (inputs.tools) ctx.tool_catalogue_hash = await hashToolCatalogue(inputs.tools);\n if (inputs.systemPrompt) ctx.system_prompt_hash = await hashSystemPrompt(inputs.systemPrompt);\n return ctx;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/replay.ts"],"sourcesContent":["// ============================================================================\n// VORIM SDK — TypeScript\n// Thin client wrapping the Vorim AI REST API\n// ============================================================================\n\nimport type {\n Agent, AgentRegistrationInput, AgentRegistrationResult,\n TrustRecord, AuditEventInput, PermissionScope, PermissionCheckResult,\n AgentDelegationRecord, DelegationLinkClaims,\n} from './types.js';\nimport { jcsCanonicalise, hashPreviousEvent } from './replay.js';\n\n// __SDK_VERSION__ is replaced at build time (tsup define) with the package.json\n// version, so the User-Agent always matches the published version. Falls back to\n// '0.0.0' when run un-bundled (e.g. ts-node / tests) where the define isn't applied.\ndeclare const __SDK_VERSION__: string | undefined;\nconst SDK_VERSION = typeof __SDK_VERSION__ !== 'undefined' ? __SDK_VERSION__ : '0.0.0';\nconst USER_AGENT = `vorim-sdk/${SDK_VERSION}`;\n\nexport interface VorimConfig {\n apiKey: string;\n baseUrl?: string;\n timeout?: number;\n /**\n * Auto-sign audit events with the agent's private key at emit time.\n * Default true in v3.1+. Set to false to opt out globally.\n * When enabled, the SDK signs the event using whichever private key was\n * stored via {@link VorimSDK.useAgentKey} or returned by\n * {@link VorimSDK.register}. Events for unknown agents pass through unsigned.\n */\n autoSign?: boolean;\n /**\n * Canonical form to use when signing. Default `\"v0\"` for backward-compat\n * with `@vorim/sdk` 3.1.x. Set to `\"v1\"` to sign the full event object\n * via RFC 8785 JCS, covering replayable-evidence fields (model_version,\n * tool_catalogue_hash, system_prompt_hash, prev_event_hash). v1 events\n * carry `canonical_form: \"v1\"` on the wire so the server can dispatch\n * verification correctly.\n */\n canonicalForm?: 'v0' | 'v1';\n /**\n * Hash-chain events per agent so deletion of a single audit row\n * becomes detectable. Default `false` (no chaining). When enabled,\n * the SDK sets `prev_event_hash` on each event to SHA-256 of the\n * previous event's canonical bytes for the same agent. The first\n * event after enable / process restart has `prev_event_hash = null`,\n * which the verifier reports as `chain_restart` (informational, not\n * a failure). Chain integrity is checked by `@vorim/verify`.\n */\n chainEvents?: boolean;\n}\n\n/**\n * VAIP v0 canonical bytes used by Vorim's per-event signing.\n *\n * Pipe-joined content fields with empty-string substitution for missing values.\n * This is intentionally duplicated from `@vorim/shared-types` so the published\n * SDK ships with zero runtime dependencies. A parity test in this package\n * imports both definitions and asserts byte-exact equality across a fixture\n * matrix, so they cannot drift silently.\n *\n * To upgrade the format, version the function (`canonicalPayloadV1`) — never\n * edit this one. Old signatures must remain verifiable.\n */\nexport function canonicalPayloadV0(event: AuditEventInput): string {\n return [\n event.event_type,\n event.action,\n event.resource ?? '',\n event.input_hash ?? '',\n event.output_hash ?? '',\n event.result,\n ].join('|');\n}\n\n/**\n * VAIP v1 canonical bytes for audit-event signing (RFC 8785 JCS).\n *\n * Signs the full event object excluding `signature` (the field being\n * computed) and `canonical_form` (metadata about the recipe). Unlike v0,\n * v1 covers the replayable-evidence fields and the metadata field.\n *\n * Re-exports `jcsCanonicalise` from `./replay.js` which is the byte-exact\n * twin of `@vorim/shared-types`' implementation. The cross-language parity\n * script enforces equivalence with the Python SDK.\n */\nexport function canonicalPayloadV1(event: AuditEventInput): string {\n // Strip the fields that are out of scope for v1 signing.\n const { signature: _sig, canonical_form: _cf, ...rest } = event as Record<string, unknown> & AuditEventInput;\n return jcsCanonicalise(rest);\n}\n\nexport class VorimSDK {\n private apiKey: string;\n private baseUrl: string;\n private timeout: number;\n private autoSign: boolean;\n private canonicalForm: 'v0' | 'v1';\n private chainEvents: boolean;\n /**\n * In-memory keyring mapping agent_id -> PEM-encoded Ed25519 private key.\n * Populated automatically by register() and registerEphemeral(), or\n * explicitly via useAgentKey(). Lost on process restart by design; the\n * caller is responsible for durable key storage.\n */\n private agentKeys: Map<string, string> = new Map();\n /**\n * Per-agent hash of the last emitted event's canonical bytes. Used to\n * populate prev_event_hash on the next emit when chainEvents is on.\n * Empty string ↔ no previous event (chain restart). Reset by\n * forgetAgentKey() so reusing an agent_id after revocation doesn't\n * link to the old chain.\n */\n private lastEventHash: Map<string, string> = new Map();\n /**\n * Per-agent monotonic counter incremented by `forgetAgentKey`. An\n * emit that started before `forgetAgentKey` ran will read a stale\n * epoch and refuse to repopulate the chain tail, preventing the\n * revoked agent from inheriting a new lastEventHash from the\n * in-flight emit that the lock was holding.\n */\n private agentForgetEpoch: Map<string, number> = new Map();\n /**\n * Per-agent emit promise. Each new emit awaits the previous one so\n * the chain is constructed in order. Concurrent emits to the same\n * agent are serialised (correct); concurrent emits to different\n * agents remain parallel (fast).\n */\n private chainLocks: Map<string, Promise<void>> = new Map();\n\n constructor(config: VorimConfig) {\n this.apiKey = config.apiKey;\n this.baseUrl = (config.baseUrl || 'https://api.vorim.ai').replace(/\\/$/, '') + '/v1';\n this.timeout = config.timeout || 10000;\n this.autoSign = config.autoSign !== false;\n // Default to v1 as of 3.4.0. v0 only covers six fields and any\n // metadata, delegation context, or replayable-evidence field is\n // unsigned tail — see crypto-1 in the deep-audit findings. Callers\n // who explicitly want v0 (legacy verifier compatibility) must opt\n // in. A console.warn fires the first time an SDK instance is\n // created with v0 so the deprecation is visible in dev.\n this.canonicalForm = config.canonicalForm ?? 'v1';\n if (config.canonicalForm === 'v0') {\n try {\n // eslint-disable-next-line no-console\n console.warn(\n '[@vorim/sdk] canonicalForm=v0 is deprecated: it leaves metadata, ' +\n 'delegation context, and replayable-evidence fields unsigned. ' +\n 'Switch to canonicalForm=v1 (the new default in 3.4.0+) for full ' +\n 'tamper coverage. Pass canonicalForm: \"v0\" explicitly only if you ' +\n 'need byte-compat with verifiers older than @vorim/verify 0.2.0.',\n );\n } catch { /* ignore logger errors */ }\n }\n this.chainEvents = config.chainEvents ?? false;\n }\n\n /**\n * Register a previously-issued agent keypair so this SDK instance can\n * auto-sign events for it on emit. Use this when restoring an agent across\n * process restarts: read the agent's private_key from durable storage,\n * call useAgentKey(agentId, privateKey), and emit() will sign automatically.\n */\n useAgentKey(agentId: string, privateKeyPem: string): void {\n this.agentKeys.set(agentId, privateKeyPem);\n }\n\n /**\n * Forget an agent's signing key (e.g. after revocation). Subsequent emit()\n * calls for that agent will pass through unsigned unless a key is provided\n * inline. Also clears the per-agent chain state — re-using the same\n * agent_id after revocation does NOT link to the old chain.\n */\n forgetAgentKey(agentId: string): void {\n this.agentKeys.delete(agentId);\n this.lastEventHash.delete(agentId);\n this.chainLocks.delete(agentId);\n // Bump the per-agent epoch so any in-flight emit that completes\n // after this call refuses to write back a chain tail. Without\n // this, an emit that holds the chain lock can repopulate\n // lastEventHash after forgetAgentKey clears it, defeating the\n // revoked-agent isolation guarantee.\n this.agentForgetEpoch.set(agentId, (this.agentForgetEpoch.get(agentId) ?? 0) + 1);\n }\n\n /**\n * Cap on how many per-agent chain entries the SDK tracks. Set\n * generously — most callers will hold ≤ 1k agent_ids in memory.\n * Long-running processes that cycle through many agent_ids without\n * calling forgetAgentKey (e.g. ephemeral test agents) would\n * otherwise grow chainLocks / agentForgetEpoch / lastEventHash\n * unbounded.\n */\n private static readonly MAX_CHAIN_STATE_ENTRIES = 10_000;\n\n /**\n * Evict the oldest chain state entries when we cross the cap. Called\n * lazily from prepareEventChained — no scheduled task, no background\n * timer; only runs when the cap is breached during a real emit.\n */\n private evictChainStateIfNeeded(): void {\n if (this.chainLocks.size <= VorimSDK.MAX_CHAIN_STATE_ENTRIES) return;\n const toRemove = Math.ceil(this.chainLocks.size * 0.1); // drop oldest 10 %\n let removed = 0;\n for (const agentId of this.chainLocks.keys()) {\n if (removed >= toRemove) break;\n // Skip agents with an active key — they're in use.\n if (this.agentKeys.has(agentId)) continue;\n this.chainLocks.delete(agentId);\n this.lastEventHash.delete(agentId);\n this.agentForgetEpoch.delete(agentId);\n removed++;\n }\n }\n\n // ─── Health Check ────────────────────────────────────────────────\n\n /**\n * Ping the Vorim API to verify connectivity and API key validity.\n * Returns { status, timestamp } on success, throws VorimError on failure.\n */\n async ping(): Promise<{ status: string; timestamp: string }> {\n const response = await fetch(`${this.baseUrl.replace('/v1', '')}/health`, {\n headers: { 'User-Agent': USER_AGENT },\n signal: AbortSignal.timeout(this.timeout),\n });\n if (!response.ok) throw new VorimError(response.status, 'UNREACHABLE', 'Vorim API is not reachable');\n return response.json() as Promise<{ status: string; timestamp: string }>;\n }\n\n // ─── Agent Identity ────────────────────────────────────────────────\n\n /**\n * Register a new agent with Vorim AI.\n * Returns the agent identity and a private key (shown once).\n *\n * Side effect: the returned private_key is cached in this SDK instance's\n * in-memory keyring so subsequent emit() calls for this agent auto-sign.\n * The keyring is process-local; the caller is responsible for persisting\n * the private_key to durable storage if the agent should survive restarts.\n */\n async register(input: AgentRegistrationInput): Promise<AgentRegistrationResult> {\n const result = await this.post('/agents', input) as AgentRegistrationResult;\n if (result?.agent?.agent_id && result?.private_key) {\n this.agentKeys.set(result.agent.agent_id, result.private_key);\n }\n return result;\n }\n\n /**\n * Verify an agent's identity via the public Trust API.\n */\n async verify(agentId: string): Promise<TrustRecord> {\n return this.get(`/trust/verify/${agentId}`);\n }\n\n /**\n * Get agent details.\n */\n async getAgent(agentId: string): Promise<Agent> {\n return this.get(`/agents/${agentId}`);\n }\n\n /**\n * List all agents in the organisation.\n */\n async listAgents(params?: { page?: number; per_page?: number; status?: string }): Promise<{ agents: Agent[]; meta: any }> {\n const qs = new URLSearchParams(params as any).toString();\n return this.get(`/agents${qs ? '?' + qs : ''}`);\n }\n\n /**\n * Update an agent's metadata.\n */\n async updateAgent(agentId: string, updates: Partial<Pick<Agent, 'name' | 'description' | 'status' | 'capabilities'>>): Promise<Agent> {\n return this.patch(`/agents/${agentId}`, updates);\n }\n\n /**\n * Revoke an agent (permanent deactivation).\n */\n async revoke(agentId: string): Promise<void> {\n await this.delete(`/agents/${agentId}`);\n }\n\n // ─── Permissions ──────────────────────────────────────────────────\n\n /**\n * Check if an agent has a specific permission scope.\n * Target: < 5ms response via Redis cache.\n */\n async check(agentId: string, scope: PermissionScope): Promise<PermissionCheckResult> {\n return this.post(`/agents/${agentId}/permissions/verify`, { scope });\n }\n\n /**\n * Grant a permission scope to an agent.\n */\n async grant(agentId: string, scope: PermissionScope, options?: {\n valid_until?: string;\n rate_limit?: { max: number; window: string };\n }): Promise<any> {\n return this.post(`/agents/${agentId}/permissions`, { scope, ...options });\n }\n\n /**\n * List all active permissions for an agent.\n */\n async listPermissions(agentId: string): Promise<any[]> {\n return this.get(`/agents/${agentId}/permissions`);\n }\n\n /**\n * Revoke a specific permission scope from an agent.\n */\n async revokePermission(agentId: string, scope: PermissionScope): Promise<any> {\n return this.delete(`/agents/${agentId}/permissions/${scope}`);\n }\n\n // ─── Agent-to-Agent Identity Delegation (VAIP -02 § 5) ──────────────\n\n /**\n * Delegate the right to act on this agent's behalf to another agent\n * in the same org, with a strict subset of this agent's scopes.\n *\n * Multi-hop chains are supported up to depth 32. Scope subset is\n * enforced at every hop. Audit events emitted by the delegate carry\n * the chain context (`on_behalf_of`, `delegator_agent_id`,\n * `delegation_chain_id`, `delegation_depth`) so a verifier walking\n * the bundle can reconstruct the full chain.\n *\n * @example\n * ```ts\n * const chain = await vorim.delegateToAgent('agid_parent_abc', {\n * delegate_agent_id: 'agid_child_xyz',\n * scopes_delegated: ['agent:read', 'agent:execute'],\n * max_chain_depth: 1, // delegate may make ONE further hop\n * valid_until: '2026-12-31T00:00:00Z',\n * });\n * console.log(chain.public_chain_id); // chain_<hex>\n * ```\n */\n async delegateToAgent(\n delegatorAgentId: string,\n input: {\n delegate_agent_id: string;\n scopes_delegated: PermissionScope[];\n max_chain_depth?: number;\n valid_until?: string;\n /**\n * Optional Ed25519-signed delegation link (VAIP -02 § 5). When\n * provided, the server verifies the signature against the\n * delegator's stored public key, persists alongside the chain\n * row, and exports it in bundle delegation_tokens so the chain\n * is offline-verifiable by `@vorim/verify`. Compute via\n * {@link signDelegationLink} or set manually if signing\n * elsewhere.\n */\n signed_link?: {\n claims: DelegationLinkClaims;\n signature: string;\n };\n },\n ): Promise<AgentDelegationRecord> {\n return this.post(`/agents/${delegatorAgentId}/delegations`, input);\n }\n\n /**\n * Sign a delegation link with the delegator's private key. Returns\n * the signed link in the shape accepted by `delegateToAgent`'s\n * `signed_link` field.\n *\n * The signature is Ed25519 over the RFC 8785 JCS-canonical bytes of\n * the claims object. Same algorithm the server and `@vorim/verify`\n * use for verification.\n *\n * Use this when the delegator's private key is in this SDK's\n * keyring (i.e. set via `register()` or `useAgentKey()`).\n *\n * @example\n * ```ts\n * const signed = await vorim.signDelegationLink({\n * v: 0,\n * type: 'vaip-delegation-link',\n * chain_id: 'chain_abc', // server returns this on first delegation\n * depth: 1,\n * delegator: 'agid_parent',\n * delegate: 'agid_child',\n * scopes: ['agent:read', 'agent:execute'],\n * max_chain_depth: 1,\n * valid_from: new Date().toISOString(),\n * valid_until: null,\n * parent_link_hash: null,\n * });\n * ```\n */\n async signDelegationLink(\n claims: DelegationLinkClaims,\n ): Promise<{ claims: DelegationLinkClaims; signature: string }> {\n const key = this.agentKeys.get(claims.delegator);\n if (!key) {\n throw new VorimError(\n 400,\n 'NO_AGENT_KEY',\n `SDK has no private key for delegator ${claims.delegator}`,\n );\n }\n // Sign using the SDK's local JCS. Byte-equivalent to shared-types\n // and the server (enforced by scripts/check-replay-parity.sh).\n const bytes = jcsCanonicalise(claims as unknown as Record<string, unknown>);\n const signature = await this.sign(bytes, key);\n return { claims, signature };\n }\n\n /**\n * List active identity-chain entries this agent participates in\n * (either as delegator or delegate). Useful for showing the current\n * delegation graph in an admin UI.\n */\n async listAgentDelegations(agentId: string): Promise<AgentDelegationRecord[]> {\n return this.get(`/agents/${agentId}/delegations`);\n }\n\n /**\n * Walk a delegation chain by its public id. Returns the full chain\n * in depth order.\n */\n async getDelegationChain(\n agentId: string,\n chainId: string,\n ): Promise<AgentDelegationRecord[]> {\n return this.get(`/agents/${agentId}/delegation-chain/${chainId}`);\n }\n\n /**\n * Revoke this agent's delegation in a given chain. Cascades to all\n * descendants beneath this agent's depth in the chain.\n */\n async revokeAgentDelegation(\n agentId: string,\n chainId: string,\n ): Promise<{ revoked: number }> {\n return this.delete(`/agents/${agentId}/delegations/${chainId}`);\n }\n\n // ─── Audit ────────────────────────────────────────────────────────\n\n /**\n * Emit an audit event for an agent action.\n *\n * By default (autoSign=true on the SDK), the event is signed with the\n * agent's private key before it leaves the process. Set options.sign=false\n * to skip signing (e.g. for testing). If the SDK has no private key for the\n * event's agent_id, the event is sent unsigned and a warning is not\n * raised — callers that require signing should check event.signature on\n * the returned event after a round-trip, or use a server-side enforcement\n * flag (VORIM_VERIFY_AUDIT_SIGNATURES).\n */\n async emit(event: AuditEventInput, options?: { sign?: boolean }): Promise<{ ingested: number }> {\n const prepared = await this.prepareEvent(event, options?.sign);\n const result = await this.post('/audit/events', { events: [prepared] }) as { ingested: number };\n this.warnOnPartialIngest(1, result?.ingested ?? 0);\n return result;\n }\n\n /**\n * Emit a batch of audit events (up to 1,000). Each event is signed\n * independently using its agent_id to look up the signing key. See\n * {@link VorimSDK.emit} for signing behaviour and opt-out.\n *\n * When the server returns `ingested < events.length` (e.g. one event\n * referenced an unknown agent_id), a `console.warn` is emitted so\n * operators don't silently lose audit rows. The result is returned\n * unchanged so callers can inspect / act on it.\n */\n async emitBatch(events: AuditEventInput[], options?: { sign?: boolean }): Promise<{ ingested: number }> {\n const prepared = await Promise.all(events.map(e => this.prepareEvent(e, options?.sign)));\n const result = await this.post('/audit/events', { events: prepared }) as { ingested: number };\n this.warnOnPartialIngest(events.length, result?.ingested ?? 0);\n return result;\n }\n\n private warnOnPartialIngest(submitted: number, ingested: number): void {\n if (ingested < submitted) {\n try {\n // eslint-disable-next-line no-console\n console.warn(\n `[@vorim/sdk] partial ingest: server stored ${ingested}/${submitted} events. ` +\n `Common causes: unknown agent_id (cross-org or typo), invalid signature when strict ` +\n `verification is enabled.`,\n );\n } catch {\n /* ignore logger errors */\n }\n }\n }\n\n /**\n * Internal: prepare an event for transmission. Auto-signs if the SDK has a\n * key for this agent and signing isn't explicitly opted out. Pre-existing\n * signatures on the event are respected (caller-signed events are not\n * re-signed). Per-agent failure is non-fatal: if signing throws, the event\n * still sends unsigned so a single bad key doesn't break a batch.\n *\n * Canonical-form dispatch:\n * - If the event already carries `canonical_form`, that wins (caller\n * opted in/out for this specific event).\n * - Otherwise the SDK-level `canonicalForm` (config) applies.\n * - v0 signs the pipe-joined 6 fields. v1 signs the RFC 8785 JCS\n * bytes over the full event minus signature and canonical_form,\n * and the event goes on the wire with `canonical_form: \"v1\"`.\n *\n * Chain construction:\n * - When chainEvents is on, the event gets `prev_event_hash` set to\n * the SHA-256 of the previous event's canonical bytes for the\n * same agent, set BEFORE the signature is computed (so v1\n * signatures cover the chain link).\n * - Chain ops are serialised per-agent via `chainLocks` so\n * concurrent emits to the same agent build a deterministic chain.\n */\n private async prepareEvent(\n event: AuditEventInput,\n signOverride?: boolean\n ): Promise<AuditEventInput> {\n const shouldSign = signOverride ?? this.autoSign;\n if (!shouldSign && !this.chainEvents) return event;\n // Even unsigned events participate in the chain if chaining is on.\n if (this.chainEvents) {\n return this.prepareEventChained(event, shouldSign);\n }\n if (!shouldSign) return event;\n if (event.signature) return event;\n return this.signEventNow(event, shouldSign);\n }\n\n /** Serialise per-agent and apply chain hash + sign. */\n private async prepareEventChained(\n event: AuditEventInput,\n shouldSign: boolean,\n ): Promise<AuditEventInput> {\n const agentId = event.agent_id;\n this.evictChainStateIfNeeded();\n const prior = this.chainLocks.get(agentId) ?? Promise.resolve();\n let release!: () => void;\n const next = new Promise<void>(r => { release = r; });\n this.chainLocks.set(agentId, prior.then(() => next));\n await prior;\n // Snapshot the forget-epoch BEFORE doing any chain work. If the\n // epoch advances while we're in flight, forgetAgentKey() ran and\n // we must not write back the chain tail.\n const startEpoch = this.agentForgetEpoch.get(agentId) ?? 0;\n try {\n // Insert prev_event_hash if we have a previous bytes-hash for this\n // agent. First event after enable / process restart has none.\n const prev = this.lastEventHash.get(agentId);\n const eventWithPrev: AuditEventInput = prev\n ? { ...event, prev_event_hash: prev }\n : event;\n\n // Sign (or pass through unsigned if signing not requested / no\n // key). If forgetAgentKey runs between the lock acquisition and\n // the sign call, skip signing — the key has been revoked and\n // we must not use it. The event still ships unsigned, which the\n // caller can detect via the missing `signature` field.\n const epochBeforeSign = this.agentForgetEpoch.get(agentId) ?? 0;\n const keyStillPresent = this.agentKeys.has(agentId);\n const prepared = shouldSign && !eventWithPrev.signature && keyStillPresent && epochBeforeSign === startEpoch\n ? await this.signEventNow(eventWithPrev, shouldSign)\n : eventWithPrev;\n\n // Record this event's canonical bytes hash as the chain's new tail.\n // Use the v1 form for v1 events (matches what the signature covered);\n // v0 form for v0 events.\n const wireForm = (prepared.canonical_form as 'v0' | 'v1' | undefined) ?? 'v0';\n const bytes = wireForm === 'v1' ? canonicalPayloadV1(prepared) : canonicalPayloadV0(prepared);\n try {\n const tail = await hashPreviousEvent(bytes);\n // Only commit the tail if forgetAgentKey didn't run while we\n // were in flight. Without this guard the revoked agent\n // silently inherits a new chain tail from the in-flight emit.\n if ((this.agentForgetEpoch.get(agentId) ?? 0) === startEpoch) {\n this.lastEventHash.set(agentId, tail);\n }\n } catch {\n // hashing failure (extreme edge) is non-fatal; chain restarts next time\n this.lastEventHash.delete(agentId);\n }\n return prepared;\n } finally {\n release();\n }\n }\n\n /** Sign an event right now, no chain handling.\n *\n * On signing failure (malformed key, Web Crypto unavailable, etc.)\n * the event ships with its requested `canonical_form` preserved and\n * a one-line warning is logged via `console.warn`. The previous\n * behaviour silently dropped both the signature AND the\n * canonical_form marker, which caused the event to be classified\n * server-side as a v0 `signature_missing` instead of a v1 attempt\n * that failed — making the breakage invisible to operators. */\n private async signEventNow(\n event: AuditEventInput,\n _shouldSign: boolean,\n ): Promise<AuditEventInput> {\n const key = this.agentKeys.get(event.agent_id);\n if (!key) return event;\n const form: 'v0' | 'v1' = (event.canonical_form as 'v0' | 'v1' | undefined) ?? this.canonicalForm;\n const withForm: AuditEventInput = form === 'v0'\n ? event\n : { ...event, canonical_form: 'v1' };\n try {\n const payload = form === 'v1' ? canonicalPayloadV1(withForm) : canonicalPayloadV0(withForm);\n const signature = await this.sign(payload, key);\n return { ...withForm, signature };\n } catch (err) {\n // Surface the failure rather than silently dropping the signature.\n // Operators need a signal to detect broken signing at the SDK\n // boundary; verifiers will otherwise misattribute the cause.\n try {\n // eslint-disable-next-line no-console\n console.warn(\n // Don't echo agent_id verbatim — emit a short prefix for\n // correlation while keeping log-sink content lower-cardinality\n // and avoiding accidental leakage of org-identifiable ids.\n `[@vorim/sdk] signing failed for agent_id=${(event.agent_id ?? '').slice(0, 12)}... form=${form}: ${(err as Error)?.message ?? err}. ` +\n `Event will be emitted unsigned with canonical_form retained.`,\n );\n } catch {\n /* ignore logger errors */\n }\n // Preserve canonical_form so the event is still classified as a\n // v1 attempt server-side, just without a signature. This makes\n // the breakage detectable via the signature_missing + v1 form\n // pair instead of looking like a legacy v0 unsigned event.\n return withForm;\n }\n }\n\n /**\n * Export a signed audit bundle for a date range.\n */\n async exportAudit(from: string, to: string, format: string = 'json'): Promise<any> {\n return this.post('/audit/export', { from, to, format });\n }\n\n // ─── API Keys ──────────────────────────────────────────────────────\n\n /**\n * List all API keys for the organisation.\n */\n async listApiKeys(): Promise<any[]> {\n return this.get('/api-keys');\n }\n\n /**\n * Create a new API key.\n */\n async createApiKey(name: string, options?: { scopes?: string[]; expires_at?: string }): Promise<any> {\n return this.post('/api-keys', { name, ...options });\n }\n\n /**\n * Revoke an API key.\n */\n async deleteApiKey(keyId: string): Promise<{ revoked: boolean }> {\n return this.delete(`/api-keys/${keyId}`);\n }\n\n // ─── Ephemeral Agents ──────────────────────────────────────────────\n\n /**\n * Register an ephemeral agent with W3C did:key identity.\n * The agent auto-expires after the specified TTL.\n *\n * Side effect: the returned private_key is cached in this SDK instance's\n * in-memory keyring (matching register()).\n */\n async registerEphemeral(input: {\n capabilities: string[];\n scopes: string[];\n ttl_seconds?: number;\n }): Promise<any> {\n const result = await this.post('/agents/ephemeral', input);\n const agentId: string | undefined = result?.agent?.agent_id ?? result?.did_key;\n if (agentId && result?.private_key) {\n this.agentKeys.set(agentId, result.private_key);\n }\n return result;\n }\n\n // ─── Credential Delegation ──────────────────────────────────────────\n\n /**\n * Register an OAuth provider for credential delegation.\n */\n async registerProvider(input: {\n provider_key: string;\n display_name?: string;\n client_id: string;\n client_secret: string;\n auth_url: string;\n token_url: string;\n revoke_url?: string;\n scopes_available?: string[];\n }): Promise<any> {\n return this.post('/credentials/providers', input);\n }\n\n /**\n * List registered OAuth providers.\n */\n async listProviders(): Promise<any[]> {\n return this.get('/credentials/providers');\n }\n\n /**\n * Store an OAuth connection (user's authorized tokens).\n */\n async storeConnection(input: {\n provider_id: string;\n refresh_token: string;\n scopes_granted: string[];\n external_account_id?: string;\n }): Promise<any> {\n return this.post('/credentials/connections', input);\n }\n\n /**\n * List OAuth connections.\n */\n async listConnections(): Promise<any[]> {\n return this.get('/credentials/connections');\n }\n\n /**\n * Delegate a credential to an agent.\n * The agent will be able to request short-lived access tokens\n * for the delegated scopes without ever seeing the refresh token.\n */\n async delegateCredential(input: {\n connection_id: string;\n agent_id: string;\n scopes_delegated: string[];\n max_requests_per_hr?: number;\n valid_until?: string;\n }): Promise<any> {\n return this.post('/credentials/delegations', input);\n }\n\n /**\n * List credential delegations for the organisation or a specific agent.\n */\n async listDelegations(agentId?: string): Promise<any[]> {\n const params = agentId ? `?agent_id=${agentId}` : '';\n return this.get(`/credentials/delegations${params}`);\n }\n\n /**\n * Revoke a credential delegation (cascades to delegation chains).\n */\n async revokeDelegation(delegationId: string): Promise<{ revoked: boolean }> {\n return this.delete(`/credentials/delegations/${delegationId}`);\n }\n\n /**\n * Request a short-lived access token for an agent.\n * The agent must have an active credential delegation.\n * The refresh token is never exposed — the platform proxies the request.\n */\n async requestToken(input: {\n agent_id: string;\n scope: string;\n provider_id?: string;\n }): Promise<{\n access_token: string;\n token_type: string;\n expires_in: number;\n scope: string;\n delegation_id: string;\n }> {\n return this.post('/credentials/token', input);\n }\n\n // ─── Signing ──────────────────────────────────────────────────────\n\n /**\n * Sign a payload with an Ed25519 private key (client-side).\n * Uses the Web Crypto API or Node.js crypto.\n */\n async sign(payload: string, privateKeyPem: string): Promise<string> {\n if (typeof globalThis.crypto?.subtle !== 'undefined') {\n // Web Crypto API\n const keyData = this.pemToArrayBuffer(privateKeyPem);\n const key = await globalThis.crypto.subtle.importKey(\n 'pkcs8', keyData, { name: 'Ed25519' }, false, ['sign']\n );\n const signature = await globalThis.crypto.subtle.sign(\n 'Ed25519', key, new TextEncoder().encode(payload)\n );\n return `ed25519:${this.arrayBufferToBase64(signature)}`;\n } else {\n // Node.js crypto fallback\n const crypto = await import('node:crypto');\n const sign = crypto.sign(null, Buffer.from(payload), privateKeyPem);\n return `ed25519:${sign.toString('base64')}`;\n }\n }\n\n // ─── HTTP Client ──────────────────────────────────────────────────\n\n private async get(path: string): Promise<any> {\n return this.request('GET', path);\n }\n\n private async post(path: string, body: any): Promise<any> {\n return this.request('POST', path, body);\n }\n\n private async patch(path: string, body: any): Promise<any> {\n return this.request('PATCH', path, body);\n }\n\n private async delete(path: string): Promise<any> {\n return this.request('DELETE', path);\n }\n\n private async request(method: string, path: string, body?: any): Promise<any> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(`${this.baseUrl}${path}`, {\n method,\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n 'User-Agent': USER_AGENT,\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const errBody = await response.json().catch(() => ({})) as Record<string, any>;\n throw new VorimError(\n response.status,\n errBody.error?.code || 'UNKNOWN_ERROR',\n errBody.error?.message || `HTTP ${response.status}`,\n errBody.error?.details\n );\n }\n\n const json = await response.json() as Record<string, any>;\n return json.data;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n private pemToArrayBuffer(pem: string): ArrayBuffer {\n const b64 = pem.replace(/-----[^-]+-----/g, '').replace(/\\s/g, '');\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n }\n\n private arrayBufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = '';\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary);\n }\n}\n\nexport class VorimError extends Error {\n constructor(\n public status: number,\n public code: string,\n message: string,\n public details?: Record<string, unknown>\n ) {\n super(message);\n this.name = 'VorimError';\n }\n}\n\n// ─── Convenience export ──────────────────────────────────────────────\n\nexport default function createVorim(config: VorimConfig): VorimSDK {\n return new VorimSDK(config);\n}\n\n// Re-export types for consumers\nexport type {\n Agent, AgentRegistrationInput, AgentRegistrationResult,\n TrustRecord, AuditEventInput, AuditEventType, AuditResult,\n PermissionScope, PermissionCheckResult, AgentStatus,\n AgentDelegationRecord, DelegationLinkClaims,\n} from './types.js';\n\n// Re-export replayable evidence helpers (VAIP -02 schema field hashing)\nexport {\n hashTool, hashToolCatalogue, hashSystemPrompt, hashPreviousEvent,\n jcsCanonicalise, prepareReplayContext, CANONICAL_TOOL_CATALOGUE_VERSION,\n} from './replay.js';\nexport type { CatalogueTool, ReplayInputs, ReplayContext } from './replay.js';\n","/**\n * Replayable agent decision evidence helpers.\n *\n * Canonical-form hashing for the VAIP -02 schema fields that the SDK\n * attaches to audit events. The hashes recorded in audit_events.tool_catalogue_hash\n * and audit_events.system_prompt_hash use these functions, so the bytes\n * an auditor or counterparty reconstructs must match what the SDK produced.\n *\n * These helpers are intentionally separate from the signing path. The\n * v0 canonical signature form (event_type|action|resource|input_hash|\n * output_hash|result) does NOT cover model_version, tool_catalogue_hash,\n * or system_prompt_hash. They will enter the canonical bytes in v1\n * (RFC 8785 JCS) in a follow-up release.\n *\n * Stable across SDK versions: the canonical-form version is documented\n * in CANONICAL_TOOL_CATALOGUE_VERSION. Future changes get a v2 etc;\n * never edit the existing v1 logic, or already-recorded hashes lose\n * their meaning.\n */\n\n// ─── Versioning ───────────────────────────────────────────────────────────\n\n/**\n * Canonical-form version for tool catalogue hashes produced by this SDK.\n * Recorded in tool_catalogue_canon_version on the event metadata (when\n * the metadata field is used) so verifiers know which hash recipe to\n * reproduce. Increment ONLY if the algorithm changes in a way that\n * would change the hash for the same logical catalogue.\n */\nexport const CANONICAL_TOOL_CATALOGUE_VERSION = 'v1' as const;\n\n// ─── Types ────────────────────────────────────────────────────────────────\n\n/**\n * Minimum shape a tool needs for catalogue hashing. The framework\n * integrations adapt their native tool objects to this shape before\n * calling hashToolCatalogue.\n */\nexport interface CatalogueTool {\n /** The name the model sees and calls. Required. */\n name: string;\n /** Human-readable description shown to the model. Optional; absent ↔ empty string. */\n description?: string;\n /**\n * JSON Schema describing the tool's input parameters. Optional;\n * absent ↔ empty object `{}`. The schema gets RFC 8785 JCS-canonicalised\n * before hashing so semantically-equivalent variations (key order,\n * whitespace) produce the same hash.\n */\n schema?: Record<string, unknown> | null;\n}\n\n// ─── RFC 8785 JCS subset ──────────────────────────────────────────────────\n\n/**\n * RFC 8785 JSON Canonicalization Scheme, sufficient subset for tool\n * catalogue values.\n *\n * Rules:\n * - Object keys sorted lexicographically by UTF-16 code units (which\n * is what JS string comparison does naturally).\n * - No whitespace between tokens.\n * - Numbers: integers as integers, finite floats per ECMAScript\n * Number.prototype.toString. JCS forbids NaN and Infinity.\n * - Strings: JSON-escape using minimal set per RFC 8259 § 7.\n * - null, true, false, arrays: as JSON.stringify produces them, since\n * JSON.stringify already produces the canonical form for these.\n *\n * Not vendoring a full library because tool schemas don't carry\n * non-integer numbers in practice and the JS spec for Number.toString\n * happens to coincide with JCS § 3.2.2.2 for the integer case.\n */\nexport function jcsCanonicalise(value: unknown): string {\n if (value === null) return 'null';\n if (value === true) return 'true';\n if (value === false) return 'false';\n\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) {\n throw new Error('jcsCanonicalise: NaN and Infinity are not JCS-valid');\n }\n // For integers in safe range, .toString() matches JCS. For\n // non-integer floats, .toString() also matches in modern JS\n // engines (V8, JavaScriptCore, SpiderMonkey all use the shortest\n // round-trip representation, which is what JCS § 3.2.2.2 requires).\n return value.toString();\n }\n\n if (typeof value === 'string') {\n return JSON.stringify(value);\n }\n\n if (Array.isArray(value)) {\n return '[' + value.map(jcsCanonicalise).join(',') + ']';\n }\n\n if (typeof value === 'object') {\n const keys = Object.keys(value as Record<string, unknown>).sort();\n const parts = keys.map(k => {\n return JSON.stringify(k) + ':' + jcsCanonicalise((value as Record<string, unknown>)[k]);\n });\n return '{' + parts.join(',') + '}';\n }\n\n // undefined, function, symbol, bigint — not JSON-representable\n throw new Error(`jcsCanonicalise: unsupported value type: ${typeof value}`);\n}\n\n// ─── SHA-256 ──────────────────────────────────────────────────────────────\n\nasync function sha256Hex(input: string | Uint8Array): Promise<string> {\n const bytes = typeof input === 'string' ? new TextEncoder().encode(input) : input;\n\n // Node.js Web Crypto (Node 18+) supports digest. Browser Web Crypto does too.\n // Fall back to node:crypto if Web Crypto is unavailable.\n const subtle = (globalThis as any).crypto?.subtle;\n if (subtle) {\n const buf = await subtle.digest('SHA-256', bytes);\n return Array.from(new Uint8Array(buf))\n .map(b => b.toString(16).padStart(2, '0'))\n .join('');\n }\n\n // Node fallback\n const nodeCrypto = await import('node:crypto');\n return nodeCrypto.createHash('sha256').update(bytes).digest('hex');\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────\n\n/**\n * Hash a single tool definition. Returns `sha256:<hex>`.\n *\n * Canonical form (v1):\n * JCS-canonicalised JSON of `{name, description, schema}` where\n * absent fields substitute `description: \"\"` and `schema: {}`.\n */\nexport async function hashTool(tool: CatalogueTool): Promise<string> {\n const normalised = {\n name: tool.name,\n description: tool.description ?? '',\n schema: tool.schema ?? {},\n };\n const hex = await sha256Hex(jcsCanonicalise(normalised));\n return `sha256:${hex}`;\n}\n\n/**\n * Hash an entire tool catalogue. Returns `sha256:<hex>`.\n *\n * Reordering tools does NOT change the hash (tool hashes sorted\n * lexicographically before concatenation). Adding, removing, or\n * modifying a tool DOES change the hash.\n *\n * Per-tool hashing first means a verifier comparing two catalogue\n * hashes that differ can also be given the per-tool hashes to\n * identify which specific tool changed.\n */\nexport async function hashToolCatalogue(tools: CatalogueTool[]): Promise<string> {\n if (tools.length === 0) {\n // Empty catalogue has a deterministic, stable hash distinct from \"no field\"\n return `sha256:${await sha256Hex('[]')}`;\n }\n const perTool = await Promise.all(tools.map(hashTool));\n perTool.sort();\n const hex = await sha256Hex(perTool.join(''));\n return `sha256:${hex}`;\n}\n\n/**\n * Hash a system prompt. Returns `sha256:<hex>`.\n *\n * The prompt is UTF-8 encoded and hashed verbatim — no normalisation.\n * If a caller wants to ignore whitespace or comment differences, they\n * should normalise before calling. The intent here is deterministic\n * reproducibility, not semantic equivalence.\n */\nexport async function hashSystemPrompt(prompt: string): Promise<string> {\n const hex = await sha256Hex(prompt);\n return `sha256:${hex}`;\n}\n\n/**\n * Convenience: hash the previous event's canonical bytes for use in\n * the prev_event_hash field of hash-chained ingest. Caller provides\n * the canonical bytes (use canonicalPayloadV0 from the main module).\n */\nexport async function hashPreviousEvent(canonicalBytes: string): Promise<string> {\n const hex = await sha256Hex(canonicalBytes);\n return `sha256:${hex}`;\n}\n\n// ─── Replay context — framework integration helper ────────────────────────\n\n/**\n * Raw inputs the integration captures from the framework. Set by the\n * integration's config; turned into hashes by {@link prepareReplayContext}.\n */\nexport interface ReplayInputs {\n /** Stable identifier for the model. E.g. `\"anthropic:claude-opus-4-8\"`. */\n modelVersion?: string;\n /** Tools available to the agent at call time. Hashed via {@link hashToolCatalogue}. */\n tools?: CatalogueTool[];\n /** System prompt active at call time. Hashed via {@link hashSystemPrompt}. */\n systemPrompt?: string;\n}\n\n/**\n * Pre-computed hashes ready to attach to audit events. The three keys\n * match the audit_events column names.\n */\nexport interface ReplayContext {\n model_version?: string;\n tool_catalogue_hash?: string;\n system_prompt_hash?: string;\n}\n\n/**\n * Compute replay context once from raw inputs. Use at integration\n * setup time so each emit can attach the hashes without re-hashing.\n *\n * Returns an object suitable for spreading into an AuditEventInput:\n * `await vorim.emit({ ...event, ...replayContext })`\n *\n * If a field is absent in the inputs, it is absent in the result\n * (not the empty string). That keeps the event lean.\n */\nexport async function prepareReplayContext(\n inputs: ReplayInputs,\n): Promise<ReplayContext> {\n const ctx: ReplayContext = {};\n if (inputs.modelVersion) ctx.model_version = inputs.modelVersion;\n if (inputs.tools) ctx.tool_catalogue_hash = await hashToolCatalogue(inputs.tools);\n if (inputs.systemPrompt) ctx.system_prompt_hash = await hashSystemPrompt(inputs.systemPrompt);\n return ctx;\n}\n"],"mappings":"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","names":[]}
package/dist/index.js CHANGED
@@ -70,7 +70,7 @@ async function prepareReplayContext(inputs) {
70
70
  }
71
71
 
72
72
  // src/index.ts
73
- var SDK_VERSION = true ? "3.3.2" : "0.0.0";
73
+ var SDK_VERSION = true ? "3.4.0" : "0.0.0";
74
74
  var USER_AGENT = `vorim-sdk/${SDK_VERSION}`;
75
75
  function canonicalPayloadV0(event) {
76
76
  return [
@@ -128,7 +128,15 @@ var VorimSDK = class _VorimSDK {
128
128
  this.baseUrl = (config.baseUrl || "https://api.vorim.ai").replace(/\/$/, "") + "/v1";
129
129
  this.timeout = config.timeout || 1e4;
130
130
  this.autoSign = config.autoSign !== false;
131
- this.canonicalForm = config.canonicalForm ?? "v0";
131
+ this.canonicalForm = config.canonicalForm ?? "v1";
132
+ if (config.canonicalForm === "v0") {
133
+ try {
134
+ console.warn(
135
+ '[@vorim/sdk] canonicalForm=v0 is deprecated: it leaves metadata, delegation context, and replayable-evidence fields unsigned. Switch to canonicalForm=v1 (the new default in 3.4.0+) for full tamper coverage. Pass canonicalForm: "v0" explicitly only if you need byte-compat with verifiers older than @vorim/verify 0.2.0.'
136
+ );
137
+ } catch {
138
+ }
139
+ }
132
140
  this.chainEvents = config.chainEvents ?? false;
133
141
  }
134
142
  /**
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/replay.ts","../src/index.ts"],"sourcesContent":["/**\n * Replayable agent decision evidence helpers.\n *\n * Canonical-form hashing for the VAIP -02 schema fields that the SDK\n * attaches to audit events. The hashes recorded in audit_events.tool_catalogue_hash\n * and audit_events.system_prompt_hash use these functions, so the bytes\n * an auditor or counterparty reconstructs must match what the SDK produced.\n *\n * These helpers are intentionally separate from the signing path. The\n * v0 canonical signature form (event_type|action|resource|input_hash|\n * output_hash|result) does NOT cover model_version, tool_catalogue_hash,\n * or system_prompt_hash. They will enter the canonical bytes in v1\n * (RFC 8785 JCS) in a follow-up release.\n *\n * Stable across SDK versions: the canonical-form version is documented\n * in CANONICAL_TOOL_CATALOGUE_VERSION. Future changes get a v2 etc;\n * never edit the existing v1 logic, or already-recorded hashes lose\n * their meaning.\n */\n\n// ─── Versioning ───────────────────────────────────────────────────────────\n\n/**\n * Canonical-form version for tool catalogue hashes produced by this SDK.\n * Recorded in tool_catalogue_canon_version on the event metadata (when\n * the metadata field is used) so verifiers know which hash recipe to\n * reproduce. Increment ONLY if the algorithm changes in a way that\n * would change the hash for the same logical catalogue.\n */\nexport const CANONICAL_TOOL_CATALOGUE_VERSION = 'v1' as const;\n\n// ─── Types ────────────────────────────────────────────────────────────────\n\n/**\n * Minimum shape a tool needs for catalogue hashing. The framework\n * integrations adapt their native tool objects to this shape before\n * calling hashToolCatalogue.\n */\nexport interface CatalogueTool {\n /** The name the model sees and calls. Required. */\n name: string;\n /** Human-readable description shown to the model. Optional; absent ↔ empty string. */\n description?: string;\n /**\n * JSON Schema describing the tool's input parameters. Optional;\n * absent ↔ empty object `{}`. The schema gets RFC 8785 JCS-canonicalised\n * before hashing so semantically-equivalent variations (key order,\n * whitespace) produce the same hash.\n */\n schema?: Record<string, unknown> | null;\n}\n\n// ─── RFC 8785 JCS subset ──────────────────────────────────────────────────\n\n/**\n * RFC 8785 JSON Canonicalization Scheme, sufficient subset for tool\n * catalogue values.\n *\n * Rules:\n * - Object keys sorted lexicographically by UTF-16 code units (which\n * is what JS string comparison does naturally).\n * - No whitespace between tokens.\n * - Numbers: integers as integers, finite floats per ECMAScript\n * Number.prototype.toString. JCS forbids NaN and Infinity.\n * - Strings: JSON-escape using minimal set per RFC 8259 § 7.\n * - null, true, false, arrays: as JSON.stringify produces them, since\n * JSON.stringify already produces the canonical form for these.\n *\n * Not vendoring a full library because tool schemas don't carry\n * non-integer numbers in practice and the JS spec for Number.toString\n * happens to coincide with JCS § 3.2.2.2 for the integer case.\n */\nexport function jcsCanonicalise(value: unknown): string {\n if (value === null) return 'null';\n if (value === true) return 'true';\n if (value === false) return 'false';\n\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) {\n throw new Error('jcsCanonicalise: NaN and Infinity are not JCS-valid');\n }\n // For integers in safe range, .toString() matches JCS. For\n // non-integer floats, .toString() also matches in modern JS\n // engines (V8, JavaScriptCore, SpiderMonkey all use the shortest\n // round-trip representation, which is what JCS § 3.2.2.2 requires).\n return value.toString();\n }\n\n if (typeof value === 'string') {\n return JSON.stringify(value);\n }\n\n if (Array.isArray(value)) {\n return '[' + value.map(jcsCanonicalise).join(',') + ']';\n }\n\n if (typeof value === 'object') {\n const keys = Object.keys(value as Record<string, unknown>).sort();\n const parts = keys.map(k => {\n return JSON.stringify(k) + ':' + jcsCanonicalise((value as Record<string, unknown>)[k]);\n });\n return '{' + parts.join(',') + '}';\n }\n\n // undefined, function, symbol, bigint — not JSON-representable\n throw new Error(`jcsCanonicalise: unsupported value type: ${typeof value}`);\n}\n\n// ─── SHA-256 ──────────────────────────────────────────────────────────────\n\nasync function sha256Hex(input: string | Uint8Array): Promise<string> {\n const bytes = typeof input === 'string' ? new TextEncoder().encode(input) : input;\n\n // Node.js Web Crypto (Node 18+) supports digest. Browser Web Crypto does too.\n // Fall back to node:crypto if Web Crypto is unavailable.\n const subtle = (globalThis as any).crypto?.subtle;\n if (subtle) {\n const buf = await subtle.digest('SHA-256', bytes);\n return Array.from(new Uint8Array(buf))\n .map(b => b.toString(16).padStart(2, '0'))\n .join('');\n }\n\n // Node fallback\n const nodeCrypto = await import('node:crypto');\n return nodeCrypto.createHash('sha256').update(bytes).digest('hex');\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────\n\n/**\n * Hash a single tool definition. Returns `sha256:<hex>`.\n *\n * Canonical form (v1):\n * JCS-canonicalised JSON of `{name, description, schema}` where\n * absent fields substitute `description: \"\"` and `schema: {}`.\n */\nexport async function hashTool(tool: CatalogueTool): Promise<string> {\n const normalised = {\n name: tool.name,\n description: tool.description ?? '',\n schema: tool.schema ?? {},\n };\n const hex = await sha256Hex(jcsCanonicalise(normalised));\n return `sha256:${hex}`;\n}\n\n/**\n * Hash an entire tool catalogue. Returns `sha256:<hex>`.\n *\n * Reordering tools does NOT change the hash (tool hashes sorted\n * lexicographically before concatenation). Adding, removing, or\n * modifying a tool DOES change the hash.\n *\n * Per-tool hashing first means a verifier comparing two catalogue\n * hashes that differ can also be given the per-tool hashes to\n * identify which specific tool changed.\n */\nexport async function hashToolCatalogue(tools: CatalogueTool[]): Promise<string> {\n if (tools.length === 0) {\n // Empty catalogue has a deterministic, stable hash distinct from \"no field\"\n return `sha256:${await sha256Hex('[]')}`;\n }\n const perTool = await Promise.all(tools.map(hashTool));\n perTool.sort();\n const hex = await sha256Hex(perTool.join(''));\n return `sha256:${hex}`;\n}\n\n/**\n * Hash a system prompt. Returns `sha256:<hex>`.\n *\n * The prompt is UTF-8 encoded and hashed verbatim — no normalisation.\n * If a caller wants to ignore whitespace or comment differences, they\n * should normalise before calling. The intent here is deterministic\n * reproducibility, not semantic equivalence.\n */\nexport async function hashSystemPrompt(prompt: string): Promise<string> {\n const hex = await sha256Hex(prompt);\n return `sha256:${hex}`;\n}\n\n/**\n * Convenience: hash the previous event's canonical bytes for use in\n * the prev_event_hash field of hash-chained ingest. Caller provides\n * the canonical bytes (use canonicalPayloadV0 from the main module).\n */\nexport async function hashPreviousEvent(canonicalBytes: string): Promise<string> {\n const hex = await sha256Hex(canonicalBytes);\n return `sha256:${hex}`;\n}\n\n// ─── Replay context — framework integration helper ────────────────────────\n\n/**\n * Raw inputs the integration captures from the framework. Set by the\n * integration's config; turned into hashes by {@link prepareReplayContext}.\n */\nexport interface ReplayInputs {\n /** Stable identifier for the model. E.g. `\"anthropic:claude-opus-4-8\"`. */\n modelVersion?: string;\n /** Tools available to the agent at call time. Hashed via {@link hashToolCatalogue}. */\n tools?: CatalogueTool[];\n /** System prompt active at call time. Hashed via {@link hashSystemPrompt}. */\n systemPrompt?: string;\n}\n\n/**\n * Pre-computed hashes ready to attach to audit events. The three keys\n * match the audit_events column names.\n */\nexport interface ReplayContext {\n model_version?: string;\n tool_catalogue_hash?: string;\n system_prompt_hash?: string;\n}\n\n/**\n * Compute replay context once from raw inputs. Use at integration\n * setup time so each emit can attach the hashes without re-hashing.\n *\n * Returns an object suitable for spreading into an AuditEventInput:\n * `await vorim.emit({ ...event, ...replayContext })`\n *\n * If a field is absent in the inputs, it is absent in the result\n * (not the empty string). That keeps the event lean.\n */\nexport async function prepareReplayContext(\n inputs: ReplayInputs,\n): Promise<ReplayContext> {\n const ctx: ReplayContext = {};\n if (inputs.modelVersion) ctx.model_version = inputs.modelVersion;\n if (inputs.tools) ctx.tool_catalogue_hash = await hashToolCatalogue(inputs.tools);\n if (inputs.systemPrompt) ctx.system_prompt_hash = await hashSystemPrompt(inputs.systemPrompt);\n return ctx;\n}\n","// ============================================================================\n// VORIM SDK — TypeScript\n// Thin client wrapping the Vorim AI REST API\n// ============================================================================\n\nimport type {\n Agent, AgentRegistrationInput, AgentRegistrationResult,\n TrustRecord, AuditEventInput, PermissionScope, PermissionCheckResult,\n AgentDelegationRecord, DelegationLinkClaims,\n} from './types.js';\nimport { jcsCanonicalise, hashPreviousEvent } from './replay.js';\n\n// __SDK_VERSION__ is replaced at build time (tsup define) with the package.json\n// version, so the User-Agent always matches the published version. Falls back to\n// '0.0.0' when run un-bundled (e.g. ts-node / tests) where the define isn't applied.\ndeclare const __SDK_VERSION__: string | undefined;\nconst SDK_VERSION = typeof __SDK_VERSION__ !== 'undefined' ? __SDK_VERSION__ : '0.0.0';\nconst USER_AGENT = `vorim-sdk/${SDK_VERSION}`;\n\nexport interface VorimConfig {\n apiKey: string;\n baseUrl?: string;\n timeout?: number;\n /**\n * Auto-sign audit events with the agent's private key at emit time.\n * Default true in v3.1+. Set to false to opt out globally.\n * When enabled, the SDK signs the event using whichever private key was\n * stored via {@link VorimSDK.useAgentKey} or returned by\n * {@link VorimSDK.register}. Events for unknown agents pass through unsigned.\n */\n autoSign?: boolean;\n /**\n * Canonical form to use when signing. Default `\"v0\"` for backward-compat\n * with `@vorim/sdk` 3.1.x. Set to `\"v1\"` to sign the full event object\n * via RFC 8785 JCS, covering replayable-evidence fields (model_version,\n * tool_catalogue_hash, system_prompt_hash, prev_event_hash). v1 events\n * carry `canonical_form: \"v1\"` on the wire so the server can dispatch\n * verification correctly.\n */\n canonicalForm?: 'v0' | 'v1';\n /**\n * Hash-chain events per agent so deletion of a single audit row\n * becomes detectable. Default `false` (no chaining). When enabled,\n * the SDK sets `prev_event_hash` on each event to SHA-256 of the\n * previous event's canonical bytes for the same agent. The first\n * event after enable / process restart has `prev_event_hash = null`,\n * which the verifier reports as `chain_restart` (informational, not\n * a failure). Chain integrity is checked by `@vorim/verify`.\n */\n chainEvents?: boolean;\n}\n\n/**\n * VAIP v0 canonical bytes used by Vorim's per-event signing.\n *\n * Pipe-joined content fields with empty-string substitution for missing values.\n * This is intentionally duplicated from `@vorim/shared-types` so the published\n * SDK ships with zero runtime dependencies. A parity test in this package\n * imports both definitions and asserts byte-exact equality across a fixture\n * matrix, so they cannot drift silently.\n *\n * To upgrade the format, version the function (`canonicalPayloadV1`) — never\n * edit this one. Old signatures must remain verifiable.\n */\nexport function canonicalPayloadV0(event: AuditEventInput): string {\n return [\n event.event_type,\n event.action,\n event.resource ?? '',\n event.input_hash ?? '',\n event.output_hash ?? '',\n event.result,\n ].join('|');\n}\n\n/**\n * VAIP v1 canonical bytes for audit-event signing (RFC 8785 JCS).\n *\n * Signs the full event object excluding `signature` (the field being\n * computed) and `canonical_form` (metadata about the recipe). Unlike v0,\n * v1 covers the replayable-evidence fields and the metadata field.\n *\n * Re-exports `jcsCanonicalise` from `./replay.js` which is the byte-exact\n * twin of `@vorim/shared-types`' implementation. The cross-language parity\n * script enforces equivalence with the Python SDK.\n */\nexport function canonicalPayloadV1(event: AuditEventInput): string {\n // Strip the fields that are out of scope for v1 signing.\n const { signature: _sig, canonical_form: _cf, ...rest } = event as Record<string, unknown> & AuditEventInput;\n return jcsCanonicalise(rest);\n}\n\nexport class VorimSDK {\n private apiKey: string;\n private baseUrl: string;\n private timeout: number;\n private autoSign: boolean;\n private canonicalForm: 'v0' | 'v1';\n private chainEvents: boolean;\n /**\n * In-memory keyring mapping agent_id -> PEM-encoded Ed25519 private key.\n * Populated automatically by register() and registerEphemeral(), or\n * explicitly via useAgentKey(). Lost on process restart by design; the\n * caller is responsible for durable key storage.\n */\n private agentKeys: Map<string, string> = new Map();\n /**\n * Per-agent hash of the last emitted event's canonical bytes. Used to\n * populate prev_event_hash on the next emit when chainEvents is on.\n * Empty string ↔ no previous event (chain restart). Reset by\n * forgetAgentKey() so reusing an agent_id after revocation doesn't\n * link to the old chain.\n */\n private lastEventHash: Map<string, string> = new Map();\n /**\n * Per-agent monotonic counter incremented by `forgetAgentKey`. An\n * emit that started before `forgetAgentKey` ran will read a stale\n * epoch and refuse to repopulate the chain tail, preventing the\n * revoked agent from inheriting a new lastEventHash from the\n * in-flight emit that the lock was holding.\n */\n private agentForgetEpoch: Map<string, number> = new Map();\n /**\n * Per-agent emit promise. Each new emit awaits the previous one so\n * the chain is constructed in order. Concurrent emits to the same\n * agent are serialised (correct); concurrent emits to different\n * agents remain parallel (fast).\n */\n private chainLocks: Map<string, Promise<void>> = new Map();\n\n constructor(config: VorimConfig) {\n this.apiKey = config.apiKey;\n this.baseUrl = (config.baseUrl || 'https://api.vorim.ai').replace(/\\/$/, '') + '/v1';\n this.timeout = config.timeout || 10000;\n this.autoSign = config.autoSign !== false;\n this.canonicalForm = config.canonicalForm ?? 'v0';\n this.chainEvents = config.chainEvents ?? false;\n }\n\n /**\n * Register a previously-issued agent keypair so this SDK instance can\n * auto-sign events for it on emit. Use this when restoring an agent across\n * process restarts: read the agent's private_key from durable storage,\n * call useAgentKey(agentId, privateKey), and emit() will sign automatically.\n */\n useAgentKey(agentId: string, privateKeyPem: string): void {\n this.agentKeys.set(agentId, privateKeyPem);\n }\n\n /**\n * Forget an agent's signing key (e.g. after revocation). Subsequent emit()\n * calls for that agent will pass through unsigned unless a key is provided\n * inline. Also clears the per-agent chain state — re-using the same\n * agent_id after revocation does NOT link to the old chain.\n */\n forgetAgentKey(agentId: string): void {\n this.agentKeys.delete(agentId);\n this.lastEventHash.delete(agentId);\n this.chainLocks.delete(agentId);\n // Bump the per-agent epoch so any in-flight emit that completes\n // after this call refuses to write back a chain tail. Without\n // this, an emit that holds the chain lock can repopulate\n // lastEventHash after forgetAgentKey clears it, defeating the\n // revoked-agent isolation guarantee.\n this.agentForgetEpoch.set(agentId, (this.agentForgetEpoch.get(agentId) ?? 0) + 1);\n }\n\n /**\n * Cap on how many per-agent chain entries the SDK tracks. Set\n * generously — most callers will hold ≤ 1k agent_ids in memory.\n * Long-running processes that cycle through many agent_ids without\n * calling forgetAgentKey (e.g. ephemeral test agents) would\n * otherwise grow chainLocks / agentForgetEpoch / lastEventHash\n * unbounded.\n */\n private static readonly MAX_CHAIN_STATE_ENTRIES = 10_000;\n\n /**\n * Evict the oldest chain state entries when we cross the cap. Called\n * lazily from prepareEventChained — no scheduled task, no background\n * timer; only runs when the cap is breached during a real emit.\n */\n private evictChainStateIfNeeded(): void {\n if (this.chainLocks.size <= VorimSDK.MAX_CHAIN_STATE_ENTRIES) return;\n const toRemove = Math.ceil(this.chainLocks.size * 0.1); // drop oldest 10 %\n let removed = 0;\n for (const agentId of this.chainLocks.keys()) {\n if (removed >= toRemove) break;\n // Skip agents with an active key — they're in use.\n if (this.agentKeys.has(agentId)) continue;\n this.chainLocks.delete(agentId);\n this.lastEventHash.delete(agentId);\n this.agentForgetEpoch.delete(agentId);\n removed++;\n }\n }\n\n // ─── Health Check ────────────────────────────────────────────────\n\n /**\n * Ping the Vorim API to verify connectivity and API key validity.\n * Returns { status, timestamp } on success, throws VorimError on failure.\n */\n async ping(): Promise<{ status: string; timestamp: string }> {\n const response = await fetch(`${this.baseUrl.replace('/v1', '')}/health`, {\n headers: { 'User-Agent': USER_AGENT },\n signal: AbortSignal.timeout(this.timeout),\n });\n if (!response.ok) throw new VorimError(response.status, 'UNREACHABLE', 'Vorim API is not reachable');\n return response.json() as Promise<{ status: string; timestamp: string }>;\n }\n\n // ─── Agent Identity ────────────────────────────────────────────────\n\n /**\n * Register a new agent with Vorim AI.\n * Returns the agent identity and a private key (shown once).\n *\n * Side effect: the returned private_key is cached in this SDK instance's\n * in-memory keyring so subsequent emit() calls for this agent auto-sign.\n * The keyring is process-local; the caller is responsible for persisting\n * the private_key to durable storage if the agent should survive restarts.\n */\n async register(input: AgentRegistrationInput): Promise<AgentRegistrationResult> {\n const result = await this.post('/agents', input) as AgentRegistrationResult;\n if (result?.agent?.agent_id && result?.private_key) {\n this.agentKeys.set(result.agent.agent_id, result.private_key);\n }\n return result;\n }\n\n /**\n * Verify an agent's identity via the public Trust API.\n */\n async verify(agentId: string): Promise<TrustRecord> {\n return this.get(`/trust/verify/${agentId}`);\n }\n\n /**\n * Get agent details.\n */\n async getAgent(agentId: string): Promise<Agent> {\n return this.get(`/agents/${agentId}`);\n }\n\n /**\n * List all agents in the organisation.\n */\n async listAgents(params?: { page?: number; per_page?: number; status?: string }): Promise<{ agents: Agent[]; meta: any }> {\n const qs = new URLSearchParams(params as any).toString();\n return this.get(`/agents${qs ? '?' + qs : ''}`);\n }\n\n /**\n * Update an agent's metadata.\n */\n async updateAgent(agentId: string, updates: Partial<Pick<Agent, 'name' | 'description' | 'status' | 'capabilities'>>): Promise<Agent> {\n return this.patch(`/agents/${agentId}`, updates);\n }\n\n /**\n * Revoke an agent (permanent deactivation).\n */\n async revoke(agentId: string): Promise<void> {\n await this.delete(`/agents/${agentId}`);\n }\n\n // ─── Permissions ──────────────────────────────────────────────────\n\n /**\n * Check if an agent has a specific permission scope.\n * Target: < 5ms response via Redis cache.\n */\n async check(agentId: string, scope: PermissionScope): Promise<PermissionCheckResult> {\n return this.post(`/agents/${agentId}/permissions/verify`, { scope });\n }\n\n /**\n * Grant a permission scope to an agent.\n */\n async grant(agentId: string, scope: PermissionScope, options?: {\n valid_until?: string;\n rate_limit?: { max: number; window: string };\n }): Promise<any> {\n return this.post(`/agents/${agentId}/permissions`, { scope, ...options });\n }\n\n /**\n * List all active permissions for an agent.\n */\n async listPermissions(agentId: string): Promise<any[]> {\n return this.get(`/agents/${agentId}/permissions`);\n }\n\n /**\n * Revoke a specific permission scope from an agent.\n */\n async revokePermission(agentId: string, scope: PermissionScope): Promise<any> {\n return this.delete(`/agents/${agentId}/permissions/${scope}`);\n }\n\n // ─── Agent-to-Agent Identity Delegation (VAIP -02 § 5) ──────────────\n\n /**\n * Delegate the right to act on this agent's behalf to another agent\n * in the same org, with a strict subset of this agent's scopes.\n *\n * Multi-hop chains are supported up to depth 32. Scope subset is\n * enforced at every hop. Audit events emitted by the delegate carry\n * the chain context (`on_behalf_of`, `delegator_agent_id`,\n * `delegation_chain_id`, `delegation_depth`) so a verifier walking\n * the bundle can reconstruct the full chain.\n *\n * @example\n * ```ts\n * const chain = await vorim.delegateToAgent('agid_parent_abc', {\n * delegate_agent_id: 'agid_child_xyz',\n * scopes_delegated: ['agent:read', 'agent:execute'],\n * max_chain_depth: 1, // delegate may make ONE further hop\n * valid_until: '2026-12-31T00:00:00Z',\n * });\n * console.log(chain.public_chain_id); // chain_<hex>\n * ```\n */\n async delegateToAgent(\n delegatorAgentId: string,\n input: {\n delegate_agent_id: string;\n scopes_delegated: PermissionScope[];\n max_chain_depth?: number;\n valid_until?: string;\n /**\n * Optional Ed25519-signed delegation link (VAIP -02 § 5). When\n * provided, the server verifies the signature against the\n * delegator's stored public key, persists alongside the chain\n * row, and exports it in bundle delegation_tokens so the chain\n * is offline-verifiable by `@vorim/verify`. Compute via\n * {@link signDelegationLink} or set manually if signing\n * elsewhere.\n */\n signed_link?: {\n claims: DelegationLinkClaims;\n signature: string;\n };\n },\n ): Promise<AgentDelegationRecord> {\n return this.post(`/agents/${delegatorAgentId}/delegations`, input);\n }\n\n /**\n * Sign a delegation link with the delegator's private key. Returns\n * the signed link in the shape accepted by `delegateToAgent`'s\n * `signed_link` field.\n *\n * The signature is Ed25519 over the RFC 8785 JCS-canonical bytes of\n * the claims object. Same algorithm the server and `@vorim/verify`\n * use for verification.\n *\n * Use this when the delegator's private key is in this SDK's\n * keyring (i.e. set via `register()` or `useAgentKey()`).\n *\n * @example\n * ```ts\n * const signed = await vorim.signDelegationLink({\n * v: 0,\n * type: 'vaip-delegation-link',\n * chain_id: 'chain_abc', // server returns this on first delegation\n * depth: 1,\n * delegator: 'agid_parent',\n * delegate: 'agid_child',\n * scopes: ['agent:read', 'agent:execute'],\n * max_chain_depth: 1,\n * valid_from: new Date().toISOString(),\n * valid_until: null,\n * parent_link_hash: null,\n * });\n * ```\n */\n async signDelegationLink(\n claims: DelegationLinkClaims,\n ): Promise<{ claims: DelegationLinkClaims; signature: string }> {\n const key = this.agentKeys.get(claims.delegator);\n if (!key) {\n throw new VorimError(\n 400,\n 'NO_AGENT_KEY',\n `SDK has no private key for delegator ${claims.delegator}`,\n );\n }\n // Sign using the SDK's local JCS. Byte-equivalent to shared-types\n // and the server (enforced by scripts/check-replay-parity.sh).\n const bytes = jcsCanonicalise(claims as unknown as Record<string, unknown>);\n const signature = await this.sign(bytes, key);\n return { claims, signature };\n }\n\n /**\n * List active identity-chain entries this agent participates in\n * (either as delegator or delegate). Useful for showing the current\n * delegation graph in an admin UI.\n */\n async listAgentDelegations(agentId: string): Promise<AgentDelegationRecord[]> {\n return this.get(`/agents/${agentId}/delegations`);\n }\n\n /**\n * Walk a delegation chain by its public id. Returns the full chain\n * in depth order.\n */\n async getDelegationChain(\n agentId: string,\n chainId: string,\n ): Promise<AgentDelegationRecord[]> {\n return this.get(`/agents/${agentId}/delegation-chain/${chainId}`);\n }\n\n /**\n * Revoke this agent's delegation in a given chain. Cascades to all\n * descendants beneath this agent's depth in the chain.\n */\n async revokeAgentDelegation(\n agentId: string,\n chainId: string,\n ): Promise<{ revoked: number }> {\n return this.delete(`/agents/${agentId}/delegations/${chainId}`);\n }\n\n // ─── Audit ────────────────────────────────────────────────────────\n\n /**\n * Emit an audit event for an agent action.\n *\n * By default (autoSign=true on the SDK), the event is signed with the\n * agent's private key before it leaves the process. Set options.sign=false\n * to skip signing (e.g. for testing). If the SDK has no private key for the\n * event's agent_id, the event is sent unsigned and a warning is not\n * raised — callers that require signing should check event.signature on\n * the returned event after a round-trip, or use a server-side enforcement\n * flag (VORIM_VERIFY_AUDIT_SIGNATURES).\n */\n async emit(event: AuditEventInput, options?: { sign?: boolean }): Promise<{ ingested: number }> {\n const prepared = await this.prepareEvent(event, options?.sign);\n const result = await this.post('/audit/events', { events: [prepared] }) as { ingested: number };\n this.warnOnPartialIngest(1, result?.ingested ?? 0);\n return result;\n }\n\n /**\n * Emit a batch of audit events (up to 1,000). Each event is signed\n * independently using its agent_id to look up the signing key. See\n * {@link VorimSDK.emit} for signing behaviour and opt-out.\n *\n * When the server returns `ingested < events.length` (e.g. one event\n * referenced an unknown agent_id), a `console.warn` is emitted so\n * operators don't silently lose audit rows. The result is returned\n * unchanged so callers can inspect / act on it.\n */\n async emitBatch(events: AuditEventInput[], options?: { sign?: boolean }): Promise<{ ingested: number }> {\n const prepared = await Promise.all(events.map(e => this.prepareEvent(e, options?.sign)));\n const result = await this.post('/audit/events', { events: prepared }) as { ingested: number };\n this.warnOnPartialIngest(events.length, result?.ingested ?? 0);\n return result;\n }\n\n private warnOnPartialIngest(submitted: number, ingested: number): void {\n if (ingested < submitted) {\n try {\n // eslint-disable-next-line no-console\n console.warn(\n `[@vorim/sdk] partial ingest: server stored ${ingested}/${submitted} events. ` +\n `Common causes: unknown agent_id (cross-org or typo), invalid signature when strict ` +\n `verification is enabled.`,\n );\n } catch {\n /* ignore logger errors */\n }\n }\n }\n\n /**\n * Internal: prepare an event for transmission. Auto-signs if the SDK has a\n * key for this agent and signing isn't explicitly opted out. Pre-existing\n * signatures on the event are respected (caller-signed events are not\n * re-signed). Per-agent failure is non-fatal: if signing throws, the event\n * still sends unsigned so a single bad key doesn't break a batch.\n *\n * Canonical-form dispatch:\n * - If the event already carries `canonical_form`, that wins (caller\n * opted in/out for this specific event).\n * - Otherwise the SDK-level `canonicalForm` (config) applies.\n * - v0 signs the pipe-joined 6 fields. v1 signs the RFC 8785 JCS\n * bytes over the full event minus signature and canonical_form,\n * and the event goes on the wire with `canonical_form: \"v1\"`.\n *\n * Chain construction:\n * - When chainEvents is on, the event gets `prev_event_hash` set to\n * the SHA-256 of the previous event's canonical bytes for the\n * same agent, set BEFORE the signature is computed (so v1\n * signatures cover the chain link).\n * - Chain ops are serialised per-agent via `chainLocks` so\n * concurrent emits to the same agent build a deterministic chain.\n */\n private async prepareEvent(\n event: AuditEventInput,\n signOverride?: boolean\n ): Promise<AuditEventInput> {\n const shouldSign = signOverride ?? this.autoSign;\n if (!shouldSign && !this.chainEvents) return event;\n // Even unsigned events participate in the chain if chaining is on.\n if (this.chainEvents) {\n return this.prepareEventChained(event, shouldSign);\n }\n if (!shouldSign) return event;\n if (event.signature) return event;\n return this.signEventNow(event, shouldSign);\n }\n\n /** Serialise per-agent and apply chain hash + sign. */\n private async prepareEventChained(\n event: AuditEventInput,\n shouldSign: boolean,\n ): Promise<AuditEventInput> {\n const agentId = event.agent_id;\n this.evictChainStateIfNeeded();\n const prior = this.chainLocks.get(agentId) ?? Promise.resolve();\n let release!: () => void;\n const next = new Promise<void>(r => { release = r; });\n this.chainLocks.set(agentId, prior.then(() => next));\n await prior;\n // Snapshot the forget-epoch BEFORE doing any chain work. If the\n // epoch advances while we're in flight, forgetAgentKey() ran and\n // we must not write back the chain tail.\n const startEpoch = this.agentForgetEpoch.get(agentId) ?? 0;\n try {\n // Insert prev_event_hash if we have a previous bytes-hash for this\n // agent. First event after enable / process restart has none.\n const prev = this.lastEventHash.get(agentId);\n const eventWithPrev: AuditEventInput = prev\n ? { ...event, prev_event_hash: prev }\n : event;\n\n // Sign (or pass through unsigned if signing not requested / no\n // key). If forgetAgentKey runs between the lock acquisition and\n // the sign call, skip signing — the key has been revoked and\n // we must not use it. The event still ships unsigned, which the\n // caller can detect via the missing `signature` field.\n const epochBeforeSign = this.agentForgetEpoch.get(agentId) ?? 0;\n const keyStillPresent = this.agentKeys.has(agentId);\n const prepared = shouldSign && !eventWithPrev.signature && keyStillPresent && epochBeforeSign === startEpoch\n ? await this.signEventNow(eventWithPrev, shouldSign)\n : eventWithPrev;\n\n // Record this event's canonical bytes hash as the chain's new tail.\n // Use the v1 form for v1 events (matches what the signature covered);\n // v0 form for v0 events.\n const wireForm = (prepared.canonical_form as 'v0' | 'v1' | undefined) ?? 'v0';\n const bytes = wireForm === 'v1' ? canonicalPayloadV1(prepared) : canonicalPayloadV0(prepared);\n try {\n const tail = await hashPreviousEvent(bytes);\n // Only commit the tail if forgetAgentKey didn't run while we\n // were in flight. Without this guard the revoked agent\n // silently inherits a new chain tail from the in-flight emit.\n if ((this.agentForgetEpoch.get(agentId) ?? 0) === startEpoch) {\n this.lastEventHash.set(agentId, tail);\n }\n } catch {\n // hashing failure (extreme edge) is non-fatal; chain restarts next time\n this.lastEventHash.delete(agentId);\n }\n return prepared;\n } finally {\n release();\n }\n }\n\n /** Sign an event right now, no chain handling.\n *\n * On signing failure (malformed key, Web Crypto unavailable, etc.)\n * the event ships with its requested `canonical_form` preserved and\n * a one-line warning is logged via `console.warn`. The previous\n * behaviour silently dropped both the signature AND the\n * canonical_form marker, which caused the event to be classified\n * server-side as a v0 `signature_missing` instead of a v1 attempt\n * that failed — making the breakage invisible to operators. */\n private async signEventNow(\n event: AuditEventInput,\n _shouldSign: boolean,\n ): Promise<AuditEventInput> {\n const key = this.agentKeys.get(event.agent_id);\n if (!key) return event;\n const form: 'v0' | 'v1' = (event.canonical_form as 'v0' | 'v1' | undefined) ?? this.canonicalForm;\n const withForm: AuditEventInput = form === 'v0'\n ? event\n : { ...event, canonical_form: 'v1' };\n try {\n const payload = form === 'v1' ? canonicalPayloadV1(withForm) : canonicalPayloadV0(withForm);\n const signature = await this.sign(payload, key);\n return { ...withForm, signature };\n } catch (err) {\n // Surface the failure rather than silently dropping the signature.\n // Operators need a signal to detect broken signing at the SDK\n // boundary; verifiers will otherwise misattribute the cause.\n try {\n // eslint-disable-next-line no-console\n console.warn(\n // Don't echo agent_id verbatim — emit a short prefix for\n // correlation while keeping log-sink content lower-cardinality\n // and avoiding accidental leakage of org-identifiable ids.\n `[@vorim/sdk] signing failed for agent_id=${(event.agent_id ?? '').slice(0, 12)}... form=${form}: ${(err as Error)?.message ?? err}. ` +\n `Event will be emitted unsigned with canonical_form retained.`,\n );\n } catch {\n /* ignore logger errors */\n }\n // Preserve canonical_form so the event is still classified as a\n // v1 attempt server-side, just without a signature. This makes\n // the breakage detectable via the signature_missing + v1 form\n // pair instead of looking like a legacy v0 unsigned event.\n return withForm;\n }\n }\n\n /**\n * Export a signed audit bundle for a date range.\n */\n async exportAudit(from: string, to: string, format: string = 'json'): Promise<any> {\n return this.post('/audit/export', { from, to, format });\n }\n\n // ─── API Keys ──────────────────────────────────────────────────────\n\n /**\n * List all API keys for the organisation.\n */\n async listApiKeys(): Promise<any[]> {\n return this.get('/api-keys');\n }\n\n /**\n * Create a new API key.\n */\n async createApiKey(name: string, options?: { scopes?: string[]; expires_at?: string }): Promise<any> {\n return this.post('/api-keys', { name, ...options });\n }\n\n /**\n * Revoke an API key.\n */\n async deleteApiKey(keyId: string): Promise<{ revoked: boolean }> {\n return this.delete(`/api-keys/${keyId}`);\n }\n\n // ─── Ephemeral Agents ──────────────────────────────────────────────\n\n /**\n * Register an ephemeral agent with W3C did:key identity.\n * The agent auto-expires after the specified TTL.\n *\n * Side effect: the returned private_key is cached in this SDK instance's\n * in-memory keyring (matching register()).\n */\n async registerEphemeral(input: {\n capabilities: string[];\n scopes: string[];\n ttl_seconds?: number;\n }): Promise<any> {\n const result = await this.post('/agents/ephemeral', input);\n const agentId: string | undefined = result?.agent?.agent_id ?? result?.did_key;\n if (agentId && result?.private_key) {\n this.agentKeys.set(agentId, result.private_key);\n }\n return result;\n }\n\n // ─── Credential Delegation ──────────────────────────────────────────\n\n /**\n * Register an OAuth provider for credential delegation.\n */\n async registerProvider(input: {\n provider_key: string;\n display_name?: string;\n client_id: string;\n client_secret: string;\n auth_url: string;\n token_url: string;\n revoke_url?: string;\n scopes_available?: string[];\n }): Promise<any> {\n return this.post('/credentials/providers', input);\n }\n\n /**\n * List registered OAuth providers.\n */\n async listProviders(): Promise<any[]> {\n return this.get('/credentials/providers');\n }\n\n /**\n * Store an OAuth connection (user's authorized tokens).\n */\n async storeConnection(input: {\n provider_id: string;\n refresh_token: string;\n scopes_granted: string[];\n external_account_id?: string;\n }): Promise<any> {\n return this.post('/credentials/connections', input);\n }\n\n /**\n * List OAuth connections.\n */\n async listConnections(): Promise<any[]> {\n return this.get('/credentials/connections');\n }\n\n /**\n * Delegate a credential to an agent.\n * The agent will be able to request short-lived access tokens\n * for the delegated scopes without ever seeing the refresh token.\n */\n async delegateCredential(input: {\n connection_id: string;\n agent_id: string;\n scopes_delegated: string[];\n max_requests_per_hr?: number;\n valid_until?: string;\n }): Promise<any> {\n return this.post('/credentials/delegations', input);\n }\n\n /**\n * List credential delegations for the organisation or a specific agent.\n */\n async listDelegations(agentId?: string): Promise<any[]> {\n const params = agentId ? `?agent_id=${agentId}` : '';\n return this.get(`/credentials/delegations${params}`);\n }\n\n /**\n * Revoke a credential delegation (cascades to delegation chains).\n */\n async revokeDelegation(delegationId: string): Promise<{ revoked: boolean }> {\n return this.delete(`/credentials/delegations/${delegationId}`);\n }\n\n /**\n * Request a short-lived access token for an agent.\n * The agent must have an active credential delegation.\n * The refresh token is never exposed — the platform proxies the request.\n */\n async requestToken(input: {\n agent_id: string;\n scope: string;\n provider_id?: string;\n }): Promise<{\n access_token: string;\n token_type: string;\n expires_in: number;\n scope: string;\n delegation_id: string;\n }> {\n return this.post('/credentials/token', input);\n }\n\n // ─── Signing ──────────────────────────────────────────────────────\n\n /**\n * Sign a payload with an Ed25519 private key (client-side).\n * Uses the Web Crypto API or Node.js crypto.\n */\n async sign(payload: string, privateKeyPem: string): Promise<string> {\n if (typeof globalThis.crypto?.subtle !== 'undefined') {\n // Web Crypto API\n const keyData = this.pemToArrayBuffer(privateKeyPem);\n const key = await globalThis.crypto.subtle.importKey(\n 'pkcs8', keyData, { name: 'Ed25519' }, false, ['sign']\n );\n const signature = await globalThis.crypto.subtle.sign(\n 'Ed25519', key, new TextEncoder().encode(payload)\n );\n return `ed25519:${this.arrayBufferToBase64(signature)}`;\n } else {\n // Node.js crypto fallback\n const crypto = await import('node:crypto');\n const sign = crypto.sign(null, Buffer.from(payload), privateKeyPem);\n return `ed25519:${sign.toString('base64')}`;\n }\n }\n\n // ─── HTTP Client ──────────────────────────────────────────────────\n\n private async get(path: string): Promise<any> {\n return this.request('GET', path);\n }\n\n private async post(path: string, body: any): Promise<any> {\n return this.request('POST', path, body);\n }\n\n private async patch(path: string, body: any): Promise<any> {\n return this.request('PATCH', path, body);\n }\n\n private async delete(path: string): Promise<any> {\n return this.request('DELETE', path);\n }\n\n private async request(method: string, path: string, body?: any): Promise<any> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(`${this.baseUrl}${path}`, {\n method,\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n 'User-Agent': USER_AGENT,\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const errBody = await response.json().catch(() => ({})) as Record<string, any>;\n throw new VorimError(\n response.status,\n errBody.error?.code || 'UNKNOWN_ERROR',\n errBody.error?.message || `HTTP ${response.status}`,\n errBody.error?.details\n );\n }\n\n const json = await response.json() as Record<string, any>;\n return json.data;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n private pemToArrayBuffer(pem: string): ArrayBuffer {\n const b64 = pem.replace(/-----[^-]+-----/g, '').replace(/\\s/g, '');\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n }\n\n private arrayBufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = '';\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary);\n }\n}\n\nexport class VorimError extends Error {\n constructor(\n public status: number,\n public code: string,\n message: string,\n public details?: Record<string, unknown>\n ) {\n super(message);\n this.name = 'VorimError';\n }\n}\n\n// ─── Convenience export ──────────────────────────────────────────────\n\nexport default function createVorim(config: VorimConfig): VorimSDK {\n return new VorimSDK(config);\n}\n\n// Re-export types for consumers\nexport type {\n Agent, AgentRegistrationInput, AgentRegistrationResult,\n TrustRecord, AuditEventInput, AuditEventType, AuditResult,\n PermissionScope, PermissionCheckResult, AgentStatus,\n AgentDelegationRecord, DelegationLinkClaims,\n} from './types.js';\n\n// Re-export replayable evidence helpers (VAIP -02 schema field hashing)\nexport {\n hashTool, hashToolCatalogue, hashSystemPrompt, hashPreviousEvent,\n jcsCanonicalise, prepareReplayContext, CANONICAL_TOOL_CATALOGUE_VERSION,\n} from './replay.js';\nexport type { CatalogueTool, ReplayInputs, ReplayContext } from './replay.js';\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/replay.ts","../src/index.ts"],"sourcesContent":["/**\n * Replayable agent decision evidence helpers.\n *\n * Canonical-form hashing for the VAIP -02 schema fields that the SDK\n * attaches to audit events. The hashes recorded in audit_events.tool_catalogue_hash\n * and audit_events.system_prompt_hash use these functions, so the bytes\n * an auditor or counterparty reconstructs must match what the SDK produced.\n *\n * These helpers are intentionally separate from the signing path. The\n * v0 canonical signature form (event_type|action|resource|input_hash|\n * output_hash|result) does NOT cover model_version, tool_catalogue_hash,\n * or system_prompt_hash. They will enter the canonical bytes in v1\n * (RFC 8785 JCS) in a follow-up release.\n *\n * Stable across SDK versions: the canonical-form version is documented\n * in CANONICAL_TOOL_CATALOGUE_VERSION. Future changes get a v2 etc;\n * never edit the existing v1 logic, or already-recorded hashes lose\n * their meaning.\n */\n\n// ─── Versioning ───────────────────────────────────────────────────────────\n\n/**\n * Canonical-form version for tool catalogue hashes produced by this SDK.\n * Recorded in tool_catalogue_canon_version on the event metadata (when\n * the metadata field is used) so verifiers know which hash recipe to\n * reproduce. Increment ONLY if the algorithm changes in a way that\n * would change the hash for the same logical catalogue.\n */\nexport const CANONICAL_TOOL_CATALOGUE_VERSION = 'v1' as const;\n\n// ─── Types ────────────────────────────────────────────────────────────────\n\n/**\n * Minimum shape a tool needs for catalogue hashing. The framework\n * integrations adapt their native tool objects to this shape before\n * calling hashToolCatalogue.\n */\nexport interface CatalogueTool {\n /** The name the model sees and calls. Required. */\n name: string;\n /** Human-readable description shown to the model. Optional; absent ↔ empty string. */\n description?: string;\n /**\n * JSON Schema describing the tool's input parameters. Optional;\n * absent ↔ empty object `{}`. The schema gets RFC 8785 JCS-canonicalised\n * before hashing so semantically-equivalent variations (key order,\n * whitespace) produce the same hash.\n */\n schema?: Record<string, unknown> | null;\n}\n\n// ─── RFC 8785 JCS subset ──────────────────────────────────────────────────\n\n/**\n * RFC 8785 JSON Canonicalization Scheme, sufficient subset for tool\n * catalogue values.\n *\n * Rules:\n * - Object keys sorted lexicographically by UTF-16 code units (which\n * is what JS string comparison does naturally).\n * - No whitespace between tokens.\n * - Numbers: integers as integers, finite floats per ECMAScript\n * Number.prototype.toString. JCS forbids NaN and Infinity.\n * - Strings: JSON-escape using minimal set per RFC 8259 § 7.\n * - null, true, false, arrays: as JSON.stringify produces them, since\n * JSON.stringify already produces the canonical form for these.\n *\n * Not vendoring a full library because tool schemas don't carry\n * non-integer numbers in practice and the JS spec for Number.toString\n * happens to coincide with JCS § 3.2.2.2 for the integer case.\n */\nexport function jcsCanonicalise(value: unknown): string {\n if (value === null) return 'null';\n if (value === true) return 'true';\n if (value === false) return 'false';\n\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) {\n throw new Error('jcsCanonicalise: NaN and Infinity are not JCS-valid');\n }\n // For integers in safe range, .toString() matches JCS. For\n // non-integer floats, .toString() also matches in modern JS\n // engines (V8, JavaScriptCore, SpiderMonkey all use the shortest\n // round-trip representation, which is what JCS § 3.2.2.2 requires).\n return value.toString();\n }\n\n if (typeof value === 'string') {\n return JSON.stringify(value);\n }\n\n if (Array.isArray(value)) {\n return '[' + value.map(jcsCanonicalise).join(',') + ']';\n }\n\n if (typeof value === 'object') {\n const keys = Object.keys(value as Record<string, unknown>).sort();\n const parts = keys.map(k => {\n return JSON.stringify(k) + ':' + jcsCanonicalise((value as Record<string, unknown>)[k]);\n });\n return '{' + parts.join(',') + '}';\n }\n\n // undefined, function, symbol, bigint — not JSON-representable\n throw new Error(`jcsCanonicalise: unsupported value type: ${typeof value}`);\n}\n\n// ─── SHA-256 ──────────────────────────────────────────────────────────────\n\nasync function sha256Hex(input: string | Uint8Array): Promise<string> {\n const bytes = typeof input === 'string' ? new TextEncoder().encode(input) : input;\n\n // Node.js Web Crypto (Node 18+) supports digest. Browser Web Crypto does too.\n // Fall back to node:crypto if Web Crypto is unavailable.\n const subtle = (globalThis as any).crypto?.subtle;\n if (subtle) {\n const buf = await subtle.digest('SHA-256', bytes);\n return Array.from(new Uint8Array(buf))\n .map(b => b.toString(16).padStart(2, '0'))\n .join('');\n }\n\n // Node fallback\n const nodeCrypto = await import('node:crypto');\n return nodeCrypto.createHash('sha256').update(bytes).digest('hex');\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────\n\n/**\n * Hash a single tool definition. Returns `sha256:<hex>`.\n *\n * Canonical form (v1):\n * JCS-canonicalised JSON of `{name, description, schema}` where\n * absent fields substitute `description: \"\"` and `schema: {}`.\n */\nexport async function hashTool(tool: CatalogueTool): Promise<string> {\n const normalised = {\n name: tool.name,\n description: tool.description ?? '',\n schema: tool.schema ?? {},\n };\n const hex = await sha256Hex(jcsCanonicalise(normalised));\n return `sha256:${hex}`;\n}\n\n/**\n * Hash an entire tool catalogue. Returns `sha256:<hex>`.\n *\n * Reordering tools does NOT change the hash (tool hashes sorted\n * lexicographically before concatenation). Adding, removing, or\n * modifying a tool DOES change the hash.\n *\n * Per-tool hashing first means a verifier comparing two catalogue\n * hashes that differ can also be given the per-tool hashes to\n * identify which specific tool changed.\n */\nexport async function hashToolCatalogue(tools: CatalogueTool[]): Promise<string> {\n if (tools.length === 0) {\n // Empty catalogue has a deterministic, stable hash distinct from \"no field\"\n return `sha256:${await sha256Hex('[]')}`;\n }\n const perTool = await Promise.all(tools.map(hashTool));\n perTool.sort();\n const hex = await sha256Hex(perTool.join(''));\n return `sha256:${hex}`;\n}\n\n/**\n * Hash a system prompt. Returns `sha256:<hex>`.\n *\n * The prompt is UTF-8 encoded and hashed verbatim — no normalisation.\n * If a caller wants to ignore whitespace or comment differences, they\n * should normalise before calling. The intent here is deterministic\n * reproducibility, not semantic equivalence.\n */\nexport async function hashSystemPrompt(prompt: string): Promise<string> {\n const hex = await sha256Hex(prompt);\n return `sha256:${hex}`;\n}\n\n/**\n * Convenience: hash the previous event's canonical bytes for use in\n * the prev_event_hash field of hash-chained ingest. Caller provides\n * the canonical bytes (use canonicalPayloadV0 from the main module).\n */\nexport async function hashPreviousEvent(canonicalBytes: string): Promise<string> {\n const hex = await sha256Hex(canonicalBytes);\n return `sha256:${hex}`;\n}\n\n// ─── Replay context — framework integration helper ────────────────────────\n\n/**\n * Raw inputs the integration captures from the framework. Set by the\n * integration's config; turned into hashes by {@link prepareReplayContext}.\n */\nexport interface ReplayInputs {\n /** Stable identifier for the model. E.g. `\"anthropic:claude-opus-4-8\"`. */\n modelVersion?: string;\n /** Tools available to the agent at call time. Hashed via {@link hashToolCatalogue}. */\n tools?: CatalogueTool[];\n /** System prompt active at call time. Hashed via {@link hashSystemPrompt}. */\n systemPrompt?: string;\n}\n\n/**\n * Pre-computed hashes ready to attach to audit events. The three keys\n * match the audit_events column names.\n */\nexport interface ReplayContext {\n model_version?: string;\n tool_catalogue_hash?: string;\n system_prompt_hash?: string;\n}\n\n/**\n * Compute replay context once from raw inputs. Use at integration\n * setup time so each emit can attach the hashes without re-hashing.\n *\n * Returns an object suitable for spreading into an AuditEventInput:\n * `await vorim.emit({ ...event, ...replayContext })`\n *\n * If a field is absent in the inputs, it is absent in the result\n * (not the empty string). That keeps the event lean.\n */\nexport async function prepareReplayContext(\n inputs: ReplayInputs,\n): Promise<ReplayContext> {\n const ctx: ReplayContext = {};\n if (inputs.modelVersion) ctx.model_version = inputs.modelVersion;\n if (inputs.tools) ctx.tool_catalogue_hash = await hashToolCatalogue(inputs.tools);\n if (inputs.systemPrompt) ctx.system_prompt_hash = await hashSystemPrompt(inputs.systemPrompt);\n return ctx;\n}\n","// ============================================================================\n// VORIM SDK — TypeScript\n// Thin client wrapping the Vorim AI REST API\n// ============================================================================\n\nimport type {\n Agent, AgentRegistrationInput, AgentRegistrationResult,\n TrustRecord, AuditEventInput, PermissionScope, PermissionCheckResult,\n AgentDelegationRecord, DelegationLinkClaims,\n} from './types.js';\nimport { jcsCanonicalise, hashPreviousEvent } from './replay.js';\n\n// __SDK_VERSION__ is replaced at build time (tsup define) with the package.json\n// version, so the User-Agent always matches the published version. Falls back to\n// '0.0.0' when run un-bundled (e.g. ts-node / tests) where the define isn't applied.\ndeclare const __SDK_VERSION__: string | undefined;\nconst SDK_VERSION = typeof __SDK_VERSION__ !== 'undefined' ? __SDK_VERSION__ : '0.0.0';\nconst USER_AGENT = `vorim-sdk/${SDK_VERSION}`;\n\nexport interface VorimConfig {\n apiKey: string;\n baseUrl?: string;\n timeout?: number;\n /**\n * Auto-sign audit events with the agent's private key at emit time.\n * Default true in v3.1+. Set to false to opt out globally.\n * When enabled, the SDK signs the event using whichever private key was\n * stored via {@link VorimSDK.useAgentKey} or returned by\n * {@link VorimSDK.register}. Events for unknown agents pass through unsigned.\n */\n autoSign?: boolean;\n /**\n * Canonical form to use when signing. Default `\"v0\"` for backward-compat\n * with `@vorim/sdk` 3.1.x. Set to `\"v1\"` to sign the full event object\n * via RFC 8785 JCS, covering replayable-evidence fields (model_version,\n * tool_catalogue_hash, system_prompt_hash, prev_event_hash). v1 events\n * carry `canonical_form: \"v1\"` on the wire so the server can dispatch\n * verification correctly.\n */\n canonicalForm?: 'v0' | 'v1';\n /**\n * Hash-chain events per agent so deletion of a single audit row\n * becomes detectable. Default `false` (no chaining). When enabled,\n * the SDK sets `prev_event_hash` on each event to SHA-256 of the\n * previous event's canonical bytes for the same agent. The first\n * event after enable / process restart has `prev_event_hash = null`,\n * which the verifier reports as `chain_restart` (informational, not\n * a failure). Chain integrity is checked by `@vorim/verify`.\n */\n chainEvents?: boolean;\n}\n\n/**\n * VAIP v0 canonical bytes used by Vorim's per-event signing.\n *\n * Pipe-joined content fields with empty-string substitution for missing values.\n * This is intentionally duplicated from `@vorim/shared-types` so the published\n * SDK ships with zero runtime dependencies. A parity test in this package\n * imports both definitions and asserts byte-exact equality across a fixture\n * matrix, so they cannot drift silently.\n *\n * To upgrade the format, version the function (`canonicalPayloadV1`) — never\n * edit this one. Old signatures must remain verifiable.\n */\nexport function canonicalPayloadV0(event: AuditEventInput): string {\n return [\n event.event_type,\n event.action,\n event.resource ?? '',\n event.input_hash ?? '',\n event.output_hash ?? '',\n event.result,\n ].join('|');\n}\n\n/**\n * VAIP v1 canonical bytes for audit-event signing (RFC 8785 JCS).\n *\n * Signs the full event object excluding `signature` (the field being\n * computed) and `canonical_form` (metadata about the recipe). Unlike v0,\n * v1 covers the replayable-evidence fields and the metadata field.\n *\n * Re-exports `jcsCanonicalise` from `./replay.js` which is the byte-exact\n * twin of `@vorim/shared-types`' implementation. The cross-language parity\n * script enforces equivalence with the Python SDK.\n */\nexport function canonicalPayloadV1(event: AuditEventInput): string {\n // Strip the fields that are out of scope for v1 signing.\n const { signature: _sig, canonical_form: _cf, ...rest } = event as Record<string, unknown> & AuditEventInput;\n return jcsCanonicalise(rest);\n}\n\nexport class VorimSDK {\n private apiKey: string;\n private baseUrl: string;\n private timeout: number;\n private autoSign: boolean;\n private canonicalForm: 'v0' | 'v1';\n private chainEvents: boolean;\n /**\n * In-memory keyring mapping agent_id -> PEM-encoded Ed25519 private key.\n * Populated automatically by register() and registerEphemeral(), or\n * explicitly via useAgentKey(). Lost on process restart by design; the\n * caller is responsible for durable key storage.\n */\n private agentKeys: Map<string, string> = new Map();\n /**\n * Per-agent hash of the last emitted event's canonical bytes. Used to\n * populate prev_event_hash on the next emit when chainEvents is on.\n * Empty string ↔ no previous event (chain restart). Reset by\n * forgetAgentKey() so reusing an agent_id after revocation doesn't\n * link to the old chain.\n */\n private lastEventHash: Map<string, string> = new Map();\n /**\n * Per-agent monotonic counter incremented by `forgetAgentKey`. An\n * emit that started before `forgetAgentKey` ran will read a stale\n * epoch and refuse to repopulate the chain tail, preventing the\n * revoked agent from inheriting a new lastEventHash from the\n * in-flight emit that the lock was holding.\n */\n private agentForgetEpoch: Map<string, number> = new Map();\n /**\n * Per-agent emit promise. Each new emit awaits the previous one so\n * the chain is constructed in order. Concurrent emits to the same\n * agent are serialised (correct); concurrent emits to different\n * agents remain parallel (fast).\n */\n private chainLocks: Map<string, Promise<void>> = new Map();\n\n constructor(config: VorimConfig) {\n this.apiKey = config.apiKey;\n this.baseUrl = (config.baseUrl || 'https://api.vorim.ai').replace(/\\/$/, '') + '/v1';\n this.timeout = config.timeout || 10000;\n this.autoSign = config.autoSign !== false;\n // Default to v1 as of 3.4.0. v0 only covers six fields and any\n // metadata, delegation context, or replayable-evidence field is\n // unsigned tail — see crypto-1 in the deep-audit findings. Callers\n // who explicitly want v0 (legacy verifier compatibility) must opt\n // in. A console.warn fires the first time an SDK instance is\n // created with v0 so the deprecation is visible in dev.\n this.canonicalForm = config.canonicalForm ?? 'v1';\n if (config.canonicalForm === 'v0') {\n try {\n // eslint-disable-next-line no-console\n console.warn(\n '[@vorim/sdk] canonicalForm=v0 is deprecated: it leaves metadata, ' +\n 'delegation context, and replayable-evidence fields unsigned. ' +\n 'Switch to canonicalForm=v1 (the new default in 3.4.0+) for full ' +\n 'tamper coverage. Pass canonicalForm: \"v0\" explicitly only if you ' +\n 'need byte-compat with verifiers older than @vorim/verify 0.2.0.',\n );\n } catch { /* ignore logger errors */ }\n }\n this.chainEvents = config.chainEvents ?? false;\n }\n\n /**\n * Register a previously-issued agent keypair so this SDK instance can\n * auto-sign events for it on emit. Use this when restoring an agent across\n * process restarts: read the agent's private_key from durable storage,\n * call useAgentKey(agentId, privateKey), and emit() will sign automatically.\n */\n useAgentKey(agentId: string, privateKeyPem: string): void {\n this.agentKeys.set(agentId, privateKeyPem);\n }\n\n /**\n * Forget an agent's signing key (e.g. after revocation). Subsequent emit()\n * calls for that agent will pass through unsigned unless a key is provided\n * inline. Also clears the per-agent chain state — re-using the same\n * agent_id after revocation does NOT link to the old chain.\n */\n forgetAgentKey(agentId: string): void {\n this.agentKeys.delete(agentId);\n this.lastEventHash.delete(agentId);\n this.chainLocks.delete(agentId);\n // Bump the per-agent epoch so any in-flight emit that completes\n // after this call refuses to write back a chain tail. Without\n // this, an emit that holds the chain lock can repopulate\n // lastEventHash after forgetAgentKey clears it, defeating the\n // revoked-agent isolation guarantee.\n this.agentForgetEpoch.set(agentId, (this.agentForgetEpoch.get(agentId) ?? 0) + 1);\n }\n\n /**\n * Cap on how many per-agent chain entries the SDK tracks. Set\n * generously — most callers will hold ≤ 1k agent_ids in memory.\n * Long-running processes that cycle through many agent_ids without\n * calling forgetAgentKey (e.g. ephemeral test agents) would\n * otherwise grow chainLocks / agentForgetEpoch / lastEventHash\n * unbounded.\n */\n private static readonly MAX_CHAIN_STATE_ENTRIES = 10_000;\n\n /**\n * Evict the oldest chain state entries when we cross the cap. Called\n * lazily from prepareEventChained — no scheduled task, no background\n * timer; only runs when the cap is breached during a real emit.\n */\n private evictChainStateIfNeeded(): void {\n if (this.chainLocks.size <= VorimSDK.MAX_CHAIN_STATE_ENTRIES) return;\n const toRemove = Math.ceil(this.chainLocks.size * 0.1); // drop oldest 10 %\n let removed = 0;\n for (const agentId of this.chainLocks.keys()) {\n if (removed >= toRemove) break;\n // Skip agents with an active key — they're in use.\n if (this.agentKeys.has(agentId)) continue;\n this.chainLocks.delete(agentId);\n this.lastEventHash.delete(agentId);\n this.agentForgetEpoch.delete(agentId);\n removed++;\n }\n }\n\n // ─── Health Check ────────────────────────────────────────────────\n\n /**\n * Ping the Vorim API to verify connectivity and API key validity.\n * Returns { status, timestamp } on success, throws VorimError on failure.\n */\n async ping(): Promise<{ status: string; timestamp: string }> {\n const response = await fetch(`${this.baseUrl.replace('/v1', '')}/health`, {\n headers: { 'User-Agent': USER_AGENT },\n signal: AbortSignal.timeout(this.timeout),\n });\n if (!response.ok) throw new VorimError(response.status, 'UNREACHABLE', 'Vorim API is not reachable');\n return response.json() as Promise<{ status: string; timestamp: string }>;\n }\n\n // ─── Agent Identity ────────────────────────────────────────────────\n\n /**\n * Register a new agent with Vorim AI.\n * Returns the agent identity and a private key (shown once).\n *\n * Side effect: the returned private_key is cached in this SDK instance's\n * in-memory keyring so subsequent emit() calls for this agent auto-sign.\n * The keyring is process-local; the caller is responsible for persisting\n * the private_key to durable storage if the agent should survive restarts.\n */\n async register(input: AgentRegistrationInput): Promise<AgentRegistrationResult> {\n const result = await this.post('/agents', input) as AgentRegistrationResult;\n if (result?.agent?.agent_id && result?.private_key) {\n this.agentKeys.set(result.agent.agent_id, result.private_key);\n }\n return result;\n }\n\n /**\n * Verify an agent's identity via the public Trust API.\n */\n async verify(agentId: string): Promise<TrustRecord> {\n return this.get(`/trust/verify/${agentId}`);\n }\n\n /**\n * Get agent details.\n */\n async getAgent(agentId: string): Promise<Agent> {\n return this.get(`/agents/${agentId}`);\n }\n\n /**\n * List all agents in the organisation.\n */\n async listAgents(params?: { page?: number; per_page?: number; status?: string }): Promise<{ agents: Agent[]; meta: any }> {\n const qs = new URLSearchParams(params as any).toString();\n return this.get(`/agents${qs ? '?' + qs : ''}`);\n }\n\n /**\n * Update an agent's metadata.\n */\n async updateAgent(agentId: string, updates: Partial<Pick<Agent, 'name' | 'description' | 'status' | 'capabilities'>>): Promise<Agent> {\n return this.patch(`/agents/${agentId}`, updates);\n }\n\n /**\n * Revoke an agent (permanent deactivation).\n */\n async revoke(agentId: string): Promise<void> {\n await this.delete(`/agents/${agentId}`);\n }\n\n // ─── Permissions ──────────────────────────────────────────────────\n\n /**\n * Check if an agent has a specific permission scope.\n * Target: < 5ms response via Redis cache.\n */\n async check(agentId: string, scope: PermissionScope): Promise<PermissionCheckResult> {\n return this.post(`/agents/${agentId}/permissions/verify`, { scope });\n }\n\n /**\n * Grant a permission scope to an agent.\n */\n async grant(agentId: string, scope: PermissionScope, options?: {\n valid_until?: string;\n rate_limit?: { max: number; window: string };\n }): Promise<any> {\n return this.post(`/agents/${agentId}/permissions`, { scope, ...options });\n }\n\n /**\n * List all active permissions for an agent.\n */\n async listPermissions(agentId: string): Promise<any[]> {\n return this.get(`/agents/${agentId}/permissions`);\n }\n\n /**\n * Revoke a specific permission scope from an agent.\n */\n async revokePermission(agentId: string, scope: PermissionScope): Promise<any> {\n return this.delete(`/agents/${agentId}/permissions/${scope}`);\n }\n\n // ─── Agent-to-Agent Identity Delegation (VAIP -02 § 5) ──────────────\n\n /**\n * Delegate the right to act on this agent's behalf to another agent\n * in the same org, with a strict subset of this agent's scopes.\n *\n * Multi-hop chains are supported up to depth 32. Scope subset is\n * enforced at every hop. Audit events emitted by the delegate carry\n * the chain context (`on_behalf_of`, `delegator_agent_id`,\n * `delegation_chain_id`, `delegation_depth`) so a verifier walking\n * the bundle can reconstruct the full chain.\n *\n * @example\n * ```ts\n * const chain = await vorim.delegateToAgent('agid_parent_abc', {\n * delegate_agent_id: 'agid_child_xyz',\n * scopes_delegated: ['agent:read', 'agent:execute'],\n * max_chain_depth: 1, // delegate may make ONE further hop\n * valid_until: '2026-12-31T00:00:00Z',\n * });\n * console.log(chain.public_chain_id); // chain_<hex>\n * ```\n */\n async delegateToAgent(\n delegatorAgentId: string,\n input: {\n delegate_agent_id: string;\n scopes_delegated: PermissionScope[];\n max_chain_depth?: number;\n valid_until?: string;\n /**\n * Optional Ed25519-signed delegation link (VAIP -02 § 5). When\n * provided, the server verifies the signature against the\n * delegator's stored public key, persists alongside the chain\n * row, and exports it in bundle delegation_tokens so the chain\n * is offline-verifiable by `@vorim/verify`. Compute via\n * {@link signDelegationLink} or set manually if signing\n * elsewhere.\n */\n signed_link?: {\n claims: DelegationLinkClaims;\n signature: string;\n };\n },\n ): Promise<AgentDelegationRecord> {\n return this.post(`/agents/${delegatorAgentId}/delegations`, input);\n }\n\n /**\n * Sign a delegation link with the delegator's private key. Returns\n * the signed link in the shape accepted by `delegateToAgent`'s\n * `signed_link` field.\n *\n * The signature is Ed25519 over the RFC 8785 JCS-canonical bytes of\n * the claims object. Same algorithm the server and `@vorim/verify`\n * use for verification.\n *\n * Use this when the delegator's private key is in this SDK's\n * keyring (i.e. set via `register()` or `useAgentKey()`).\n *\n * @example\n * ```ts\n * const signed = await vorim.signDelegationLink({\n * v: 0,\n * type: 'vaip-delegation-link',\n * chain_id: 'chain_abc', // server returns this on first delegation\n * depth: 1,\n * delegator: 'agid_parent',\n * delegate: 'agid_child',\n * scopes: ['agent:read', 'agent:execute'],\n * max_chain_depth: 1,\n * valid_from: new Date().toISOString(),\n * valid_until: null,\n * parent_link_hash: null,\n * });\n * ```\n */\n async signDelegationLink(\n claims: DelegationLinkClaims,\n ): Promise<{ claims: DelegationLinkClaims; signature: string }> {\n const key = this.agentKeys.get(claims.delegator);\n if (!key) {\n throw new VorimError(\n 400,\n 'NO_AGENT_KEY',\n `SDK has no private key for delegator ${claims.delegator}`,\n );\n }\n // Sign using the SDK's local JCS. Byte-equivalent to shared-types\n // and the server (enforced by scripts/check-replay-parity.sh).\n const bytes = jcsCanonicalise(claims as unknown as Record<string, unknown>);\n const signature = await this.sign(bytes, key);\n return { claims, signature };\n }\n\n /**\n * List active identity-chain entries this agent participates in\n * (either as delegator or delegate). Useful for showing the current\n * delegation graph in an admin UI.\n */\n async listAgentDelegations(agentId: string): Promise<AgentDelegationRecord[]> {\n return this.get(`/agents/${agentId}/delegations`);\n }\n\n /**\n * Walk a delegation chain by its public id. Returns the full chain\n * in depth order.\n */\n async getDelegationChain(\n agentId: string,\n chainId: string,\n ): Promise<AgentDelegationRecord[]> {\n return this.get(`/agents/${agentId}/delegation-chain/${chainId}`);\n }\n\n /**\n * Revoke this agent's delegation in a given chain. Cascades to all\n * descendants beneath this agent's depth in the chain.\n */\n async revokeAgentDelegation(\n agentId: string,\n chainId: string,\n ): Promise<{ revoked: number }> {\n return this.delete(`/agents/${agentId}/delegations/${chainId}`);\n }\n\n // ─── Audit ────────────────────────────────────────────────────────\n\n /**\n * Emit an audit event for an agent action.\n *\n * By default (autoSign=true on the SDK), the event is signed with the\n * agent's private key before it leaves the process. Set options.sign=false\n * to skip signing (e.g. for testing). If the SDK has no private key for the\n * event's agent_id, the event is sent unsigned and a warning is not\n * raised — callers that require signing should check event.signature on\n * the returned event after a round-trip, or use a server-side enforcement\n * flag (VORIM_VERIFY_AUDIT_SIGNATURES).\n */\n async emit(event: AuditEventInput, options?: { sign?: boolean }): Promise<{ ingested: number }> {\n const prepared = await this.prepareEvent(event, options?.sign);\n const result = await this.post('/audit/events', { events: [prepared] }) as { ingested: number };\n this.warnOnPartialIngest(1, result?.ingested ?? 0);\n return result;\n }\n\n /**\n * Emit a batch of audit events (up to 1,000). Each event is signed\n * independently using its agent_id to look up the signing key. See\n * {@link VorimSDK.emit} for signing behaviour and opt-out.\n *\n * When the server returns `ingested < events.length` (e.g. one event\n * referenced an unknown agent_id), a `console.warn` is emitted so\n * operators don't silently lose audit rows. The result is returned\n * unchanged so callers can inspect / act on it.\n */\n async emitBatch(events: AuditEventInput[], options?: { sign?: boolean }): Promise<{ ingested: number }> {\n const prepared = await Promise.all(events.map(e => this.prepareEvent(e, options?.sign)));\n const result = await this.post('/audit/events', { events: prepared }) as { ingested: number };\n this.warnOnPartialIngest(events.length, result?.ingested ?? 0);\n return result;\n }\n\n private warnOnPartialIngest(submitted: number, ingested: number): void {\n if (ingested < submitted) {\n try {\n // eslint-disable-next-line no-console\n console.warn(\n `[@vorim/sdk] partial ingest: server stored ${ingested}/${submitted} events. ` +\n `Common causes: unknown agent_id (cross-org or typo), invalid signature when strict ` +\n `verification is enabled.`,\n );\n } catch {\n /* ignore logger errors */\n }\n }\n }\n\n /**\n * Internal: prepare an event for transmission. Auto-signs if the SDK has a\n * key for this agent and signing isn't explicitly opted out. Pre-existing\n * signatures on the event are respected (caller-signed events are not\n * re-signed). Per-agent failure is non-fatal: if signing throws, the event\n * still sends unsigned so a single bad key doesn't break a batch.\n *\n * Canonical-form dispatch:\n * - If the event already carries `canonical_form`, that wins (caller\n * opted in/out for this specific event).\n * - Otherwise the SDK-level `canonicalForm` (config) applies.\n * - v0 signs the pipe-joined 6 fields. v1 signs the RFC 8785 JCS\n * bytes over the full event minus signature and canonical_form,\n * and the event goes on the wire with `canonical_form: \"v1\"`.\n *\n * Chain construction:\n * - When chainEvents is on, the event gets `prev_event_hash` set to\n * the SHA-256 of the previous event's canonical bytes for the\n * same agent, set BEFORE the signature is computed (so v1\n * signatures cover the chain link).\n * - Chain ops are serialised per-agent via `chainLocks` so\n * concurrent emits to the same agent build a deterministic chain.\n */\n private async prepareEvent(\n event: AuditEventInput,\n signOverride?: boolean\n ): Promise<AuditEventInput> {\n const shouldSign = signOverride ?? this.autoSign;\n if (!shouldSign && !this.chainEvents) return event;\n // Even unsigned events participate in the chain if chaining is on.\n if (this.chainEvents) {\n return this.prepareEventChained(event, shouldSign);\n }\n if (!shouldSign) return event;\n if (event.signature) return event;\n return this.signEventNow(event, shouldSign);\n }\n\n /** Serialise per-agent and apply chain hash + sign. */\n private async prepareEventChained(\n event: AuditEventInput,\n shouldSign: boolean,\n ): Promise<AuditEventInput> {\n const agentId = event.agent_id;\n this.evictChainStateIfNeeded();\n const prior = this.chainLocks.get(agentId) ?? Promise.resolve();\n let release!: () => void;\n const next = new Promise<void>(r => { release = r; });\n this.chainLocks.set(agentId, prior.then(() => next));\n await prior;\n // Snapshot the forget-epoch BEFORE doing any chain work. If the\n // epoch advances while we're in flight, forgetAgentKey() ran and\n // we must not write back the chain tail.\n const startEpoch = this.agentForgetEpoch.get(agentId) ?? 0;\n try {\n // Insert prev_event_hash if we have a previous bytes-hash for this\n // agent. First event after enable / process restart has none.\n const prev = this.lastEventHash.get(agentId);\n const eventWithPrev: AuditEventInput = prev\n ? { ...event, prev_event_hash: prev }\n : event;\n\n // Sign (or pass through unsigned if signing not requested / no\n // key). If forgetAgentKey runs between the lock acquisition and\n // the sign call, skip signing — the key has been revoked and\n // we must not use it. The event still ships unsigned, which the\n // caller can detect via the missing `signature` field.\n const epochBeforeSign = this.agentForgetEpoch.get(agentId) ?? 0;\n const keyStillPresent = this.agentKeys.has(agentId);\n const prepared = shouldSign && !eventWithPrev.signature && keyStillPresent && epochBeforeSign === startEpoch\n ? await this.signEventNow(eventWithPrev, shouldSign)\n : eventWithPrev;\n\n // Record this event's canonical bytes hash as the chain's new tail.\n // Use the v1 form for v1 events (matches what the signature covered);\n // v0 form for v0 events.\n const wireForm = (prepared.canonical_form as 'v0' | 'v1' | undefined) ?? 'v0';\n const bytes = wireForm === 'v1' ? canonicalPayloadV1(prepared) : canonicalPayloadV0(prepared);\n try {\n const tail = await hashPreviousEvent(bytes);\n // Only commit the tail if forgetAgentKey didn't run while we\n // were in flight. Without this guard the revoked agent\n // silently inherits a new chain tail from the in-flight emit.\n if ((this.agentForgetEpoch.get(agentId) ?? 0) === startEpoch) {\n this.lastEventHash.set(agentId, tail);\n }\n } catch {\n // hashing failure (extreme edge) is non-fatal; chain restarts next time\n this.lastEventHash.delete(agentId);\n }\n return prepared;\n } finally {\n release();\n }\n }\n\n /** Sign an event right now, no chain handling.\n *\n * On signing failure (malformed key, Web Crypto unavailable, etc.)\n * the event ships with its requested `canonical_form` preserved and\n * a one-line warning is logged via `console.warn`. The previous\n * behaviour silently dropped both the signature AND the\n * canonical_form marker, which caused the event to be classified\n * server-side as a v0 `signature_missing` instead of a v1 attempt\n * that failed — making the breakage invisible to operators. */\n private async signEventNow(\n event: AuditEventInput,\n _shouldSign: boolean,\n ): Promise<AuditEventInput> {\n const key = this.agentKeys.get(event.agent_id);\n if (!key) return event;\n const form: 'v0' | 'v1' = (event.canonical_form as 'v0' | 'v1' | undefined) ?? this.canonicalForm;\n const withForm: AuditEventInput = form === 'v0'\n ? event\n : { ...event, canonical_form: 'v1' };\n try {\n const payload = form === 'v1' ? canonicalPayloadV1(withForm) : canonicalPayloadV0(withForm);\n const signature = await this.sign(payload, key);\n return { ...withForm, signature };\n } catch (err) {\n // Surface the failure rather than silently dropping the signature.\n // Operators need a signal to detect broken signing at the SDK\n // boundary; verifiers will otherwise misattribute the cause.\n try {\n // eslint-disable-next-line no-console\n console.warn(\n // Don't echo agent_id verbatim — emit a short prefix for\n // correlation while keeping log-sink content lower-cardinality\n // and avoiding accidental leakage of org-identifiable ids.\n `[@vorim/sdk] signing failed for agent_id=${(event.agent_id ?? '').slice(0, 12)}... form=${form}: ${(err as Error)?.message ?? err}. ` +\n `Event will be emitted unsigned with canonical_form retained.`,\n );\n } catch {\n /* ignore logger errors */\n }\n // Preserve canonical_form so the event is still classified as a\n // v1 attempt server-side, just without a signature. This makes\n // the breakage detectable via the signature_missing + v1 form\n // pair instead of looking like a legacy v0 unsigned event.\n return withForm;\n }\n }\n\n /**\n * Export a signed audit bundle for a date range.\n */\n async exportAudit(from: string, to: string, format: string = 'json'): Promise<any> {\n return this.post('/audit/export', { from, to, format });\n }\n\n // ─── API Keys ──────────────────────────────────────────────────────\n\n /**\n * List all API keys for the organisation.\n */\n async listApiKeys(): Promise<any[]> {\n return this.get('/api-keys');\n }\n\n /**\n * Create a new API key.\n */\n async createApiKey(name: string, options?: { scopes?: string[]; expires_at?: string }): Promise<any> {\n return this.post('/api-keys', { name, ...options });\n }\n\n /**\n * Revoke an API key.\n */\n async deleteApiKey(keyId: string): Promise<{ revoked: boolean }> {\n return this.delete(`/api-keys/${keyId}`);\n }\n\n // ─── Ephemeral Agents ──────────────────────────────────────────────\n\n /**\n * Register an ephemeral agent with W3C did:key identity.\n * The agent auto-expires after the specified TTL.\n *\n * Side effect: the returned private_key is cached in this SDK instance's\n * in-memory keyring (matching register()).\n */\n async registerEphemeral(input: {\n capabilities: string[];\n scopes: string[];\n ttl_seconds?: number;\n }): Promise<any> {\n const result = await this.post('/agents/ephemeral', input);\n const agentId: string | undefined = result?.agent?.agent_id ?? result?.did_key;\n if (agentId && result?.private_key) {\n this.agentKeys.set(agentId, result.private_key);\n }\n return result;\n }\n\n // ─── Credential Delegation ──────────────────────────────────────────\n\n /**\n * Register an OAuth provider for credential delegation.\n */\n async registerProvider(input: {\n provider_key: string;\n display_name?: string;\n client_id: string;\n client_secret: string;\n auth_url: string;\n token_url: string;\n revoke_url?: string;\n scopes_available?: string[];\n }): Promise<any> {\n return this.post('/credentials/providers', input);\n }\n\n /**\n * List registered OAuth providers.\n */\n async listProviders(): Promise<any[]> {\n return this.get('/credentials/providers');\n }\n\n /**\n * Store an OAuth connection (user's authorized tokens).\n */\n async storeConnection(input: {\n provider_id: string;\n refresh_token: string;\n scopes_granted: string[];\n external_account_id?: string;\n }): Promise<any> {\n return this.post('/credentials/connections', input);\n }\n\n /**\n * List OAuth connections.\n */\n async listConnections(): Promise<any[]> {\n return this.get('/credentials/connections');\n }\n\n /**\n * Delegate a credential to an agent.\n * The agent will be able to request short-lived access tokens\n * for the delegated scopes without ever seeing the refresh token.\n */\n async delegateCredential(input: {\n connection_id: string;\n agent_id: string;\n scopes_delegated: string[];\n max_requests_per_hr?: number;\n valid_until?: string;\n }): Promise<any> {\n return this.post('/credentials/delegations', input);\n }\n\n /**\n * List credential delegations for the organisation or a specific agent.\n */\n async listDelegations(agentId?: string): Promise<any[]> {\n const params = agentId ? `?agent_id=${agentId}` : '';\n return this.get(`/credentials/delegations${params}`);\n }\n\n /**\n * Revoke a credential delegation (cascades to delegation chains).\n */\n async revokeDelegation(delegationId: string): Promise<{ revoked: boolean }> {\n return this.delete(`/credentials/delegations/${delegationId}`);\n }\n\n /**\n * Request a short-lived access token for an agent.\n * The agent must have an active credential delegation.\n * The refresh token is never exposed — the platform proxies the request.\n */\n async requestToken(input: {\n agent_id: string;\n scope: string;\n provider_id?: string;\n }): Promise<{\n access_token: string;\n token_type: string;\n expires_in: number;\n scope: string;\n delegation_id: string;\n }> {\n return this.post('/credentials/token', input);\n }\n\n // ─── Signing ──────────────────────────────────────────────────────\n\n /**\n * Sign a payload with an Ed25519 private key (client-side).\n * Uses the Web Crypto API or Node.js crypto.\n */\n async sign(payload: string, privateKeyPem: string): Promise<string> {\n if (typeof globalThis.crypto?.subtle !== 'undefined') {\n // Web Crypto API\n const keyData = this.pemToArrayBuffer(privateKeyPem);\n const key = await globalThis.crypto.subtle.importKey(\n 'pkcs8', keyData, { name: 'Ed25519' }, false, ['sign']\n );\n const signature = await globalThis.crypto.subtle.sign(\n 'Ed25519', key, new TextEncoder().encode(payload)\n );\n return `ed25519:${this.arrayBufferToBase64(signature)}`;\n } else {\n // Node.js crypto fallback\n const crypto = await import('node:crypto');\n const sign = crypto.sign(null, Buffer.from(payload), privateKeyPem);\n return `ed25519:${sign.toString('base64')}`;\n }\n }\n\n // ─── HTTP Client ──────────────────────────────────────────────────\n\n private async get(path: string): Promise<any> {\n return this.request('GET', path);\n }\n\n private async post(path: string, body: any): Promise<any> {\n return this.request('POST', path, body);\n }\n\n private async patch(path: string, body: any): Promise<any> {\n return this.request('PATCH', path, body);\n }\n\n private async delete(path: string): Promise<any> {\n return this.request('DELETE', path);\n }\n\n private async request(method: string, path: string, body?: any): Promise<any> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(`${this.baseUrl}${path}`, {\n method,\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n 'User-Agent': USER_AGENT,\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const errBody = await response.json().catch(() => ({})) as Record<string, any>;\n throw new VorimError(\n response.status,\n errBody.error?.code || 'UNKNOWN_ERROR',\n errBody.error?.message || `HTTP ${response.status}`,\n errBody.error?.details\n );\n }\n\n const json = await response.json() as Record<string, any>;\n return json.data;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n private pemToArrayBuffer(pem: string): ArrayBuffer {\n const b64 = pem.replace(/-----[^-]+-----/g, '').replace(/\\s/g, '');\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n }\n\n private arrayBufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = '';\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary);\n }\n}\n\nexport class VorimError extends Error {\n constructor(\n public status: number,\n public code: string,\n message: string,\n public details?: Record<string, unknown>\n ) {\n super(message);\n this.name = 'VorimError';\n }\n}\n\n// ─── Convenience export ──────────────────────────────────────────────\n\nexport default function createVorim(config: VorimConfig): VorimSDK {\n return new VorimSDK(config);\n}\n\n// Re-export types for consumers\nexport type {\n Agent, AgentRegistrationInput, AgentRegistrationResult,\n TrustRecord, AuditEventInput, AuditEventType, AuditResult,\n PermissionScope, PermissionCheckResult, AgentStatus,\n AgentDelegationRecord, DelegationLinkClaims,\n} from './types.js';\n\n// Re-export replayable evidence helpers (VAIP -02 schema field hashing)\nexport {\n hashTool, hashToolCatalogue, hashSystemPrompt, hashPreviousEvent,\n jcsCanonicalise, prepareReplayContext, CANONICAL_TOOL_CATALOGUE_VERSION,\n} from './replay.js';\nexport type { CatalogueTool, ReplayInputs, ReplayContext } from './replay.js';\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vorim/sdk",
3
- "version": "3.3.2",
3
+ "version": "3.4.0",
4
4
  "description": "Official TypeScript SDK for Vorim AI — AI Agent Identity, Permissions & Audit",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",