@volidator/node
v1.0.7
Published
Zero-knowledge audit logging SDK for Node.js, Next.js, and edge runtimes
Maintainers
Readme
Volidator Node.js SDK
Zero-knowledge, server-blind audit logging for Node.js, Next.js, and edge runtimes.
Volidator encrypts every log entry locally — on your server — before sending it. The Volidator backend stores only ciphertext and blind indexes. Your plaintext data never leaves your infrastructure unencrypted.
Website & Sign Up | Developer Documentation
What is Volidator?
Volidator is the developer-first, zero-knowledge audit log infrastructure built for modern applications, enterprise B2B SaaS, and autonomous AI agents. By utilizing local AES-256-GCM encryption and blind indexing (HMAC-SHA-256) on your servers before ingestion, Volidator allows you to store, query, and stream audit trails without ever holding or exposing raw PII (Personally Identifiable Information) or sensitive activity data (though configurable if you want to host PII/PHI with us).
Why Volidator? (Pain Points We Solve)
Traditional logging tools force a dangerous compromise: either send raw customer data to a third-party logging vendor (creating security liabilities, compliance issues, and API keys leakage risks), or spend months building a custom, secure compliance database in-house.
Volidator solves this with a Zero-Knowledge, High-Accountability Audit Ledger:
- Enterprise Compliance in Minutes: Unlocks enterprise-ready audit logging matching SOC 2 (CC6.x), ISO 27001 (A.12.4), HIPAA, and GDPR standards under 5 minutes.
- Zero Trust Security: Even if Volidator's databases were compromised, hackers see only randomized ciphertext. Decryption keys live exclusively in your server environment variables and the user's browser hash fragments.
- AI Agent Attribution & Accountability: Structurally validates the caller type (
human,agent, orservice) at Layer 0 (under 1µs) using prefix taxonomies (val_human_,val_agent_,val_service_). Automatically detects credential handovers if human keys are used inside agent contexts. - WebAuthn Biometric Attestation: Cryptographically binds high-risk human operations (like approvals) using browser WebAuthn browser enclaves (FaceID/TouchID/YubiKey) with atomic challenge invalidation to prevent concurrent replay attacks.
- Asynchronous Context Propagation: Automatically tracks reasoning rationales, tracing spans, and causal logical clocks across complex asynchronous loops using thread-local V8
AsyncLocalStoragestores. - Claim-Check Large Payload Support: Streams encrypted log components exceeding 30KB automatically to secure Cloudflare R2 object storage, maintaining instant query performance while keeping zero-knowledge client decryption intact.
- Instant Customer-Facing Dashboards: Embed fully-interactive, securely hydrated log tables inside your React frontends using our signed JIT tokens.
Who is it for?
- B2B SaaS Engineering Teams: Developers who need to provide enterprise tenants with search, filter, and CSV exports of system events.
- Security & Compliance Teams: Organizations aiming to achieve security certifications without expanding their data privacy liability or telemetry footprint.
- AI & Agentic App Developers: Builders establishing guardrails and debug logs for autonomous systems to audit agent decisions, LLM outputs, and automated tool calls.
Table of Contents
- Install
- Environment Setup
- Initialize the Client
- Log an Event
- Pass Request Context
- Telemetry Configuration
- PII Redaction
- JIT Hydration (referenceKeys)
- Keyring Rotation
- Embed Token
- Compliance Helpers
- Next.js Middleware
- Auth Plugins
@volidator/react- AI Agent Auditing (VolidatorAgent)
- Batch Ingestion (logBatch)
- Large Payloads (Claim Check Pattern)
- Fluent Batcher (batcher)
- OpenTelemetry Integration (otel)
- Flight Data Recorder (FDR)
1. Install
npm install @volidator/node2. Environment Setup
Generate a secure 32-byte encryption key (64 hex characters) with the vol-dek- prefix:
node -e "const b=require('crypto').randomBytes(32);console.log('vol-dek-'+b.toString('hex'))"Then add it as an environment secret:
# Authenticates your server with the Volidator ingestion endpoint
VOLIDATOR_API_KEY="val_live_xxxxxxxx..."
# AES-256-GCM encryption key — your data is encrypted with this before leaving your server
VOLIDATOR_ENCRYPTION_KEY="vol-dek-xxxxxxxx..."3. Initialize the Client
Create one instance per application and reuse it. Do not instantiate per-request.
import { VolidatorClient } from "@volidator/node";
export const volidator = new VolidatorClient({
apiKey: process.env.VOLIDATOR_API_KEY!,
encryptionKey: process.env.VOLIDATOR_ENCRYPTION_KEY!,
// Optional configuration for delivery retries and sizes:
maxRetries: 3, // Retry up to 3 times on transient errors (default: 3)
maxMetadataSize: 10240, // Cap serialized metadata size at 10KB (default: 10KB)
onDeliveryFailure: (payload, error) => {
// Callback invoked when a log permanently fails to deliver after all retries
console.error(`Log delivery failed permanently for action "${payload.action}": ${error.message}`);
}
});Transient Errors & Retry Strategy
By default, the SDK automatically retries log delivery on network errors or 5xx server responses using an exponential backoff strategy (delays: ~500ms → ~1500ms → ~4500ms). Both single log() and batch logBatch() operations utilize this retry strategy. Client errors (4xx) are never retried.
If a batch ingestion operation (logBatch()) fails after exhausting all retries, the onDeliveryFailure callback will be invoked once for each individual log payload contained in that batch.
⚠️ Serverless / Edge Function execution time caveat: Worst-case retry attempts take up to ~6.5 seconds. If you are running inside a serverless or Edge environment (e.g. Vercel, Next.js Edge, Cloudflare Workers) with strict duration limits:
- Wrap log calls in
ctx.waitUntil(volidator.log(...))orctx.waitUntil(volidator.logBatch(...))so the worker doesn't block response delivery.- Or reduce
maxRetriesto1(or0to disable retries) to avoid hitting runtime execution limits.
Metadata Limits & Truncation
Log metadata is subject to a hard depth limit of 5 levels and string value length limit of 1000 characters. In non-production environments (NODE_ENV !== 'production'), the SDK will emit warnings in the console if any metadata is truncated.
4. Log an Event
await volidator.log({
actor: "usr_12345", // Who performed the action
action: "user.login.success", // What happened (use dot notation)
target: "workspace_abc789", // What was affected
metadata: {
deviceName: "MacBook Pro",
authProvider: "Google OAuth",
},
});log() returns true if the event was accepted, false if delivery failed. It never throws — failures are swallowed and logged to console.error.
5. Pass Request Context
Pass your framework's Request object directly. The SDK extracts IP, User-Agent, and geolocation headers automatically.
// Next.js App Router / Cloudflare Workers / Express
await volidator.log({
actor: session.userId,
action: "settings.update",
req: request, // Web API Request or Node.js IncomingMessage
metadata: { fieldChanged: "email_address" },
});Supported request formats:
Request— Next.js App Router, Cloudflare Workers, BunIncomingMessage— Node.jshttp, Express, Fastify
6. Telemetry Configuration
Control how IP, User-Agent, and location data are handled. Choose a preset, then override individual fields as needed.
| Preset | IP | User-Agent | Location |
|---|---|---|---|
| "strict" | skip | skip | disabled |
| "standard" (default) | anonymized (hashed) | parsed to browser/OS | country + region |
| "full" | stored as-is | stored as-is | country + region + city |
const volidator = new VolidatorClient({
apiKey: process.env.VOLIDATOR_API_KEY!,
encryptionKey: process.env.VOLIDATOR_ENCRYPTION_KEY!,
telemetry: {
preset: "standard", // baseline
ip: "skip", // override: don't store IP at all
location: false, // override: disable geolocation
},
});7. PII Redaction
For fields containing sensitive data that should never be stored — even in encrypted form — use redactKeys. The value is replaced with [REDACTED:fieldName] before encryption.
const volidator = new VolidatorClient({
apiKey: process.env.VOLIDATOR_API_KEY!,
encryptionKey: process.env.VOLIDATOR_ENCRYPTION_KEY!,
redactKeys: ["actor", "metadata.socialSecurityNumber", "metadata.email"],
});Supported key patterns:
"actor"— the top-level actor field"target"— the top-level target field"metadata.fieldName"— any metadata field by name
Blind indexes are still computed from the original value before redaction, so the Volidator dashboard can still filter and search by actor/target even after redaction.
8. JIT Hydration (referenceKeys)
JIT (Just-In-Time) Hydration lets you store a non-sensitive reference ID instead of PII, while preserving full dashboard display names. PII never reaches Volidator's servers.
When you configure referenceKeys, you pass fields as { id, pii } objects:
id— the internal identifier stored as[REF:id]in the encrypted logpii— the real value used only to compute the blind index, then discarded
The dashboard resolves [REF:id] to a display name at render time by sending a postMessage request back to your application. See the @volidator/react section for the client-side hook.
const volidator = new VolidatorClient({
apiKey: process.env.VOLIDATOR_API_KEY!,
encryptionKey: process.env.VOLIDATOR_ENCRYPTION_KEY!,
referenceKeys: ["actor"],
});
await volidator.log({
// Pass { id, pii } for any field in referenceKeys
actor: { id: "usr_890", pii: "[email protected]" },
action: "document.deleted",
target: "doc_4521",
});
// Stored: actor = "[REF:usr_890]"
// Blind index computed from "[email protected]" — search still worksreferenceKeys and redactKeys can coexist. If a field is in both, referenceKeys takes precedence.
9. Keyring Rotation
Rotate your encryption key without re-encrypting historical logs. Provide a keyring (all active key versions) and activeEncryptionKeyId (the key used for new writes). Old logs are decrypted with whichever key was active when they were written.
const volidator = new VolidatorClient({
apiKey: process.env.VOLIDATOR_API_KEY!,
keyring: {
v1: process.env.VOLIDATOR_KEY_V1!, // old — decrypts historical logs
v2: process.env.VOLIDATOR_KEY_V2!, // new — encrypts all new writes
},
activeEncryptionKeyId: "v2",
});Constraints:
- Keyring size is capped at 5 keys (security + performance bound).
activeEncryptionKeyIdmust be present in thekeyringobject.
10. Embed Token
Generate a signed JWT that scopes the embeddable dashboard widget to a specific actor, target, or tenant. This is called server-side; the returned embedUrl is dropped directly into an <iframe>.
const volidator = new VolidatorClient({
apiKey: process.env.VOLIDATOR_API_KEY!,
encryptionKey: process.env.VOLIDATOR_ENCRYPTION_KEY!,
// Required for generateEmbedToken():
projectId: process.env.VOLIDATOR_PROJECT_ID!,
clientSecret: process.env.VOLIDATOR_CLIENT_SECRET!,
});
const { embedUrl } = await volidator.generateEmbedToken({
actorId: session.userId, // Scope to this actor's logs
scope: "actor", // "actor" | "target" | "tenant" | "all" | "auditor"
expiresIn: "1h", // Max: 1h for actor/target/tenant; 7d for auditor
hostOrigin: "https://app.yourcompany.com", // Enables strict postMessage origin validation
view: {
columns: ["actor", "action", "metadata.ipAddress", "createdAt"],
defaultFilter: { action: "user.login" },
},
});
// In your API route response:
return Response.json({ embedUrl });// In your React component:
<iframe src={embedUrl} width="100%" height="600" />11. Compliance Helpers
volidator.compliance provides pre-tagged methods for common SOC 2 and ISO 27001 audit events. Each method automatically appends the correct soc2_control and iso27001 keys to the log metadata.
// Access provisioning
await volidator.compliance.accessGranted({ actor: "admin_01", target: "usr_890" });
await volidator.compliance.accessRevoked({ actor: "admin_01", target: "usr_890" });
// Data movement
await volidator.compliance.dataExported({
actor: "usr_123",
metadata: { exportFormat: "csv", rowCount: 5420 },
});
// System changes
await volidator.compliance.systemConfigChanged({
actor: "usr_123",
metadata: { setting: "mfa_enforcement", newValue: "required" },
});
// Authentication
await volidator.compliance.mfaEnabled({ actor: "usr_890" });| Method | Action stored | SOC 2 | ISO 27001 |
|---|---|---|---|
| accessGranted | access.granted | CC6.1 | A.9.2.1 |
| accessRevoked | access.revoked | CC6.1 | A.9.2.6 |
| dataExported | data.exported | CC6.6 | A.12.4.1 |
| systemConfigChanged | system.config_changed | CC6.2 | A.12.1.2 |
| mfaEnabled | mfa.enabled | CC6.3 | A.9.4.2 |
12. Next.js Middleware
The withVolidator wrapper injects a request-scoped volidator object into every Next.js App Router handler. It automatically extracts IP, User-Agent, and geolocation from the incoming request and merges it into every log() and compliance.*() call — no manual req passing needed.
import { withVolidator } from "@volidator/node/next";
import { volidator } from "@/lib/volidator";
export const POST = withVolidator(volidator, async (req: Request, ctx) => {
await ctx.volidator.log({
actor: session.userId,
action: "invoice.created",
target: invoiceId,
});
// Compliance methods also receive full telemetry context:
await ctx.volidator.compliance.dataExported({ actor: session.userId });
return Response.json({ ok: true });
});13. Auth Plugins
Auth plugins extend withVolidator to automatically inject the authenticated user's ID as actor on every log call.
Clerk
import { createClerkAudit } from "@volidator/node/clerk";
import { auth } from "@clerk/nextjs/server";
import { volidator } from "@/lib/volidator";
const withClerkAudit = createClerkAudit({ client: volidator, getAuth: auth });
export const DELETE = withClerkAudit(async (req: Request, ctx) => {
// ctx.session — Clerk session object
// actor is automatically set to ctx.session.userId
await ctx.volidator.log({ action: "record.deleted", target: recordId });
return Response.json({ ok: true });
});Universal (Auth0, NextAuth, BetterAuth, Kinde, Supabase, ...)
import { createUniversalAudit } from "@volidator/node/universal";
import { getServerSession } from "next-auth";
import { volidator } from "@/lib/volidator";
const withAudit = createUniversalAudit({
client: volidator,
getSession: (req) => getServerSession(),
getUserId: (req, session) => session?.user?.id,
// Optionally inject extra metadata into every log call:
getMetadata: (req, session) => ({ userEmail: session?.user?.email }),
});
export const PUT = withAudit(async (req: Request, ctx) => {
await ctx.volidator.log({ action: "profile.updated" });
return Response.json({ ok: true });
});14. @volidator/react
The @volidator/react package provides the useVolidatorHydration hook, which manages the JIT Hydration postMessage handshake between your application and the Volidator embed iframe.
npm install @volidator/reactimport { useRef } from "react";
import { useVolidatorHydration } from "@volidator/react";
export function AuditLogPage({ embedUrl }: { embedUrl: string }) {
const iframeRef = useRef<HTMLIFrameElement>(null);
useVolidatorHydration({
iframeRef,
volidatorOrigin: "https://dash.volidator.com",
resolveActors: async (ids) => {
// Called with a deduplicated batch of reference IDs from decrypted logs.
// Return a map of id → { name, avatarUrl? }.
const res = await fetch("/api/users/resolve", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ ids }),
});
return res.json();
},
});
return <iframe ref={iframeRef} src={embedUrl} width="100%" height="600" />;
}The hook:
- Listens for
VOLIDATOR_RESOLVE_ACTORSmessages from the iframe. - Validates
event.originstrictly againstvolidatorOrigin(wildcard"*"is not accepted). - Calls
resolveActors(ids)with only the IDs not already in the local cache. - Posts the resolution map back into the iframe as
VOLIDATOR_RESOLVE_RESPONSE. - Cleans up the event listener on component unmount.
15. AI Agent Auditing (VolidatorAgent)
Volidator provides a specialized compliance logging namespace tailored for autonomous AI systems, LLMs, and multi-agent chains. Access these methods via volidator.agent.*.
Every call automatically appends the correct mapping metadata for EU AI Act compliance, NIST AI RMF guidelines, SOC 2, and ISO 27001.
// 1. Log an agent tool call or external API request
await volidator.agent.toolCall({
actor: "writer-agent-v1",
traceId: runId,
spanId: spanId,
toolName: "fetch_news",
toolInput: { topic: "AI Act updates" },
toolOutput: { results: ["..." ] },
success: true,
latencyMs: 140,
});
// 2. Log an autonomous decision made by the model
await volidator.agent.decision({
actor: "writer-agent-v1",
traceId: runId,
decision: "publish_article",
rationale: "article scoring passed verification checks",
confidenceScore: 0.96,
modelId: "claude-3-5-sonnet",
});
// 3. Request human oversight/escalation (EU AI Act Article 14)
await volidator.agent.escalation({
actor: "writer-agent-v1",
traceId: runId,
reason: "article output score fell below threshold",
urgency: "medium",
blockedAction: "auto_publish",
});
// 4. Log suspected anomalies, injections, or system security events
await volidator.agent.anomaly({
actor: "guardrail-shield",
traceId: runId,
description: "jailbreak prompt pattern detected in input stream",
severity: "critical",
anomalyType: "prompt_injection",
});
// 5. Log a model refusal based on safety alignment rules
await volidator.agent.refusal({
actor: "writer-agent-v1",
traceId: runId,
refusedInstruction: "write code to extract system logs",
reason: "corporate security policy alignment violation",
});
// 6. Log execution context handoffs in multi-agent workflows
await volidator.agent.handoff({
actor: "orchestrator",
toAgentId: "designer-agent-v1",
instruction: "generate banner image matching text outline",
agentContext: { prompt: "neon style workspace banner" },
});Framework Integrations
Instead of manually logging agent actions, you can use our built-in framework plugins.
LangChain.js Callback Handler
Import from @volidator/node/agent-langchain to automatically track tool start, end, error states, outputs, and latencies:
import { VolidatorLangChainHandler } from "@volidator/node/agent-langchain";
import { ChatOpenAI } from "@langchain/openai";
const handler = new VolidatorLangChainHandler(volidator, {
actor: "search-agent-v1",
tenant: "customer_acme" // Optional
});
const model = new ChatOpenAI({
callbacks: [handler] // Pass globally, or per-run
});Vercel AI SDK Callback
Import from @volidator/node/agent-vercel to automatically instrument tool execution inside generateText or streamText steps:
import { createVercelAISDKCallback } from "@volidator/node/agent-vercel";
import { generateText } from "ai";
const onStepFinish = createVercelAISDKCallback(volidator, {
actor: "customer-support-agent"
});
const result = await generateText({
model: openai("gpt-4o"),
prompt: "What's the weather like?",
tools: { ... },
onStepFinish // Pass the callback wrapper here
});Trace Correlation & Logical Clocks (Lamport Timestamps)
Pass standard trace metadata (traceId, spanId, parentSpanId) to map out parent-child relationships and causality graphs between agent steps.
Volidator parses W3C traceparent headers automatically when you pass a request object. Telemetry contexts emitted by LangChain, LlamaIndex, or standard instrumentations are inherited without manual piping:
await volidator.agent.toolCall({
req: request, // Automatically extracts traceId/spanId from incoming headers
toolName: "database_write",
success: true,
});Deterministic Edge Trace Ordering
To resolve NTP (Network Time Protocol) clock drift anomalies between distributed edge servers or serverless invocations, the SDK automatically maintains and propagates a Lamport Logical Clock value inside request headers (x-volidator-clock). Clocks are synchronized across boundary calls using:
$$\text{localClock} = \max(\text{localClock}, \text{incomingClock}) + 1$$
This guarantees that visualizer graphs and dashboard causality lines render completely deterministically in chronological order.
16. Batch Ingestion (logBatch)
For high-throughput runtimes (like agents executing iterative reasoning loops or massive data imports), use logBatch to prepare and send multiple logs in a single HTTP request.
All cryptographic preparation (AES-256-GCM encryption, blind indexing) runs in parallel on the client before a single POST request is made.
const logs = [
{ actor: "agent-1", action: "thought", metadata: { step: 1 } },
{ actor: "agent-1", action: "tool_call", metadata: { toolName: "search" } },
{ actor: "agent-1", action: "thought", metadata: { step: 2 } },
];
const { accepted, rejected } = await volidator.logBatch(logs);
console.log(`Successfully ingested ${accepted} logs, failed to prepare ${rejected}`);Maximum batch size is 100 entries per request.
17. Large Payloads (Claim Check Pattern)
When logging autonomous agent thinking processes, prompt contexts, or tool data, payloads can easily grow quite large. If your encrypted log payload exceeds 30KB, the SDK automatically and transparently switches to the Claim Check Pattern:
- The SDK uploads the encrypted ciphertext chunk to Cloudflare R2 object storage securely before database ingestion.
- It writes a content-addressed SHA-256 hash pointer to the database log record instead of the full payload, setting
isClaimCheckto true. - The Volidator dashboard and embed widgets detect this flag and automatically retrieve the encrypted chunk from the storage proxy to decrypt it locally in the browser.
This maintains absolute Zero-Knowledge privacy guarantees for large payloads without bloat.
18. Fluent Batcher (batcher)
Instead of managing arrays and calling logBatch manually, you can use the fluent batcher() client helper. This is highly recommended for loop-heavy agent runs or script execution paths.
const batcher = volidator.batcher({
autoFlushCount: 50, // Automatically flush and send when buffer hits 50 logs
autoFlushInterval: 5000, // Or automatically flush every 5 seconds (Node-only, see warning)
});
// Inside your loop or agent reasoning cycle:
batcher.push({
actor: "agent-1",
action: "thought",
metadata: { step: 1, text: "Thinking..." }
});
// Always call flush manually at the end of the script or request path to send any leftovers:
await batcher.flush();⚠️ Serverless / Edge Warning:
autoFlushIntervalusessetIntervalinternally. In serverless and Edge environments (like Cloudflare Workers, Vercel Edge, Next.js Edge), the V8 isolate is frozen or destroyed as soon as the response is returned to the user. Background timers will silently fail to execute, resulting in dropped logs. Only useautoFlushIntervalin long-lived Node.js applications (Express, Fastify, CLI tools). For serverless/edge functions, always manually callawait batcher.flush()or pass the promise toctx.waitUntil().
19. OpenTelemetry Integration (@volidator/node/otel)
Volidator integrates seamlessly with OpenTelemetry (OTel) pipelines to trace and audit system executions (e.g. AI agent tool calls) while maintaining E2EE security guarantees.
Import the Plugin
Importing the otel plugin automatically registers context propagation:
import "@volidator/node/otel";Auto-Enrich Spans
When you call volidator.log(), it automatically extracts the traceId and spanId from the active OTel context. You can also manually enrich any payload:
import { enrichWithOtel } from "@volidator/node/otel";
const payload = enrichWithOtel({
action: "agent.thought",
actor: "writer-agent",
});OTel Driver Redirect
You can redirect all client log events to the active OTel span instead of sending HTTP requests directly. This is useful for collecting all events into a single OTel trace first, then exporting them:
import { enableOtelDriverRedirect } from "@volidator/node/otel";
enableOtelDriverRedirect(volidator);
// This log will now be recorded as a span event on the active OTel span
await volidator.log({
action: "user.login.success",
actor: "usr_123",
});Exporting Spans/Logs to Volidator
Use VolidatorSpanExporter or VolidatorLogExporter in your OpenTelemetry Collector SDK setup to push captured events securely back into the Volidator ledger:
import { SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { VolidatorSpanExporter } from "@volidator/node/otel";
import { volidator } from "./volidator";
// Register Volidator Span Exporter
const provider = new BasicTracerProvider();
provider.addSpanProcessor(
new SimpleSpanProcessor(new VolidatorSpanExporter(volidator))
);20. Flight Data Recorder (FDR)
The Flight Data Recorder (FDR) enables Input-Side Forensic Reconstruction of autonomous AI agent runs. When enabled, it captures the exact prompt context, LLM metadata ("alibi"), and tool inputs/outputs, compressing and shipping them securely to Volidator's R2 + D1 ledger.
Enable FDR
FDR is strictly opt-in. Enable it during client initialization:
import { VolidatorClient } from "@volidator/node";
const volidator = new VolidatorClient({
apiKey: process.env.VOLIDATOR_API_KEY,
encryptionKey: process.env.VOLIDATOR_ENCRYPTION_KEY,
fdr: { enabled: true } // Opt-in to Flight Data Recorder
});Wrapping Tools
Wrap your critical tools at the execution level to record arguments and outputs while scrubbing transport-layer secrets:
import { wrapToolForVCR } from "@volidator/node/fdr-vcr";
const runCtx = volidator.fdr.createRun("run_uuid_123", "proj_abc");
const calculateTax = volidator.fdr.wrapToolForVCR(
"calculate_tax",
async (args) => {
// Perform calculation or call API
return { tax: args.amount * 0.15 };
},
runCtx,
{ allowList: ["amount"] } // Scrubs keys like API keys, cookies, or auth tokens
);
// Call wrapped tool normally inside your agent execution loop
const result = await calculateTax({ amount: 100, apiKeySecret: "sensitive_secret" });Capturing Prompts and Alibis
Attach prompt information and provider metadata to the run context:
// Capture system prompt
await volidator.fdr.captureSystemPrompt(runCtx, "You are a financial analyst agent...");
// Capture provider alibi after generation
volidator.fdr.captureProviderAlibi(runCtx, {
modelId: "gpt-4o-2024-08-06",
systemFingerprint: "fp_e2908f90...",
seed: 42
});Committing the Run
Commit the completed run context to upload gzipped payload to R2 and insert the hash-chained row into the immutable D1 ledger:
const commitResult = await volidator.fdr.commitRun(runCtx);
console.log(`Run committed with chain hash: ${commitResult.chainHash}`);Certifying Proxy
For environments where you do not want to install any SDK, you can route HTTP requests (such as LLM completion requests) directly through the Volidator edge proxy to automatically encrypt logs and extract batch proofs.
Why Use the Proxy?
- No libraries to install or maintain. Works universally in Python, Go, Rust, or plain HTTP requests.
- Sub-5ms stream overhead, supporting full real-time Server-Sent Events (SSE).
- E2EE at the edge: request and response logs are encrypted with your key before storage.
Quickstart Request
Target the proxy endpoint and supply your API and encryption keys in the headers:
curl -X POST https://ingestion.volidator.com/v1/proxy \
-H "Authorization: Bearer val_agent_bb48417cb42cb26fc88106247d" \
-H "X-Volidator-Encryption-Key: test-key-32-chars-xyz-abcdefghij" \
-H "X-Volidator-Agent-ID: my-agent" \
-H "Content-Type: application/json" \
-d '{
"target": "https://api.anthropic.com/v1/messages",
"payload": {
"model": "claude-5-sonnet",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Hello"}]
},
"requestProof": true
}'Retrieving Proof Receipts
- Via Terminal (REST API): Query the project endpoint with your log identifier:
curl -H "Authorization: Bearer val_live_bb48417cb42cb26fc88106247d" \ "https://management.volidator.com/v1/projects/proj_123/logs/log_5678abcd90ef/proof" - Via Dashboard: Open the Story Visualizer, click on any visual node in the canvas, and inspect the verification results (including FreeTSA certificates and Sigstore Rekor links) in the drawer.
Local Fallback Backups
To guarantee zero audit trail loss during network failures or outages, you can register a local backup file transport.
Import the decoupled file transport adapter and pass it as the onDeliveryFailure callback:
import { VolidatorClient } from "@volidator/node";
import { createFileFallbackTransport } from "@volidator/node/fallback-file";
const fallback = createFileFallbackTransport({
directory: "./backups/volidator-logs",
filenamePrefix: "my-app-logs",
});
const client = new VolidatorClient({
apiKey: "...",
encryptionKey: "...",
onDeliveryFailure: fallback,
});License
MIT © Volidator Contributors
