npm.io
4.0.0 • Published 6d ago

@proofchain/sdk

Licence
MIT
Version
4.0.0
Deps
0
Size
493 kB
Vulns
0
Weekly
172

ProofChain JavaScript/TypeScript SDK

Official JavaScript/TypeScript SDK for ProofChain - blockchain-anchored document attestation.

Works in Node.js and browsers.

Installation

npm install @proofchain/sdk
# or
yarn add @proofchain/sdk
# or
pnpm add @proofchain/sdk

Quick Start

import { ProofChain } from '@proofchain/sdk';

// Create client
const client = new ProofChain({ apiKey: 'your-api-key' });

// Attest a document
const result = await client.documents.attest({
  file: myFile, // File, Blob, or Buffer
  userId: 'user@example.com',
  eventType: 'contract_signed',
});

console.log('IPFS Hash:', result.ipfsHash);
console.log('Verify URL:', result.verifyUrl);

// Verify
const verification = await client.verify(result.ipfsHash);
console.log('Valid:', verification.valid);

High-Performance Ingestion

For maximum throughput, use the dedicated IngestionClient which connects directly to the Rust ingestion API:

import { IngestionClient } from '@proofchain/sdk';

const ingestion = new IngestionClient({ apiKey: 'your-api-key' });

// Single event (immediate attestation)
const result = await ingestion.ingest({
  userId: 'user-123',
  eventType: 'purchase',
  data: { amount: 99.99, product: 'widget' },
});

console.log('Event ID:', result.eventId);
console.log('Certificate:', result.certificateId);

// Batch events (up to 1000 per request)
const batchResult = await ingestion.ingestBatch({
  events: [
    { userId: 'user-1', eventType: 'click', data: { page: '/home' } },
    { userId: 'user-2', eventType: 'click', data: { page: '/products' } },
    // ... up to 1000 events
  ],
});

console.log('Queued:', batchResult.queued);
console.log('Failed:', batchResult.failed);

State Channels (High-Volume Streaming)

For high-throughput scenarios (100K+ events/sec):

import { ProofChain } from '@proofchain/sdk';

const client = new ProofChain({ apiKey: 'your-api-key' });

// Create a state channel
const channel = await client.channels.create({ name: 'iot-sensors' });

// Stream events
for (const reading of sensorReadings) {
  await client.channels.stream(channel.channelId, {
    eventType: 'sensor_reading',
    userId: reading.deviceId,
    data: { temperature: reading.temp, humidity: reading.humidity },
  });
}

// Settle on-chain
const settlement = await client.channels.settle(channel.channelId);
console.log('TX Hash:', settlement.txHash);

Features

Documents
// Attest a file (Node.js)
import { readFileSync } from 'fs';

const result = await client.documents.attest({
  file: readFileSync('contract.pdf'),
  filename: 'contract.pdf',
  userId: 'user@example.com',
  eventType: 'document_uploaded',
  metadata: { department: 'legal' },
});

// Attest a file (Browser)
const fileInput = document.querySelector('input[type="file"]');
const result = await client.documents.attest({
  file: fileInput.files[0],
  userId: 'user@example.com',
});

// Get document by hash
const doc = await client.documents.get('Qm...');
Events
// Create an event
const event = await client.events.create({
  eventType: 'user_action',
  userId: 'user123',
  data: { action: 'login', ip: '192.168.1.1' },
});

// List events
const events = await client.events.list({
  userId: 'user123',
  eventType: 'user_action',
  limit: 100,
});

// Search events
const results = await client.events.search({
  query: 'login',
  startDate: '2024-01-01',
  endDate: '2024-12-31',
});
Verification
// Verify by IPFS hash
const result = await client.verify('Qm...');

if (result.valid) {
  console.log('Timestamp:', result.timestamp);
  console.log('Blockchain TX:', result.blockchainTx);
  console.log('Certificate ID:', result.certificateId);
}
Certificates
// Issue a certificate
const cert = await client.certificates.issue({
  recipientName: 'John Doe',
  recipientEmail: 'john@example.com',
  title: 'Course Completion',
  description: 'Completed JavaScript Fundamentals',
  metadata: { courseId: 'JS101', score: 95 },
});

console.log('Certificate ID:', cert.certificateId);
console.log('QR Code:', cert.qrCodeUrl);

// Revoke
await client.certificates.revoke(cert.certificateId, 'Issued in error');
Webhooks
// Register a webhook
const webhook = await client.webhooks.create({
  url: 'https://your-app.com/webhook',
  events: ['document.attested', 'channel.settled'],
  secret: 'your-secret',
});

// List webhooks
const webhooks = await client.webhooks.list();

// Delete
await client.webhooks.delete(webhook.id);
Quests

Quests are gamified user journeys with steps that can be completed via events.

// List available quests for a user (with their progress)
const quests = await client.quests.listAvailable(userId);
// Returns: { quest: Quest, progress?: UserQuestProgress }[]

// Each quest has a type that determines behavior:
// - 'epic': Long-form quests - user must explicitly start
// - 'quick_hit': Short quests - auto-enrolls on matching event
// - 'challenge': Time-limited quests - auto-enrolls on matching event

for (const { quest, progress } of quests) {
  console.log(`${quest.name} (${quest.quest_type})`);
  if (progress) {
    console.log(`  Progress: ${progress.completion_percentage}%`);
  }
}

// Start an Epic quest (required for epic type only)
const progress = await client.quests.startQuest(questId, userId);

// Get user's progress on a specific quest
const questProgress = await client.quests.getUserProgress(questId, userId);

// Get all quest progress for a user
const allProgress = await client.quests.getAllUserProgress(userId);

// Complete a step manually (for manual step types)
const result = await client.quests.completeStep(questId, userId, stepIndex);
console.log('Step completed:', result.step_completed);
console.log('Quest completed:', result.quest_completed);

Quest Types:

Type Behavior
epic Long-form, multi-step quests. User must call startQuest() to begin.
quick_hit Short, easy quests. Auto-enrolls when user triggers a matching event.
challenge Time-limited or competitive. Auto-enrolls when user triggers a matching event.
Real-Time Notifications (SSE)

Push notifications to your frontend in real-time when quest/reward events happen. Uses Server-Sent Events (SSE) — no WebSocket setup needed.

import { ProofChain } from '@proofchain/sdk';

const client = new ProofChain({ apiKey: 'your-api-key' });

// Subscribe to notifications for a user
const unsubscribe = client.notifications.subscribe('user-123', (event) => {
  console.log('Notification:', event.event, event.data);

  switch (event.event) {
    case 'quest_step_completed':
      showToast(`Step completed: ${event.data.step_name}`);
      break;

    case 'quest_completed':
      showConfetti();
      showToast(`Quest completed: ${event.data.quest_name}! 🎉`);
      break;

    case 'badge_earned':
      showBadgeModal({
        name: event.data.reward_name,
        image: event.data.image_url,
      });
      break;

    case 'reward_claimable':
      showClaimButton(event.data.quest_id);
      break;

    case 'reward_earned':
      showToast(`Reward earned: ${event.data.reward_name}`);
      break;
  }
}, {
  onConnect: () => console.log('Connected to notifications'),
  onDisconnect: () => console.log('Disconnected, will auto-reconnect...'),
  onError: (err) => console.error('Notification error:', err),
  autoReconnect: true,    // default: true
  reconnectDelay: 3000,   // default: 3000ms
});

// Cleanup when component unmounts or user logs out
unsubscribe();

React example:

import { useEffect } from 'react';
import { ProofChain } from '@proofchain/sdk';

function useNotifications(client: ProofChain, userId: string) {
  useEffect(() => {
    const unsub = client.notifications.subscribe(userId, (event) => {
      // Handle notification (show toast, update UI, etc.)
      console.log(event.event, event.data);
    });
    return () => unsub(); // cleanup on unmount
  }, [client, userId]);
}

End-user JWT auth (for PWA/frontend without API key):

const client = ProofChain.forEndUser({
  userToken: auth.getIdToken(),
  tenantId: 'my-tenant-slug',
});

// End-user can only subscribe to their own notifications
const unsub = client.notifications.subscribe(myUserId, (event) => {
  // ...
});

Notification event types:

Event When Data fields
quest_step_completed A quest step is completed quest_id, quest_name, step_index, step_name, steps_completed, total_steps, points_earned
quest_completed A quest is fully completed (auto-award) quest_id, quest_name, points_earned, completion_count
reward_claimable A quest is completed (claimable mode) quest_id, quest_name, points_earned, reward_definition_id
badge_earned A badge reward is distributed quest_id, quest_name, reward_id, reward_name, reward_type, image_url
reward_earned A non-badge reward is distributed quest_id, quest_name, reward_id, reward_name, reward_type, value, image_url

Notification payload shape:

interface NotificationEvent {
  id: string;           // unique event ID
  event: string;        // event type (see table above)
  data: Record<string, any>; // event-specific data
  tenant_id: string;
  user_id: string;
  timestamp: string;    // ISO 8601
}

Error Handling

import { ProofChain, ProofChainError, AuthenticationError, RateLimitError } from '@proofchain/sdk';

try {
  const result = await client.documents.attest(req);
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error('Invalid API key');
  } else if (error instanceof RateLimitError) {
    console.error(`Rate limited. Retry after ${error.retryAfter} seconds`);
  } else if (error instanceof ProofChainError) {
    console.error(`API error: ${error.message}`);
  }
}

Configuration

import { ProofChain } from '@proofchain/sdk';

// Full configuration
const client = new ProofChain({
  apiKey: 'your-api-key',
  baseUrl: 'https://ingest.proofchain.co.za', // Ingestion API (Rust)
  mgmtUrl: 'https://api.proofchain.co.za',    // Management API (Python)
  timeout: 30000, // 30 seconds
  maxRetries: 3,
});

// From environment variable (Node.js)
// Set PROOFCHAIN_API_KEY
const client = ProofChain.fromEnv();

TypeScript Support

Full TypeScript support with exported types:

import type {
  AttestationResult,
  Event,
  Channel,
  ChannelStatus,
  Settlement,
  Certificate,
  Webhook,
  VerificationResult,
  SearchResult,
} from '@proofchain/sdk';

Browser Usage

The SDK works in browsers with no additional configuration:

<script type="module">
  import { ProofChain } from 'https://esm.sh/@proofchain/sdk';

  const client = new ProofChain({ apiKey: 'your-api-key' });
  
  // Use with file input
  document.querySelector('#upload').addEventListener('change', async (e) => {
    const file = e.target.files[0];
    const result = await client.documents.attest({
      file,
      userId: 'user@example.com',
    });
    console.log('Attested:', result.ipfsHash);
  });
</script>

License

MIT License - see LICENSE for details.

Support

Keywords