npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@voideddev/e2ee-client

v0.3.0

Published

Browser-based E2EE client library for true end-to-end encryption including keys, crypto, compression, and local storage adapters.

Readme

voideddev E2EE Client Library

A comprehensive browser-based end-to-end encryption library that provides true client-side encryption with advanced security features, automatic compression, and user-friendly key management UI components.

⚡ Powered by Rust + WebAssembly - Cryptographic operations can run through Rust-compiled WASM for enhanced performance, with automatic fallback to Web Crypto API.

📋 Table of Contents

🚀 Features

  • Rust + WASM Core: Optional WebAssembly backend powered by Rust for maximum performance
  • True E2EE: All encryption/decryption happens in the browser - your server never sees keys
  • Advanced Security: Digital signatures, forward secrecy, key agreement, and identity verification
  • Automatic Compression: Intelligent compression with Brotli and Gzip support
  • Large File Support: Automatic chunking with client-side limits up to 32 GiB
  • Benchmarks: Built-in benchmarking helpers for compression and pipeline
  • Key Management UI: Built-in export/import modals with QR code support
  • Multiple Storage Options: IndexedDB, custom storage adapters
  • Framework Agnostic: Works with React, Vue, Svelte, or vanilla JavaScript
  • Signal-Level Security: High-iteration key derivation, safety numbers, and fingerprint verification
  • Key Rotation: Support for secure key rotation with migration workflows
  • Passkey-Derived Keys (0.3.0): Deterministic key derivation from passkey material
  • X25519 Key Sharing (0.3.0): Secure key exchange and device transfer helpers

🎯 Quick Start

import { VoidedE2EEClient } from "@voideddev/e2ee-client";

// Create client with default settings
const client = new VoidedE2EEClient();

// Encrypt data (full pipeline: compression + encryption + signatures)
const encrypted = await client.encrypt("Hello, World!");
// Non-chunked return shape:
// {
//   data: "base64_encrypted_data",
//   iv: "base64_iv",
//   keyId: "default",
//   algorithm: "AES-GCM",
//   version: "1.0",
//   compression: { algorithm: "brotli" | "gzip" | "none", originalSize: 13, compressedSize: 11 },
//   signature?: "base64_signature",
//   ephemeralPublicKey?: "base64_public_key",
//   textEncoding?: "utf8" | "utf16le"
// }

// Decrypt data
const decrypted = await client.decrypt(encrypted);
console.log(decrypted); // 'Hello, World!'

// Export key for backup
const key = await client.exportKey();
console.log("Backup this key:", key); // "U2FsdGVkX19QYXNzd29yZFRlc3Q="

📦 Installation

npm install @voideddev/e2ee-client

🔧 Core Components

1. Main Client (VoidedE2EEClient)

The primary encryption client that handles all cryptographic operations, compression, optional signatures, optional forward secrecy, and automatic chunking of large payloads.

import { VoidedE2EEClient } from "@voideddev/e2ee-client";

// Basic usage
const client = new VoidedE2EEClient();

// Advanced configuration
const client = new VoidedE2EEClient({
  keyId: "user123",
  autoGenerateKey: true,
  enableSignatures: true,
  enableForwardSecrecy: true,
  enableChunking: true,
  chunkSize: 2 * 1024 * 1024, // 2MB chunks
  minChunkThreshold: 10 * 1024 * 1024, // 10MB threshold
});

// Example usage with return values (non-chunked):
const encrypted = await client.encrypt("sensitive data");
// Returns: { data, iv, keyId: 'user123', algorithm: 'AES-GCM', version: '1.0', compression, signature?, ephemeralPublicKey?, textEncoding? }

const decrypted = await client.decrypt(encrypted);
// Returns: "sensitive data"

Configuration Options:

  • keyId: Unique identifier for the key (default: 'default')
  • autoGenerateKey: Auto-generate key if none exists (default: true)
  • enableSignatures: Enable digital signatures for authenticity
  • enableForwardSecrecy: Enable ephemeral keys for forward secrecy
  • enableChunking: Enable automatic chunking for large data
  • chunkSize: Size of chunks in bytes (default: 2MB)
  • minChunkThreshold: Minimum size to trigger chunking (default: 10MB)

Additional encryption-time options passed to encrypt(data, options):

  • compressionAlgorithm: 'auto' | 'gzip' | 'brotli' | 'none' (default: 'auto')
  • compressionLevel: number (gzip: 1–9, brotli: 1–11; default: 6)
  • forceCompression: boolean (override auto-skip logic)
  • originalSizeBytes: number (explicit data size for limit enforcement)
  • resumeTokenOriginalSize: number (explicit size when resuming)

2. Crypto Service (CryptoService)

Handles all cryptographic operations using Web Crypto API.

import { CryptoService } from "@voideddev/e2ee-client";

const crypto = new CryptoService();

// Generate encryption key
const key = await crypto.generateKey();
// Returns: CryptoKey (Web Crypto API key object)

// Generate signing key pair
const signingKeyPair = await crypto.generateSigningKeyPair();
// Returns: { publicKey: CryptoKey, privateKey: CryptoKey }

// Generate key agreement key pair
const agreementKeyPair = await crypto.generateKeyAgreementKeyPair();
// Returns: { publicKey: CryptoKey, privateKey: CryptoKey }

// Derive key from data
const derivedKey = await crypto.deriveKeyFromPassword(data, salt, iterations);
// Returns: CryptoKey (Derived AES-GCM key)

// Perform key agreement
const sharedKey = await crypto.deriveSharedKey(privateKey, publicKey);
// Returns: CryptoKey (Shared AES-GCM key)

// Get key fingerprint (SHA-256 hex of key material)
const fingerprint = await crypto.getKeyFingerprint(key);
// Returns: 64-character hex string (e.g., "dffd6021bb2bd5b0af67...")

// Get safety numbers (like Signal)
const safetyNumbers = await crypto.getSafetyNumbers(key);
// Returns: "123 456 789 012 345" (Human-readable safety numbers)

Key Functions:

  • generateKey(): Generate AES-GCM encryption key
  • generateSigningKeyPair(): Generate ECDSA key pair for signatures
  • generateKeyAgreementKeyPair(): Generate ECDH key pair for key agreement
  • deriveKeyFromPassword(): PBKDF2-based key derivation from data (deterministic keys for cloud deployments)
  • deriveSharedKey(): ECDH key agreement
  • getKeyFingerprint(): Generate key fingerprint for verification
  • getSafetyNumbers(): Generate human-readable safety numbers

3. Compression Module (compression.ts)

Provides intelligent compression with automatic and explicit algorithm selection.

import {
  compress,
  decompress,
  analyzeCompression,
} from "@voideddev/e2ee-client";

// Compress with explicit or automatic algorithm selection
const result = await compress(data, {
  algorithm: "auto", // 'auto' | 'brotli' | 'gzip' | 'none'
  minSizeThreshold: 100, // Skip compression below threshold
  compressionLevel: 6, // 1-9 for gzip, 1-11 for brotli
});
// Returns: { compressed: Uint8Array(23) [...], algorithm: "brotli", originalSize: 52, compressedSize: 23, compressionRatio: 0.44 }

// Decompress
const decompressed = await decompress(result.compressed, result.algorithm);
// Returns: Uint8Array(52) [...] (Decompressed data)

// Analyze compression effectiveness
const analysis = await analyzeCompression(data);
// Returns: { originalSize: 52, gzipSize: 25, brotliSize: 23, gzipRatio: 0.48, brotliRatio: 0.44, recommendation: "brotli" }
console.log(`Recommendation: ${analysis.recommendation}`);
console.log(`Brotli ratio: ${analysis.brotliRatio}`);
console.log(`Gzip ratio: ${analysis.gzipRatio}`);

Features:

  • Automatic algorithm selection (Brotli preferred, Gzip fallback)
  • Size-based compression decisions
  • Entropy analysis to avoid compressing already-compressed data
  • Compression ratio analysis
  • Browser-compatible using fflate and brotli-wasm

4. Key Manager (KeyManager)

Manages encryption keys with versioning, rotation, and migration support. Rotation is protected by an internal lock to prevent concurrent operations. During migration, a legacy key is cached and used transparently for decryption until finalizeMigration() is called.

Important: The KeyManager uses in-memory caching for performance but relies on the provided StorageService for persistence. Keys are automatically loaded from storage and cached in memory. If you're using a custom storage implementation, ensure it provides reliable persistence.

import { KeyManager } from "@voideddev/e2ee-client";

const keyManager = new KeyManager(storage, crypto, keyId);

// Get current key
const key = await keyManager.getCurrentKey();
// Returns: CryptoKey (Current encryption key)

// Force rotate key (delete old, generate new)
const newKey = await keyManager.forceRotate();
// Returns: "base64_new_key_string"

// Start migration (keep old key, generate new)
const newKey = await keyManager.startMigration(cutoffTime);
// Returns: "base64_new_key_string"

// Finalize migration (remove old key)
await keyManager.finalizeMigration();
// Returns: void (No return value)

// Get migration status
const status = await keyManager.getMigrationStatus();
// Returns: { isActive: true, oldKeyVersion: 1, newKeyVersion: 2, cutoffTime: Date, lastProgress: 0.75, createdAt: Date } | null

Key Features:

  • Automatic key generation and caching
  • Key versioning with migration support
  • Rotation lock to prevent concurrent operations
  • Legacy key support during migration
  • Secure key storage and retrieval
  • In-memory caching with persistent storage backend

5. Storage Service (StorageService)

Abstracts storage operations for keys and metadata with robust IndexedDB implementation. The built-in IndexedDBStorage now also persists signing and agreement key pairs and migration state alongside the main key.

Why Frontend Keys?

Client-Side Security Model: The e2ee-client library operates on a true client-side security model where encryption keys never leave the user's browser. This approach provides several critical security benefits:

  • Zero Server Knowledge: Your server never sees encryption keys, eliminating a major attack vector
  • User Control: Users maintain complete control over their encryption keys
  • Privacy by Design: Even if your server is compromised, encrypted data remains secure
  • Compliance: Meets strict privacy requirements (GDPR, HIPAA, etc.)

Key Management Strategy:

  • Keys are generated, stored, and managed entirely in the browser
  • Users can export/import keys for backup and device migration
  • Key rotation and migration happen locally without server involvement
  • Multiple key versions can coexist during migration periods

IndexedDB Utilization

The library uses IndexedDB as the primary storage mechanism for several reasons:

Why IndexedDB?

  • Persistent Storage: Survives browser restarts and device reboots
  • Large Capacity: Can store multiple keys, key pairs, and migration states
  • Structured Data: Supports complex data structures and relationships
  • Security: Sandboxed per origin, isolated from other websites
  • Performance: Asynchronous operations don't block the main thread

Database Structure:

// IndexedDB Database: 'voideddev-e2ee' (version 3)
{
    // Store: 'keys' - Main encryption keys
    keys: {
        keyPath: 'id',
        records: [
            { id: 'user123', key: 'base64_encryption_key' },
            { id: 'default', key: 'base64_encryption_key' }
        ]
    },

    // Store: 'migrations' - Key migration states
    migrations: {
        keyPath: 'id',
        records: [
            {
                id: 'user123',
                isActive: true,
                oldKeyVersion: 1,
                newKeyVersion: 2,
                cutoffTime: Date,
                lastProgress: 0.75,
                createdAt: Date
            }
        ]
    },

    // Store: 'keyPairs' - Signing and agreement keys
    keyPairs: {
        keyPath: 'id',
        records: [
            { id: 'user123-signing', keyPair: 'base64_signing_key_pair' },
            { id: 'user123-agreement', keyPair: 'base64_agreement_key_pair' }
        ]
    }
}

Storage Operations:

import { StorageService, IndexedDBStorage } from "@voideddev/e2ee-client";

// Use built-in IndexedDB storage
const storage = new StorageService(new IndexedDBStorage());

// Or implement custom storage
const customStorage = {
  async getKey(keyId: string): Promise<string | null> {
    /* ... */
  },
  async setKey(keyId: string, key: string): Promise<void> {
    /* ... */
  },
  async removeKey(keyId: string): Promise<void> {
    /* ... */
  },
  // ... other methods
};

const storage = new StorageService(customStorage);

// Example storage operations with return values:
const key = await storage.getKey("user123");
// Returns: "base64_key_string" | null

await storage.setKey("user123", "base64_key_string");
// Returns: void (No return value)

await storage.removeKey("user123");
// Returns: void (No return value)

Storage Interface:

  • getKey(keyId): Retrieve encryption key
  • setKey(keyId, key): Store encryption key
  • removeKey(keyId): Delete encryption key
  • getMigrationState(keyId): Get migration status
  • setMigrationState(keyId, state): Store migration state
  • getKeyPair(keyId, type): Retrieve key pairs
  • setKeyPair(keyId, type, keyPair): Store key pairs

IndexedDB Features:

  • Automatic Versioning: Database schema upgrades handled automatically
  • Error Handling: Graceful fallbacks when IndexedDB is unavailable
  • Transaction Safety: ACID-compliant operations for data integrity
  • Memory Management: Efficient caching with automatic cleanup
  • Cross-Tab Support: Keys accessible across browser tabs/windows

6. Key UI Components (key-ui.ts)

Built-in UI components for key export and import with QR code support and extensive customization options.

QR Modal Integration

The library provides sophisticated QR code integration for secure key backup and transfer:

Key Export Modal Features:

  • QR Code Generation: Automatic QR code generation using the qrcode library
  • Fallback Support: Graceful degradation when QR library is unavailable
  • Web Share API: Native sharing capabilities on supported platforms
  • Multiple Export Formats: Text, QR code, download, and share options
  • Responsive Design: Mobile-friendly interface with touch support

Key Import Modal Features:

  • QR Code Scanning: Built-in QR code scanning capability (requires camera access)
  • Manual Input: Text area for pasting keys manually
  • Validation: Automatic key format validation
  • Error Handling: Comprehensive error messages and recovery options

Customization Options

The UI components are highly customizable through CSS classes and configuration options:

import { createKeyExport, createKeyImport } from "@voideddev/e2ee-client";

// Create export UI with full customization
const keyExport = createKeyExport(client, {
  // Display options
  showQR: true, // Show QR code
  showText: true, // Show text area
  showShare: true, // Enable Web Share API

  // Content
  title: "Backup Your Encryption Key",

  // CSS customization classes
  className: "my-key-export",
  overlayClassName: "my-overlay",
  modalClassName: "my-modal",
  qrContainerClassName: "my-qr-container",
  textAreaClassName: "my-textarea",
  buttonClassName: "my-button",
  copyButtonClassName: "my-copy-btn",
  downloadButtonClassName: "my-download-btn",
  shareButtonClassName: "my-share-btn",
  closeButtonClassName: "my-close-btn",
  warningClassName: "my-warning",
  keyIdClassName: "my-key-id",

  // Event callbacks
  onClose: () => console.log("Modal closed"),
  onCopy: () => console.log("Key copied!"),
  onDownload: () => console.log("Key downloaded!"),
  onShare: () => console.log("Key shared!"),
});
// Returns: VoidedKeyExport (Key export UI component instance)

// Create import UI with customization
const keyImport = createKeyImport(client, {
  title: "Import Encryption Key",
  showQRScan: true, // Enable QR scanning

  // CSS customization classes
  className: "my-key-import",
  overlayClassName: "my-overlay",
  modalClassName: "my-modal",
  textAreaClassName: "my-textarea",
  buttonClassName: "my-button",
  importButtonClassName: "my-import-btn",
  scanButtonClassName: "my-scan-btn",
  cancelButtonClassName: "my-cancel-btn",
  closeButtonClassName: "my-close-btn",
  warningClassName: "my-warning",

  // Event callbacks
  onClose: () => console.log("Modal closed"),
  onSuccess: () => console.log("Key imported!"),
  onError: (error) => console.error("Import failed:", error),
});
// Returns: VoidedKeyImport (Key import UI component instance)

// Show modals
keyExport.show(); // Returns: void (No return value, shows modal)
keyImport.show(); // Returns: void (No return value, shows modal)

QR Code Implementation Details

QR Code Generation:

  • Uses the qrcode library for high-quality QR codes
  • Automatic fallback to text representation if library unavailable
  • Configurable QR code size, margin, and colors
  • Includes key ID and metadata in QR format

QR Code Scanning:

  • Camera-based QR code scanning (requires user permission)
  • Automatic key extraction and validation
  • Support for multiple QR code formats
  • Error handling for invalid or corrupted QR codes

Web Share API Integration:

  • Native sharing on mobile devices
  • Fallback to clipboard copy if sharing unavailable
  • Configurable share content and format
  • Cross-platform compatibility

CSS Customization

The components use semantic HTML with data attributes for easy styling:

/* Example custom styling */
.my-modal {
  background: white;
  border-radius: 12px;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
  max-width: 500px;
  width: 90%;
}

.my-qr-container {
  text-align: center;
  padding: 20px;
  background: #f8f9fa;
  border-radius: 8px;
  margin: 20px 0;
}

.my-button {
  background: #007bff;
  color: white;
  border: none;
  padding: 12px 24px;
  border-radius: 6px;
  cursor: pointer;
  transition: background 0.2s;
}

.my-button:hover {
  background: #0056b3;
}

.my-warning {
  background: #fff3cd;
  border: 1px solid #ffeaa7;
  color: #856404;
  padding: 12px;
  border-radius: 6px;
  margin-top: 20px;
}

Data Attributes for Targeting

Components include data attributes for precise CSS targeting:

/* Target specific elements */
[data-voideddev-component="qr-container"] {
  /* QR code container styles */
}

[data-voideddev-component="key-textarea"] {
  /* Text area styles */
}

[data-voideddev-action="copy"] {
  /* Copy button styles */
}

7. Hash Service (HashService)

Comprehensive hashing utilities for data integrity and verification.

import { hashService } from "@voideddev/e2ee-client";

// Basic hashing
const hash = await hashService.generateHash(data, "sha256");

// Salted hashing
const saltedHash = await hashService.generateHashWithSalt(
  data,
  "mysalt",
  "sha256"
);

// High-iteration hashing (PBKDF2-SHA256)
const { hash: iterHash, salt } = await hashService.hashWithHighIterations(data);
const isValid = await hashService.verifyWithHighIterations(
  data,
  iterHash,
  salt
);

// Verify salted hash
const isValidSalted = await hashService.verifyWithSalt(
  data,
  saltedHash,
  "mysalt",
  "sha256"
);

// Fingerprints and safety numbers
const fingerprint = await hashService.generateFingerprint(data);
const safetyNumbers = await hashService.generateSafetyNumbers(data);

// Random utilities
const randomHash = await hashService.generateRandomHash("sha256");
const randomSalt = hashService.generateRandomSalt(32);

HashService Methods:

  • generateHash(data, algorithm): Generate basic hash
  • generateHashWithSalt(data, salt, algorithm): Generate salted hash
  • compareHash(data, hash, algorithm): Compare data with hash
  • hashWithHighIterations(data, salt): High-iteration PBKDF2 hashing
  • verifyWithHighIterations(data, hash, salt): Verify high-iteration hash
  • verifyWithSalt(data, hash, salt, algorithm): Verify salted hash
  • generateRandomHash(algorithm): Generate random hash
  • generateFingerprint(data, length): Generate key fingerprint
  • generateSafetyNumbers(data, groupSize): Generate safety numbers
  • generateRandomSalt(length): Generate random salt
  • secureWipe(buffer): Securely wipe buffer from memory

8. Passkey + Key Sharing (PasskeyKeyDeriver, KeySharing) - 0.3.0

Additive key-management APIs for deterministic passkey-derived keys and X25519-based sharing.

import { VoidedE2EEClient, PasskeyKeyDeriver, KeySharing } from "@voideddev/e2ee-client";

// 1) Client-level PDK flow
const client = new VoidedE2EEClient({
  keyId: "user-123",
  autoGenerateKey: false,
  pdkConfig: {
    salt: "my-app-v1",
    appId: "my-app",
    cacheKey: true,
  },
});

await client.deriveAndSetPDK(credentialPublicKey, credentialId);

// 2) Advanced derivation flow
const deriver = new PasskeyKeyDeriver({
  salt: "my-app-v1",
  appId: "my-app",
  cacheKey: true,
});

const masterPdk = await deriver.deriveKey(credentialPublicKey, credentialId);
const appScopedKey = await deriver.deriveAppKey(masterPdk, "chat");
const identity = await deriver.deriveIdentityKeyPair(masterPdk, "user-123");

// 3) X25519 key sharing flow
const sharing = new KeySharing();
const encryptedKeyBlob = await sharing.encryptKeyForRecipient(
  appScopedKey,
  senderPrivateKeyBytes,   // 32-byte X25519 private key
  recipientPublicKeyBytes  // 32-byte X25519 public key
);

const recoveredKey = await sharing.decryptKeyFromSender(
  encryptedKeyBlob,
  recipientPrivateKeyBytes,
  senderPublicKeyBytes
);

New Methods/Capabilities in 0.3.0:

  • VoidedE2EEClient.deriveAndSetPDK(credentialPublicKey, credentialId)
  • PasskeyKeyDeriver.deriveKey(...)
  • PasskeyKeyDeriver.deriveAppKey(...)
  • PasskeyKeyDeriver.deriveIdentityKeyPair(...)
  • KeySharing.encryptKeyForRecipient(...)
  • KeySharing.decryptKeyFromSender(...)
  • KeySharing.deriveTransferKey(...)
  • KeySharing.encryptKeyForTransfer(...)
  • KeySharing.decryptKeyFromTransfer(...)

🎯 Usage Patterns

Understanding the Different Flows

Important: The encrypt() and decrypt() methods in VoidedE2EEClient are full pipeline functions that handle compression, encryption, digital signatures (if enabled), forward secrecy (if enabled), and chunking (if enabled) automatically. These are the primary methods you should use for most encryption/decryption tasks.

The library also provides individual components (CryptoService, compression, HashService) for advanced users who need fine-grained control over the encryption process.

1. Full Pipeline Encryption (Recommended)

import { VoidedE2EEClient } from "@voideddev/e2ee-client";

const client = new VoidedE2EEClient({
  enableSignatures: true,
  enableForwardSecrecy: true,
  enableChunking: true,
});

// Encrypt data with full pipeline (compression + encryption + signatures + forward secrecy + chunking)
const encrypted = await client.encrypt("sensitive data", {
  compressionAlgorithm: "auto",
  compressionLevel: 6,
  forceCompression: false,
});
// Returns: Non-chunked or chunked shape depending on size (see Large File Handling)

// Decrypt data with full pipeline
const decrypted = await client.decrypt(encrypted);
// Returns: "sensitive data"

console.log(decrypted); // 'sensitive data'

2. Individual Components (Advanced Usage)

For advanced users who need fine-grained control over the encryption process:

import { CryptoService } from "@voideddev/e2ee-client";
import { compress, decompress } from "@voideddev/e2ee-client";
import { hashService } from "@voideddev/e2ee-client";

const crypto = new CryptoService();

// Step 1: Compress data
const compressionResult = await compress("sensitive data", {
  algorithm: "brotli",
});
// Returns: { compressed: Uint8Array(23) [...], algorithm: "brotli", originalSize: 14, compressedSize: 12, compressionRatio: 0.86 }

// Step 2: Generate encryption key
const key = await crypto.generateKey();
// Returns: CryptoKey (Web Crypto API key object)

// Step 3: Encrypt compressed data
const encrypted = await crypto.encrypt(compressionResult.compressed, key);
// Returns: ArrayBuffer (Encrypted data, IV is prefixed to the ciphertext)

// Step 4: Generate hash for integrity
const hash = await hashService.generateHash("sensitive data");
// Returns: "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f" (Hex string hash)

// For decryption, reverse the process
const decrypted = await crypto.decrypt(encrypted, iv, key);
// Returns: Uint8Array (Decrypted data)
const decompressed = await decompress(decrypted, "brotli");
// Returns: Uint8Array(14) [...] (Decompressed data)
const finalData = new TextDecoder().decode(decompressed);
// Returns: "sensitive data"

3. Advanced Security Features

import { VoidedE2EEClient } from "@voideddev/e2ee-client";

const client = new VoidedE2EEClient({
  enableSignatures: true,
  enableForwardSecrecy: true,
});

// Derive key from password using PBKDF2 (salt auto-generated if omitted)
await client.deriveKeyFromPassword({
  password: "my-secure-data",
  iterations: 100000,
});
// Returns: void (No return value, key is stored internally)

// Generate signing keys
const signingPublicKey = await client.generateSigningKeys();
// Returns: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE..." (Base64 ECDSA public key)

// Generate agreement keys
const agreementPublicKey = await client.generateAgreementKeys();
// Returns: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE..." (Base64 ECDH public key)

// Get identity verification info
const fingerprint = await client.getKeyFingerprint();
// Returns: "a1b2c3d4" (8-character fingerprint for key verification)
const safetyNumbers = await client.getSafetyNumbers();
// Returns: "123 456 789 012 345" (Human-readable safety numbers like Signal)

// Encrypt with all security features
const encrypted = await client.encrypt("maximum security message", {
  compressionAlgorithm: "auto",
});
// Returns: Non-chunked or chunked shape depending on size (see Large File Handling)
const decrypted = await client.decrypt(encrypted);
// Returns: "maximum security message"

4. Key Management

import { VoidedE2EEClient } from "@voideddev/e2ee-client";

const client = new VoidedE2EEClient();

// Export key
const exportedKey = await client.exportKey();
// Returns: "U2FsdGVkX19QYXNzd29yZFRlc3Q=" (Base64 exported key string)

// Import key
await client.importKey(exportedKey);
// Returns: void (No return value)

// Rotate key (force - delete old key)
const newKey = await client.rotateKey({ force: true });
// Returns: "base64_new_key_string"

// Rotate key (migration - keep old key)
const newKey = await client.rotateKey({
  migrate: true,
  cutoffTime: new Date(),
});
// Returns: "base64_new_key_string"

// Check migration status
const status = await client.getMigrationStatus();
// Returns: { isActive: true, oldKeyVersion: 1, newKeyVersion: 2, cutoffTime: Date, lastProgress: 0.75, createdAt: Date } | null
if (status?.isActive) {
  await client.finalizeMigration();
  // Returns: void (No return value)
}

5. Key Agreement (Secure Key Exchange)

import { VoidedE2EEClient } from "@voideddev/e2ee-client";

const alice = new VoidedE2EEClient({ keyId: "alice" });
const bob = new VoidedE2EEClient({ keyId: "bob" });

// Generate key agreement keys
const alicePublicKey = await alice.generateAgreementKeys();
// Returns: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE..." (Base64 ECDH public key)
const bobPublicKey = await bob.generateAgreementKeys();
// Returns: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE..." (Base64 ECDH public key)

// Perform key agreement
await alice.performKeyAgreement(bobPublicKey);
// Returns: void (No return value, shared key is derived internally)
await bob.performKeyAgreement(alicePublicKey);
// Returns: void (No return value, shared key is derived internally)

// Now they share the same encryption key
const message = "Secret message";
const encrypted = await alice.encrypt(message, {
  compressionAlgorithm: "auto",
});
// Returns: Non-chunked or chunked shape depending on size (see Large File Handling)
const decrypted = await bob.decrypt(encrypted);
// Returns: "Secret message"

6. Identity Verification

import { VoidedE2EEClient } from "@voideddev/e2ee-client";

const alice = new VoidedE2EEClient({ keyId: "alice" });
const bob = new VoidedE2EEClient({ keyId: "bob" });

// Get fingerprints
const aliceFingerprint = await alice.getKeyFingerprint();
// Returns: 64-character hex string fingerprint
const aliceSafetyNumbers = await alice.getSafetyNumbers();
// Returns: "123 456 789 012 345" (Human-readable safety numbers like Signal)

// Verify identity (in real usage, share through secure channel)
const verification = await bob.verifyFingerprint(aliceFingerprint);
// Returns: { fingerprint: string /* 64-char hex */, safetyNumbers: "123 456 789 012 345", verified: true }
console.log("Verified:", verification.verified);

7. UI Integration

import {
  VoidedE2EEClient,
  createKeyExport,
  createKeyImport,
} from "@voideddev/e2ee-client";

const client = new VoidedE2EEClient();

// Create UI components
const keyExport = createKeyExport(client, {
  title: "Backup Your Key",
  showQR: true,
  onCopy: () => showToast("Key copied!"),
});
// Returns: VoidedKeyExport (Key export UI component instance)

const keyImport = createKeyImport(client, {
  onSuccess: () => showToast("Key imported!"),
  onError: (error) => showError("Import failed: " + error),
});
// Returns: VoidedKeyImport (Key import UI component instance)

// React component example
function KeyManagement() {
  return (
    <div>
      <button onClick={() => keyExport?.show()}>Export Key</button>
      <button onClick={() => keyImport?.show()}>Import Key</button>
      <button onClick={() => client.rotateKey()}>Rotate Key</button>
    </div>
  );
}

8. Large File Handling (Chunked vs Non-Chunked)

import { VoidedE2EEClient } from "@voideddev/e2ee-client";

const client = new VoidedE2EEClient({
  enableChunking: true,
  chunkSize: 1024 * 1024, // 1MB chunks
  minChunkThreshold: 5 * 1024 * 1024, // 5MB threshold
});

// Large data will be automatically chunked
const largeData = "x".repeat(10 * 1024 * 1024); // 10MB
const encrypted = await client.encrypt(largeData);
// Chunked return shape:
// {
//   keyId: "default",
//   algorithm: "AES-GCM",
//   version: "1.0",
//   compression: { algorithm: 'brotli' | 'gzip' | 'none', originalSize: 10485760, compressedSize: 10485760 },
//   chunks: Array<{ data: string; iv: string; index: number; signature?: string }>,
//   chunkInfo: { isChunked: true, totalChunks: 10, chunkSize: 1048576 },
//   signature?: string,
//   ephemeralPublicKey?: string,
//   textEncoding?: 'utf8' | 'utf16le'
// }

// Check if data was chunked
if (encrypted.chunkInfo?.isChunked) {
  console.log(`Data chunked into ${encrypted.chunkInfo.totalChunks} chunks`);
}

const decrypted = await client.decrypt(encrypted);
// Returns: "x".repeat(10 * 1024 * 1024) (Decrypted large data string)

// Tip: You can fine-tune compression during encryption
const encryptedAuto = await client.encrypt(largeData, {
  compressionAlgorithm: "auto",
});
const encryptedNone = await client.encrypt(largeData, {
  compressionAlgorithm: "none",
});

9. Custom Storage

import { VoidedE2EEClient } from "@voideddev/e2ee-client";

// Implement custom storage (must implement the E2EEStorage interface)
// Note: Avoid localStorage/sessionStorage; use a secure storage backend.
const customStorage = {
  async getKey(keyId) {
    /* ... return base64 string or null ... */
  },
  async setKey(keyId, key) {
    /* ... persist securely ... */
  },
  async removeKey(keyId) {
    /* ... */
  },
  async getMigrationState(keyId) {
    /* ... return MigrationState or null ... */
  },
  async setMigrationState(keyId, state) {
    /* ... */
  },
  async removeMigrationState(keyId) {
    /* ... */
  },
  async getKeyPair(keyId, type) {
    /* ... */
  },
  async setKeyPair(keyId, type, keyPair) {
    /* ... */
  },
  async removeKeyPair(keyId, type) {
    /* ... */
  },
};

const client = new VoidedE2EEClient({ storage: customStorage });

🔒 Security Features

High-Iteration Key Derivation

  • Uses PBKDF2 with configurable iterations (default: 100,000)
  • OWASP-compliant security parameters
  • Salt generation and management

Hashing Types and Purposes

Basic Hashing (generateHash):

  • Purpose: Data integrity verification, checksums
  • Use case: Verify files haven't been corrupted
  • Algorithm: SHA-256, SHA-512

Salted Hashing (generateHashWithSalt):

  • Purpose: Data integrity with salt protection
  • Use case: Store hashes that need to be verified later
  • Algorithm: SHA-256, SHA-512 with salt

High-Iteration Hashing (hashWithHighIterations):

  • Purpose: Secure storage of sensitive data
  • Use case: Storing hashes that need to be resistant to brute force attacks
  • Algorithm: PBKDF2(SHA-256) with 100,000+ iterations

// Note: HMAC utilities are not part of the current API surface.

Digital Signatures

  • Default algorithm: ECDSA P-256 with SHA-256
  • Per-chunk and global signature support (when enabled via enableSignatures)
  • Automatic signature verification on decryption when signatures are present

Forward Secrecy

  • Ephemeral key generation for each message
  • ECDH key agreement for shared secrets
  • Perfect forward secrecy implementation

Identity Verification

  • Key fingerprints for identity verification
  • Safety numbers (like Signal) for human verification
  • Timing-safe comparisons to prevent attacks

Key Rotation

  • Secure key rotation with migration support
  • Time-based cutoff for migration
  • Legacy key support during transition (client tries current key, then legacy during active migration)
  • Rotation lock prevents concurrent rotations; client waits to avoid races

Large File Security

  • Automatic chunking for large files
  • Per-chunk signatures and encryption
  • Memory-efficient processing

🚦 Limits

  • Client-side upload limit: 32 GiB per file (enforced via size checks)
  • Non-chunked encryption max payload: ~64 MB per AES-GCM operation
  • Default chunking: 2 MB chunks; chunking automatically enabled for payloads ≥ 10 MB
  • Limits can be tuned via chunkSize and minChunkThreshold

Benchmarks

You can run quick in-browser benchmarks to gauge performance:

import {
  benchmarkCompression,
  benchmarkEncryption,
  benchmarkAll,
} from "@voideddev/e2ee-client/benchmark-all";

const comp = await benchmarkCompression("sample text", 10);
const enc = await benchmarkEncryption("sample text", 10);
const all = await benchmarkAll("sample text", 10);

📊 Performance Features

Compression

  • Automatic or explicit algorithm selection ('auto' | 'brotli' | 'gzip' | 'none')
  • Threshold-based compression with minSizeThreshold
  • Configurable compressionLevel (gzip: 1–9, brotli: 1–11)
  • Compression can be forced via forceCompression

Chunking

  • Automatic chunking for large files
  • Parallel chunk processing
  • Memory-efficient streaming
  • Configurable chunk sizes and threshold
  • Decryption reassembles compressed bytes, then decompresses once for correctness and speed

Caching

  • Key caching for performance
  • Secure memory management
  • Automatic cache invalidation

🧪 Testing and Validation

import { VoidedE2EEClient } from "@voideddev/e2ee-client";

// Test encryption round-trip
async function testEncryption() {
  const client = new VoidedE2EEClient();
  const data = "test data";

  const encrypted = await client.encrypt(data);
  const decrypted = await client.decrypt(encrypted);

  console.log("Round-trip successful:", data === decrypted);
}

// Test key rotation (migration preserves ability to decrypt old data)
async function testKeyRotation() {
  const client = new VoidedE2EEClient();

  const data = "test data";
  const encrypted1 = await client.encrypt(data);

  // Use migrate to keep old key available during transition
  await client.rotateKey({ migrate: true, cutoffTime: new Date() });
  const encrypted2 = await client.encrypt(data);

  // Old data should still be decryptable during active migration
  const decrypted1 = await client.decrypt(encrypted1);
  const decrypted2 = await client.decrypt(encrypted2);

  console.log("Rotation test:", decrypted1 === data && decrypted2 === data);
}

🔧 Integration Examples

React Integration

import React, { useEffect, useState } from "react";
import {
  VoidedE2EEClient,
  createKeyExport,
  createKeyImport,
} from "@voideddev/e2ee-client";

function EncryptionApp() {
  const [client, setClient] = useState<VoidedE2EEClient | null>(null);
  const [keyExport, setKeyExport] = useState<any>(null);
  const [keyImport, setKeyImport] = useState<any>(null);

  useEffect(() => {
    const e2eeClient = new VoidedE2EEClient();
    setClient(e2eeClient);

    setKeyExport(createKeyExport(e2eeClient));
    setKeyImport(createKeyImport(e2eeClient));
  }, []);

  const handleEncrypt = async (data: string) => {
    if (!client) return;
    const encrypted = await client.encrypt(data);
    console.log("Encrypted:", encrypted);
  };

  return (
    <div>
      <button onClick={() => keyExport?.show()}>Export Key</button>
      <button onClick={() => keyImport?.show()}>Import Key</button>
      <button onClick={() => handleEncrypt("test data")}>Encrypt</button>
    </div>
  );
}

Vue Integration

<template>
  <div>
    <button @click="exportKey">Export Key</button>
    <button @click="importKey">Import Key</button>
    <button @click="encryptData">Encrypt</button>
  </div>
</template>

<script setup>
import { onMounted, ref } from "vue";
import {
  VoidedE2EEClient,
  createKeyExport,
  createKeyImport,
} from "@voideddev/e2ee-client";

const client = ref(null);
const keyExport = ref(null);
const keyImport = ref(null);

onMounted(() => {
  client.value = new VoidedE2EEClient();
  keyExport.value = createKeyExport(client.value);
  keyImport.value = createKeyImport(client.value);
});

const exportKey = () => keyExport.value?.show();
const importKey = () => keyImport.value?.show();
const encryptData = async () => {
  const encrypted = await client.value.encrypt("test data");
  console.log("Encrypted:", encrypted);
};
</script>

Svelte Integration

<script>
  import { onMount } from 'svelte';
  import { VoidedE2EEClient, createKeyExport, createKeyImport } from '@voideddev/e2ee-client';

  let client, keyExport, keyImport;

  onMount(() => {
    client = new VoidedE2EEClient();
    keyExport = createKeyExport(client);
    keyImport = createKeyImport(client);
  });

  function exportKey() {
    keyExport?.show();
  }

  function importKey() {
    keyImport?.show();
  }

  async function encryptData() {
    const encrypted = await client.encrypt('test data');
    console.log('Encrypted:', encrypted);
  }
</script>

<div>
  <button on:click={exportKey}>Export Key</button>
  <button on:click={importKey}>Import Key</button>
  <button on:click={encryptData}>Encrypt</button>
</div>

🚨 Error Handling

import {
  VoidedE2EEClient,
  ValidationError,
  CryptoError,
  KeyError,
} from "@voideddev/e2ee-client";

const client = new VoidedE2EEClient();

try {
  const encrypted = await client.encrypt(data);
} catch (error) {
  if (error instanceof ValidationError) {
    console.error("Validation error:", error.message);
  } else if (error instanceof CryptoError) {
    console.error("Crypto error:", error.message);
  } else if (error instanceof KeyError) {
    console.error("Key error:", error.message);
  } else {
    console.error("Unknown error:", error);
  }
}

Build and Publishing Workflow

From packages/e2ee-client:

  • npm run build:wasm
    • Builds Rust WASM (crates/voided-wasm) via wasm-pack
    • Copies generated artifacts into packages/e2ee-client/wasm
    • Generates/updates wasm/init.js
  • npm run copy:wasm
    • Only copies already-built artifacts from crates/voided-wasm/pkg into packages/e2ee-client/wasm
    • Use when Rust/WASM is already built and you just need to sync package artifacts
  • npm run test
    • Runs Jest suite
  • npm run build
    • Builds dist/ bundles and types

Recommended publish validation:

  1. npm run build:wasm
  2. npm run copy:wasm
  3. npm run test
  4. npm run build
  5. npm pack --dry-run
  6. npm publish

Note: The repo pins Rust toolchain in crates/rust-toolchain.toml to 1.93.0.

📚 API Reference

Quick Reference: EncryptedBlob Shapes

Non-chunked (small/medium data):

{
  data: string; // base64
  iv: string; // base64
  keyId: string;
  algorithm: 'AES-GCM';
  version: '1.0';
  compression: { algorithm: 'gzip' | 'brotli' | 'none'; originalSize: number; compressedSize: number };
  signature?: string; // base64
  ephemeralPublicKey?: string; // base64
  textEncoding?: 'utf8' | 'utf16le';
}

Chunked (large data):

{
  keyId: string;
  algorithm: 'AES-GCM';
  version: '1.0';
  compression: { algorithm: 'gzip' | 'brotli' | 'none'; originalSize: number; compressedSize: number };
  chunks: Array<{ data: string; iv: string; index: number; signature?: string }>;
  chunkInfo: { isChunked: true; totalChunks: number; chunkSize: number };
  signature?: string; // global signature (base64)
  ephemeralPublicKey?: string; // base64
  textEncoding?: 'utf8' | 'utf16le';
}

Main Functions

  • encrypt(data): Encrypt data with all features
  • decrypt(blob): Decrypt encrypted blob
  • exportKey(): Export current key as string
  • importKey(keyString): Import key from string
  • rotateKey(options): Rotate encryption key
  • deriveKeyFromPassword(options): Derive key from data
  • deriveAndSetPDK(credentialPublicKey, credentialId): Derive and set active key from passkey material
  • getKeyFingerprint(): Get key fingerprint
  • getSafetyNumbers(): Get safety numbers
  • generateSigningKeys(): Generate signing key pair
  • generateAgreementKeys(): Generate agreement key pair
  • performKeyAgreement(publicKey): Perform key agreement

Classes

  • VoidedE2EEClient: Main encryption client
  • CryptoService: Cryptographic operations
  • KeyManager: Key lifecycle management
  • StorageService: Storage abstraction
  • IndexedDBStorage: Built-in IndexedDB storage
  • VoidedKeyExport: Key export UI component
  • VoidedKeyImport: Key import UI component
  • HashService: Hashing utilities
  • PasskeyKeyDeriver: Passkey-derived key helper
  • KeySharing: X25519 key sharing/transfer helper

Interfaces

  • E2EEConfig: Client configuration
  • RotationOptions: Key rotation options
  • MigrationState: Migration status
  • E2EEStorage: Storage interface
  • EncryptedBlob: Encrypted data structure
  • EncryptedChunk: Chunked data structure
  • KeyDerivationOptions: Data derivation options
  • KeyVerificationResult: Identity verification result
  • KeyExportOptions: Export UI options
  • KeyImportOptions: Import UI options
void // No return value

clearCachedKey Response:

void // No return value

hasKey Response:

true; // boolean indicating if key exists

getMigrationStatus Response:

{
    isActive: true,
    oldKeyVersion: 1,
    newKeyVersion: 2,
    cutoffTime: Date,
    lastProgress: 0.75,
    createdAt: Date
} | null

finalizeMigration Response:

void // No return value

getCurrentKeyVersion Response:

2; // number representing current key version

getMigrationInfo Response:

{
    oldKeyVersion: 1,
    newKeyVersion: 2,
    cutoffTime: Date,
    createdAt: Date
} | null

Compression Functions

compress Response:

// Example: compress("Hello, World! This is a test message for compression.")
{
    compressed: Uint8Array(23) [72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33, 32, 84, 104, 105, 115, 32, 105, 115, 32, 97], // Compressed data
    algorithm: "brotli", // "gzip" | "brotli" | "none"
    originalSize: 52,
    compressedSize: 23,
    compressionRatio: 0.44 // 44% of original size
}

decompress Response:

// Example: decompress(compressedData, "brotli")
Uint8Array(52)[
  (72,
  101,
  108,
  108,
  111,
  44,
  32,
  87,
  111,
  114,
  108,
  100,
  33,
  32,
  84,
  104,
  105,
  115,
  32,
  105,
  115,
  32,
  97,
  32,
  116,
  101,
  115,
  116,
  32,
  109,
  101,
  115,
  115,
  97,
  103,
  101,
  32,
  102,
  111,
  114,
  32,
  99,
  111,
  109,
  112,
  114,
  101,
  115,
  115,
  105,
  111,
  110,
  46)
]; // Decompressed data

analyzeCompression Response:

// Example: analyzeCompression("Hello, World! This is a test message for compression.")
{
    originalSize: 52,
    gzipSize: 25,
    brotliSize: 23,
    gzipRatio: 0.48, // 48% of original size
    brotliRatio: 0.44, // 44% of original size
    recommendation: "brotli" // "gzip" | "brotli" | "none"
}

stringToUint8Array Response:

Uint8Array; // Converted string to bytes

uint8ArrayToString Response:

"string"; // Converted bytes to string

CryptoService Methods

generateKey Response:

CryptoKey; // Web Crypto API key object

generateSigningKeyPair Response:

{
    publicKey: CryptoKey,
    privateKey: CryptoKey
}

generateKeyAgreementKeyPair Response:

{
    publicKey: CryptoKey,
    privateKey: CryptoKey
}

deriveKeyFromPassword Response:

CryptoKey; // Derived AES-GCM key

deriveSharedKey Response:

CryptoKey; // Shared AES-GCM key

generateSalt Response:

Uint8Array; // Random salt bytes

signData Response:

ArrayBuffer; // ECDSA signature

verifySignature Response:

true; // boolean indicating signature validity

getKeyFingerprint Response:

"<64-hex>"; // 64-character hex fingerprint

getSafetyNumbers Response:

"123 456 789 012 345"; // Human-readable safety numbers

encrypt Response:

ArrayBuffer; // Encrypted data

decrypt Response:

Uint8Array; // Decrypted data

exportKey Response:

"base64_key_string";

exportPublicKey Response:

"base64_public_key_string";

importKey Response:

CryptoKey; // Imported key object

importPublicKey Response:

CryptoKey; // Imported public key object

validateKeyFormat Response:

true; // boolean indicating valid format

secureWipe Response:

void // No return value, buffer is wiped

KeyManager Methods

getCurrentKey Response:

CryptoKey; // Current encryption key

getKeyForDecryption Response:

CryptoKey; // Key for decryption (current or legacy)

setKey Response:

void // No return value

forceRotate Response:

"base64_new_key_string";

startMigration Response:

"base64_new_key_string";

finalizeMigration Response:

void // No return value

deleteKey Response:

void // No return value

hasKey Response:

true; // boolean indicating if key exists

getCurrentKeyVersion Response:

2; // number representing current key version

getMigrationStatus Response:

{
    isActive: true,
    oldKeyVersion: 1,
    newKeyVersion: 2,
    cutoffTime: Date,
    lastProgress: 0.75,
    createdAt: Date
} | null

getLegacyKey Response:

CryptoKey | null; // Legacy key during migration

clearCache Response:

void // No return value

HashService Methods

generateHash Response:

// Example: generateHash("Hello, World!", "sha256")
"dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f"; // Hex string hash

generateHashWithSalt Response:

// Example: generateHashWithSalt("Hello, World!", "mysalt", "sha256")
"a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456"; // Hex string salted hash

compareHash Response:

// Example: compareHash("Hello, World!", "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f", "sha256")
true; // boolean indicating hash match

hashWithHighIterations Response:

// Example: hashWithHighIterations("Hello, World!")
{
    hash: "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8",
    salt: "a1b2c3d4e5f67890" // Generated salt
}

verifyWithHighIterations Response:

true; // boolean indicating verification success

verifyWithSalt Response:

true; // boolean indicating verification success

generateRandomHash Response:

"a1b2c3d4e5f6..."; // Hex string random hash

generateFingerprint Response:

"<64-hex>"; // 64-character hex fingerprint

generateSafetyNumbers Response:

"123 456 789 012 345"; // Human-readable safety numbers

generateRandomSalt Response:

"a1b2c3d4e5f6..."; // Hex string random salt

secureWipe Response:

void // No return value, buffer is wiped

Key UI Methods

VoidedKeyExport.show Response:

void // No return value, shows modal

VoidedKeyExport.hide Response:

void // No return value, hides modal

VoidedKeyImport.show Response:

void // No return value, shows modal

VoidedKeyImport.hide Response:

void // No return value, hides modal

createKeyExport Response:

VoidedKeyExport; // Key export UI component instance

createKeyImport Response:

VoidedKeyImport; // Key import UI component instance

Storage Methods

IndexedDBStorage.getKey Response:

"base64_key_string" | null;

IndexedDBStorage.setKey Response:

void // No return value

IndexedDBStorage.removeKey Response:

void // No return value

IndexedDBStorage.getMigrationState Response:

{
    isActive: true,
    oldKeyVersion: 1,
    newKeyVersion: 2,
    cutoffTime: Date,
    lastProgress: 0.75,
    createdAt: Date
} | null

IndexedDBStorage.setMigrationState Response:

void // No return value

IndexedDBStorage.removeMigrationState Response:

void // No return value

IndexedDBStorage.getKeyPair Response:

"base64_key_pair_string" | null;

IndexedDBStorage.setKeyPair Response:

void // No return value

IndexedDBStorage.removeKeyPair Response:

void // No return value

Convenience Functions

encrypt (convenience) Response:

{
    data?: "base64_encrypted_data",
    iv?: "base64_iv",
    keyId: "default",
    algorithm: "AES-GCM",
    version: "1.0",
    compression: {
        algorithm: "brotli" | "gzip" | "none",
        originalSize: 13,
        compressedSize: 11
    },
    chunks?: Array<{ data: string; iv: string; index: number; signature?: string }>,
    chunkInfo?: { isChunked: true; totalChunks: number; chunkSize: number },
    signature?: string,
    ephemeralPublicKey?: string,
    textEncoding?: 'utf8' | 'utf16le'
}

decrypt (convenience) Response:

"decrypted_string";

exportKey (convenience) Response:

"base64_exported_key_string";

importKey (convenience) Response:

void // No return value

rotateKey (convenience) Response:

"base64_new_key_string";

deriveKeyFromPassword (convenience) Response:

void // No return value

getKeyFingerprint (convenience) Response:

"a1b2c3d4";

getSafetyNumbers (convenience) Response:

"123 456 789 012 345";

🤝 Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. Submit a pull request

📄 License

MIT License - see LICENSE file for details.

🆘 Support

For issues, questions, or contributions, please open an issue on the GitHub repository.