npm.io
0.6.0 • Published 1 month ago

privaro-sdk

Licence
MIT
Version
0.6.0
Deps
0
Size
303 kB
Vulns
0
Weekly
0
Stars
1

privaro-sdk

Privacy infrastructure for enterprise AI — intercepts PII before it reaches any LLM.

Drop-in SDK for Node.js and edge runtimes. Wraps your existing OpenAI, Anthropic, LangChain, or Vercel AI calls with automatic PII detection, tokenisation, and blockchain-certified audit logging — no architecture changes required.

npm install privaro-sdk

Quickstart

import { PrivaroClient } from "privaro-sdk";

const privaro = new PrivaroClient({
  apiKey: process.env.PRIVARO_API_KEY!,      // starts with "prvr_"
  pipelineId: process.env.PRIVARO_PIPELINE_ID!,
});

const result = await privaro.protect(
  "Solicitante: Laura Sánchez Blanco, DNI 23456789D, IBAN ES98 2100 0418 6819 6340 7321"
);

console.log(result.protected);
// → "Solicitante: [NM-0001], DNI [ID-0001], IBAN [BK-0001]"

console.log(result.total_detected);  // 3
console.log(result.gdpr_compliant);  // true
console.log(result.audit_log_id);    // Supabase row UUID — linked to iBS blockchain cert

Pass result.protected to your LLM. The original values are stored in the Privaro token vault — retrievable on demand, never logged in plaintext.


Installation

npm install privaro-sdk

Node.js ≥ 18 required. No native dependencies — uses the built-in fetch API.

Peer dependencies are optional — install only what you use:

npm install openai          # OpenAI adapter
npm install @langchain/openai langchain   # LangChain adapter
npm install ai              # Vercel AI SDK adapter

Configuration

const privaro = new PrivaroClient({
  apiKey: "prvr_...",           // required — from /app/admin/api-keys
  pipelineId: "uuid",          // required — from /app/pipelines
  baseUrl: "https://...",      // optional — defaults to https://api.privaro.ai
  timeout: 10_000,             // optional — ms, default 10s
  defaultMode: "tokenise",     // optional — tokenise | anonymise | block
});

Get your API key and pipeline ID from privaro.ai/app/admin.


Core API

client.protect(prompt, opts?)

Detect and tokenise PII. Writes an audit log entry with iBS blockchain certification.

const result = await privaro.protect("Patient María García, DNI 34521789X", {
  mode: "tokenise",          // tokenise | anonymise | block
  reversible: true,          // store reversible tokens in vault
  includeDetections: true,   // include per-entity details
});

// Send result.protected to your LLM
const llmResponse = await openai.chat.completions.create({
  messages: [{ role: "user", content: result.protected }],
  model: "gpt-4o",
});

ProtectResult properties:

result.protected        // tokenised prompt — send to LLM
result.original         // original text — stored client-side only
result.detections       // per-entity details array
result.total_detected   // number of PII entities found
result.total_masked     // number tokenised/anonymised
result.gdpr_compliant   // boolean
result.risk_score       // 0.0–1.0 | null
result.riskLevel        // "high" | "medium" | "low" | "unknown"
result.hasPii           // boolean convenience
result.isSafe           // gdpr_compliant && leaked === 0
result.audit_log_id     // Supabase UUID for DPO reports
result.processing_ms    // detection latency
result.summary()        // one-line log string
client.detect(prompt)

Scan for PII without masking. No audit log written, no state changes. Use for analysis and reporting.

const result = await privaro.detect("Please call María at 677-23-45-67");
result.detections.forEach(d => {
  console.log(d.type, d.severity, d.start, d.end);
  // "phone", "high", 21, 33
});
client.relay(messages, opts?)

Full-cycle relay: protect → route to your configured LLM → de-tokenise response. Requires an LLM provider configured in /app/admin/providers.

const result = await privaro.relay([
  { role: "user", content: "Analiza el contrato de María García, DNI 34521789X..." }
]);

console.log(result.response);   // LLM reply with original values restored
console.log(result.pii_masked); // number of entities protected
client.relayStream(messages, opts?) — for chat UIs

Same as relay(), but yields the LLM's response as it's generated (SSE under the hood), for chat-style products that show responses token-by-token. Deltas are already de-tokenised — never emits a raw token, safe to render directly.

for await (const delta of privaro.relayStream([
  { role: "user", content: "Soy Juan Pérez, ¿podéis confirmarme mi cita?" },
])) {
  process.stdout.write(delta); // already clean text, ready to show
}

Supported for streaming today: OpenAI, Azure OpenAI, Anthropic. Other providers throw a clear error — use relay() (non-streaming) for those instead. idempotencyKey is not supported on this method (replaying a completed stream doesn't have the same semantics as retrying a short response) — use relay() if you need idempotent retries.

client.protectOutput(responseText, opts?) — scan the LLM's response

relay()/relayStream() already scan the LLM's response for you (Privaro makes the call itself there). If instead you call protect() and then hit your own LLM directly, use protectOutput() to scan that response before returning it to your end user — RAG retrieval, tool-call results, and model memorization can all leak PII that was never in the original prompt.

Requires the pipeline to have output scanning enabled (dashboard: Pipelines → Settings → Output scanning) — otherwise throws OutputScanningDisabledError rather than silently skipping the scan.

const out = await privaro.protectOutput(llmResponseText, {
  conversationId, // same id used for the matching protect() call
});

console.log(out.protected);         // send this to your end user
console.log(out.scan_mode);         // "shadow" (informational) | "enforce"
console.log(out.response_modified);

Adapters

OpenAI — drop-in wrapper

Replace your OpenAI client with the Privaro-wrapped version. Identical API surface.

import OpenAI from "openai";
import { PrivaroClient } from "privaro-sdk";
import { wrapOpenAI } from "privaro-sdk/adapters/openai";

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const privaro = new PrivaroClient({
  apiKey: process.env.PRIVARO_API_KEY!,
  pipelineId: process.env.PRIVARO_PIPELINE_ID!,
});

const safe = wrapOpenAI(openai, privaro);

// Exactly the same call — PII protected and de-tokenised automatically
const response = await safe.chat.completions.create({
  model: "gpt-4o",
  messages: [{ role: "user", content: "Analiza hipoteca de Laura Sánchez, DNI 23456789D" }],
});

console.log(response.choices[0].message.content); // real names restored in response
console.log(response._privaro?.pii_detected);      // 2
LangChain — callback handler

Attach to any LangChain LLM or chain.

import { ChatOpenAI } from "@langchain/openai";
import { PrivaroClient } from "privaro-sdk";
import { PrivaroCallbackHandler } from "privaro-sdk/adapters/langchain";

const privaro = new PrivaroClient({
  apiKey: process.env.PRIVARO_API_KEY!,
  pipelineId: process.env.PRIVARO_PIPELINE_ID!,
});

const handler = new PrivaroCallbackHandler(privaro);

const llm = new ChatOpenAI({
  modelName: "gpt-4o",
  callbacks: [handler],
});

// PII tokenised automatically before reaching OpenAI
const response = await llm.invoke(
  "Revisa el contrato de María García, DNI 34521789X"
);
Vercel AI SDK — middleware

Works with generateText, streamText, and useChat.

import { openai } from "@ai-sdk/openai";
import { generateText } from "ai";
import { PrivaroClient } from "privaro-sdk";
import { privaroMiddleware } from "privaro-sdk/adapters/vercel-ai";

const privaro = new PrivaroClient({
  apiKey: process.env.PRIVARO_API_KEY!,
  pipelineId: process.env.PRIVARO_PIPELINE_ID!,
});

const { text } = await generateText({
  model: openai("gpt-4o"),
  prompt: "Analiza el perfil de Carlos Gómez, DNI 45678901C",
  experimental_transform: privaroMiddleware(privaro),
});
// PII protected before OpenAI, de-tokenised in response

Agent runs

For multi-step agents, AgentRun shares token scope across turns — [NM-0001] always refers to the same person throughout the conversation.

import { AgentRun } from "privaro-sdk";

const run = new AgentRun({
  apiKey: process.env.PRIVARO_API_KEY!,
  pipelineId: process.env.PRIVARO_PIPELINE_ID!,
});

// Step 1 — protect user input
const step1 = await run.protect(
  "Review mortgage for Laura Sánchez, DNI 23456789D, income €2,340/mo"
);
const llmResponse = await openai.chat.completions.create({
  messages: step1.protected_messages,
  model: "gpt-4o",
});

// Step 2 — protect tool output (same run, same token scope)
const step2 = await run.protect("CIRBE score: 742 for DNI 23456789D");

// Restore original values in final response
const finalText = await run.reveal(llmResponse.choices[0].message.content!);

Module-level API

Mirrors the Python SDK pattern for simpler apps:

import privaro from "privaro-sdk";

privaro.init({
  apiKey: process.env.PRIVARO_API_KEY!,
  pipelineId: process.env.PRIVARO_PIPELINE_ID!,
});

const result = await privaro.protect("Patient DNI 34521789X...");

Error handling

import {
  PrivaroError,
  AuthError,
  PipelineNotFoundError,
  PolicyBlockError,
  RateLimitError,
  ProxyUnavailableError,
  OutputScanningDisabledError,
} from "privaro-sdk";

try {
  const result = await privaro.protect(prompt);
} catch (err) {
  if (err instanceof PolicyBlockError) {
    // Request blocked by privacy policy (mode: "block")
    return res.status(403).json({ error: "PII blocked" });
  }
  if (err instanceof AuthError) {
    // Invalid or expired API key
  }
  if (err instanceof RateLimitError) {
    // Implement exponential backoff
  }
  if (err instanceof ProxyUnavailableError) {
    // Network issue — proxy unreachable
  }
  if (err instanceof OutputScanningDisabledError) {
    // protectOutput() called on a pipeline that hasn't enabled output scanning
  }
  // All errors extend PrivaroError
}

Detected entity types

Type Severity Examples
full_name medium María López Fernández, Dr. García
email medium user@empresa.com
phone high 677 23 45 67, +34 612 345 678
dni critical 23456789D, 34521789X
iban critical ES91 2100 0418 4502 0005 1332
credit_card critical 4111 1111 1111 1111
ssn critical 123-45-6789
health_record critical SIP/TSI card numbers
ip_address medium 192.168.1.45
date_of_birth medium nacido 14/03/1978
session_id low sess_8f3a2b1c
policy_number high nº póliza 00123456

Detection uses a hybrid engine: deterministic regex (Tier 1) + Microsoft Presidio with spaCy es_core_news_md (Tier 2). All detection runs server-side on the Railway proxy.


Environment variables

PRIVARO_API_KEY=prvr_...
PRIVARO_PIPELINE_ID=550e8400-e29b-41d4-a716-446655440000
PRIVARO_BASE_URL=https://privaro-proxy-production.up.railway.app/v1  # optional

Requirements

  • Node.js ≥ 18 — uses native fetch and crypto.randomUUID
  • Edge runtimes — Cloudflare Workers, Vercel Edge, Deno: all supported
  • CommonJS — bundled as both ESM and CJS


MIT iCommunity Labs

Keywords