@volidator/node 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,518 @@
1
+ # Volidator Node.js SDK
2
+
3
+ **Zero-knowledge, server-blind audit logging for Node.js, Next.js, and edge runtimes.**
4
+
5
+ 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.
6
+
7
+ [![npm](https://img.shields.io/npm/v/@volidator/node)](https://www.npmjs.com/package/@volidator/node)
8
+ [![license](https://img.shields.io/npm/l/@volidator/node)](LICENSE)
9
+
10
+ ---
11
+
12
+ ## What is Volidator?
13
+
14
+ **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).
15
+
16
+ ---
17
+
18
+ ## Why Volidator? (Pain Points We Solve)
19
+
20
+ 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.
21
+
22
+ Volidator solves this with **Zero-Knowledge Audit Trails**:
23
+ * **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.
24
+ * **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.
25
+ * **AI Agent Action Auditing & Accountability:** Autonomous AI agents make decisions, run API calls, and modify databases. Volidator provides a tamper-proof ledger to trace exactly *which* agent tool was executed, *why* (LLM prompt/context), and *what* was modified, satisfying critical alignment and security monitoring requirements.
26
+ * **Instant Customer-Facing Dashboards:** Embed fully-interactive, securely hydrated log tables inside your React frontends using our signed JIT tokens.
27
+
28
+ ---
29
+
30
+ ## Who is it for?
31
+
32
+ * **B2B SaaS Engineering Teams:** Developers who need to provide enterprise tenants with search, filter, and CSV exports of system events.
33
+ * **Security & Compliance Teams:** Organizations aiming to achieve security certifications without expanding their data privacy liability or telemetry footprint.
34
+ * **AI & Agentic App Developers:** Builders establishing guardrails and debug logs for autonomous systems to audit agent decisions, LLM outputs, and automated tool calls.
35
+
36
+ ---
37
+
38
+ ## Table of Contents
39
+
40
+ 1. [Install](#1-install)
41
+ 2. [Environment Setup](#2-environment-setup)
42
+ 3. [Initialize the Client](#3-initialize-the-client)
43
+ 4. [Log an Event](#4-log-an-event)
44
+ 5. [Pass Request Context](#5-pass-request-context)
45
+ 6. [Telemetry Configuration](#6-telemetry-configuration)
46
+ 7. [PII Redaction](#7-pii-redaction)
47
+ 8. [JIT Hydration (referenceKeys)](#8-jit-hydration-referencekeys)
48
+ 9. [Keyring Rotation](#9-keyring-rotation)
49
+ 10. [Embed Token](#10-embed-token)
50
+ 11. [Compliance Helpers](#11-compliance-helpers)
51
+ 12. [Next.js Middleware](#12-nextjs-middleware)
52
+ 14. [`@volidator/react`](#14-volidatorreact)
53
+ 15. [AI Agent Auditing (VolidatorAgent)](#15-ai-agent-auditing-volidatoragent)
54
+ 16. [Batch Ingestion (logBatch)](#16-batch-ingestion-logbatch)
55
+
56
+ ---
57
+
58
+ ## 1. Install
59
+
60
+ ```bash
61
+ npm install @volidator/node
62
+ ```
63
+
64
+ ---
65
+
66
+ ## 2. Environment Setup
67
+
68
+ Store secrets as environment variables. Never hardcode them.
69
+
70
+ ```bash
71
+ # Authenticates your server with the Volidator ingestion endpoint
72
+ VOLIDATOR_API_KEY="val_live_xxxxxxxx..."
73
+
74
+ # AES-256-GCM encryption key — your data is encrypted with this before leaving your server
75
+ VOLIDATOR_ENCRYPTION_KEY="vol-dek-xxxxxxxx..."
76
+ ```
77
+
78
+ ---
79
+
80
+ ## 3. Initialize the Client
81
+
82
+ Create **one instance** per application and reuse it. Do not instantiate per-request.
83
+
84
+ ```typescript
85
+ import { VolidatorClient } from "@volidator/node";
86
+
87
+ export const volidator = new VolidatorClient({
88
+ apiKey: process.env.VOLIDATOR_API_KEY!,
89
+ encryptionKey: process.env.VOLIDATOR_ENCRYPTION_KEY!,
90
+ });
91
+ ```
92
+
93
+ ---
94
+
95
+ ## 4. Log an Event
96
+
97
+ ```typescript
98
+ await volidator.log({
99
+ actor: "usr_12345", // Who performed the action
100
+ action: "user.login.success", // What happened (use dot notation)
101
+ target: "workspace_abc789", // What was affected
102
+ metadata: {
103
+ deviceName: "MacBook Pro",
104
+ authProvider: "Google OAuth",
105
+ },
106
+ });
107
+ ```
108
+
109
+ `log()` returns `true` if the event was accepted, `false` if delivery failed. It never throws — failures are swallowed and logged to `console.error`.
110
+
111
+ ---
112
+
113
+ ## 5. Pass Request Context
114
+
115
+ Pass your framework's `Request` object directly. The SDK extracts IP, User-Agent, and geolocation headers automatically.
116
+
117
+ ```typescript
118
+ // Next.js App Router / Cloudflare Workers / Express
119
+ await volidator.log({
120
+ actor: session.userId,
121
+ action: "settings.update",
122
+ req: request, // Web API Request or Node.js IncomingMessage
123
+ metadata: { fieldChanged: "email_address" },
124
+ });
125
+ ```
126
+
127
+ Supported request formats:
128
+ - `Request` — Next.js App Router, Cloudflare Workers, Bun
129
+ - `IncomingMessage` — Node.js `http`, Express, Fastify
130
+
131
+ ---
132
+
133
+ ## 6. Telemetry Configuration
134
+
135
+ Control how IP, User-Agent, and location data are handled. Choose a preset, then override individual fields as needed.
136
+
137
+ | Preset | IP | User-Agent | Location |
138
+ |---|---|---|---|
139
+ | `"strict"` | skip | skip | disabled |
140
+ | `"standard"` *(default)* | anonymized (hashed) | parsed to browser/OS | country + region |
141
+ | `"full"` | stored as-is | stored as-is | country + region + city |
142
+
143
+ ```typescript
144
+ const volidator = new VolidatorClient({
145
+ apiKey: process.env.VOLIDATOR_API_KEY!,
146
+ encryptionKey: process.env.VOLIDATOR_ENCRYPTION_KEY!,
147
+ telemetry: {
148
+ preset: "standard", // baseline
149
+ ip: "skip", // override: don't store IP at all
150
+ location: false, // override: disable geolocation
151
+ },
152
+ });
153
+ ```
154
+
155
+ ---
156
+
157
+ ## 7. PII Redaction
158
+
159
+ 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.
160
+
161
+ ```typescript
162
+ const volidator = new VolidatorClient({
163
+ apiKey: process.env.VOLIDATOR_API_KEY!,
164
+ encryptionKey: process.env.VOLIDATOR_ENCRYPTION_KEY!,
165
+ redactKeys: ["actor", "metadata.socialSecurityNumber", "metadata.email"],
166
+ });
167
+ ```
168
+
169
+ Supported key patterns:
170
+ - `"actor"` — the top-level actor field
171
+ - `"target"` — the top-level target field
172
+ - `"metadata.fieldName"` — any metadata field by name
173
+
174
+ > **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.
175
+
176
+ ---
177
+
178
+ ## 8. JIT Hydration (`referenceKeys`)
179
+
180
+ 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.
181
+
182
+ When you configure `referenceKeys`, you pass fields as `{ id, pii }` objects:
183
+ - `id` — the internal identifier stored as `[REF:id]` in the encrypted log
184
+ - `pii` — the real value used **only** to compute the blind index, then discarded
185
+
186
+ 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`](#14-volidatorreact) section for the client-side hook.
187
+
188
+ ```typescript
189
+ const volidator = new VolidatorClient({
190
+ apiKey: process.env.VOLIDATOR_API_KEY!,
191
+ encryptionKey: process.env.VOLIDATOR_ENCRYPTION_KEY!,
192
+ referenceKeys: ["actor"],
193
+ });
194
+
195
+ await volidator.log({
196
+ // Pass { id, pii } for any field in referenceKeys
197
+ actor: { id: "usr_890", pii: "alice@company.com" },
198
+ action: "document.deleted",
199
+ target: "doc_4521",
200
+ });
201
+ // Stored: actor = "[REF:usr_890]"
202
+ // Blind index computed from "alice@company.com" — search still works
203
+ ```
204
+
205
+ `referenceKeys` and `redactKeys` can coexist. If a field is in both, `referenceKeys` takes precedence.
206
+
207
+ → [Full JIT Hydration guide](https://docs.volidator.com/guides/jit-hydration/)
208
+
209
+ ---
210
+
211
+ ## 9. Keyring Rotation
212
+
213
+ 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.
214
+
215
+ ```typescript
216
+ const volidator = new VolidatorClient({
217
+ apiKey: process.env.VOLIDATOR_API_KEY!,
218
+ keyring: {
219
+ v1: process.env.VOLIDATOR_KEY_V1!, // old — decrypts historical logs
220
+ v2: process.env.VOLIDATOR_KEY_V2!, // new — encrypts all new writes
221
+ },
222
+ activeEncryptionKeyId: "v2",
223
+ });
224
+ ```
225
+
226
+ Constraints:
227
+ - Keyring size is capped at **5 keys** (security + performance bound).
228
+ - `activeEncryptionKeyId` must be present in the `keyring` object.
229
+
230
+ ---
231
+
232
+ ## 10. Embed Token
233
+
234
+ 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>`.
235
+
236
+ ```typescript
237
+ const volidator = new VolidatorClient({
238
+ apiKey: process.env.VOLIDATOR_API_KEY!,
239
+ encryptionKey: process.env.VOLIDATOR_ENCRYPTION_KEY!,
240
+ // Required for generateEmbedToken():
241
+ projectId: process.env.VOLIDATOR_PROJECT_ID!,
242
+ clientSecret: process.env.VOLIDATOR_CLIENT_SECRET!,
243
+ });
244
+
245
+ const { embedUrl } = await volidator.generateEmbedToken({
246
+ actorId: session.userId, // Scope to this actor's logs
247
+ scope: "actor", // "actor" | "target" | "tenant" | "all" | "auditor"
248
+ expiresIn: "1h", // Max: 1h for actor/target/tenant; 7d for auditor
249
+ hostOrigin: "https://app.yourcompany.com", // Enables strict postMessage origin validation
250
+ view: {
251
+ columns: ["actor", "action", "metadata.ipAddress", "createdAt"],
252
+ defaultFilter: { action: "user.login" },
253
+ },
254
+ });
255
+
256
+ // In your API route response:
257
+ return Response.json({ embedUrl });
258
+ ```
259
+
260
+ ```tsx
261
+ // In your React component:
262
+ <iframe src={embedUrl} width="100%" height="600" />
263
+ ```
264
+
265
+ ---
266
+
267
+ ## 11. Compliance Helpers
268
+
269
+ `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.
270
+
271
+ ```typescript
272
+ // Access provisioning
273
+ await volidator.compliance.accessGranted({ actor: "admin_01", target: "usr_890" });
274
+ await volidator.compliance.accessRevoked({ actor: "admin_01", target: "usr_890" });
275
+
276
+ // Data movement
277
+ await volidator.compliance.dataExported({
278
+ actor: "usr_123",
279
+ metadata: { exportFormat: "csv", rowCount: 5420 },
280
+ });
281
+
282
+ // System changes
283
+ await volidator.compliance.systemConfigChanged({
284
+ actor: "usr_123",
285
+ metadata: { setting: "mfa_enforcement", newValue: "required" },
286
+ });
287
+
288
+ // Authentication
289
+ await volidator.compliance.mfaEnabled({ actor: "usr_890" });
290
+ ```
291
+
292
+ | Method | Action stored | SOC 2 | ISO 27001 |
293
+ |---|---|---|---|
294
+ | `accessGranted` | `access.granted` | CC6.1 | A.9.2.1 |
295
+ | `accessRevoked` | `access.revoked` | CC6.1 | A.9.2.6 |
296
+ | `dataExported` | `data.exported` | CC6.6 | A.12.4.1 |
297
+ | `systemConfigChanged` | `system.config_changed` | CC6.2 | A.12.1.2 |
298
+ | `mfaEnabled` | `mfa.enabled` | CC6.3 | A.9.4.2 |
299
+
300
+ ---
301
+
302
+ ## 12. Next.js Middleware
303
+
304
+ 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.
305
+
306
+ ```typescript
307
+ import { withVolidator } from "@volidator/node/next";
308
+ import { volidator } from "@/lib/volidator";
309
+
310
+ export const POST = withVolidator(volidator, async (req: Request, ctx) => {
311
+ await ctx.volidator.log({
312
+ actor: session.userId,
313
+ action: "invoice.created",
314
+ target: invoiceId,
315
+ });
316
+
317
+ // Compliance methods also receive full telemetry context:
318
+ await ctx.volidator.compliance.dataExported({ actor: session.userId });
319
+
320
+ return Response.json({ ok: true });
321
+ });
322
+ ```
323
+
324
+ ---
325
+
326
+ ## 13. Auth Plugins
327
+
328
+ Auth plugins extend `withVolidator` to automatically inject the authenticated user's ID as `actor` on every log call.
329
+
330
+ ### Clerk
331
+
332
+ ```typescript
333
+ import { createClerkAudit } from "@volidator/node/clerk";
334
+ import { auth } from "@clerk/nextjs/server";
335
+ import { volidator } from "@/lib/volidator";
336
+
337
+ const withClerkAudit = createClerkAudit({ client: volidator, getAuth: auth });
338
+
339
+ export const DELETE = withClerkAudit(async (req: Request, ctx) => {
340
+ // ctx.session — Clerk session object
341
+ // actor is automatically set to ctx.session.userId
342
+ await ctx.volidator.log({ action: "record.deleted", target: recordId });
343
+ return Response.json({ ok: true });
344
+ });
345
+ ```
346
+
347
+ ### Universal (Auth0, NextAuth, BetterAuth, Kinde, Supabase, ...)
348
+
349
+ ```typescript
350
+ import { createUniversalAudit } from "@volidator/node/universal";
351
+ import { getServerSession } from "next-auth";
352
+ import { volidator } from "@/lib/volidator";
353
+
354
+ const withAudit = createUniversalAudit({
355
+ client: volidator,
356
+ getSession: (req) => getServerSession(),
357
+ getUserId: (req, session) => session?.user?.id,
358
+ // Optionally inject extra metadata into every log call:
359
+ getMetadata: (req, session) => ({ userEmail: session?.user?.email }),
360
+ });
361
+
362
+ export const PUT = withAudit(async (req: Request, ctx) => {
363
+ await ctx.volidator.log({ action: "profile.updated" });
364
+ return Response.json({ ok: true });
365
+ });
366
+ ```
367
+
368
+ ---
369
+
370
+ ## 14. `@volidator/react`
371
+
372
+ The `@volidator/react` package provides the `useVolidatorHydration` hook, which manages the JIT Hydration postMessage handshake between your application and the Volidator embed iframe.
373
+
374
+ ```bash
375
+ npm install @volidator/react
376
+ ```
377
+
378
+ ```tsx
379
+ import { useRef } from "react";
380
+ import { useVolidatorHydration } from "@volidator/react";
381
+
382
+ export function AuditLogPage({ embedUrl }: { embedUrl: string }) {
383
+ const iframeRef = useRef<HTMLIFrameElement>(null);
384
+
385
+ useVolidatorHydration({
386
+ iframeRef,
387
+ volidatorOrigin: "https://dash.volidator.com",
388
+ resolveActors: async (ids) => {
389
+ // Called with a deduplicated batch of reference IDs from decrypted logs.
390
+ // Return a map of id → { name, avatarUrl? }.
391
+ const res = await fetch("/api/users/resolve", {
392
+ method: "POST",
393
+ headers: { "Content-Type": "application/json" },
394
+ body: JSON.stringify({ ids }),
395
+ });
396
+ return res.json();
397
+ },
398
+ });
399
+
400
+ return <iframe ref={iframeRef} src={embedUrl} width="100%" height="600" />;
401
+ }
402
+ ```
403
+
404
+ The hook:
405
+ 1. Listens for `VOLIDATOR_RESOLVE_ACTORS` messages from the iframe.
406
+ 2. Validates `event.origin` strictly against `volidatorOrigin` (wildcard `"*"` is not accepted).
407
+ 3. Calls `resolveActors(ids)` with only the IDs not already in the local cache.
408
+ 4. Posts the resolution map back into the iframe as `VOLIDATOR_RESOLVE_RESPONSE`.
409
+ 5. Cleans up the event listener on component unmount.
410
+
411
+ → [Full JIT Hydration guide](https://docs.volidator.com/guides/jit-hydration/)
412
+
413
+ ---
414
+
415
+ ## 15. AI Agent Auditing (`VolidatorAgent`)
416
+
417
+ Volidator provides a specialized compliance logging namespace tailored for autonomous AI systems, LLMs, and multi-agent chains. Access these methods via `volidator.agent.*`.
418
+
419
+ Every call automatically appends the correct mapping metadata for **EU AI Act compliance**, **NIST AI RMF guidelines**, **SOC 2**, and **ISO 27001**.
420
+
421
+ ```typescript
422
+ // 1. Log an agent tool call or external API request
423
+ await volidator.agent.toolCall({
424
+ actor: "writer-agent-v1",
425
+ traceId: runId,
426
+ spanId: spanId,
427
+ toolName: "fetch_news",
428
+ toolInput: { topic: "AI Act updates" },
429
+ toolOutput: { results: ["..." ] },
430
+ success: true,
431
+ latencyMs: 140,
432
+ });
433
+
434
+ // 2. Log an autonomous decision made by the model
435
+ await volidator.agent.decision({
436
+ actor: "writer-agent-v1",
437
+ traceId: runId,
438
+ decision: "publish_article",
439
+ rationale: "article scoring passed verification checks",
440
+ confidenceScore: 0.96,
441
+ modelId: "claude-3-5-sonnet",
442
+ });
443
+
444
+ // 3. Request human oversight/escalation (EU AI Act Article 14)
445
+ await volidator.agent.escalation({
446
+ actor: "writer-agent-v1",
447
+ traceId: runId,
448
+ reason: "article output score fell below threshold",
449
+ urgency: "medium",
450
+ blockedAction: "auto_publish",
451
+ });
452
+
453
+ // 4. Log suspected anomalies, injections, or system security events
454
+ await volidator.agent.anomaly({
455
+ actor: "guardrail-shield",
456
+ traceId: runId,
457
+ description: "jailbreak prompt pattern detected in input stream",
458
+ severity: "critical",
459
+ anomalyType: "prompt_injection",
460
+ });
461
+
462
+ // 5. Log a model refusal based on safety alignment rules
463
+ await volidator.agent.refusal({
464
+ actor: "writer-agent-v1",
465
+ traceId: runId,
466
+ refusedInstruction: "write code to extract system logs",
467
+ reason: "corporate security policy alignment violation",
468
+ });
469
+
470
+ // 6. Log execution context handoffs in multi-agent workflows
471
+ await volidator.agent.handoff({
472
+ actor: "orchestrator",
473
+ toAgentId: "designer-agent-v1",
474
+ instruction: "generate banner image matching text outline",
475
+ agentContext: { prompt: "neon style workspace banner" },
476
+ });
477
+ ```
478
+
479
+ ### Trace Correlation (OpenTelemetry Compatibility)
480
+
481
+ Pass standard trace metadata (`traceId`, `spanId`, `parentSpanId`) to map out parent-child relationships and causality graphs between agent steps.
482
+
483
+ 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:
484
+
485
+ ```typescript
486
+ await volidator.agent.toolCall({
487
+ req: request, // Automatically extracts traceId/spanId from incoming headers
488
+ toolName: "database_write",
489
+ success: true,
490
+ });
491
+ ```
492
+
493
+ ---
494
+
495
+ ## 16. Batch Ingestion (`logBatch`)
496
+
497
+ 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.
498
+
499
+ All cryptographic preparation (AES-256-GCM encryption, blind indexing) runs in parallel on the client before a single POST request is made.
500
+
501
+ ```typescript
502
+ const logs = [
503
+ { actor: "agent-1", action: "thought", metadata: { step: 1 } },
504
+ { actor: "agent-1", action: "tool_call", metadata: { toolName: "search" } },
505
+ { actor: "agent-1", action: "thought", metadata: { step: 2 } },
506
+ ];
507
+
508
+ const { accepted, rejected } = await volidator.logBatch(logs);
509
+ console.log(`Successfully ingested ${accepted} logs, failed to prepare ${rejected}`);
510
+ ```
511
+
512
+ *Maximum batch size is 100 entries per request.*
513
+
514
+ ---
515
+
516
+ ## License
517
+
518
+ MIT © Volidator Contributors
@@ -0,0 +1,56 @@
1
+ import {
2
+ VolidatorClient
3
+ } from "./chunk-YI4DCCHT.js";
4
+
5
+ // src/middleware/next.ts
6
+ function withVolidator(client, handler) {
7
+ return async (req, ctx = {}, ...args) => {
8
+ const extractedContext = VolidatorClient.extractContext(req);
9
+ const scopedLog = async (payload) => {
10
+ return client.log({
11
+ ...payload,
12
+ context: {
13
+ ...extractedContext,
14
+ ...payload.context,
15
+ location: {
16
+ ...extractedContext.location,
17
+ ...payload.context?.location || {}
18
+ },
19
+ device: {
20
+ ...extractedContext.device,
21
+ ...payload.context?.device || {}
22
+ }
23
+ }
24
+ });
25
+ };
26
+ const withControl = (action, soc2Control, isoControl, payload) => scopedLog({
27
+ ...payload,
28
+ action,
29
+ metadata: {
30
+ ...payload.metadata,
31
+ soc2_control: soc2Control,
32
+ iso27001: isoControl
33
+ }
34
+ });
35
+ const scopedCompliance = {
36
+ accessRevoked: (p) => withControl("access.revoked", "CC6.1", "A.9.2.6", p),
37
+ accessGranted: (p) => withControl("access.granted", "CC6.1", "A.9.2.1", p),
38
+ dataExported: (p) => withControl("data.exported", "CC6.6", "A.12.4.1", p),
39
+ systemConfigChanged: (p) => withControl("system.config_changed", "CC6.2", "A.12.1.2", p),
40
+ mfaEnabled: (p) => withControl("mfa.enabled", "CC6.3", "A.9.4.2", p)
41
+ };
42
+ const newCtx = {
43
+ ...ctx,
44
+ volidator: {
45
+ log: scopedLog,
46
+ compliance: scopedCompliance
47
+ }
48
+ };
49
+ return handler(req, newCtx, ...args);
50
+ };
51
+ }
52
+
53
+ export {
54
+ withVolidator
55
+ };
56
+ //# sourceMappingURL=chunk-KEXIKZGN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/middleware/next.ts"],"sourcesContent":["import { VolidatorClient, LogPayload } from \"../index\";\n\n/**\n * Next.js App Router Middleware for Volidator.\n * Automatically extracts telemetry context (IP, User Agent, Location)\n * from the Next.js standard Request object and injects it into every\n * `volidator.log()` and `volidator.compliance.*()` call made inside\n * the wrapped handler.\n */\nexport function withVolidator<T extends Function>(client: VolidatorClient, handler: T) {\n return async (req: Request, ctx: any = {}, ...args: any[]) => {\n const extractedContext = VolidatorClient.extractContext(req);\n\n // ---------------------------------------------------------------------------\n // Scoped log — merges request-level IP/UA context into every log call.\n // ---------------------------------------------------------------------------\n const scopedLog = async (payload: LogPayload) => {\n return client.log({\n ...payload,\n context: {\n ...extractedContext,\n ...payload.context,\n location: {\n ...extractedContext.location,\n ...(payload.context?.location || {}),\n },\n device: {\n ...extractedContext.device,\n ...(payload.context?.device || {}),\n },\n },\n });\n };\n\n // ---------------------------------------------------------------------------\n // Scoped compliance — mirrors VolidatorCompliance but routes through\n // scopedLog so that IP/UA telemetry is preserved in compliance events.\n //\n // Previously this passed client.compliance directly, which called\n // client.log() without the request context — silently dropping telemetry\n // from every compliance audit event.\n // ---------------------------------------------------------------------------\n const withControl = (\n action: string,\n soc2Control: string,\n isoControl: string,\n payload: Omit<LogPayload, \"action\">\n ) =>\n scopedLog({\n ...payload,\n action,\n metadata: {\n ...payload.metadata,\n soc2_control: soc2Control,\n iso27001: isoControl,\n },\n });\n\n const scopedCompliance = {\n accessRevoked: (p: Omit<LogPayload, \"action\">) =>\n withControl(\"access.revoked\", \"CC6.1\", \"A.9.2.6\", p),\n accessGranted: (p: Omit<LogPayload, \"action\">) =>\n withControl(\"access.granted\", \"CC6.1\", \"A.9.2.1\", p),\n dataExported: (p: Omit<LogPayload, \"action\">) =>\n withControl(\"data.exported\", \"CC6.6\", \"A.12.4.1\", p),\n systemConfigChanged: (p: Omit<LogPayload, \"action\">) =>\n withControl(\"system.config_changed\", \"CC6.2\", \"A.12.1.2\", p),\n mfaEnabled: (p: Omit<LogPayload, \"action\">) =>\n withControl(\"mfa.enabled\", \"CC6.3\", \"A.9.4.2\", p),\n };\n\n const newCtx = {\n ...ctx,\n volidator: {\n log: scopedLog,\n compliance: scopedCompliance,\n },\n };\n\n return handler(req, newCtx, ...args);\n };\n}\n"],"mappings":";;;;;AASO,SAAS,cAAkC,QAAyB,SAAY;AACrF,SAAO,OAAO,KAAc,MAAW,CAAC,MAAM,SAAgB;AAC5D,UAAM,mBAAmB,gBAAgB,eAAe,GAAG;AAK3D,UAAM,YAAY,OAAO,YAAwB;AAC/C,aAAO,OAAO,IAAI;AAAA,QAChB,GAAG;AAAA,QACH,SAAS;AAAA,UACP,GAAG;AAAA,UACH,GAAG,QAAQ;AAAA,UACX,UAAU;AAAA,YACR,GAAG,iBAAiB;AAAA,YACpB,GAAI,QAAQ,SAAS,YAAY,CAAC;AAAA,UACpC;AAAA,UACA,QAAQ;AAAA,YACN,GAAG,iBAAiB;AAAA,YACpB,GAAI,QAAQ,SAAS,UAAU,CAAC;AAAA,UAClC;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAUA,UAAM,cAAc,CAClB,QACA,aACA,YACA,YAEA,UAAU;AAAA,MACR,GAAG;AAAA,MACH;AAAA,MACA,UAAU;AAAA,QACR,GAAG,QAAQ;AAAA,QACX,cAAc;AAAA,QACd,UAAU;AAAA,MACZ;AAAA,IACF,CAAC;AAEH,UAAM,mBAAmB;AAAA,MACvB,eAAe,CAAC,MACd,YAAY,kBAAkB,SAAS,WAAW,CAAC;AAAA,MACrD,eAAe,CAAC,MACd,YAAY,kBAAkB,SAAS,WAAW,CAAC;AAAA,MACrD,cAAc,CAAC,MACb,YAAY,iBAAiB,SAAS,YAAY,CAAC;AAAA,MACrD,qBAAqB,CAAC,MACpB,YAAY,yBAAyB,SAAS,YAAY,CAAC;AAAA,MAC7D,YAAY,CAAC,MACX,YAAY,eAAe,SAAS,WAAW,CAAC;AAAA,IACpD;AAEA,UAAM,SAAS;AAAA,MACb,GAAG;AAAA,MACH,WAAW;AAAA,QACT,KAAK;AAAA,QACL,YAAY;AAAA,MACd;AAAA,IACF;AAEA,WAAO,QAAQ,KAAK,QAAQ,GAAG,IAAI;AAAA,EACrC;AACF;","names":[]}