UNPKG

@opendatalabs/vana-sdk

Version:

A TypeScript library for interacting with Vana Network smart contracts.

410 lines (409 loc) 13.2 kB
/** * Defines platform abstraction interfaces for environment-specific implementations. * * @remarks * This module provides the contract for platform-specific operations, allowing * the SDK to work seamlessly across Node.js and browser environments. Platform * adapters handle all environment-specific dependencies including cryptography, * HTTP requests, caching, and PGP operations. * * The SDK automatically selects the appropriate adapter based on the runtime * environment. Custom implementations can be provided for specialized use cases. * * **Implementation Context:** * - Node.js: Uses native crypto modules, in-memory cache, and full OpenPGP support * - Browser: Uses Web Crypto API, sessionStorage cache, and browser-compatible libraries * - SSR: Automatically selects appropriate implementation based on runtime detection * * @example * ```typescript * // Custom platform adapter implementation * class CustomPlatformAdapter implements VanaPlatformAdapter { * crypto = new CustomCryptoAdapter(); * pgp = new CustomPGPAdapter(); * http = new CustomHttpAdapter(); * cache = new CustomCacheAdapter(); * platform = 'browser' as const; * } * * // Use with SDK * const client = createClient({ * platformAdapter: new CustomPlatformAdapter() * }); * ``` * * @category Platform * @module platform/interface */ /** * Identifies the runtime platform for adapter selection. * * @remarks * Used for debugging, telemetry, and conditional logic based on * the execution environment. * * @category Platform */ export type PlatformType = "node" | "browser"; /** * Provides platform-specific cryptographic operations. * * @remarks * Implements ECIES encryption/decryption, key generation, and password-based * encryption using platform-appropriate libraries. Node.js uses Buffer-based * libraries while browser uses Uint8Array and Web Crypto where possible. * * @category Platform */ export interface VanaCryptoAdapter { /** * Encrypts data with a public key using ECIES. * * @remarks * Uses Elliptic Curve Integrated Encryption Scheme (ECIES) for * asymmetric encryption. The implementation varies by platform but * maintains compatible output format. * * @param data - The plaintext data to encrypt. * Typically user data or encryption keys. * @param publicKey - The recipient's public key in hex format. * Can be compressed or uncompressed secp256k1 key. * @returns Hex-encoded encrypted data containing IV, ephemeral key, ciphertext, and MAC * * @example * ```typescript * const encrypted = await adapter.crypto.encryptWithPublicKey( * 'sensitive data', * '04abcd...' // 65-byte uncompressed public key * ); * ``` */ encryptWithPublicKey(data: string, publicKey: string): Promise<string>; /** * Decrypts ECIES-encrypted data with a private key. * * @param encryptedData - Hex-encoded encrypted data. * Must contain IV, ephemeral key, ciphertext, and MAC. * @param privateKey - The private key in hex format. * Must correspond to the public key used for encryption. * @returns The decrypted plaintext string * * @throws {Error} If decryption or MAC verification fails */ decryptWithPrivateKey(encryptedData: string, privateKey: string): Promise<string>; /** * Generates a new secp256k1 key pair. * * @returns Object with hex-encoded keys * @returns returns.publicKey - Compressed public key in hex * @returns returns.privateKey - Private key in hex * * @example * ```typescript * const { publicKey, privateKey } = await adapter.crypto.generateKeyPair(); * console.log('Public key:', publicKey); // 33 bytes compressed * ``` */ generateKeyPair(): Promise<{ publicKey: string; privateKey: string; }>; /** * Encrypts data with an Ethereum wallet's public key. * * @remarks * Specifically designed for wallet-based encryption where the public * key comes from an Ethereum wallet. Handles key format conversion * and uses ECIES for encryption. * * @param data - The plaintext data to encrypt. * Typically permission grants or metadata. * @param publicKey - The wallet's public key. * Accepts compressed/uncompressed, with/without 0x prefix. * @returns Hex-encoded encrypted data * * @example * ```typescript * const encrypted = await adapter.crypto.encryptWithWalletPublicKey( * JSON.stringify({ permission: 'read' }), * walletPublicKey * ); * ``` */ encryptWithWalletPublicKey(data: string, publicKey: string): Promise<string>; /** * Decrypts data with an Ethereum wallet's private key. * * @param encryptedData - Hex-encoded encrypted data. * Must be encrypted with corresponding wallet public key. * @param privateKey - The wallet's private key. * Handle with extreme care - never log or store. * @returns The decrypted plaintext string * * @throws {Error} If decryption fails or key is invalid */ decryptWithWalletPrivateKey(encryptedData: string, privateKey: string): Promise<string>; /** * Encrypts binary data with password-based encryption. * * @remarks * Uses OpenPGP password-based encryption with automatic salt * generation. Often used with wallet signatures as passwords for * deterministic key derivation. * * @param data - Binary data to encrypt. * Typically file contents or serialized data. * @param password - Password for encryption. * Often derived from wallet signatures. * @returns Encrypted data as Uint8Array * * @example * ```typescript * const fileData = new Uint8Array([1, 2, 3, 4]); * const encrypted = await adapter.crypto.encryptWithPassword( * fileData, * walletSignature * ); * ``` */ encryptWithPassword(data: Uint8Array, password: string): Promise<Uint8Array>; /** * Decrypts password-encrypted binary data. * * @param encryptedData - Password-encrypted data. * Must be encrypted with the same password. * @param password - Password for decryption. * Must match the encryption password exactly. * @returns Decrypted data as Uint8Array * * @throws {Error} If decryption fails or password is incorrect */ decryptWithPassword(encryptedData: Uint8Array, password: string): Promise<Uint8Array>; } /** * Provides platform-specific PGP operations. * * @remarks * Implements PGP encryption, decryption, and key generation using * OpenPGP.js with platform-appropriate configuration. Node.js uses * optimizations like zlib compression. * * @category Platform */ export interface VanaPGPAdapter { /** * Encrypts data using PGP public key encryption. * * @param data - The plaintext data to encrypt. * Typically messages or structured data. * @param publicKey - ASCII-armored PGP public key. * Obtain from generateKeyPair or key servers. * @returns ASCII-armored encrypted message * * @example * ```typescript * const encrypted = await adapter.pgp.encrypt( * 'secret message', * armoredPublicKey * ); * ``` */ encrypt(data: string, publicKey: string): Promise<string>; /** * Decrypts PGP-encrypted data. * * @param encryptedData - ASCII-armored encrypted message. * Must be encrypted with corresponding public key. * @param privateKey - ASCII-armored PGP private key. * May be passphrase-protected. * @returns The decrypted plaintext string * * @throws {Error} If decryption fails or key is invalid */ decrypt(encryptedData: string, privateKey: string): Promise<string>; /** * Generates a new PGP key pair. * * @param options - Key generation configuration * @param options.name - Identity name. * Defaults to 'Vana User'. * @param options.email - Identity email. * Defaults to 'user@vana.com'. * @param options.passphrase - Private key passphrase. * If omitted, private key is unprotected. * @returns ASCII-armored public and private keys * * @example * ```typescript * const { publicKey, privateKey } = await adapter.pgp.generateKeyPair({ * name: 'Alice Smith', * email: 'alice@example.com', * passphrase: 'secure-passphrase' * }); * ``` */ generateKeyPair(options?: { name?: string; email?: string; passphrase?: string; }): Promise<{ publicKey: string; privateKey: string; }>; } /** * Provides platform-specific HTTP operations. * * @remarks * Wraps the fetch API to ensure consistent behavior across * Node.js and browser environments. * * @category Platform */ export interface VanaHttpAdapter { /** * Performs an HTTP request. * * @param url - The URL to request. * Must be a valid HTTP/HTTPS URL. * @param options - Standard fetch RequestInit options. * See MDN documentation for details. * @returns Standard fetch Response object * * @example * ```typescript * const response = await adapter.http.fetch( * 'https://api.vana.com/data', * { method: 'GET', headers: { 'Authorization': 'Bearer token' } } * ); * ``` */ fetch(url: string, options?: RequestInit): Promise<Response>; } /** * Provides platform-specific caching operations. * * @remarks * Implements simple key-value caching with platform-appropriate storage. * Node.js uses in-memory Map with TTL, browser uses sessionStorage for * security (cleared on tab close). * * @category Platform */ export interface VanaCacheAdapter { /** * Retrieves a cached value. * * @param key - The cache key. * Should be unique per operation. * @returns The cached value or null if not found/expired * * @example * ```typescript * const cachedSignature = adapter.cache.get('sig_0x123...'); * if (cachedSignature) { * return cachedSignature; * } * ``` */ get(key: string): string | null; /** * Stores a value in the cache. * * @param key - The cache key. * Should be unique and descriptive. * @param value - The value to cache. * Typically signatures or computed results. * * @remarks * Node.js: Cached for 2 hours with TTL * Browser: Cached until tab closes (sessionStorage) */ set(key: string, value: string): void; /** * Removes a cached value. * * @param key - The cache key to remove. * Use when cached data becomes invalid. */ delete(key: string): void; /** * Clears all cached values. * * @remarks * Use with caution as this removes all performance optimizations. * Browser implementation only clears Vana-prefixed keys. */ clear(): void; } /** * Aggregates all platform-specific adapters into a single interface. * * @remarks * This is the main interface for platform abstraction. Implementations * must provide all required adapters while maintaining consistent behavior * and data formats across platforms. * * **Implementation Guidelines:** * 1. All methods must maintain consistent behavior across platforms * 2. Error types and messages should be unified * 3. Data formats (encoding, serialization) must be identical * 4. Performance characteristics can vary but API must be consistent * * @example * ```typescript * // Custom implementation for specialized environment * class EdgePlatformAdapter implements VanaPlatformAdapter { * crypto = new EdgeCryptoAdapter(); * pgp = new EdgePGPAdapter(); * http = new EdgeHttpAdapter(); * cache = new EdgeCacheAdapter(); * platform = 'browser' as const; // Edge is browser-like * } * * // Use with SDK * const client = createClient({ * platformAdapter: new EdgePlatformAdapter() * }); * ``` * * @category Platform */ export interface VanaPlatformAdapter { /** * Provides cryptographic operations. * * @remarks * Handles ECIES, wallet encryption, and password-based encryption. */ crypto: VanaCryptoAdapter; /** * Provides PGP operations. * * @remarks * Handles PGP encryption, decryption, and key generation. */ pgp: VanaPGPAdapter; /** * Provides HTTP operations. * * @remarks * Wraps fetch API for consistent cross-platform behavior. */ http: VanaHttpAdapter; /** * Provides caching operations. * * @remarks * Platform-appropriate storage for temporary data. */ cache: VanaCacheAdapter; /** * Identifies the platform type. * * @remarks * Used for debugging, telemetry, and conditional logic. * Must be 'node' or 'browser'. */ readonly platform: PlatformType; }