@vectorforge-ai/sdk
v0.1.2
Published
Official Node.js/TypeScript SDK for VectorForge Cloud APIs
Maintainers
Readme
VectorForge Node SDK
Official TypeScript/Node.js client for VectorForge Cloud APIs.
VectorForge is a trust and confidence layer for AI and automations, providing:
- DIVTs (Digital Integrity Verification Tokens) - Cryptographic "birth certificates" for data
- AI Answer Confidence Scoring - Privacy-preserving and comprehensive scoring
- Worldstate Logging - Immutable event capture for AI operations
- Hybrid Post-Quantum Cryptography - ECDSA P-521 + ML-DSA-65 signatures
Installation
From npm (Recommended)
npm install @vectorforge-ai/sdkFrom Source (Development)
git clone https://github.com/vectorforge/api
cd api/sdk/node
npm install
npm run buildFor image support:
npm install sharpQuick Start
Configuration
import { createVectorForgeClient } from '@vectorforge-ai/sdk';
// Option 1: Use environment variables (recommended)
// export VF_API_BASE_URL="https://api.vectorforge.ai"
// export VF_API_KEY="vf_prod_YourApiKeyHere"
const client = createVectorForgeClient();
// Option 2: Pass config directly
const client = createVectorForgeClient({
baseUrl: "https://api.vectorforge.ai",
apiKey: "vf_prod_YourApiKeyHere",
});High-Level API (Recommended)
The SDK provides high-level methods that handle canonicalization and hashing automatically. These are the recommended way to use VectorForge.
Register Text Content
import { createVectorForgeClient } from '@vectorforge-ai/sdk';
const client = createVectorForgeClient();
const result = await client.registerContent(
'prompt:123',
'What is the capital of France?',
'prompt_receipt_v1',
{ user_id: 'user-456', session: 'sess-789' }
);
console.log(`DIVT ID: ${result.divt_id}`);
console.log(`ECDSA signature: ${result.ecdsa_sig_b64.substring(0, 32)}...`);
console.log(`ML-DSA signature: ${result.ml_dsa_sig_b64.substring(0, 32)}...`);
console.log(`Ledger status: ${result.ledger_status}`);What it does:
- Normalizes text (Unicode NFC, line endings, trim whitespace)
- Computes SHA3-512 hash
- Creates DIVT with hybrid post-quantum signatures
- Returns
divt_idfor future verification
Register JSON Data
const result = await client.registerJson(
'rag_snapshot:v42',
{
snapshot_type: 'rag-corpus',
doc_hashes: ['hash1', 'hash2'],
index_hash: 'index_hash_value',
timestamp: '2025-11-21T10:00:00Z',
},
'rag_snapshot_v1',
{ project: 'hr-assistant', env: 'prod' }
);
console.log(`RAG snapshot registered: ${result.divt_id}`);What it does:
- Canonical JSON serialization (sorted keys, minimal whitespace)
- Computes SHA3-512 hash
- Creates DIVT
Register Embedding Vector
const result = await client.registerEmbedding(
'chunk:doc-123:p5',
[0.123456, -0.987654, 0.456789, ...], // Your embedding vector
'rag_chunk_v1',
{ document_id: 'doc-123', paragraph: 5 },
6 // Decimal precision
);
console.log(`Embedding registered: ${result.divt_id}`);What it does:
- Validates embedding (rejects NaN/Infinity)
- Formats with fixed precision for deterministic hashing
- Computes SHA3-512 hash
- Creates DIVT
Register Image
Requires: npm install sharp
import { readFile } from 'fs/promises';
const imageBuffer = await readFile('receipt.png');
const result = await client.registerImage(
'image:receipt-456',
imageBuffer,
'image_receipt_v1',
{ source: 'mobile_app', user_id: 'user-789' },
1024 // Max dimension
);
console.log(`Image registered: ${result.divt_id}`);What it does:
- Decodes image (supports PNG, JPEG, WebP)
- Normalizes to sRGB color space
- Resizes if needed (preserves aspect ratio)
- Re-encodes as deterministic PNG
- Computes SHA3-512 hash
- Creates DIVT
Complete Example: Prompt Receipt with Verification
import { createVectorForgeClient } from '@vectorforge-ai/sdk';
const client = createVectorForgeClient();
// Register AI prompt + response
const promptData = {
prompt: 'What is the capital of France?',
response: 'Paris',
model: 'gpt-4',
timestamp: '2025-11-21T10:00:00Z',
};
const registerResult = await client.registerJson(
'prompt_receipt:flow-abc-123',
promptData,
'prompt_receipt_v1',
{ workflow: 'customer_support' }
);
const divtId = registerResult.divt_id;
console.log(`✓ Prompt receipt registered: ${divtId}`);
// Later: Verify the prompt receipt
const verifyResult = await client.verifyJson(divtId, promptData);
if (verifyResult.verified) {
console.log('✓ DIVT is valid');
console.log(` - Hash valid: ${verifyResult.hash_valid}`);
console.log(` - ECDSA signature valid: ${verifyResult.ecdsa_signature_valid}`);
console.log(` - ML-DSA signature valid: ${verifyResult.ml_dsa_signature_valid}`);
console.log(` - Object ID: ${verifyResult.object_id}`);
console.log(` - Created: ${verifyResult.created_at}`);
console.log(` - Ledger status: ${verifyResult.ledger_status}`);
} else {
console.log('✗ DIVT verification failed');
console.log(` - Hash valid: ${verifyResult.hash_valid}`);
console.log(` - Revoked: ${verifyResult.revoked}`);
}Low-Level API (Advanced)
For advanced use cases where you want to compute hashes yourself, use the low-level register() method:
import { canon } from '@vectorforge-ai/sdk';
// Compute hash manually
const text = 'Hello, World!';
const hashB64 = canon.hashContentV1(text);
// Register with pre-computed hash
const result = await client.register({
object_id: 'doc-123',
hash_mode: 'content',
hash_version: 'content_v1',
hash_b64: hashB64,
data_type: 'prompt_receipt_v1',
});Canonicalization Utilities
import { canon } from '@vectorforge-ai/sdk';
// Text canonicalization
const hashB64 = canon.hashContentV1('Hello, World!');
// JSON canonicalization
const hashB64 = canon.hashJsonV1({ key: 'value', nested: { a: 1 } });
// Embedding canonicalization
const hashB64 = canon.hashEmbeddingV1([0.1, 0.2, 0.3], 6);
// Image canonicalization (requires sharp)
const imageBuffer = await readFile('image.png');
const hashB64 = await canon.hashImageV1(imageBuffer, 1024);
// Or get canonical bytes without hashing
const canonicalBuffer = canon.canonicalizeContentV1('Hello');
const hashB64 = canon.sha3512Digest(canonicalBuffer);Verification
Verify a Single DIVT
// Using hash_b64 (advanced)
const result = await client.verify({
divt_id: '019abc12-3456-7890-abcd-ef0123456789',
hash_b64: 'your-precomputed-hash-base64',
});
if (result.verified) {
console.log('✓ DIVT is valid');
console.log(` - Hash valid: ${result.hash_valid}`);
console.log(` - ECDSA valid: ${result.ecdsa_signature_valid}`);
console.log(` - ML-DSA valid: ${result.ml_dsa_signature_valid}`);
console.log(` - Revoked: ${result.revoked}`);
} else {
console.log('✗ DIVT verification failed');
}Verify with High-Level Helpers
// Verify text content
const result = await client.verifyContent(divtId, 'Hello, World!');
// Verify JSON data
const result = await client.verifyJson(divtId, { key: 'value' });Bundle API
Get comprehensive verification bundles for DIVTs including worldstate context and scoring results.
Get Bundle by DIVT ID
const bundle = await client.getBundle({
divt_id: '019abc12-3456-7890-abcd-ef0123456789',
});
console.log('DIVT Verification:');
console.log(` - Verified: ${bundle.divt.verified}`);
console.log(` - Hash valid: ${bundle.divt.hash_valid}`);
console.log(` - Ledger status: ${bundle.divt.ledger_status}`);
console.log(`Worldstate events: ${bundle.worldstate.length}`);
console.log(`Scoring events: ${bundle.scoring.length}`);
console.log(`Generated at: ${bundle.generated_at}`);Get Bundle by Object ID
const bundle = await client.getBundle({
object_id: 'prompt_receipt:flow-abc-123',
include_history: true,
});Scoring API
Privacy Score (No Raw Content Sent)
const result = await client.scorePrivacy({
query_id: 'query-123',
answer_id: 'answer-456',
evidence: [
{
object_id: 'chunk:doc-1:p1',
divt_id: '019abc...',
tenant_id: 'my-tenant',
similarity: 0.95,
chunk_confidence: 0.9,
},
],
});
console.log(`Overall confidence: ${result.overall_confidence}`);
console.log(`Semantic confidence: ${result.semantic_confidence}`);
console.log(`Integrity score: ${result.integrity_score}`);
console.log(`Verified count: ${result.verified_count}/${result.vector_count}`);Full Score (With Groq Judge)
const result = await client.scoreFull({
query: 'What is the capital of France?',
answer: 'The capital of France is Paris.',
evidence: [
{
object_id: 'chunk:doc-1:p1',
divt_id: '019abc...',
tenant_id: 'my-tenant',
text: 'Paris is the capital city of France.',
similarity: 0.95,
},
],
options: {
log_worldstate: 'minimal',
},
});
console.log(`Overall confidence: ${result.overall_confidence}`);
console.log(`Support score: ${result.support_score}`);
console.log(`Faithfulness score: ${result.faithfulness_score}`);Worldstate Read
Get Single Worldstate Record
// Get worldstate record metadata
const item = await client.getWorldstateItem({
wsl_id: '019abc12-3456-7890-abcd-ef0123456789',
});
console.log(`Kind: ${item.kind}`);
console.log(`Timestamp: ${item.timestamp}`);
console.log(`Ledger status: ${item.ledger_status}`);
console.log(`Summary: ${item.data_summary}`);
// Get worldstate record with full data from S3
const itemWithData = await client.getWorldstateItem({
wsl_id: '019abc12-3456-7890-abcd-ef0123456789',
include_data: true,
});
console.log('Full data:', itemWithData.data);List Worldstate Records
// List all records
const result = await client.listWorldstate();
console.log(`Found ${result.count} records`);
// List with filters
const promptReceipts = await client.listWorldstate({
kind: 'prompt_receipt',
created_from: '2025-11-01T00:00:00Z',
created_to: '2025-11-30T23:59:59Z',
limit: 50,
});
// Paginate through all results
let cursor = promptReceipts.cursor;
while (cursor) {
const page = await client.listWorldstate({ cursor });
for (const item of page.items) {
console.log(`${item.wsl_id}: ${item.data_summary}`);
}
cursor = page.cursor;
}Available Filters:
kind: Filter by event type (prompt_receipt,scoring_event,rag_snapshot, etc.)created_from: Start of time range (ISO 8601)created_to: End of time range (ISO 8601)limit: Page size (max 100, default 50)cursor: Pagination cursor from previous response
Stream Events (SSE)
const oneHourAgo = new Date(Date.now() - 3600000).toISOString();
await client.streamEvents(
{
since: oneHourAgo,
types: ['divt_registered', 'scoring_event'],
limit: 50,
},
(event) => {
console.log(`[${event.type}] ${event.id} at ${event.timestamp}`);
}
);Error Handling
import { VectorForgeAPIError } from '@vectorforge-ai/sdk';
try {
const result = await client.registerContent(
'doc-123',
'Hello, World!',
'prompt_receipt_v1'
);
} catch (error) {
if (error instanceof VectorForgeAPIError) {
console.error(`API Error: ${error.message}`);
console.error(`Status: ${error.statusCode}`);
console.error(`Code: ${error.error}`);
if (error.details) {
console.error(`Details: ${error.details}`);
}
} else {
console.error(`Unexpected error: ${error}`);
}
}Common Error Codes:
invalid_api_key(401) - API key invalid or expiredquota_exceeded(429) - Monthly request limit reachedrate_limit_exceeded(429) - Too many requestsplan_limitation(403) - Feature not available on your plannetwork_error(0) - Network connectivity issue
Type Support
Full TypeScript support with type definitions:
import type {
RegisterInput,
RegisterResult,
VerifyInput,
VerifyResult,
BundleInput,
BundleResult,
PrivacyScoreInput,
FullScoreInput,
ScoreResult,
StreamEventsInput,
StreamEvent,
} from '@vectorforge-ai/sdk';Integration Tests
To run integration tests against the live API:
export VF_API_BASE_URL="https://api.vectorforge.ai"
export VF_API_KEY="your-api-key"
npm testRequirements
- Node.js: >= 18.0.0 (uses native fetch)
- Dependencies:
js-sha3(SHA3-512 hashing)
- Optional:
sharp>= 0.33.0 (for image registration)
Related Documentation
- API Reference - Complete HTTP API documentation
- Implementation Plan - Full system specification
- Python SDK - Python SDK documentation
Support
- Issues: GitHub Issues
- Website: https://vectorforge.ai
License
MIT © VectorForge
