@unicitylabs/sphere-sdk 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../impl/browser/index.ts","../../../constants.ts","../../../impl/browser/storage/LocalStorageProvider.ts","../../../impl/browser/storage/IndexedDBTokenStorageProvider.ts","../../../transport/NostrTransportProvider.ts","../../../node_modules/@noble/hashes/src/utils.ts","../../../node_modules/@noble/hashes/src/hmac.ts","../../../node_modules/@noble/hashes/src/hkdf.ts","../../../node_modules/@noble/hashes/src/_md.ts","../../../node_modules/@noble/hashes/src/sha2.ts","../../../core/crypto.ts","../../../core/bech32.ts","../../../transport/websocket.ts","../../../impl/browser/transport/index.ts","../../../oracle/UnicityAggregatorProvider.ts","../../../assets/trustbase.ts","../../../impl/shared/trustbase-loader.ts","../../../impl/browser/oracle/index.ts","../../../impl/browser/download.ts","../../../price/CoinGeckoPriceProvider.ts","../../../price/index.ts","../../../impl/shared/resolvers.ts"],"sourcesContent":["/**\n * Browser-specific implementations\n * All platform-dependent code lives here\n */\n\n// Polyfill Buffer for browser environment\n// Many crypto libraries depend on Node.js Buffer API\nimport { Buffer } from 'buffer';\nif (typeof globalThis.Buffer === 'undefined') {\n globalThis.Buffer = Buffer;\n}\n\nexport * from './storage';\nexport * from './transport';\nexport * from './oracle';\nexport * from './download';\n\n// Re-export shared types for convenience\nexport type {\n BaseTransportConfig,\n BaseOracleConfig,\n L1Config,\n BaseProviders,\n} from '../shared';\n\n// =============================================================================\n// Convenience Factory\n// =============================================================================\n\nimport { createLocalStorageProvider, type LocalStorageProviderConfig, createIndexedDBTokenStorageProvider } from './storage';\nimport { createNostrTransportProvider } from './transport';\nimport { createUnicityAggregatorProvider } from './oracle';\nimport type { StorageProvider, TokenStorageProvider, TxfStorageDataBase } from '../../storage';\nimport type { TransportProvider } from '../../transport';\nimport type { OracleProvider } from '../../oracle';\nimport type { NetworkType } from '../../constants';\nimport type { PriceProvider } from '../../price';\nimport { createPriceProvider } from '../../price';\nimport {\n type BaseTransportConfig,\n type BaseOracleConfig,\n type BasePriceConfig,\n type L1Config,\n type BrowserTransportExtensions,\n resolveTransportConfig,\n resolveOracleConfig,\n resolveL1Config,\n resolvePriceConfig,\n resolveArrayConfig,\n getNetworkConfig,\n} from '../shared';\n\n// =============================================================================\n// Browser-Specific Configuration Extensions\n// =============================================================================\n\n/**\n * Browser transport configuration\n * Extends base with browser-specific options\n */\nexport type TransportConfig = BaseTransportConfig & BrowserTransportExtensions;\n\n/**\n * Browser oracle configuration\n * Same as base (no browser-specific extensions)\n */\nexport type OracleConfig = BaseOracleConfig;\n\n// =============================================================================\n// Token Sync Backend Configurations\n// =============================================================================\n\n/**\n * IPFS sync backend configuration\n */\nexport interface IpfsSyncConfig {\n /** Enable IPFS sync (default: false) */\n enabled?: boolean;\n /** Replace default gateways entirely */\n gateways?: string[];\n /** Add gateways to network defaults */\n additionalGateways?: string[];\n /** Replace default bootstrap peers */\n bootstrapPeers?: string[];\n /** Add bootstrap peers to defaults */\n additionalBootstrapPeers?: string[];\n /** Use browser DHT (Helia) vs HTTP-only mode */\n useDht?: boolean;\n}\n\n/**\n * File sync backend configuration (future)\n */\nexport interface FileSyncConfig {\n /** Enable file sync (default: false) */\n enabled?: boolean;\n /** Directory path for token files */\n directory?: string;\n /** File format: 'json' | 'txf' */\n format?: 'json' | 'txf';\n}\n\n/**\n * Cloud sync backend configuration (future)\n */\nexport interface CloudSyncConfig {\n /** Enable cloud sync (default: false) */\n enabled?: boolean;\n /** Cloud provider */\n provider?: 'aws' | 'gcp' | 'azure' | 'custom';\n /** Bucket/container name */\n bucket?: string;\n /** API endpoint (for custom provider) */\n endpoint?: string;\n /** API key or credentials */\n apiKey?: string;\n}\n\n/**\n * MongoDB sync backend configuration\n */\nexport interface MongoDbSyncConfig {\n /** Enable MongoDB sync (default: false) */\n enabled?: boolean;\n /** MongoDB connection URI */\n uri?: string;\n /** Database name */\n database?: string;\n /** Collection name (default: 'tokens') */\n collection?: string;\n /** Enable authentication */\n authEnabled?: boolean;\n /** Username (if authEnabled) */\n username?: string;\n /** Password (if authEnabled) */\n password?: string;\n}\n\n/**\n * Token sync configuration - supports multiple backends\n */\nexport interface TokenSyncConfig {\n /** IPFS sync backend */\n ipfs?: IpfsSyncConfig;\n /** File sync backend (future) */\n file?: FileSyncConfig;\n /** Cloud sync backend (future) */\n cloud?: CloudSyncConfig;\n /** MongoDB sync backend */\n mongodb?: MongoDbSyncConfig;\n}\n\n// =============================================================================\n// Browser Providers Configuration\n// =============================================================================\n\nexport interface BrowserProvidersConfig {\n /** Network preset: mainnet, testnet, or dev. Sets default URLs for all services */\n network?: NetworkType;\n /** Storage configuration (localStorage) */\n storage?: LocalStorageProviderConfig;\n /** Transport (Nostr) configuration - supports extend/override pattern */\n transport?: TransportConfig;\n /** Oracle (Aggregator) configuration - supports extend/override pattern */\n oracle?: OracleConfig;\n /** L1 (ALPHA blockchain) configuration */\n l1?: L1Config;\n /**\n * Token sync backends configuration\n * Supports multiple backends: IPFS, file, cloud (future)\n * Each backend can be enabled/disabled independently\n */\n tokenSync?: TokenSyncConfig;\n /** Price provider configuration (optional — enables fiat value display) */\n price?: BasePriceConfig;\n}\n\nexport interface BrowserProviders {\n storage: StorageProvider;\n transport: TransportProvider;\n oracle: OracleProvider;\n /** Token storage provider for local persistence (IndexedDB) */\n tokenStorage: TokenStorageProvider<TxfStorageDataBase>;\n /** L1 configuration (for passing to Sphere.init) */\n l1?: L1Config;\n /** Price provider (optional — enables fiat value display) */\n price?: PriceProvider;\n /**\n * Token sync configuration (resolved from tokenSync options)\n * For advanced use cases when additional sync backends are needed\n * @deprecated Use tokenStorage provider instead. For custom sync backends,\n * use Sphere.addTokenStorageProvider() after initialization.\n */\n tokenSyncConfig?: {\n ipfs?: {\n enabled: boolean;\n gateways: string[];\n bootstrapPeers?: string[];\n useDht?: boolean;\n };\n file?: {\n enabled: boolean;\n directory?: string;\n format?: 'json' | 'txf';\n };\n cloud?: {\n enabled: boolean;\n provider?: string;\n bucket?: string;\n endpoint?: string;\n apiKey?: string;\n };\n mongodb?: {\n enabled: boolean;\n uri?: string;\n database?: string;\n collection?: string;\n };\n };\n}\n\n// =============================================================================\n// Token Sync Resolution\n// =============================================================================\n\n/**\n * Resolve IPFS sync configuration with extend/override pattern\n */\nfunction resolveIpfsSyncConfig(\n network: NetworkType,\n config?: IpfsSyncConfig\n): NonNullable<BrowserProviders['tokenSyncConfig']>['ipfs'] | undefined {\n if (!config) return undefined;\n\n const networkConfig = getNetworkConfig(network);\n const gateways = resolveArrayConfig(\n networkConfig.ipfsGateways,\n config.gateways,\n config.additionalGateways\n );\n\n return {\n enabled: config.enabled ?? false,\n gateways,\n bootstrapPeers: config.bootstrapPeers ?? config.additionalBootstrapPeers,\n useDht: config.useDht,\n };\n}\n\n/**\n * Resolve all token sync backends\n */\nfunction resolveTokenSyncConfig(\n network: NetworkType,\n config?: TokenSyncConfig\n): BrowserProviders['tokenSyncConfig'] {\n if (!config) return undefined;\n\n const result: BrowserProviders['tokenSyncConfig'] = {};\n\n // IPFS backend\n const ipfs = resolveIpfsSyncConfig(network, config.ipfs);\n if (ipfs) result.ipfs = ipfs;\n\n // File backend\n if (config.file) {\n result.file = {\n enabled: config.file.enabled ?? false,\n directory: config.file.directory,\n format: config.file.format,\n };\n }\n\n // Cloud backend\n if (config.cloud) {\n result.cloud = {\n enabled: config.cloud.enabled ?? false,\n provider: config.cloud.provider,\n bucket: config.cloud.bucket,\n endpoint: config.cloud.endpoint,\n apiKey: config.cloud.apiKey,\n };\n }\n\n // MongoDB backend\n if (config.mongodb) {\n result.mongodb = {\n enabled: config.mongodb.enabled ?? false,\n uri: config.mongodb.uri,\n database: config.mongodb.database,\n collection: config.mongodb.collection,\n };\n }\n\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\n/**\n * Create all browser providers with default configuration\n *\n * Supports extend/override pattern for flexible configuration:\n * - Use `network` preset for quick setup (mainnet/testnet/dev)\n * - Override specific values (e.g., `oracle.url` replaces default)\n * - Extend arrays with `additional*` (e.g., `additionalRelays` adds to defaults)\n *\n * @example\n * ```ts\n * // Simple - uses mainnet defaults\n * const providers = createBrowserProviders();\n *\n * // Testnet - all services use testnet URLs\n * const providers = createBrowserProviders({ network: 'testnet' });\n *\n * // Add extra relays to testnet defaults\n * const providers = createBrowserProviders({\n * network: 'testnet',\n * transport: {\n * additionalRelays: ['wss://my-relay.com', 'wss://backup-relay.com'],\n * },\n * });\n *\n * // Replace relays entirely (ignores network defaults)\n * const providers = createBrowserProviders({\n * network: 'testnet',\n * transport: {\n * relays: ['wss://only-this-relay.com'],\n * },\n * });\n *\n * // Use with Sphere.init (tokenStorage is automatically included)\n * const { sphere } = await Sphere.init({\n * ...providers,\n * autoGenerate: true,\n * });\n *\n * // Add additional sync backends dynamically after init\n * // await sphere.addTokenStorageProvider(myMongoDbProvider);\n * ```\n */\nexport function createBrowserProviders(config?: BrowserProvidersConfig): BrowserProviders {\n const network = config?.network ?? 'mainnet';\n\n // Resolve configurations using shared utilities\n const transportConfig = resolveTransportConfig(network, config?.transport);\n const oracleConfig = resolveOracleConfig(network, config?.oracle);\n const l1Config = resolveL1Config(network, config?.l1);\n const tokenSyncConfig = resolveTokenSyncConfig(network, config?.tokenSync);\n const priceConfig = resolvePriceConfig(config?.price);\n\n const storage = createLocalStorageProvider(config?.storage);\n\n return {\n storage,\n transport: createNostrTransportProvider({\n relays: transportConfig.relays,\n timeout: transportConfig.timeout,\n autoReconnect: transportConfig.autoReconnect,\n reconnectDelay: transportConfig.reconnectDelay,\n maxReconnectAttempts: transportConfig.maxReconnectAttempts,\n debug: transportConfig.debug,\n storage,\n }),\n oracle: createUnicityAggregatorProvider({\n url: oracleConfig.url,\n apiKey: oracleConfig.apiKey,\n timeout: oracleConfig.timeout,\n skipVerification: oracleConfig.skipVerification,\n debug: oracleConfig.debug,\n network,\n }),\n tokenStorage: createIndexedDBTokenStorageProvider(),\n l1: l1Config,\n price: priceConfig ? createPriceProvider(priceConfig) : undefined,\n tokenSyncConfig,\n };\n}\n","/**\n * SDK2 Constants\n * Default configuration values and storage keys\n */\n\n// =============================================================================\n// Storage Keys\n// =============================================================================\n\n/** Default prefix for all storage keys */\nexport const STORAGE_PREFIX = 'sphere_' as const;\n\n/**\n * Default encryption key for wallet data\n * WARNING: This is a placeholder. In production, use user-provided password.\n * This key is used when no password is provided to encrypt/decrypt mnemonic.\n */\nexport const DEFAULT_ENCRYPTION_KEY = 'sphere-default-key' as const;\n\n/**\n * Global storage keys (one per wallet, no address index)\n * Final key format: sphere_{key}\n */\nexport const STORAGE_KEYS_GLOBAL = {\n /** Encrypted BIP39 mnemonic */\n MNEMONIC: 'mnemonic',\n /** Encrypted master private key */\n MASTER_KEY: 'master_key',\n /** BIP32 chain code */\n CHAIN_CODE: 'chain_code',\n /** HD derivation path (full path like m/44'/0'/0'/0/0) */\n DERIVATION_PATH: 'derivation_path',\n /** Base derivation path (like m/44'/0'/0' without chain/index) */\n BASE_PATH: 'base_path',\n /** Derivation mode: bip32, wif_hmac, legacy_hmac */\n DERIVATION_MODE: 'derivation_mode',\n /** Wallet source: mnemonic, file, unknown */\n WALLET_SOURCE: 'wallet_source',\n /** Wallet existence flag */\n WALLET_EXISTS: 'wallet_exists',\n /** Current active address index */\n CURRENT_ADDRESS_INDEX: 'current_address_index',\n /** Nametag cache per address (separate from tracked addresses registry) */\n ADDRESS_NAMETAGS: 'address_nametags',\n /** Active addresses registry (JSON: TrackedAddressesStorage) */\n TRACKED_ADDRESSES: 'tracked_addresses',\n /** Last processed Nostr wallet event timestamp (unix seconds), keyed per pubkey */\n LAST_WALLET_EVENT_TS: 'last_wallet_event_ts',\n} as const;\n\n/**\n * Per-address storage keys (one per derived address)\n * Final key format: sphere_{DIRECT_xxx_yyy}_{key}\n * Example: sphere_DIRECT_abc123_xyz789_pending_transfers\n *\n * Note: Token data (tokens, tombstones, archived, forked) is stored via\n * TokenStorageProvider, not here. This avoids duplication.\n */\nexport const STORAGE_KEYS_ADDRESS = {\n /** Pending transfers for this address */\n PENDING_TRANSFERS: 'pending_transfers',\n /** Transfer outbox for this address */\n OUTBOX: 'outbox',\n /** Conversations for this address */\n CONVERSATIONS: 'conversations',\n /** Messages for this address */\n MESSAGES: 'messages',\n /** Transaction history for this address */\n TRANSACTION_HISTORY: 'transaction_history',\n} as const;\n\n/** @deprecated Use STORAGE_KEYS_GLOBAL and STORAGE_KEYS_ADDRESS instead */\nexport const STORAGE_KEYS = {\n ...STORAGE_KEYS_GLOBAL,\n ...STORAGE_KEYS_ADDRESS,\n} as const;\n\n/**\n * Build a per-address storage key using address identifier\n * @param addressId - Short identifier for the address (e.g., first 8 chars of pubkey hash, or direct address hash)\n * @param key - The key from STORAGE_KEYS_ADDRESS\n * @returns Key in format: \"{addressId}_{key}\" e.g., \"a1b2c3d4_tokens\"\n */\nexport function getAddressStorageKey(addressId: string, key: string): string {\n return `${addressId}_${key}`;\n}\n\n/**\n * Create a readable address identifier from directAddress or chainPubkey\n * Format: DIRECT_first6_last6 (sanitized for filesystem/storage)\n * @param directAddress - The L3 direct address (DIRECT:xxx) or chainPubkey\n * @returns Sanitized identifier like \"DIRECT_abc123_xyz789\"\n */\nexport function getAddressId(directAddress: string): string {\n // Remove DIRECT:// or DIRECT: prefix if present\n let hash = directAddress;\n if (hash.startsWith('DIRECT://')) {\n hash = hash.slice(9);\n } else if (hash.startsWith('DIRECT:')) {\n hash = hash.slice(7);\n }\n // Format: DIRECT_first6_last6 (sanitized)\n const first = hash.slice(0, 6).toLowerCase();\n const last = hash.slice(-6).toLowerCase();\n return `DIRECT_${first}_${last}`;\n}\n\n// =============================================================================\n// Nostr Defaults\n// =============================================================================\n\n/** Default Nostr relays */\nexport const DEFAULT_NOSTR_RELAYS = [\n 'wss://relay.unicity.network',\n 'wss://relay.damus.io',\n 'wss://nos.lol',\n 'wss://relay.nostr.band',\n] as const;\n\n/** Nostr event kinds used by SDK - must match @unicitylabs/nostr-js-sdk */\nexport const NOSTR_EVENT_KINDS = {\n /** NIP-04 encrypted direct message */\n DIRECT_MESSAGE: 4,\n /** Token transfer (Unicity custom - 31113) */\n TOKEN_TRANSFER: 31113,\n /** Payment request (Unicity custom - 31115) */\n PAYMENT_REQUEST: 31115,\n /** Payment request response (Unicity custom - 31116) */\n PAYMENT_REQUEST_RESPONSE: 31116,\n /** Nametag binding (NIP-78 app-specific data) */\n NAMETAG_BINDING: 30078,\n /** Public broadcast */\n BROADCAST: 1,\n} as const;\n\n// =============================================================================\n// Aggregator (Oracle) Defaults\n// =============================================================================\n\n/**\n * Default aggregator URL\n * Note: The aggregator is conceptually an oracle - a trusted service that provides\n * verifiable truth about token state through cryptographic inclusion proofs.\n */\nexport const DEFAULT_AGGREGATOR_URL = 'https://aggregator.unicity.network/rpc' as const;\n\n/** Dev aggregator URL */\nexport const DEV_AGGREGATOR_URL = 'https://dev-aggregator.dyndns.org/rpc' as const;\n\n/** Test aggregator URL (Goggregator) */\nexport const TEST_AGGREGATOR_URL = 'https://goggregator-test.unicity.network' as const;\n\n/** Default aggregator request timeout (ms) */\nexport const DEFAULT_AGGREGATOR_TIMEOUT = 30000;\n\n/** Default API key for aggregator authentication */\nexport const DEFAULT_AGGREGATOR_API_KEY = 'sk_06365a9c44654841a366068bcfc68986' as const;\n\n// =============================================================================\n// IPFS Defaults\n// =============================================================================\n\n/** Default IPFS gateways */\nexport const DEFAULT_IPFS_GATEWAYS = [\n 'https://ipfs.unicity.network',\n 'https://dweb.link',\n 'https://ipfs.io',\n] as const;\n\n/** Unicity IPFS bootstrap peers */\nexport const DEFAULT_IPFS_BOOTSTRAP_PEERS = [\n '/dns4/unicity-ipfs2.dyndns.org/tcp/4001/p2p/12D3KooWLNi5NDPPHbrfJakAQqwBqymYTTwMQXQKEWuCrJNDdmfh',\n '/dns4/unicity-ipfs3.dyndns.org/tcp/4001/p2p/12D3KooWQ4aujVE4ShLjdusNZBdffq3TbzrwT2DuWZY9H1Gxhwn6',\n '/dns4/unicity-ipfs4.dyndns.org/tcp/4001/p2p/12D3KooWJ1ByPfUzUrpYvgxKU8NZrR8i6PU1tUgMEbQX9Hh2DEn1',\n '/dns4/unicity-ipfs5.dyndns.org/tcp/4001/p2p/12D3KooWB1MdZZGHN5B8TvWXntbycfe7Cjcz7n6eZ9eykZadvmDv',\n] as const;\n\n// =============================================================================\n// Wallet Defaults\n// =============================================================================\n\n/** Default BIP32 base path (without chain/index) */\nexport const DEFAULT_BASE_PATH = \"m/44'/0'/0'\" as const;\n\n/** Default BIP32 derivation path (full path with chain/index) */\nexport const DEFAULT_DERIVATION_PATH = `${DEFAULT_BASE_PATH}/0/0` as const;\n\n/** Coin types */\nexport const COIN_TYPES = {\n /** ALPHA token (L1 blockchain) */\n ALPHA: 'ALPHA',\n /** Test token */\n TEST: 'TEST',\n} as const;\n\n// =============================================================================\n// L1 (ALPHA Blockchain) Defaults\n// =============================================================================\n\n/** Default Fulcrum electrum server for mainnet */\nexport const DEFAULT_ELECTRUM_URL = 'wss://fulcrum.alpha.unicity.network:50004' as const;\n\n/** Testnet Fulcrum electrum server */\nexport const TEST_ELECTRUM_URL = 'wss://fulcrum.alpha.testnet.unicity.network:50004' as const;\n\n// =============================================================================\n// Network Defaults\n// =============================================================================\n\n/** Testnet Nostr relays */\nexport const TEST_NOSTR_RELAYS = [\n 'wss://nostr-relay.testnet.unicity.network',\n] as const;\n\n/** Network configurations */\nexport const NETWORKS = {\n mainnet: {\n name: 'Mainnet',\n aggregatorUrl: DEFAULT_AGGREGATOR_URL,\n nostrRelays: DEFAULT_NOSTR_RELAYS,\n ipfsGateways: DEFAULT_IPFS_GATEWAYS,\n electrumUrl: DEFAULT_ELECTRUM_URL,\n },\n testnet: {\n name: 'Testnet',\n aggregatorUrl: TEST_AGGREGATOR_URL,\n nostrRelays: TEST_NOSTR_RELAYS,\n ipfsGateways: DEFAULT_IPFS_GATEWAYS,\n electrumUrl: TEST_ELECTRUM_URL,\n },\n dev: {\n name: 'Development',\n aggregatorUrl: DEV_AGGREGATOR_URL,\n nostrRelays: TEST_NOSTR_RELAYS,\n ipfsGateways: DEFAULT_IPFS_GATEWAYS,\n electrumUrl: TEST_ELECTRUM_URL,\n },\n} as const;\n\nexport type NetworkType = keyof typeof NETWORKS;\nexport type NetworkConfig = (typeof NETWORKS)[NetworkType];\n\n// =============================================================================\n// Timeouts & Limits\n// =============================================================================\n\n/** Default timeouts (ms) */\nexport const TIMEOUTS = {\n /** WebSocket connection timeout */\n WEBSOCKET_CONNECT: 10000,\n /** Nostr relay reconnect delay */\n NOSTR_RECONNECT_DELAY: 3000,\n /** Max reconnect attempts */\n MAX_RECONNECT_ATTEMPTS: 5,\n /** Proof polling interval */\n PROOF_POLL_INTERVAL: 1000,\n /** Sync interval */\n SYNC_INTERVAL: 60000,\n} as const;\n\n/** Validation limits */\nexport const LIMITS = {\n /** Min nametag length */\n NAMETAG_MIN_LENGTH: 3,\n /** Max nametag length */\n NAMETAG_MAX_LENGTH: 20,\n /** Max memo length */\n MEMO_MAX_LENGTH: 500,\n /** Max message length */\n MESSAGE_MAX_LENGTH: 10000,\n} as const;\n","/**\n * Browser LocalStorage Provider\n * Implements StorageProvider using browser localStorage\n */\n\nimport type { ProviderStatus, FullIdentity, TrackedAddressEntry } from '../../../types';\nimport type { StorageProvider } from '../../../storage';\nimport { STORAGE_KEYS_ADDRESS, STORAGE_KEYS_GLOBAL, getAddressId } from '../../../constants';\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\nexport interface LocalStorageProviderConfig {\n /** Key prefix (default: 'sphere_') */\n prefix?: string;\n /** Custom storage instance (for testing/SSR) */\n storage?: Storage;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\nexport class LocalStorageProvider implements StorageProvider {\n readonly id = 'localStorage';\n readonly name = 'Local Storage';\n readonly type = 'local' as const;\n readonly description = 'Browser localStorage for single-device persistence';\n\n private config: Required<Pick<LocalStorageProviderConfig, 'prefix' | 'debug'>> & {\n storage: Storage;\n };\n private identity: FullIdentity | null = null;\n private status: ProviderStatus = 'disconnected';\n\n constructor(config?: LocalStorageProviderConfig) {\n // SSR fallback: use in-memory storage if localStorage unavailable\n const storage = config?.storage ?? this.getStorageSafe();\n\n this.config = {\n prefix: config?.prefix ?? 'sphere_',\n storage,\n debug: config?.debug ?? false,\n };\n }\n\n // ===========================================================================\n // BaseProvider Implementation\n // ===========================================================================\n\n async connect(): Promise<void> {\n if (this.status === 'connected') return;\n\n this.status = 'connecting';\n\n try {\n // Test storage availability\n const testKey = `${this.config.prefix}_test`;\n this.config.storage.setItem(testKey, 'test');\n this.config.storage.removeItem(testKey);\n\n this.status = 'connected';\n this.log('Connected to localStorage');\n } catch (error) {\n this.status = 'error';\n throw new Error(`LocalStorage not available: ${error}`);\n }\n }\n\n async disconnect(): Promise<void> {\n this.status = 'disconnected';\n this.log('Disconnected from localStorage');\n }\n\n isConnected(): boolean {\n return this.status === 'connected';\n }\n\n getStatus(): ProviderStatus {\n return this.status;\n }\n\n // ===========================================================================\n // StorageProvider Implementation\n // ===========================================================================\n\n setIdentity(identity: FullIdentity): void {\n this.identity = identity;\n this.log('Identity set:', identity.l1Address);\n }\n\n async get(key: string): Promise<string | null> {\n this.ensureConnected();\n const fullKey = this.getFullKey(key);\n return this.config.storage.getItem(fullKey);\n }\n\n async set(key: string, value: string): Promise<void> {\n this.ensureConnected();\n const fullKey = this.getFullKey(key);\n this.config.storage.setItem(fullKey, value);\n }\n\n async remove(key: string): Promise<void> {\n this.ensureConnected();\n const fullKey = this.getFullKey(key);\n this.config.storage.removeItem(fullKey);\n }\n\n async has(key: string): Promise<boolean> {\n this.ensureConnected();\n const fullKey = this.getFullKey(key);\n return this.config.storage.getItem(fullKey) !== null;\n }\n\n async keys(prefix?: string): Promise<string[]> {\n this.ensureConnected();\n const basePrefix = this.getFullKey('');\n const searchPrefix = prefix ? this.getFullKey(prefix) : basePrefix;\n const result: string[] = [];\n\n for (let i = 0; i < this.config.storage.length; i++) {\n const key = this.config.storage.key(i);\n if (key?.startsWith(searchPrefix)) {\n // Return key without the base prefix\n result.push(key.slice(basePrefix.length));\n }\n }\n\n return result;\n }\n\n async clear(prefix?: string): Promise<void> {\n this.ensureConnected();\n const keysToRemove = await this.keys(prefix);\n for (const key of keysToRemove) {\n await this.remove(key);\n }\n }\n\n async saveTrackedAddresses(entries: TrackedAddressEntry[]): Promise<void> {\n await this.set(STORAGE_KEYS_GLOBAL.TRACKED_ADDRESSES, JSON.stringify({ version: 1, addresses: entries }));\n }\n\n async loadTrackedAddresses(): Promise<TrackedAddressEntry[]> {\n const data = await this.get(STORAGE_KEYS_GLOBAL.TRACKED_ADDRESSES);\n if (!data) return [];\n try {\n const parsed = JSON.parse(data);\n return parsed.addresses ?? [];\n } catch {\n return [];\n }\n }\n\n // ===========================================================================\n // Helpers\n // ===========================================================================\n\n /**\n * Get JSON data\n */\n async getJSON<T>(key: string): Promise<T | null> {\n const value = await this.get(key);\n if (!value) return null;\n try {\n return JSON.parse(value) as T;\n } catch {\n return null;\n }\n }\n\n /**\n * Set JSON data\n */\n async setJSON<T>(key: string, value: T): Promise<void> {\n await this.set(key, JSON.stringify(value));\n }\n\n // ===========================================================================\n // Private Methods\n // ===========================================================================\n\n private getFullKey(key: string): string {\n // Check if this is a per-address key\n const isPerAddressKey = Object.values(STORAGE_KEYS_ADDRESS).includes(key as typeof STORAGE_KEYS_ADDRESS[keyof typeof STORAGE_KEYS_ADDRESS]);\n\n if (isPerAddressKey && this.identity?.directAddress) {\n // Add address ID prefix for per-address data\n const addressId = getAddressId(this.identity.directAddress);\n return `${this.config.prefix}${addressId}_${key}`;\n }\n\n // Global key - no address prefix\n return `${this.config.prefix}${key}`;\n }\n\n private ensureConnected(): void {\n if (this.status !== 'connected') {\n throw new Error('LocalStorageProvider not connected');\n }\n }\n\n private getStorageSafe(): Storage {\n if (typeof window !== 'undefined' && window.localStorage) {\n return window.localStorage;\n }\n\n // SSR fallback: in-memory storage\n return createInMemoryStorage();\n }\n\n private log(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[LocalStorageProvider]', ...args);\n }\n }\n}\n\n// =============================================================================\n// In-Memory Storage (SSR Fallback)\n// =============================================================================\n\nfunction createInMemoryStorage(): Storage {\n const data = new Map<string, string>();\n\n return {\n get length() {\n return data.size;\n },\n clear() {\n data.clear();\n },\n getItem(key: string) {\n return data.get(key) ?? null;\n },\n setItem(key: string, value: string) {\n data.set(key, value);\n },\n removeItem(key: string) {\n data.delete(key);\n },\n key(index: number) {\n return Array.from(data.keys())[index] ?? null;\n },\n };\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\nexport function createLocalStorageProvider(\n config?: LocalStorageProviderConfig\n): LocalStorageProvider {\n return new LocalStorageProvider(config);\n}\n","/**\n * IndexedDB Token Storage Provider for Browser\n * Stores tokens in IndexedDB for persistent browser storage\n * Each address gets its own database for multi-address support\n */\n\nimport type { TokenStorageProvider, TxfStorageDataBase, SyncResult, SaveResult, LoadResult } from '../../../storage';\nimport type { FullIdentity, ProviderStatus } from '../../../types';\nimport { getAddressId } from '../../../constants';\n\nconst DB_NAME = 'sphere-token-storage';\nconst DB_VERSION = 1;\nconst STORE_TOKENS = 'tokens';\nconst STORE_META = 'meta';\n\nexport interface IndexedDBTokenStorageConfig {\n /** Database name prefix (default: 'sphere-token-storage') */\n dbNamePrefix?: string;\n}\n\nexport class IndexedDBTokenStorageProvider implements TokenStorageProvider<TxfStorageDataBase> {\n readonly id = 'indexeddb-token-storage';\n readonly name = 'IndexedDB Token Storage';\n readonly type = 'local' as const;\n\n private dbNamePrefix: string;\n private dbName: string;\n private db: IDBDatabase | null = null;\n private status: ProviderStatus = 'disconnected';\n private identity: FullIdentity | null = null;\n\n constructor(config?: IndexedDBTokenStorageConfig) {\n this.dbNamePrefix = config?.dbNamePrefix ?? DB_NAME;\n this.dbName = this.dbNamePrefix;\n }\n\n setIdentity(identity: FullIdentity): void {\n this.identity = identity;\n // Scope database to address using consistent addressId format\n if (identity.directAddress) {\n const addressId = getAddressId(identity.directAddress);\n this.dbName = `${this.dbNamePrefix}-${addressId}`;\n }\n }\n\n async initialize(): Promise<boolean> {\n try {\n this.db = await this.openDatabase();\n this.status = 'connected';\n return true;\n } catch (error) {\n console.error('[IndexedDBTokenStorage] Failed to initialize:', error);\n this.status = 'error';\n return false;\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n this.status = 'disconnected';\n }\n\n async connect(): Promise<void> {\n await this.initialize();\n }\n\n async disconnect(): Promise<void> {\n await this.shutdown();\n }\n\n isConnected(): boolean {\n return this.status === 'connected' && this.db !== null;\n }\n\n getStatus(): ProviderStatus {\n return this.status;\n }\n\n async load(): Promise<LoadResult<TxfStorageDataBase>> {\n if (!this.db) {\n return {\n success: false,\n error: 'Database not initialized',\n source: 'local',\n timestamp: Date.now(),\n };\n }\n\n try {\n const data: TxfStorageDataBase = {\n _meta: {\n version: 1,\n address: this.identity?.l1Address ?? '',\n formatVersion: '2.0',\n updatedAt: Date.now(),\n },\n };\n\n // Load meta\n const meta = await this.getFromStore<TxfStorageDataBase['_meta']>(STORE_META, 'meta');\n if (meta) {\n data._meta = meta;\n }\n\n // Load all tokens from store\n const tokens = await this.getAllFromStore<{ id: string; data: unknown }>(STORE_TOKENS);\n for (const token of tokens) {\n // Skip file-format entries (token-, nametag-) - they are loaded via loadTokensFromFileStorage\n if (token.id.startsWith('token-') || token.id.startsWith('nametag-')) {\n continue;\n }\n\n if (token.id.startsWith('archived-')) {\n // Archived tokens: keep as-is (archived-tokenId key)\n data[token.id as keyof TxfStorageDataBase] = token.data;\n } else {\n // Other entries: add _ prefix for TXF format\n const key = `_${token.id}` as `_${string}`;\n data[key] = token.data;\n }\n }\n\n // Load tombstones\n const tombstones = await this.getFromStore<TxfStorageDataBase['_tombstones']>(STORE_META, 'tombstones');\n if (tombstones) {\n data._tombstones = tombstones;\n }\n\n // Load outbox\n const outbox = await this.getFromStore<TxfStorageDataBase['_outbox']>(STORE_META, 'outbox');\n if (outbox) {\n data._outbox = outbox;\n }\n\n // Load sent\n const sent = await this.getFromStore<TxfStorageDataBase['_sent']>(STORE_META, 'sent');\n if (sent) {\n data._sent = sent;\n }\n\n // Load invalid\n const invalid = await this.getFromStore<TxfStorageDataBase['_invalid']>(STORE_META, 'invalid');\n if (invalid) {\n data._invalid = invalid;\n }\n\n return {\n success: true,\n data,\n source: 'local',\n timestamp: Date.now(),\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error',\n source: 'local',\n timestamp: Date.now(),\n };\n }\n }\n\n async save(data: TxfStorageDataBase): Promise<SaveResult> {\n if (!this.db) {\n return {\n success: false,\n error: 'Database not initialized',\n timestamp: Date.now(),\n };\n }\n\n try {\n // Save meta\n await this.putToStore(STORE_META, 'meta', data._meta);\n\n // Save special arrays\n if (data._tombstones) {\n await this.putToStore(STORE_META, 'tombstones', data._tombstones);\n }\n if (data._outbox) {\n await this.putToStore(STORE_META, 'outbox', data._outbox);\n }\n if (data._sent) {\n await this.putToStore(STORE_META, 'sent', data._sent);\n }\n if (data._invalid) {\n await this.putToStore(STORE_META, 'invalid', data._invalid);\n }\n\n // Save each token (active tokens start with _, archived with archived-)\n const reservedKeys = ['_meta', '_tombstones', '_outbox', '_sent', '_invalid'];\n for (const [key, value] of Object.entries(data)) {\n if (reservedKeys.includes(key)) continue;\n\n if (key.startsWith('_')) {\n // Active token: _tokenId -> tokenId\n const tokenId = key.slice(1);\n await this.putToStore(STORE_TOKENS, tokenId, { id: tokenId, data: value });\n } else if (key.startsWith('archived-')) {\n // Archived token: archived-tokenId -> archived-tokenId (keep prefix)\n await this.putToStore(STORE_TOKENS, key, { id: key, data: value });\n }\n }\n\n // Handle tombstones - delete tokens\n if (data._tombstones) {\n for (const tombstone of data._tombstones) {\n await this.deleteFromStore(STORE_TOKENS, tombstone.tokenId);\n }\n }\n\n return {\n success: true,\n timestamp: Date.now(),\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error',\n timestamp: Date.now(),\n };\n }\n }\n\n async sync(localData: TxfStorageDataBase): Promise<SyncResult<TxfStorageDataBase>> {\n // For local IndexedDB storage, just save and return\n const saveResult = await this.save(localData);\n return {\n success: saveResult.success,\n merged: localData,\n added: 0,\n removed: 0,\n conflicts: 0,\n error: saveResult.error,\n };\n }\n\n async exists(): Promise<boolean> {\n if (!this.db) return false;\n const meta = await this.getFromStore(STORE_META, 'meta');\n return meta !== null;\n }\n\n async clear(): Promise<boolean> {\n // Close the open connection so deleteDatabase isn't blocked\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n this.status = 'disconnected';\n\n const CLEAR_TIMEOUT = 1500;\n\n const withTimeout = <T>(promise: Promise<T>, ms: number, label: string): Promise<T> =>\n Promise.race([\n promise,\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms),\n ),\n ]);\n\n const deleteDb = (name: string) =>\n new Promise<void>((resolve) => {\n const req = indexedDB.deleteDatabase(name);\n req.onsuccess = () => resolve();\n req.onerror = () => resolve();\n req.onblocked = () => resolve();\n });\n\n try {\n // Delete all databases matching our prefix (covers all addresses)\n if (typeof indexedDB.databases === 'function') {\n const dbs = await withTimeout(\n indexedDB.databases(),\n CLEAR_TIMEOUT,\n 'indexedDB.databases()',\n );\n await Promise.all(\n dbs\n .filter(db => db.name?.startsWith(this.dbNamePrefix))\n .map(db => deleteDb(db.name!)),\n );\n } else {\n // Fallback: delete only the current database\n await deleteDb(this.dbName);\n }\n return true;\n } catch (err) {\n console.warn('[IndexedDBTokenStorage] clear() failed:', err);\n return false;\n }\n }\n\n // =========================================================================\n // Helper methods for individual token operations\n // =========================================================================\n\n async deleteToken(tokenId: string): Promise<void> {\n if (this.db) {\n await this.deleteFromStore(STORE_TOKENS, tokenId);\n }\n }\n\n async saveToken(tokenId: string, tokenData: unknown): Promise<void> {\n if (this.db) {\n await this.putToStore(STORE_TOKENS, tokenId, { id: tokenId, data: tokenData });\n }\n }\n\n async getToken(tokenId: string): Promise<unknown | null> {\n if (!this.db) return null;\n const result = await this.getFromStore<{ id: string; data: unknown }>(STORE_TOKENS, tokenId);\n return result?.data ?? null;\n }\n\n async listTokenIds(): Promise<string[]> {\n if (!this.db) return [];\n const tokens = await this.getAllFromStore<{ id: string }>(STORE_TOKENS);\n return tokens.map(t => t.id);\n }\n\n // =========================================================================\n // Private IndexedDB helpers\n // =========================================================================\n\n private openDatabase(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(this.dbName, DB_VERSION);\n\n request.onerror = () => {\n reject(request.error);\n };\n\n request.onsuccess = () => {\n resolve(request.result);\n };\n\n request.onupgradeneeded = (event) => {\n const db = (event.target as IDBOpenDBRequest).result;\n\n // Create tokens store\n if (!db.objectStoreNames.contains(STORE_TOKENS)) {\n db.createObjectStore(STORE_TOKENS, { keyPath: 'id' });\n }\n\n // Create meta store\n if (!db.objectStoreNames.contains(STORE_META)) {\n db.createObjectStore(STORE_META);\n }\n };\n });\n }\n\n private getFromStore<T>(storeName: string, key: string): Promise<T | null> {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n resolve(null);\n return;\n }\n\n const transaction = this.db.transaction(storeName, 'readonly');\n const store = transaction.objectStore(storeName);\n const request = store.get(key);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result ?? null);\n });\n }\n\n private getAllFromStore<T>(storeName: string): Promise<T[]> {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n resolve([]);\n return;\n }\n\n const transaction = this.db.transaction(storeName, 'readonly');\n const store = transaction.objectStore(storeName);\n const request = store.getAll();\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result ?? []);\n });\n }\n\n private putToStore(storeName: string, key: string, value: unknown): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n\n const transaction = this.db.transaction(storeName, 'readwrite');\n const store = transaction.objectStore(storeName);\n\n // For meta store, use put with explicit key\n // For tokens store, value contains the key (keyPath: 'id')\n const request = storeName === STORE_META\n ? store.put(value, key)\n : store.put(value);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n });\n }\n\n private deleteFromStore(storeName: string, key: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n resolve();\n return;\n }\n\n const transaction = this.db.transaction(storeName, 'readwrite');\n const store = transaction.objectStore(storeName);\n const request = store.delete(key);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n });\n }\n\n private clearStore(storeName: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n resolve();\n return;\n }\n\n const transaction = this.db.transaction(storeName, 'readwrite');\n const store = transaction.objectStore(storeName);\n const request = store.clear();\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n });\n }\n}\n\nexport function createIndexedDBTokenStorageProvider(\n config?: IndexedDBTokenStorageConfig\n): IndexedDBTokenStorageProvider {\n return new IndexedDBTokenStorageProvider(config);\n}\n","/**\n * Nostr Transport Provider\n * Platform-independent implementation using Nostr protocol for P2P messaging\n *\n * Uses @unicitylabs/nostr-js-sdk for:\n * - Real secp256k1 event signing\n * - NIP-04 encryption/decryption\n * - Event ID calculation\n * - NostrClient for reliable connection management (ping, reconnect, NIP-42)\n *\n * WebSocket is injected via factory for cross-platform support\n */\n\nimport { Buffer } from 'buffer';\nimport { hkdf } from '@noble/hashes/hkdf.js';\nimport { sha256 as sha256Noble } from '@noble/hashes/sha2.js';\nimport {\n NostrKeyManager,\n NIP04,\n NIP17,\n Event as NostrEventClass,\n EventKinds,\n hashNametag,\n NostrClient,\n Filter,\n} from '@unicitylabs/nostr-js-sdk';\nimport { getPublicKey, publicKeyToAddress } from '../core/crypto';\nimport type { ProviderStatus, FullIdentity } from '../types';\nimport type {\n TransportProvider,\n MessageHandler,\n TokenTransferHandler,\n BroadcastHandler,\n PaymentRequestHandler,\n PaymentRequestResponseHandler,\n IncomingMessage,\n IncomingTokenTransfer,\n IncomingBroadcast,\n IncomingPaymentRequest,\n IncomingPaymentRequestResponse,\n TokenTransferPayload,\n PaymentRequestPayload,\n PaymentRequestResponsePayload,\n TransportEvent,\n TransportEventCallback,\n PeerInfo,\n} from './transport-provider';\nimport type { WebSocketFactory, UUIDGenerator } from './websocket';\nimport { defaultUUIDGenerator } from './websocket';\nimport {\n DEFAULT_NOSTR_RELAYS,\n NOSTR_EVENT_KINDS,\n STORAGE_KEYS_GLOBAL,\n TIMEOUTS,\n} from '../constants';\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\n/**\n * Minimal key-value storage interface for transport persistence.\n * Used to persist the last processed event timestamp across sessions.\n */\nexport interface TransportStorageAdapter {\n get(key: string): Promise<string | null>;\n set(key: string, value: string): Promise<void>;\n}\n\nexport interface NostrTransportProviderConfig {\n /** Nostr relay URLs */\n relays?: string[];\n /** Connection timeout (ms) */\n timeout?: number;\n /** Auto-reconnect on disconnect */\n autoReconnect?: boolean;\n /** Reconnect delay (ms) */\n reconnectDelay?: number;\n /** Max reconnect attempts */\n maxReconnectAttempts?: number;\n /** Enable debug logging */\n debug?: boolean;\n /** WebSocket factory (required for platform support) */\n createWebSocket: WebSocketFactory;\n /** UUID generator (optional, defaults to crypto.randomUUID) */\n generateUUID?: UUIDGenerator;\n /** Optional storage adapter for persisting subscription timestamps */\n storage?: TransportStorageAdapter;\n}\n\n// Alias for backward compatibility\nconst EVENT_KINDS = NOSTR_EVENT_KINDS;\n\n// =============================================================================\n// Address Hashing Utility\n// =============================================================================\n\n/**\n * Hash an address (DIRECT:// or PROXY://) for use as indexed 't' tag value.\n * Enables reverse lookup: address → binding event → transport pubkey.\n * @param address - Address string (e.g., DIRECT://... or PROXY://...)\n * @returns Hex-encoded SHA-256 hash\n */\nfunction hashAddressForTag(address: string): string {\n const bytes = new TextEncoder().encode('unicity:address:' + address);\n return Buffer.from(sha256Noble(bytes)).toString('hex');\n}\n\n// =============================================================================\n// Nametag Encryption Utilities\n// =============================================================================\n\n/**\n * Derive encryption key from private key using HKDF\n * @param privateKeyHex - 32-byte private key as hex\n * @returns 32-byte derived key as Uint8Array\n */\nfunction deriveNametagEncryptionKey(privateKeyHex: string): Uint8Array {\n const privateKeyBytes = Buffer.from(privateKeyHex, 'hex');\n // Use HKDF with SHA-256, salt derived from constant, info = \"nametag-encryption\"\n const saltInput = new TextEncoder().encode('sphere-nametag-salt');\n const salt = sha256Noble(saltInput);\n const info = new TextEncoder().encode('nametag-encryption');\n return hkdf(sha256Noble, privateKeyBytes, salt, info, 32);\n}\n\n/**\n * Encrypt nametag with AES-GCM using derived key\n * @param nametag - Plain text nametag\n * @param privateKeyHex - Private key for key derivation\n * @returns Base64 encoded encrypted data (iv + ciphertext + tag)\n */\nasync function encryptNametag(nametag: string, privateKeyHex: string): Promise<string> {\n const key = deriveNametagEncryptionKey(privateKeyHex);\n const iv = crypto.getRandomValues(new Uint8Array(12)); // 96-bit IV for AES-GCM\n const encoder = new TextEncoder();\n const data = encoder.encode(nametag);\n\n const cryptoKey = await crypto.subtle.importKey(\n 'raw',\n new Uint8Array(key).buffer as ArrayBuffer,\n { name: 'AES-GCM' },\n false,\n ['encrypt']\n );\n\n const encrypted = await crypto.subtle.encrypt(\n { name: 'AES-GCM', iv: new Uint8Array(iv).buffer as ArrayBuffer },\n cryptoKey,\n new Uint8Array(data).buffer as ArrayBuffer\n );\n\n // Combine IV + ciphertext (includes auth tag)\n const combined = new Uint8Array(iv.length + encrypted.byteLength);\n combined.set(iv, 0);\n combined.set(new Uint8Array(encrypted), iv.length);\n\n return Buffer.from(combined).toString('base64');\n}\n\n/**\n * Decrypt nametag with AES-GCM using derived key\n * @param encryptedBase64 - Base64 encoded encrypted data (iv + ciphertext + tag)\n * @param privateKeyHex - Private key for key derivation\n * @returns Decrypted nametag or null if decryption fails\n */\nasync function decryptNametag(encryptedBase64: string, privateKeyHex: string): Promise<string | null> {\n try {\n const key = deriveNametagEncryptionKey(privateKeyHex);\n const combined = Buffer.from(encryptedBase64, 'base64');\n\n const iv = combined.slice(0, 12);\n const ciphertext = combined.slice(12);\n\n const cryptoKey = await crypto.subtle.importKey(\n 'raw',\n new Uint8Array(key).buffer as ArrayBuffer,\n { name: 'AES-GCM' },\n false,\n ['decrypt']\n );\n\n const decrypted = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv: new Uint8Array(iv).buffer as ArrayBuffer },\n cryptoKey,\n new Uint8Array(ciphertext).buffer as ArrayBuffer\n );\n\n const decoder = new TextDecoder();\n return decoder.decode(decrypted);\n } catch {\n return null;\n }\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\nexport class NostrTransportProvider implements TransportProvider {\n readonly id = 'nostr';\n readonly name = 'Nostr Transport';\n readonly type = 'p2p' as const;\n readonly description = 'P2P messaging via Nostr protocol';\n\n private config: Required<Omit<NostrTransportProviderConfig, 'createWebSocket' | 'generateUUID' | 'storage'>> & {\n createWebSocket: WebSocketFactory;\n generateUUID: UUIDGenerator;\n };\n private storage: TransportStorageAdapter | null = null;\n /** In-memory max event timestamp to avoid read-before-write races in updateLastEventTimestamp. */\n private lastEventTs: number = 0;\n private identity: FullIdentity | null = null;\n private keyManager: NostrKeyManager | null = null;\n private status: ProviderStatus = 'disconnected';\n\n // NostrClient from nostr-js-sdk handles all WebSocket management,\n // keepalive pings, reconnection, and NIP-42 authentication\n private nostrClient: NostrClient | null = null;\n private mainSubscriptionId: string | null = null;\n\n // Event handlers\n private messageHandlers: Set<MessageHandler> = new Set();\n private transferHandlers: Set<TokenTransferHandler> = new Set();\n private paymentRequestHandlers: Set<PaymentRequestHandler> = new Set();\n private paymentRequestResponseHandlers: Set<PaymentRequestResponseHandler> = new Set();\n private broadcastHandlers: Map<string, Set<BroadcastHandler>> = new Map();\n private eventCallbacks: Set<TransportEventCallback> = new Set();\n\n constructor(config: NostrTransportProviderConfig) {\n this.config = {\n relays: config.relays ?? [...DEFAULT_NOSTR_RELAYS],\n timeout: config.timeout ?? TIMEOUTS.WEBSOCKET_CONNECT,\n autoReconnect: config.autoReconnect ?? true,\n reconnectDelay: config.reconnectDelay ?? TIMEOUTS.NOSTR_RECONNECT_DELAY,\n maxReconnectAttempts: config.maxReconnectAttempts ?? TIMEOUTS.MAX_RECONNECT_ATTEMPTS,\n debug: config.debug ?? false,\n createWebSocket: config.createWebSocket,\n generateUUID: config.generateUUID ?? defaultUUIDGenerator,\n };\n this.storage = config.storage ?? null;\n }\n\n // ===========================================================================\n // BaseProvider Implementation\n // ===========================================================================\n\n async connect(): Promise<void> {\n if (this.status === 'connected') return;\n\n this.status = 'connecting';\n\n try {\n // Ensure keyManager exists for NostrClient\n if (!this.keyManager) {\n // Create a temporary key manager - will be replaced when setIdentity is called\n const tempKey = Buffer.alloc(32);\n crypto.getRandomValues(tempKey);\n this.keyManager = NostrKeyManager.fromPrivateKey(tempKey);\n }\n\n // Create NostrClient with robust connection handling:\n // - autoReconnect: automatic reconnection with exponential backoff\n // - pingIntervalMs: keepalive pings to detect stale connections\n // - NIP-42 AUTH handling built-in\n this.nostrClient = new NostrClient(this.keyManager, {\n autoReconnect: this.config.autoReconnect,\n reconnectIntervalMs: this.config.reconnectDelay,\n maxReconnectIntervalMs: this.config.reconnectDelay * 16, // exponential backoff cap\n pingIntervalMs: 15000, // 15 second keepalive pings (more aggressive to prevent drops)\n });\n\n // Add connection event listener for logging\n this.nostrClient.addConnectionListener({\n onConnect: (url) => {\n this.log('NostrClient connected to relay:', url);\n this.emitEvent({ type: 'transport:connected', timestamp: Date.now() });\n },\n onDisconnect: (url, reason) => {\n this.log('NostrClient disconnected from relay:', url, 'reason:', reason);\n },\n onReconnecting: (url, attempt) => {\n this.log('NostrClient reconnecting to relay:', url, 'attempt:', attempt);\n this.emitEvent({ type: 'transport:reconnecting', timestamp: Date.now() });\n },\n onReconnected: (url) => {\n this.log('NostrClient reconnected to relay:', url);\n this.emitEvent({ type: 'transport:connected', timestamp: Date.now() });\n },\n });\n\n // Connect to all relays (with timeout to prevent indefinite hang)\n await Promise.race([\n this.nostrClient.connect(...this.config.relays),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(\n `Transport connection timed out after ${this.config.timeout}ms`\n )), this.config.timeout)\n ),\n ]);\n\n // Need at least one successful connection\n if (!this.nostrClient.isConnected()) {\n throw new Error('Failed to connect to any relay');\n }\n\n this.status = 'connected';\n this.emitEvent({ type: 'transport:connected', timestamp: Date.now() });\n this.log('Connected to', this.nostrClient.getConnectedRelays().size, 'relays');\n\n // Set up subscriptions\n if (this.identity) {\n await this.subscribeToEvents();\n }\n } catch (error) {\n this.status = 'error';\n throw error;\n }\n }\n\n async disconnect(): Promise<void> {\n if (this.nostrClient) {\n this.nostrClient.disconnect();\n this.nostrClient = null;\n }\n this.mainSubscriptionId = null;\n this.walletSubscriptionId = null;\n this.chatSubscriptionId = null;\n this.status = 'disconnected';\n this.emitEvent({ type: 'transport:disconnected', timestamp: Date.now() });\n this.log('Disconnected from all relays');\n }\n\n isConnected(): boolean {\n return this.status === 'connected' && this.nostrClient?.isConnected() === true;\n }\n\n getStatus(): ProviderStatus {\n return this.status;\n }\n\n // ===========================================================================\n // Dynamic Relay Management\n // ===========================================================================\n\n /**\n * Get list of configured relay URLs\n */\n getRelays(): string[] {\n return [...this.config.relays];\n }\n\n /**\n * Get list of currently connected relay URLs\n */\n getConnectedRelays(): string[] {\n if (!this.nostrClient) return [];\n return Array.from(this.nostrClient.getConnectedRelays());\n }\n\n /**\n * Add a new relay dynamically\n * Will connect immediately if provider is already connected\n */\n async addRelay(relayUrl: string): Promise<boolean> {\n // Check if already configured\n if (this.config.relays.includes(relayUrl)) {\n this.log('Relay already configured:', relayUrl);\n return false;\n }\n\n // Add to config\n this.config.relays.push(relayUrl);\n\n // Connect if provider is connected\n if (this.status === 'connected' && this.nostrClient) {\n try {\n await this.nostrClient.connect(relayUrl);\n this.log('Added and connected to relay:', relayUrl);\n this.emitEvent({\n type: 'transport:relay_added',\n timestamp: Date.now(),\n data: { relay: relayUrl, connected: true },\n });\n return true;\n } catch (error) {\n this.log('Failed to connect to new relay:', relayUrl, error);\n this.emitEvent({\n type: 'transport:relay_added',\n timestamp: Date.now(),\n data: { relay: relayUrl, connected: false, error: String(error) },\n });\n return false;\n }\n }\n\n this.emitEvent({\n type: 'transport:relay_added',\n timestamp: Date.now(),\n data: { relay: relayUrl, connected: false },\n });\n return true;\n }\n\n /**\n * Remove a relay dynamically\n * Will disconnect from the relay if connected\n * NOTE: NostrClient doesn't support removing individual relays at runtime.\n * We remove from config so it won't be used on next connect().\n */\n async removeRelay(relayUrl: string): Promise<boolean> {\n const index = this.config.relays.indexOf(relayUrl);\n if (index === -1) {\n this.log('Relay not found:', relayUrl);\n return false;\n }\n\n // Remove from config\n this.config.relays.splice(index, 1);\n this.log('Removed relay from config:', relayUrl);\n\n this.emitEvent({\n type: 'transport:relay_removed',\n timestamp: Date.now(),\n data: { relay: relayUrl },\n });\n\n // Check if we still have connections\n if (this.nostrClient && !this.nostrClient.isConnected() && this.status === 'connected') {\n this.status = 'error';\n this.emitEvent({\n type: 'transport:error',\n timestamp: Date.now(),\n data: { error: 'No connected relays remaining' },\n });\n }\n\n return true;\n }\n\n /**\n * Check if a relay is configured\n */\n hasRelay(relayUrl: string): boolean {\n return this.config.relays.includes(relayUrl);\n }\n\n /**\n * Check if a relay is currently connected\n */\n isRelayConnected(relayUrl: string): boolean {\n if (!this.nostrClient) return false;\n return this.nostrClient.getConnectedRelays().has(relayUrl);\n }\n\n // ===========================================================================\n // TransportProvider Implementation\n // ===========================================================================\n\n async setIdentity(identity: FullIdentity): Promise<void> {\n this.identity = identity;\n\n // Create NostrKeyManager from private key\n const secretKey = Buffer.from(identity.privateKey, 'hex');\n this.keyManager = NostrKeyManager.fromPrivateKey(secretKey);\n\n // Use Nostr-format pubkey (32 bytes / 64 hex chars) from keyManager\n const nostrPubkey = this.keyManager.getPublicKeyHex();\n this.log('Identity set, Nostr pubkey:', nostrPubkey.slice(0, 16) + '...');\n\n // If we already have a NostrClient with a temp key, we need to reconnect with the real key\n // NostrClient doesn't support changing key at runtime\n if (this.nostrClient && this.status === 'connected') {\n this.log('Identity changed while connected - recreating NostrClient');\n const oldClient = this.nostrClient;\n\n // Create new client with real identity\n this.nostrClient = new NostrClient(this.keyManager, {\n autoReconnect: this.config.autoReconnect,\n reconnectIntervalMs: this.config.reconnectDelay,\n maxReconnectIntervalMs: this.config.reconnectDelay * 16,\n pingIntervalMs: 15000, // 15 second keepalive pings\n });\n\n // Add connection event listener\n this.nostrClient.addConnectionListener({\n onConnect: (url) => {\n this.log('NostrClient connected to relay:', url);\n },\n onDisconnect: (url, reason) => {\n this.log('NostrClient disconnected from relay:', url, 'reason:', reason);\n },\n onReconnecting: (url, attempt) => {\n this.log('NostrClient reconnecting to relay:', url, 'attempt:', attempt);\n },\n onReconnected: (url) => {\n this.log('NostrClient reconnected to relay:', url);\n },\n });\n\n // Connect with new identity, set up subscriptions, then disconnect old client\n await Promise.race([\n this.nostrClient.connect(...this.config.relays),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(\n `Transport reconnection timed out after ${this.config.timeout}ms`\n )), this.config.timeout)\n ),\n ]);\n await this.subscribeToEvents();\n oldClient.disconnect();\n } else if (this.isConnected()) {\n // Already connected with right key, just subscribe\n await this.subscribeToEvents();\n }\n }\n\n /**\n * Get the Nostr-format public key (32 bytes / 64 hex chars)\n * This is the x-coordinate only, without the 02/03 prefix.\n */\n getNostrPubkey(): string {\n if (!this.keyManager) {\n throw new Error('KeyManager not initialized - call setIdentity first');\n }\n return this.keyManager.getPublicKeyHex();\n }\n\n async sendMessage(recipientPubkey: string, content: string): Promise<string> {\n this.ensureReady();\n\n // NIP-17 requires 32-byte x-only pubkey; strip 02/03 prefix if present\n const nostrRecipient = recipientPubkey.length === 66 && (recipientPubkey.startsWith('02') || recipientPubkey.startsWith('03'))\n ? recipientPubkey.slice(2)\n : recipientPubkey;\n\n // Wrap content with sender nametag for Sphere app compatibility\n const senderNametag = this.identity?.nametag;\n const wrappedContent = senderNametag\n ? JSON.stringify({ senderNametag, text: content })\n : content;\n\n // Create NIP-17 gift-wrapped message (kind 1059)\n const giftWrap = NIP17.createGiftWrap(this.keyManager!, nostrRecipient, wrappedContent);\n\n await this.publishEvent(giftWrap);\n\n this.emitEvent({\n type: 'message:sent',\n timestamp: Date.now(),\n data: { recipient: recipientPubkey },\n });\n\n return giftWrap.id;\n }\n\n onMessage(handler: MessageHandler): () => void {\n this.messageHandlers.add(handler);\n return () => this.messageHandlers.delete(handler);\n }\n\n async sendTokenTransfer(\n recipientPubkey: string,\n payload: TokenTransferPayload\n ): Promise<string> {\n this.ensureReady();\n\n // Create encrypted token transfer event\n // Content must have \"token_transfer:\" prefix for nostr-js-sdk compatibility\n const content = 'token_transfer:' + JSON.stringify(payload);\n const event = await this.createEncryptedEvent(\n EVENT_KINDS.TOKEN_TRANSFER,\n content,\n [\n ['p', recipientPubkey],\n ['d', 'token-transfer'],\n ['type', 'token_transfer'],\n ]\n );\n\n await this.publishEvent(event);\n\n this.emitEvent({\n type: 'transfer:sent',\n timestamp: Date.now(),\n data: { recipient: recipientPubkey },\n });\n\n return event.id;\n }\n\n onTokenTransfer(handler: TokenTransferHandler): () => void {\n this.transferHandlers.add(handler);\n return () => this.transferHandlers.delete(handler);\n }\n\n async sendPaymentRequest(\n recipientPubkey: string,\n payload: PaymentRequestPayload\n ): Promise<string> {\n this.ensureReady();\n\n const requestId = this.config.generateUUID();\n const amount = typeof payload.amount === 'bigint' ? payload.amount.toString() : payload.amount;\n\n // Build request content matching nostr-js-sdk format\n const requestContent = {\n requestId,\n amount,\n coinId: payload.coinId,\n message: payload.message,\n recipientNametag: payload.recipientNametag,\n deadline: Date.now() + 5 * 60 * 1000, // 5 minutes default\n };\n\n // Content must have \"payment_request:\" prefix for nostr-js-sdk compatibility\n const content = 'payment_request:' + JSON.stringify(requestContent);\n\n // Build tags matching nostr-js-sdk format\n const tags: string[][] = [\n ['p', recipientPubkey],\n ['type', 'payment_request'],\n ['amount', amount],\n ];\n if (payload.recipientNametag) {\n tags.push(['recipient', payload.recipientNametag]);\n }\n\n const event = await this.createEncryptedEvent(\n EVENT_KINDS.PAYMENT_REQUEST,\n content,\n tags\n );\n\n await this.publishEvent(event);\n\n this.log('Sent payment request:', event.id);\n\n return event.id;\n }\n\n onPaymentRequest(handler: PaymentRequestHandler): () => void {\n this.paymentRequestHandlers.add(handler);\n return () => this.paymentRequestHandlers.delete(handler);\n }\n\n async sendPaymentRequestResponse(\n recipientPubkey: string,\n payload: PaymentRequestResponsePayload\n ): Promise<string> {\n this.ensureReady();\n\n // Build response content\n const responseContent = {\n requestId: payload.requestId,\n responseType: payload.responseType,\n message: payload.message,\n transferId: payload.transferId,\n };\n\n // Create encrypted payment request response event\n // Content must have \"payment_response:\" prefix for nostr-js-sdk compatibility\n const content = 'payment_response:' + JSON.stringify(responseContent);\n const event = await this.createEncryptedEvent(\n EVENT_KINDS.PAYMENT_REQUEST_RESPONSE,\n content,\n [\n ['p', recipientPubkey],\n ['e', payload.requestId], // Reference to original request\n ['d', 'payment-request-response'],\n ['type', 'payment_response'],\n ]\n );\n\n await this.publishEvent(event);\n\n this.log('Sent payment request response:', event.id, 'type:', payload.responseType);\n\n return event.id;\n }\n\n onPaymentRequestResponse(handler: PaymentRequestResponseHandler): () => void {\n this.paymentRequestResponseHandlers.add(handler);\n return () => this.paymentRequestResponseHandlers.delete(handler);\n }\n\n /**\n * Resolve any identifier to full peer information.\n * Routes to the appropriate specific resolve method based on identifier format.\n */\n async resolve(identifier: string): Promise<PeerInfo | null> {\n // @nametag\n if (identifier.startsWith('@')) {\n return this.resolveNametagInfo(identifier.slice(1));\n }\n\n // DIRECT:// or PROXY:// address\n if (identifier.startsWith('DIRECT:') || identifier.startsWith('PROXY:')) {\n return this.resolveAddressInfo(identifier);\n }\n\n // L1 address (alpha1... or alphat1...)\n if (identifier.startsWith('alpha1') || identifier.startsWith('alphat1')) {\n return this.resolveAddressInfo(identifier);\n }\n\n // 66-char hex starting with 02/03 → compressed chain pubkey (33 bytes)\n if (/^0[23][0-9a-f]{64}$/i.test(identifier)) {\n return this.resolveAddressInfo(identifier);\n }\n\n // 64-char hex string → transport pubkey\n if (/^[0-9a-f]{64}$/i.test(identifier)) {\n return this.resolveTransportPubkeyInfo(identifier);\n }\n\n // Fallback: treat as bare nametag\n return this.resolveNametagInfo(identifier);\n }\n\n async resolveNametag(nametag: string): Promise<string | null> {\n this.ensureConnected();\n\n // Query for nametag binding events using hashed nametag (privacy-preserving)\n // Try both '#d' and '#t' filters for compatibility with nostr-js-sdk\n const hashedNametag = hashNametag(nametag);\n\n // First try '#t' tag (nostr-js-sdk format)\n let events = await this.queryEvents({\n kinds: [EVENT_KINDS.NAMETAG_BINDING],\n '#t': [hashedNametag],\n limit: 1,\n });\n\n // Fallback to '#d' tag (legacy format)\n if (events.length === 0) {\n events = await this.queryEvents({\n kinds: [EVENT_KINDS.NAMETAG_BINDING],\n '#d': [hashedNametag],\n limit: 1,\n });\n }\n\n if (events.length === 0) return null;\n\n // Parse binding event\n const bindingEvent = events[0];\n\n // For Nostr messaging (NIP-04 encryption), we MUST use the event author's pubkey.\n // The 'address' tag contains the Unicity blockchain address (not a hex pubkey),\n // which cannot be used for Nostr encryption.\n // The event.pubkey is always the hex pubkey of the nametag owner.\n if (bindingEvent.pubkey) {\n return bindingEvent.pubkey;\n }\n\n // Fallback: try 'p' tag (our SDK format uses hex pubkey here)\n const pubkeyTag = bindingEvent.tags.find((t: string[]) => t[0] === 'p');\n if (pubkeyTag?.[1]) return pubkeyTag[1];\n\n return null;\n }\n\n async resolveNametagInfo(nametag: string): Promise<PeerInfo | null> {\n this.ensureConnected();\n\n // Query for nametag binding events using hashed nametag (privacy-preserving)\n const hashedNametag = hashNametag(nametag);\n\n // First try '#t' tag (nostr-js-sdk format)\n let events = await this.queryEvents({\n kinds: [EVENT_KINDS.NAMETAG_BINDING],\n '#t': [hashedNametag],\n limit: 1,\n });\n\n // Fallback to '#d' tag (legacy format)\n if (events.length === 0) {\n events = await this.queryEvents({\n kinds: [EVENT_KINDS.NAMETAG_BINDING],\n '#d': [hashedNametag],\n limit: 1,\n });\n }\n\n if (events.length === 0) return null;\n\n const bindingEvent = events[0];\n\n try {\n const content = JSON.parse(bindingEvent.content);\n\n // Compute proper PROXY address using state-transition-sdk\n const { ProxyAddress } = await import('@unicitylabs/state-transition-sdk/lib/address/ProxyAddress');\n const proxyAddr = await ProxyAddress.fromNameTag(nametag);\n const proxyAddress = proxyAddr.toString();\n\n // Check if event has extended fields\n if (content.public_key && content.l1_address) {\n return {\n nametag,\n transportPubkey: bindingEvent.pubkey,\n chainPubkey: content.public_key,\n l1Address: content.l1_address,\n directAddress: content.direct_address || '',\n proxyAddress,\n timestamp: bindingEvent.created_at * 1000,\n };\n }\n\n // Legacy event - only has Nostr pubkey\n // Cannot derive l1_address or l3_address without 33-byte pubkey\n this.log('Legacy nametag event without extended fields:', nametag);\n\n // Try to get info from tags as fallback\n const pubkeyTag = bindingEvent.tags.find((t: string[]) => t[0] === 'pubkey');\n const l1Tag = bindingEvent.tags.find((t: string[]) => t[0] === 'l1');\n\n if (pubkeyTag?.[1] && l1Tag?.[1]) {\n return {\n nametag,\n transportPubkey: bindingEvent.pubkey,\n chainPubkey: pubkeyTag[1],\n l1Address: l1Tag[1],\n directAddress: '',\n proxyAddress,\n timestamp: bindingEvent.created_at * 1000,\n };\n }\n\n // Return partial info with empty addresses for legacy events\n return {\n nametag,\n transportPubkey: bindingEvent.pubkey,\n chainPubkey: '', // Cannot derive from 32-byte Nostr pubkey\n l1Address: '', // Cannot derive without 33-byte pubkey\n directAddress: '',\n proxyAddress,\n timestamp: bindingEvent.created_at * 1000,\n };\n } catch {\n // If content is not JSON, try legacy format\n const { ProxyAddress } = await import('@unicitylabs/state-transition-sdk/lib/address/ProxyAddress');\n const proxyAddr = await ProxyAddress.fromNameTag(nametag);\n return {\n nametag,\n transportPubkey: bindingEvent.pubkey,\n chainPubkey: '',\n l1Address: '',\n directAddress: '',\n proxyAddress: proxyAddr.toString(),\n timestamp: bindingEvent.created_at * 1000,\n };\n }\n }\n\n /**\n * Resolve a DIRECT://, PROXY://, or L1 address to full peer info.\n * Performs reverse lookup: hash(address) → query '#t' tag → parse binding event.\n * Works with both new identity binding events and legacy nametag binding events.\n */\n async resolveAddressInfo(address: string): Promise<PeerInfo | null> {\n this.ensureConnected();\n\n const addressHash = hashAddressForTag(address);\n\n const events = await this.queryEvents({\n kinds: [EVENT_KINDS.NAMETAG_BINDING],\n '#t': [addressHash],\n limit: 1,\n });\n\n if (events.length === 0) return null;\n\n const bindingEvent = events[0];\n\n try {\n const content = JSON.parse(bindingEvent.content);\n\n return {\n nametag: content.nametag || undefined,\n transportPubkey: bindingEvent.pubkey,\n chainPubkey: content.public_key || '',\n l1Address: content.l1_address || '',\n directAddress: content.direct_address || '',\n proxyAddress: content.proxy_address || undefined,\n timestamp: bindingEvent.created_at * 1000,\n };\n } catch {\n return {\n transportPubkey: bindingEvent.pubkey,\n chainPubkey: '',\n l1Address: '',\n directAddress: '',\n timestamp: bindingEvent.created_at * 1000,\n };\n }\n }\n\n /**\n * Resolve transport pubkey (Nostr pubkey) to full peer info.\n * Queries binding events authored by the given pubkey.\n */\n async resolveTransportPubkeyInfo(transportPubkey: string): Promise<PeerInfo | null> {\n this.ensureConnected();\n\n const events = await this.queryEvents({\n kinds: [EVENT_KINDS.NAMETAG_BINDING],\n authors: [transportPubkey],\n limit: 5,\n });\n\n if (events.length === 0) return null;\n\n // Sort by timestamp descending and take the most recent\n events.sort((a, b) => b.created_at - a.created_at);\n const bindingEvent = events[0];\n\n try {\n const content = JSON.parse(bindingEvent.content);\n\n return {\n nametag: content.nametag || undefined,\n transportPubkey: bindingEvent.pubkey,\n chainPubkey: content.public_key || '',\n l1Address: content.l1_address || '',\n directAddress: content.direct_address || '',\n proxyAddress: content.proxy_address || undefined,\n timestamp: bindingEvent.created_at * 1000,\n };\n } catch {\n return {\n transportPubkey: bindingEvent.pubkey,\n chainPubkey: '',\n l1Address: '',\n directAddress: '',\n timestamp: bindingEvent.created_at * 1000,\n };\n }\n }\n\n /**\n * Recover nametag for the current identity by searching for encrypted nametag events\n * Used after wallet import to recover associated nametag\n * @returns Decrypted nametag or null if none found\n */\n async recoverNametag(): Promise<string | null> {\n this.ensureReady();\n\n if (!this.identity || !this.keyManager) {\n throw new Error('Identity not set');\n }\n\n const nostrPubkey = this.getNostrPubkey();\n this.log('Searching for nametag events for pubkey:', nostrPubkey.slice(0, 16) + '...');\n\n // Query for nametag binding events authored by this pubkey\n const events = await this.queryEvents({\n kinds: [EVENT_KINDS.NAMETAG_BINDING],\n authors: [nostrPubkey],\n limit: 10, // Get recent events in case of updates\n });\n\n if (events.length === 0) {\n this.log('No nametag events found for this pubkey');\n return null;\n }\n\n // Sort by timestamp descending to get most recent\n events.sort((a, b) => b.created_at - a.created_at);\n\n // Try to decrypt nametag from events\n for (const event of events) {\n try {\n const content = JSON.parse(event.content);\n if (content.encrypted_nametag) {\n const decrypted = await decryptNametag(\n content.encrypted_nametag,\n this.identity.privateKey\n );\n if (decrypted) {\n this.log('Recovered nametag:', decrypted);\n return decrypted;\n }\n }\n } catch {\n // Try next event\n continue;\n }\n }\n\n this.log('Could not decrypt nametag from any event');\n return null;\n }\n\n /**\n * Publish identity binding event on Nostr.\n * Without nametag: publishes base binding (chainPubkey, l1Address, directAddress).\n * With nametag: also publishes nametag hash, proxy address, encrypted nametag for recovery.\n *\n * Uses kind 30078 parameterized replaceable event with d=SHA256('unicity:identity:' + nostrPubkey).\n * Each HD address index has its own Nostr key → its own binding event.\n *\n * @returns true if successful, false if nametag is taken by another pubkey\n */\n async publishIdentityBinding(\n chainPubkey: string,\n l1Address: string,\n directAddress: string,\n nametag?: string,\n ): Promise<boolean> {\n this.ensureReady();\n\n if (!this.identity) {\n throw new Error('Identity not set');\n }\n\n const nostrPubkey = this.getNostrPubkey();\n\n // Deterministic d-tag: SHA256('unicity:identity:' + nostrPubkey) — privacy-preserving\n const dTagBytes = new TextEncoder().encode('unicity:identity:' + nostrPubkey);\n const dTag = Buffer.from(sha256Noble(dTagBytes)).toString('hex');\n\n // Content — event.pubkey already identifies the author, event.created_at provides timestamp\n const contentObj: Record<string, unknown> = {\n public_key: chainPubkey,\n l1_address: l1Address,\n direct_address: directAddress,\n };\n\n // Tags — 'd' for replacement, 't' for indexed lookups\n const tags: string[][] = [\n ['d', dTag],\n ['t', hashAddressForTag(chainPubkey)],\n ['t', hashAddressForTag(directAddress)],\n ['t', hashAddressForTag(l1Address)],\n ];\n\n // If nametag provided, check availability and add nametag-specific fields\n if (nametag) {\n const existing = await this.resolveNametag(nametag);\n if (existing && existing !== nostrPubkey) {\n this.log('Nametag already taken:', nametag, '- owner:', existing);\n return false;\n }\n\n // Compute proxy address\n const { ProxyAddress } = await import('@unicitylabs/state-transition-sdk/lib/address/ProxyAddress');\n const proxyAddr = await ProxyAddress.fromNameTag(nametag);\n const proxyAddress = proxyAddr.toString();\n\n // Encrypt nametag for recovery\n const encryptedNametag = await encryptNametag(nametag, this.identity.privateKey);\n const hashedNametag = hashNametag(nametag);\n\n // Add nametag fields to content\n contentObj.nametag = nametag;\n contentObj.encrypted_nametag = encryptedNametag;\n contentObj.proxy_address = proxyAddress;\n\n // Add nametag-specific 't' tags for indexed lookup\n tags.push(['t', hashedNametag]);\n tags.push(['t', hashAddressForTag(proxyAddress)]);\n }\n\n const content = JSON.stringify(contentObj);\n const event = await this.createEvent(EVENT_KINDS.NAMETAG_BINDING, content, tags);\n await this.publishEvent(event);\n\n if (nametag) {\n this.log('Published identity binding with nametag:', nametag, 'for pubkey:', nostrPubkey.slice(0, 16) + '...');\n } else {\n this.log('Published identity binding (no nametag) for pubkey:', nostrPubkey.slice(0, 16) + '...');\n }\n\n return true;\n }\n\n /** @deprecated Use publishIdentityBinding instead */\n async publishNametag(nametag: string, address: string): Promise<void> {\n this.ensureReady();\n\n // Use hashed nametag (privacy-preserving)\n const hashedNametag = hashNametag(nametag);\n const event = await this.createEvent(EVENT_KINDS.NAMETAG_BINDING, address, [\n ['d', hashedNametag],\n ['a', address],\n ]);\n\n await this.publishEvent(event);\n this.log('Published nametag binding:', nametag);\n }\n\n async registerNametag(nametag: string, _publicKey: string, directAddress: string = ''): Promise<boolean> {\n this.ensureReady();\n\n if (!this.identity) {\n throw new Error('Identity not set');\n }\n\n // Always use 32-byte Nostr-format pubkey from keyManager (not the 33-byte compressed key)\n const nostrPubkey = this.getNostrPubkey();\n\n // Check if nametag is already taken by someone else\n const existing = await this.resolveNametag(nametag);\n\n this.log('registerNametag:', nametag, 'existing:', existing, 'myPubkey:', nostrPubkey);\n\n if (existing && existing !== nostrPubkey) {\n this.log('Nametag already taken:', nametag, '- owner:', existing);\n return false;\n }\n\n // Always (re)publish to ensure event has correct format with all required tags\n // This is a parameterized replaceable event (kind 30078), so publishing with same 'd' tag\n // will replace any old event. This ensures the event has ['t', hash] tag for nostr-js-sdk.\n\n // Derive extended address info for full nametag support:\n // - encrypted_nametag: AES-GCM encrypted nametag for recovery\n // - public_key: 33-byte compressed public key for L3 operations\n // - l1_address: L1 address (alpha1...) for L1 transfers\n const privateKeyHex = this.identity.privateKey;\n const compressedPubkey = getPublicKey(privateKeyHex, true); // 33-byte compressed\n const l1Address = publicKeyToAddress(compressedPubkey, 'alpha'); // alpha1...\n const encryptedNametag = await encryptNametag(nametag, privateKeyHex);\n\n // Compute PROXY address for reverse lookup\n const { ProxyAddress } = await import('@unicitylabs/state-transition-sdk/lib/address/ProxyAddress');\n const proxyAddr = await ProxyAddress.fromNameTag(nametag);\n const proxyAddress = proxyAddr.toString();\n\n // Publish nametag binding with extended info\n const hashedNametag = hashNametag(nametag);\n const content = JSON.stringify({\n nametag_hash: hashedNametag,\n address: nostrPubkey,\n verified: Date.now(),\n // Extended fields for nametag recovery and address lookup\n encrypted_nametag: encryptedNametag,\n public_key: compressedPubkey,\n l1_address: l1Address,\n direct_address: directAddress,\n proxy_address: proxyAddress,\n });\n\n // Build tags with indexed 't' tags for reverse lookup by nametag and address\n const tags: string[][] = [\n ['d', hashedNametag],\n ['nametag', hashedNametag],\n ['t', hashedNametag],\n ['t', hashAddressForTag(directAddress)],\n ['t', hashAddressForTag(proxyAddress)],\n ['address', nostrPubkey],\n ['pubkey', compressedPubkey],\n ['l1', l1Address],\n ];\n\n const event = await this.createEvent(EVENT_KINDS.NAMETAG_BINDING, content, tags);\n\n await this.publishEvent(event);\n this.log('Registered nametag:', nametag, 'for pubkey:', nostrPubkey.slice(0, 16) + '...', 'l1:', l1Address.slice(0, 12) + '...');\n return true;\n }\n\n // Track broadcast subscriptions\n private broadcastSubscriptions: Map<string, string> = new Map(); // key -> subId\n\n subscribeToBroadcast(tags: string[], handler: BroadcastHandler): () => void {\n const key = tags.sort().join(':');\n\n if (!this.broadcastHandlers.has(key)) {\n this.broadcastHandlers.set(key, new Set());\n\n // Subscribe to relay\n if (this.isConnected() && this.nostrClient) {\n this.subscribeToTags(tags);\n }\n }\n\n this.broadcastHandlers.get(key)!.add(handler);\n\n return () => {\n this.broadcastHandlers.get(key)?.delete(handler);\n if (this.broadcastHandlers.get(key)?.size === 0) {\n this.broadcastHandlers.delete(key);\n // Unsubscribe from relay\n const subId = this.broadcastSubscriptions.get(key);\n if (subId && this.nostrClient) {\n this.nostrClient.unsubscribe(subId);\n this.broadcastSubscriptions.delete(key);\n }\n }\n };\n }\n\n async publishBroadcast(content: string, tags?: string[]): Promise<string> {\n this.ensureReady();\n\n const eventTags = tags?.map((t) => ['t', t]) ?? [];\n const event = await this.createEvent(EVENT_KINDS.BROADCAST, content, eventTags);\n\n await this.publishEvent(event);\n return event.id;\n }\n\n // ===========================================================================\n // Event Subscription\n // ===========================================================================\n\n onEvent(callback: TransportEventCallback): () => void {\n this.eventCallbacks.add(callback);\n return () => this.eventCallbacks.delete(callback);\n }\n\n // ===========================================================================\n // Private: Message Handling\n // ===========================================================================\n\n private async handleEvent(event: NostrEvent): Promise<void> {\n this.log('Processing event kind:', event.kind, 'id:', event.id?.slice(0, 12));\n try {\n switch (event.kind) {\n case EVENT_KINDS.DIRECT_MESSAGE:\n await this.handleDirectMessage(event);\n break;\n case EventKinds.GIFT_WRAP:\n this.log('Handling gift wrap (NIP-17 DM)');\n await this.handleGiftWrap(event);\n break;\n case EVENT_KINDS.TOKEN_TRANSFER:\n await this.handleTokenTransfer(event);\n break;\n case EVENT_KINDS.PAYMENT_REQUEST:\n await this.handlePaymentRequest(event);\n break;\n case EVENT_KINDS.PAYMENT_REQUEST_RESPONSE:\n await this.handlePaymentRequestResponse(event);\n break;\n case EVENT_KINDS.BROADCAST:\n this.handleBroadcast(event);\n break;\n }\n\n // Persist the latest event timestamp for resumption on reconnect.\n // Only update for wallet event kinds (not chat/broadcast).\n if (event.created_at && this.storage && this.keyManager) {\n const kind = event.kind;\n if (\n kind === EVENT_KINDS.DIRECT_MESSAGE ||\n kind === EVENT_KINDS.TOKEN_TRANSFER ||\n kind === EVENT_KINDS.PAYMENT_REQUEST ||\n kind === EVENT_KINDS.PAYMENT_REQUEST_RESPONSE\n ) {\n this.updateLastEventTimestamp(event.created_at);\n }\n }\n } catch (error) {\n this.log('Failed to handle event:', error);\n }\n }\n\n /**\n * Save the max event timestamp to storage (fire-and-forget, no await needed by caller).\n * Uses in-memory `lastEventTs` to avoid read-before-write race conditions\n * when multiple events arrive in quick succession.\n */\n private updateLastEventTimestamp(createdAt: number): void {\n if (!this.storage || !this.keyManager) return;\n if (createdAt <= this.lastEventTs) return;\n\n this.lastEventTs = createdAt;\n const pubkey = this.keyManager.getPublicKeyHex();\n const storageKey = `${STORAGE_KEYS_GLOBAL.LAST_WALLET_EVENT_TS}_${pubkey.slice(0, 16)}`;\n\n this.storage.set(storageKey, createdAt.toString()).catch(err => {\n this.log('Failed to save last event timestamp:', err);\n });\n }\n\n private async handleDirectMessage(event: NostrEvent): Promise<void> {\n // NIP-04 (kind 4) is deprecated for DMs - only used for legacy token transfers\n // DMs should come through NIP-17 (kind 1059 gift wrap) via handleGiftWrap\n // This handler is kept for backwards compatibility but does NOT dispatch to messageHandlers\n this.log('Ignoring NIP-04 kind 4 event (DMs use NIP-17):', event.id?.slice(0, 12));\n }\n\n private async handleGiftWrap(event: NostrEvent): Promise<void> {\n if (!this.identity || !this.keyManager) {\n this.log('handleGiftWrap: no identity/keyManager');\n return;\n }\n\n try {\n const pm = NIP17.unwrap(event as any, this.keyManager);\n this.log('Gift wrap unwrapped, sender:', pm.senderPubkey?.slice(0, 16), 'kind:', pm.kind);\n if (pm.senderPubkey === this.keyManager.getPublicKeyHex()) {\n this.log('Skipping own message');\n return;\n }\n if (pm.kind !== EventKinds.CHAT_MESSAGE) {\n this.log('Skipping non-chat message, kind:', pm.kind);\n return;\n }\n\n // Sphere app wraps DM content as JSON: {senderNametag, text}\n let content = pm.content;\n let senderNametag: string | undefined;\n try {\n const parsed = JSON.parse(content);\n if (typeof parsed === 'object' && parsed.text !== undefined) {\n content = parsed.text;\n senderNametag = parsed.senderNametag || undefined;\n }\n } catch {\n // Plain text — use as-is\n }\n\n this.log('DM received from:', senderNametag || pm.senderPubkey?.slice(0, 16), 'content:', content?.slice(0, 50));\n\n const message: IncomingMessage = {\n id: pm.eventId,\n senderTransportPubkey: pm.senderPubkey,\n senderNametag,\n content,\n timestamp: pm.timestamp * 1000,\n encrypted: true,\n };\n\n this.emitEvent({ type: 'message:received', timestamp: Date.now() });\n\n this.log('Dispatching to', this.messageHandlers.size, 'handlers');\n for (const handler of this.messageHandlers) {\n try {\n handler(message);\n } catch (error) {\n this.log('Message handler error:', error);\n }\n }\n } catch (err) {\n // Expected for gift wraps meant for other recipients\n this.log('Gift wrap decrypt failed (expected if not for us):', (err as Error)?.message?.slice(0, 50));\n }\n }\n\n private async handleTokenTransfer(event: NostrEvent): Promise<void> {\n if (!this.identity) return;\n\n // Decrypt content\n const content = await this.decryptContent(event.content, event.pubkey);\n const payload = JSON.parse(content) as TokenTransferPayload;\n\n const transfer: IncomingTokenTransfer = {\n id: event.id,\n senderTransportPubkey: event.pubkey,\n payload,\n timestamp: event.created_at * 1000,\n };\n\n this.emitEvent({ type: 'transfer:received', timestamp: Date.now() });\n\n for (const handler of this.transferHandlers) {\n try {\n handler(transfer);\n } catch (error) {\n this.log('Transfer handler error:', error);\n }\n }\n }\n\n private async handlePaymentRequest(event: NostrEvent): Promise<void> {\n if (!this.identity) return;\n\n try {\n // Decrypt content\n const content = await this.decryptContent(event.content, event.pubkey);\n const requestData = JSON.parse(content) as {\n requestId: string;\n amount: string;\n coinId: string;\n message?: string;\n recipientNametag?: string;\n metadata?: Record<string, unknown>;\n };\n\n const request: IncomingPaymentRequest = {\n id: event.id,\n senderTransportPubkey: event.pubkey,\n senderNametag: requestData.recipientNametag,\n request: {\n requestId: requestData.requestId,\n amount: requestData.amount,\n coinId: requestData.coinId,\n message: requestData.message,\n recipientNametag: requestData.recipientNametag,\n metadata: requestData.metadata,\n },\n timestamp: event.created_at * 1000,\n };\n\n this.log('Received payment request:', request.id);\n\n for (const handler of this.paymentRequestHandlers) {\n try {\n handler(request);\n } catch (error) {\n this.log('Payment request handler error:', error);\n }\n }\n } catch (error) {\n this.log('Failed to handle payment request:', error);\n }\n }\n\n private async handlePaymentRequestResponse(event: NostrEvent): Promise<void> {\n if (!this.identity) return;\n\n try {\n // Decrypt content\n const content = await this.decryptContent(event.content, event.pubkey);\n const responseData = JSON.parse(content) as {\n requestId: string;\n responseType: 'accepted' | 'rejected' | 'paid';\n message?: string;\n transferId?: string;\n };\n\n const response: IncomingPaymentRequestResponse = {\n id: event.id,\n responderTransportPubkey: event.pubkey,\n response: {\n requestId: responseData.requestId,\n responseType: responseData.responseType,\n message: responseData.message,\n transferId: responseData.transferId,\n },\n timestamp: event.created_at * 1000,\n };\n\n this.log('Received payment request response:', response.id, 'type:', responseData.responseType);\n\n for (const handler of this.paymentRequestResponseHandlers) {\n try {\n handler(response);\n } catch (error) {\n this.log('Payment request response handler error:', error);\n }\n }\n } catch (error) {\n this.log('Failed to handle payment request response:', error);\n }\n }\n\n private handleBroadcast(event: NostrEvent): void {\n const tags = event.tags\n .filter((t: string[]) => t[0] === 't')\n .map((t: string[]) => t[1]);\n\n const broadcast: IncomingBroadcast = {\n id: event.id,\n authorTransportPubkey: event.pubkey,\n content: event.content,\n tags,\n timestamp: event.created_at * 1000,\n };\n\n // Find matching handlers\n for (const [key, handlers] of this.broadcastHandlers) {\n const subscribedTags = key.split(':');\n if (tags.some((t) => subscribedTags.includes(t))) {\n for (const handler of handlers) {\n try {\n handler(broadcast);\n } catch (error) {\n this.log('Broadcast handler error:', error);\n }\n }\n }\n }\n }\n\n // ===========================================================================\n // Private: Event Creation & Publishing\n // ===========================================================================\n\n private async createEvent(\n kind: number,\n content: string,\n tags: string[][]\n ): Promise<NostrEvent> {\n if (!this.identity) throw new Error('Identity not set');\n if (!this.keyManager) throw new Error('KeyManager not initialized');\n\n // Create and sign event using SDK\n const signedEvent = NostrEventClass.create(this.keyManager, {\n kind,\n content,\n tags,\n });\n\n // Convert to our interface\n const event: NostrEvent = {\n id: signedEvent.id,\n kind: signedEvent.kind,\n content: signedEvent.content,\n tags: signedEvent.tags,\n pubkey: signedEvent.pubkey,\n created_at: signedEvent.created_at,\n sig: signedEvent.sig,\n };\n\n return event;\n }\n\n private async createEncryptedEvent(\n kind: number,\n content: string,\n tags: string[][]\n ): Promise<NostrEvent> {\n if (!this.keyManager) throw new Error('KeyManager not initialized');\n\n // Extract recipient pubkey from tags (first 'p' tag)\n const recipientTag = tags.find((t) => t[0] === 'p');\n if (!recipientTag || !recipientTag[1]) {\n throw new Error('No recipient pubkey in tags for encryption');\n }\n const recipientPubkey = recipientTag[1];\n\n // Encrypt content with NIP-04 (using hex variant for string keys)\n const encrypted = await NIP04.encryptHex(\n content,\n this.keyManager.getPrivateKeyHex(),\n recipientPubkey\n );\n\n return this.createEvent(kind, encrypted, tags);\n }\n\n private async publishEvent(event: NostrEvent): Promise<void> {\n if (!this.nostrClient) {\n throw new Error('NostrClient not initialized');\n }\n\n // Convert to nostr-js-sdk Event and publish\n const sdkEvent = NostrEventClass.fromJSON(event);\n await this.nostrClient.publishEvent(sdkEvent);\n }\n\n private async queryEvents(filterObj: NostrFilter): Promise<NostrEvent[]> {\n if (!this.nostrClient || !this.nostrClient.isConnected()) {\n throw new Error('No connected relays');\n }\n\n const events: NostrEvent[] = [];\n const filter = new Filter(filterObj);\n\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n if (subId) {\n this.nostrClient?.unsubscribe(subId);\n }\n resolve(events);\n }, 5000);\n\n const subId = this.nostrClient!.subscribe(filter, {\n onEvent: (event) => {\n events.push({\n id: event.id,\n kind: event.kind,\n content: event.content,\n tags: event.tags,\n pubkey: event.pubkey,\n created_at: event.created_at,\n sig: event.sig,\n });\n },\n onEndOfStoredEvents: () => {\n clearTimeout(timeout);\n this.nostrClient?.unsubscribe(subId);\n resolve(events);\n },\n });\n });\n }\n\n // ===========================================================================\n // Private: Subscriptions\n // ===========================================================================\n\n // Track subscription IDs for cleanup\n private walletSubscriptionId: string | null = null;\n private chatSubscriptionId: string | null = null;\n\n private async subscribeToEvents(): Promise<void> {\n this.log('subscribeToEvents called, identity:', !!this.identity, 'keyManager:', !!this.keyManager, 'nostrClient:', !!this.nostrClient);\n if (!this.identity || !this.keyManager || !this.nostrClient) {\n this.log('subscribeToEvents: skipped - no identity, keyManager, or nostrClient');\n return;\n }\n\n // Unsubscribe from previous subscriptions if any\n if (this.walletSubscriptionId) {\n this.nostrClient.unsubscribe(this.walletSubscriptionId);\n this.walletSubscriptionId = null;\n }\n if (this.chatSubscriptionId) {\n this.nostrClient.unsubscribe(this.chatSubscriptionId);\n this.chatSubscriptionId = null;\n }\n if (this.mainSubscriptionId) {\n this.nostrClient.unsubscribe(this.mainSubscriptionId);\n this.mainSubscriptionId = null;\n }\n\n // Use 32-byte Nostr pubkey (x-coordinate only), not 33-byte compressed key\n const nostrPubkey = this.keyManager.getPublicKeyHex();\n this.log('Subscribing with Nostr pubkey:', nostrPubkey);\n\n // Determine 'since' filter from persisted last event timestamp.\n // - Existing wallet: resume from last processed event (inclusive >=, dedup handles replays)\n // - Fresh wallet / no storage: use current time (no historical replay)\n let since: number;\n if (this.storage) {\n const storageKey = `${STORAGE_KEYS_GLOBAL.LAST_WALLET_EVENT_TS}_${nostrPubkey.slice(0, 16)}`;\n try {\n const stored = await this.storage.get(storageKey);\n if (stored) {\n since = parseInt(stored, 10);\n this.lastEventTs = since; // Seed in-memory tracker from storage\n this.log('Resuming from stored event timestamp:', since);\n } else {\n // No stored timestamp = fresh wallet, start from now\n since = Math.floor(Date.now() / 1000);\n this.log('No stored timestamp, starting from now:', since);\n }\n } catch (err) {\n this.log('Failed to read last event timestamp, falling back to now:', err);\n since = Math.floor(Date.now() / 1000);\n }\n } else {\n // No storage adapter — fallback to last 24h (legacy behavior)\n since = Math.floor(Date.now() / 1000) - 86400;\n this.log('No storage adapter, using 24h fallback');\n }\n\n // Subscribe to wallet events (token transfers, payment requests) with since filter\n const walletFilter = new Filter();\n walletFilter.kinds = [\n EVENT_KINDS.DIRECT_MESSAGE,\n EVENT_KINDS.TOKEN_TRANSFER,\n EVENT_KINDS.PAYMENT_REQUEST,\n EVENT_KINDS.PAYMENT_REQUEST_RESPONSE,\n ];\n walletFilter['#p'] = [nostrPubkey];\n walletFilter.since = since;\n\n this.walletSubscriptionId = this.nostrClient.subscribe(walletFilter, {\n onEvent: (event) => {\n this.log('Received wallet event kind:', event.kind, 'id:', event.id?.slice(0, 12));\n this.handleEvent({\n id: event.id,\n kind: event.kind,\n content: event.content,\n tags: event.tags,\n pubkey: event.pubkey,\n created_at: event.created_at,\n sig: event.sig,\n });\n },\n onEndOfStoredEvents: () => {\n this.log('Wallet subscription ready (EOSE)');\n },\n onError: (_subId, error) => {\n this.log('Wallet subscription error:', error);\n },\n });\n this.log('Wallet subscription created, subId:', this.walletSubscriptionId);\n\n // Subscribe to chat events (NIP-17 gift wrap) WITHOUT since filter\n // This matches Sphere app's approach - chat messages rely on deduplication\n const chatFilter = new Filter();\n chatFilter.kinds = [EventKinds.GIFT_WRAP];\n chatFilter['#p'] = [nostrPubkey];\n // NO since filter for chat - we want real-time messages\n\n this.chatSubscriptionId = this.nostrClient.subscribe(chatFilter, {\n onEvent: (event) => {\n this.log('Received chat event kind:', event.kind, 'id:', event.id?.slice(0, 12));\n this.handleEvent({\n id: event.id,\n kind: event.kind,\n content: event.content,\n tags: event.tags,\n pubkey: event.pubkey,\n created_at: event.created_at,\n sig: event.sig,\n });\n },\n onEndOfStoredEvents: () => {\n this.log('Chat subscription ready (EOSE)');\n },\n onError: (_subId, error) => {\n this.log('Chat subscription error:', error);\n },\n });\n this.log('Chat subscription created, subId:', this.chatSubscriptionId);\n }\n\n private subscribeToTags(tags: string[]): void {\n if (!this.nostrClient) return;\n\n const key = tags.sort().join(':');\n const filter = new Filter({\n kinds: [EVENT_KINDS.BROADCAST],\n '#t': tags,\n since: Math.floor(Date.now() / 1000) - 3600, // Last hour\n });\n\n const subId = this.nostrClient.subscribe(filter, {\n onEvent: (event) => {\n this.handleBroadcast({\n id: event.id,\n kind: event.kind,\n content: event.content,\n tags: event.tags,\n pubkey: event.pubkey,\n created_at: event.created_at,\n sig: event.sig,\n });\n },\n });\n\n this.broadcastSubscriptions.set(key, subId);\n }\n\n // ===========================================================================\n // Private: Encryption\n // ===========================================================================\n\n private async decryptContent(content: string, senderPubkey: string): Promise<string> {\n if (!this.keyManager) throw new Error('KeyManager not initialized');\n\n // Decrypt content using NIP-04 (using hex variant for string keys)\n const decrypted = await NIP04.decryptHex(\n content,\n this.keyManager.getPrivateKeyHex(),\n senderPubkey\n );\n\n // Strip known prefixes for compatibility with nostr-js-sdk\n return this.stripContentPrefix(decrypted);\n }\n\n /**\n * Strip known content prefixes (nostr-js-sdk compatibility)\n * Handles: payment_request:, token_transfer:, etc.\n */\n private stripContentPrefix(content: string): string {\n const prefixes = [\n 'payment_request:',\n 'token_transfer:',\n 'payment_response:',\n ];\n\n for (const prefix of prefixes) {\n if (content.startsWith(prefix)) {\n return content.slice(prefix.length);\n }\n }\n\n return content;\n }\n\n // ===========================================================================\n // Private: Helpers\n // ===========================================================================\n\n private ensureConnected(): void {\n if (!this.isConnected()) {\n throw new Error('NostrTransportProvider not connected');\n }\n }\n\n private ensureReady(): void {\n this.ensureConnected();\n if (!this.identity) {\n throw new Error('Identity not set');\n }\n }\n\n private emitEvent(event: TransportEvent): void {\n for (const callback of this.eventCallbacks) {\n try {\n callback(event);\n } catch (error) {\n this.log('Event callback error:', error);\n }\n }\n }\n\n private log(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[NostrTransportProvider]', ...args);\n }\n }\n}\n\n// =============================================================================\n// Types\n// =============================================================================\n\ninterface NostrEvent {\n id: string;\n kind: number;\n content: string;\n tags: string[][];\n pubkey: string;\n created_at: number;\n sig: string;\n}\n\ninterface NostrFilter {\n ids?: string[];\n authors?: string[];\n kinds?: number[];\n '#p'?: string[];\n '#t'?: string[];\n '#d'?: string[];\n since?: number;\n until?: number;\n limit?: number;\n}\n","/**\n * Utilities for hex, bytes, CSPRNG.\n * @module\n */\n/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */\n/** Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. */\nexport function isBytes(a: unknown): a is Uint8Array {\n return a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');\n}\n\n/** Asserts something is positive integer. */\nexport function anumber(n: number, title: string = ''): void {\n if (!Number.isSafeInteger(n) || n < 0) {\n const prefix = title && `\"${title}\" `;\n throw new Error(`${prefix}expected integer >= 0, got ${n}`);\n }\n}\n\n/** Asserts something is Uint8Array. */\nexport function abytes(value: Uint8Array, length?: number, title: string = ''): Uint8Array {\n const bytes = isBytes(value);\n const len = value?.length;\n const needsLen = length !== undefined;\n if (!bytes || (needsLen && len !== length)) {\n const prefix = title && `\"${title}\" `;\n const ofLen = needsLen ? ` of length ${length}` : '';\n const got = bytes ? `length=${len}` : `type=${typeof value}`;\n throw new Error(prefix + 'expected Uint8Array' + ofLen + ', got ' + got);\n }\n return value;\n}\n\n/** Asserts something is hash */\nexport function ahash(h: CHash): void {\n if (typeof h !== 'function' || typeof h.create !== 'function')\n throw new Error('Hash must wrapped by utils.createHasher');\n anumber(h.outputLen);\n anumber(h.blockLen);\n}\n\n/** Asserts a hash instance has not been destroyed / finished */\nexport function aexists(instance: any, checkFinished = true): void {\n if (instance.destroyed) throw new Error('Hash instance has been destroyed');\n if (checkFinished && instance.finished) throw new Error('Hash#digest() has already been called');\n}\n\n/** Asserts output is properly-sized byte array */\nexport function aoutput(out: any, instance: any): void {\n abytes(out, undefined, 'digestInto() output');\n const min = instance.outputLen;\n if (out.length < min) {\n throw new Error('\"digestInto() output\" expected to be of length >=' + min);\n }\n}\n\n/** Generic type encompassing 8/16/32-byte arrays - but not 64-byte. */\n// prettier-ignore\nexport type TypedArray = Int8Array | Uint8ClampedArray | Uint8Array |\n Uint16Array | Int16Array | Uint32Array | Int32Array;\n\n/** Cast u8 / u16 / u32 to u8. */\nexport function u8(arr: TypedArray): Uint8Array {\n return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);\n}\n\n/** Cast u8 / u16 / u32 to u32. */\nexport function u32(arr: TypedArray): Uint32Array {\n return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));\n}\n\n/** Zeroize a byte array. Warning: JS provides no guarantees. */\nexport function clean(...arrays: TypedArray[]): void {\n for (let i = 0; i < arrays.length; i++) {\n arrays[i].fill(0);\n }\n}\n\n/** Create DataView of an array for easy byte-level manipulation. */\nexport function createView(arr: TypedArray): DataView {\n return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);\n}\n\n/** The rotate right (circular right shift) operation for uint32 */\nexport function rotr(word: number, shift: number): number {\n return (word << (32 - shift)) | (word >>> shift);\n}\n\n/** The rotate left (circular left shift) operation for uint32 */\nexport function rotl(word: number, shift: number): number {\n return (word << shift) | ((word >>> (32 - shift)) >>> 0);\n}\n\n/** Is current platform little-endian? Most are. Big-Endian platform: IBM */\nexport const isLE: boolean = /* @__PURE__ */ (() =>\n new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44)();\n\n/** The byte swap operation for uint32 */\nexport function byteSwap(word: number): number {\n return (\n ((word << 24) & 0xff000000) |\n ((word << 8) & 0xff0000) |\n ((word >>> 8) & 0xff00) |\n ((word >>> 24) & 0xff)\n );\n}\n/** Conditionally byte swap if on a big-endian platform */\nexport const swap8IfBE: (n: number) => number = isLE\n ? (n: number) => n\n : (n: number) => byteSwap(n);\n\n/** In place byte swap for Uint32Array */\nexport function byteSwap32(arr: Uint32Array): Uint32Array {\n for (let i = 0; i < arr.length; i++) {\n arr[i] = byteSwap(arr[i]);\n }\n return arr;\n}\n\nexport const swap32IfBE: (u: Uint32Array) => Uint32Array = isLE\n ? (u: Uint32Array) => u\n : byteSwap32;\n\n// Built-in hex conversion https://caniuse.com/mdn-javascript_builtins_uint8array_fromhex\nconst hasHexBuiltin: boolean = /* @__PURE__ */ (() =>\n // @ts-ignore\n typeof Uint8Array.from([]).toHex === 'function' && typeof Uint8Array.fromHex === 'function')();\n\n// Array where index 0xf0 (240) is mapped to string 'f0'\nconst hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>\n i.toString(16).padStart(2, '0')\n);\n\n/**\n * Convert byte array to hex string. Uses built-in function, when available.\n * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n abytes(bytes);\n // @ts-ignore\n if (hasHexBuiltin) return bytes.toHex();\n // pre-caching improves the speed 6x\n let hex = '';\n for (let i = 0; i < bytes.length; i++) {\n hex += hexes[bytes[i]];\n }\n return hex;\n}\n\n// We use optimized technique to convert hex string to byte array\nconst asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 } as const;\nfunction asciiToBase16(ch: number): number | undefined {\n if (ch >= asciis._0 && ch <= asciis._9) return ch - asciis._0; // '2' => 50-48\n if (ch >= asciis.A && ch <= asciis.F) return ch - (asciis.A - 10); // 'B' => 66-(65-10)\n if (ch >= asciis.a && ch <= asciis.f) return ch - (asciis.a - 10); // 'b' => 98-(97-10)\n return;\n}\n\n/**\n * Convert hex string to byte array. Uses built-in function, when available.\n * @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])\n */\nexport function hexToBytes(hex: string): Uint8Array {\n if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);\n // @ts-ignore\n if (hasHexBuiltin) return Uint8Array.fromHex(hex);\n const hl = hex.length;\n const al = hl / 2;\n if (hl % 2) throw new Error('hex string expected, got unpadded hex of length ' + hl);\n const array = new Uint8Array(al);\n for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {\n const n1 = asciiToBase16(hex.charCodeAt(hi));\n const n2 = asciiToBase16(hex.charCodeAt(hi + 1));\n if (n1 === undefined || n2 === undefined) {\n const char = hex[hi] + hex[hi + 1];\n throw new Error('hex string expected, got non-hex character \"' + char + '\" at index ' + hi);\n }\n array[ai] = n1 * 16 + n2; // multiply first octet, e.g. 'a3' => 10*16+3 => 160 + 3 => 163\n }\n return array;\n}\n\n/**\n * There is no setImmediate in browser and setTimeout is slow.\n * Call of async fn will return Promise, which will be fullfiled only on\n * next scheduler queue processing step and this is exactly what we need.\n */\nexport const nextTick = async (): Promise<void> => {};\n\n/** Returns control to thread each 'tick' ms to avoid blocking. */\nexport async function asyncLoop(\n iters: number,\n tick: number,\n cb: (i: number) => void\n): Promise<void> {\n let ts = Date.now();\n for (let i = 0; i < iters; i++) {\n cb(i);\n // Date.now() is not monotonic, so in case if clock goes backwards we return return control too\n const diff = Date.now() - ts;\n if (diff >= 0 && diff < tick) continue;\n await nextTick();\n ts += diff;\n }\n}\n\n// Global symbols, but ts doesn't see them: https://github.com/microsoft/TypeScript/issues/31535\ndeclare const TextEncoder: any;\n\n/**\n * Converts string to bytes using UTF8 encoding.\n * Built-in doesn't validate input to be string: we do the check.\n * @example utf8ToBytes('abc') // Uint8Array.from([97, 98, 99])\n */\nexport function utf8ToBytes(str: string): Uint8Array {\n if (typeof str !== 'string') throw new Error('string expected');\n return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809\n}\n\n/** KDFs can accept string or Uint8Array for user convenience. */\nexport type KDFInput = string | Uint8Array;\n\n/**\n * Helper for KDFs: consumes uint8array or string.\n * When string is passed, does utf8 decoding, using TextDecoder.\n */\nexport function kdfInputToBytes(data: KDFInput, errorTitle = ''): Uint8Array {\n if (typeof data === 'string') return utf8ToBytes(data);\n return abytes(data, undefined, errorTitle);\n}\n\n/** Copies several Uint8Arrays into one. */\nexport function concatBytes(...arrays: Uint8Array[]): Uint8Array {\n let sum = 0;\n for (let i = 0; i < arrays.length; i++) {\n const a = arrays[i];\n abytes(a);\n sum += a.length;\n }\n const res = new Uint8Array(sum);\n for (let i = 0, pad = 0; i < arrays.length; i++) {\n const a = arrays[i];\n res.set(a, pad);\n pad += a.length;\n }\n return res;\n}\n\ntype EmptyObj = {};\n/** Merges default options and passed options. */\nexport function checkOpts<T1 extends EmptyObj, T2 extends EmptyObj>(\n defaults: T1,\n opts?: T2\n): T1 & T2 {\n if (opts !== undefined && {}.toString.call(opts) !== '[object Object]')\n throw new Error('options must be object or undefined');\n const merged = Object.assign(defaults, opts);\n return merged as T1 & T2;\n}\n\n/** Common interface for all hashes. */\nexport interface Hash<T> {\n blockLen: number; // Bytes per block\n outputLen: number; // Bytes in output\n update(buf: Uint8Array): this;\n digestInto(buf: Uint8Array): void;\n digest(): Uint8Array;\n destroy(): void;\n _cloneInto(to?: T): T;\n clone(): T;\n}\n\n/** PseudoRandom (number) Generator */\nexport interface PRG {\n addEntropy(seed: Uint8Array): void;\n randomBytes(length: number): Uint8Array;\n clean(): void;\n}\n\n/**\n * XOF: streaming API to read digest in chunks.\n * Same as 'squeeze' in keccak/k12 and 'seek' in blake3, but more generic name.\n * When hash used in XOF mode it is up to user to call '.destroy' afterwards, since we cannot\n * destroy state, next call can require more bytes.\n */\nexport type HashXOF<T extends Hash<T>> = Hash<T> & {\n xof(bytes: number): Uint8Array; // Read 'bytes' bytes from digest stream\n xofInto(buf: Uint8Array): Uint8Array; // read buf.length bytes from digest stream into buf\n};\n\n/** Hash constructor */\nexport type HasherCons<T, Opts = undefined> = Opts extends undefined ? () => T : (opts?: Opts) => T;\n/** Optional hash params. */\nexport type HashInfo = {\n oid?: Uint8Array; // DER encoded OID in bytes\n};\n/** Hash function */\nexport type CHash<T extends Hash<T> = Hash<any>, Opts = undefined> = {\n outputLen: number;\n blockLen: number;\n} & HashInfo &\n (Opts extends undefined\n ? {\n (msg: Uint8Array): Uint8Array;\n create(): T;\n }\n : {\n (msg: Uint8Array, opts?: Opts): Uint8Array;\n create(opts?: Opts): T;\n });\n/** XOF with output */\nexport type CHashXOF<T extends HashXOF<T> = HashXOF<any>, Opts = undefined> = CHash<T, Opts>;\n\n/** Creates function with outputLen, blockLen, create properties from a class constructor. */\nexport function createHasher<T extends Hash<T>, Opts = undefined>(\n hashCons: HasherCons<T, Opts>,\n info: HashInfo = {}\n): CHash<T, Opts> {\n const hashC: any = (msg: Uint8Array, opts?: Opts) => hashCons(opts).update(msg).digest();\n const tmp = hashCons(undefined);\n hashC.outputLen = tmp.outputLen;\n hashC.blockLen = tmp.blockLen;\n hashC.create = (opts?: Opts) => hashCons(opts);\n Object.assign(hashC, info);\n return Object.freeze(hashC);\n}\n\n/** Cryptographically secure PRNG. Uses internal OS-level `crypto.getRandomValues`. */\nexport function randomBytes(bytesLength = 32): Uint8Array {\n const cr = typeof globalThis === 'object' ? (globalThis as any).crypto : null;\n if (typeof cr?.getRandomValues !== 'function')\n throw new Error('crypto.getRandomValues must be defined');\n return cr.getRandomValues(new Uint8Array(bytesLength));\n}\n\n/** Creates OID opts for NIST hashes, with prefix 06 09 60 86 48 01 65 03 04 02. */\nexport const oidNist = (suffix: number): Required<HashInfo> => ({\n oid: Uint8Array.from([0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, suffix]),\n});\n","/**\n * HMAC: RFC2104 message authentication code.\n * @module\n */\nimport { abytes, aexists, ahash, clean, type CHash, type Hash } from './utils.ts';\n\n/** Internal class for HMAC. */\nexport class _HMAC<T extends Hash<T>> implements Hash<_HMAC<T>> {\n oHash: T;\n iHash: T;\n blockLen: number;\n outputLen: number;\n private finished = false;\n private destroyed = false;\n\n constructor(hash: CHash, key: Uint8Array) {\n ahash(hash);\n abytes(key, undefined, 'key');\n this.iHash = hash.create() as T;\n if (typeof this.iHash.update !== 'function')\n throw new Error('Expected instance of class which extends utils.Hash');\n this.blockLen = this.iHash.blockLen;\n this.outputLen = this.iHash.outputLen;\n const blockLen = this.blockLen;\n const pad = new Uint8Array(blockLen);\n // blockLen can be bigger than outputLen\n pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);\n for (let i = 0; i < pad.length; i++) pad[i] ^= 0x36;\n this.iHash.update(pad);\n // By doing update (processing of first block) of outer hash here we can re-use it between multiple calls via clone\n this.oHash = hash.create() as T;\n // Undo internal XOR && apply outer XOR\n for (let i = 0; i < pad.length; i++) pad[i] ^= 0x36 ^ 0x5c;\n this.oHash.update(pad);\n clean(pad);\n }\n update(buf: Uint8Array): this {\n aexists(this);\n this.iHash.update(buf);\n return this;\n }\n digestInto(out: Uint8Array): void {\n aexists(this);\n abytes(out, this.outputLen, 'output');\n this.finished = true;\n this.iHash.digestInto(out);\n this.oHash.update(out);\n this.oHash.digestInto(out);\n this.destroy();\n }\n digest(): Uint8Array {\n const out = new Uint8Array(this.oHash.outputLen);\n this.digestInto(out);\n return out;\n }\n _cloneInto(to?: _HMAC<T>): _HMAC<T> {\n // Create new instance without calling constructor since key already in state and we don't know it.\n to ||= Object.create(Object.getPrototypeOf(this), {});\n const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;\n to = to as this;\n to.finished = finished;\n to.destroyed = destroyed;\n to.blockLen = blockLen;\n to.outputLen = outputLen;\n to.oHash = oHash._cloneInto(to.oHash);\n to.iHash = iHash._cloneInto(to.iHash);\n return to;\n }\n clone(): _HMAC<T> {\n return this._cloneInto();\n }\n destroy(): void {\n this.destroyed = true;\n this.oHash.destroy();\n this.iHash.destroy();\n }\n}\n\n/**\n * HMAC: RFC2104 message authentication code.\n * @param hash - function that would be used e.g. sha256\n * @param key - message key\n * @param message - message data\n * @example\n * import { hmac } from '@noble/hashes/hmac';\n * import { sha256 } from '@noble/hashes/sha2';\n * const mac1 = hmac(sha256, 'key', 'message');\n */\nexport const hmac: {\n (hash: CHash, key: Uint8Array, message: Uint8Array): Uint8Array;\n create(hash: CHash, key: Uint8Array): _HMAC<any>;\n} = (hash: CHash, key: Uint8Array, message: Uint8Array): Uint8Array =>\n new _HMAC<any>(hash, key).update(message).digest();\nhmac.create = (hash: CHash, key: Uint8Array) => new _HMAC<any>(hash, key);\n","/**\n * HKDF (RFC 5869): extract + expand in one step.\n * See https://soatok.blog/2021/11/17/understanding-hkdf/.\n * @module\n */\nimport { hmac } from './hmac.ts';\nimport { abytes, ahash, anumber, type CHash, clean } from './utils.ts';\n\n/**\n * HKDF-extract from spec. Less important part. `HKDF-Extract(IKM, salt) -> PRK`\n * Arguments position differs from spec (IKM is first one, since it is not optional)\n * @param hash - hash function that would be used (e.g. sha256)\n * @param ikm - input keying material, the initial key\n * @param salt - optional salt value (a non-secret random value)\n */\nexport function extract(hash: CHash, ikm: Uint8Array, salt?: Uint8Array): Uint8Array {\n ahash(hash);\n // NOTE: some libraries treat zero-length array as 'not provided';\n // we don't, since we have undefined as 'not provided'\n // https://github.com/RustCrypto/KDFs/issues/15\n if (salt === undefined) salt = new Uint8Array(hash.outputLen);\n return hmac(hash, salt, ikm);\n}\n\nconst HKDF_COUNTER = /* @__PURE__ */ Uint8Array.of(0);\nconst EMPTY_BUFFER = /* @__PURE__ */ Uint8Array.of();\n\n/**\n * HKDF-expand from the spec. The most important part. `HKDF-Expand(PRK, info, L) -> OKM`\n * @param hash - hash function that would be used (e.g. sha256)\n * @param prk - a pseudorandom key of at least HashLen octets (usually, the output from the extract step)\n * @param info - optional context and application specific information (can be a zero-length string)\n * @param length - length of output keying material in bytes\n */\nexport function expand(\n hash: CHash,\n prk: Uint8Array,\n info?: Uint8Array,\n length: number = 32\n): Uint8Array {\n ahash(hash);\n anumber(length, 'length');\n const olen = hash.outputLen;\n if (length > 255 * olen) throw new Error('Length must be <= 255*HashLen');\n const blocks = Math.ceil(length / olen);\n if (info === undefined) info = EMPTY_BUFFER;\n else abytes(info, undefined, 'info');\n // first L(ength) octets of T\n const okm = new Uint8Array(blocks * olen);\n // Re-use HMAC instance between blocks\n const HMAC = hmac.create(hash, prk);\n const HMACTmp = HMAC._cloneInto();\n const T = new Uint8Array(HMAC.outputLen);\n for (let counter = 0; counter < blocks; counter++) {\n HKDF_COUNTER[0] = counter + 1;\n // T(0) = empty string (zero length)\n // T(N) = HMAC-Hash(PRK, T(N-1) | info | N)\n HMACTmp.update(counter === 0 ? EMPTY_BUFFER : T)\n .update(info)\n .update(HKDF_COUNTER)\n .digestInto(T);\n okm.set(T, olen * counter);\n HMAC._cloneInto(HMACTmp);\n }\n HMAC.destroy();\n HMACTmp.destroy();\n clean(T, HKDF_COUNTER);\n return okm.slice(0, length);\n}\n\n/**\n * HKDF (RFC 5869): derive keys from an initial input.\n * Combines hkdf_extract + hkdf_expand in one step\n * @param hash - hash function that would be used (e.g. sha256)\n * @param ikm - input keying material, the initial key\n * @param salt - optional salt value (a non-secret random value)\n * @param info - optional context and application specific information (can be a zero-length string)\n * @param length - length of output keying material in bytes\n * @example\n * import { hkdf } from '@noble/hashes/hkdf';\n * import { sha256 } from '@noble/hashes/sha2';\n * import { randomBytes } from '@noble/hashes/utils';\n * const inputKey = randomBytes(32);\n * const salt = randomBytes(32);\n * const info = 'application-key';\n * const hk1 = hkdf(sha256, inputKey, salt, info, 32);\n */\nexport const hkdf = (\n hash: CHash,\n ikm: Uint8Array,\n salt: Uint8Array | undefined,\n info: Uint8Array | undefined,\n length: number\n): Uint8Array => expand(hash, extract(hash, ikm, salt), info, length);\n","/**\n * Internal Merkle-Damgard hash utils.\n * @module\n */\nimport { abytes, aexists, aoutput, clean, createView, type Hash } from './utils.ts';\n\n/** Choice: a ? b : c */\nexport function Chi(a: number, b: number, c: number): number {\n return (a & b) ^ (~a & c);\n}\n\n/** Majority function, true if any two inputs is true. */\nexport function Maj(a: number, b: number, c: number): number {\n return (a & b) ^ (a & c) ^ (b & c);\n}\n\n/**\n * Merkle-Damgard hash construction base class.\n * Could be used to create MD5, RIPEMD, SHA1, SHA2.\n */\nexport abstract class HashMD<T extends HashMD<T>> implements Hash<T> {\n protected abstract process(buf: DataView, offset: number): void;\n protected abstract get(): number[];\n protected abstract set(...args: number[]): void;\n abstract destroy(): void;\n protected abstract roundClean(): void;\n\n readonly blockLen: number;\n readonly outputLen: number;\n readonly padOffset: number;\n readonly isLE: boolean;\n\n // For partial updates less than block size\n protected buffer: Uint8Array;\n protected view: DataView;\n protected finished = false;\n protected length = 0;\n protected pos = 0;\n protected destroyed = false;\n\n constructor(blockLen: number, outputLen: number, padOffset: number, isLE: boolean) {\n this.blockLen = blockLen;\n this.outputLen = outputLen;\n this.padOffset = padOffset;\n this.isLE = isLE;\n this.buffer = new Uint8Array(blockLen);\n this.view = createView(this.buffer);\n }\n update(data: Uint8Array): this {\n aexists(this);\n abytes(data);\n const { view, buffer, blockLen } = this;\n const len = data.length;\n for (let pos = 0; pos < len; ) {\n const take = Math.min(blockLen - this.pos, len - pos);\n // Fast path: we have at least one block in input, cast it to view and process\n if (take === blockLen) {\n const dataView = createView(data);\n for (; blockLen <= len - pos; pos += blockLen) this.process(dataView, pos);\n continue;\n }\n buffer.set(data.subarray(pos, pos + take), this.pos);\n this.pos += take;\n pos += take;\n if (this.pos === blockLen) {\n this.process(view, 0);\n this.pos = 0;\n }\n }\n this.length += data.length;\n this.roundClean();\n return this;\n }\n digestInto(out: Uint8Array): void {\n aexists(this);\n aoutput(out, this);\n this.finished = true;\n // Padding\n // We can avoid allocation of buffer for padding completely if it\n // was previously not allocated here. But it won't change performance.\n const { buffer, view, blockLen, isLE } = this;\n let { pos } = this;\n // append the bit '1' to the message\n buffer[pos++] = 0b10000000;\n clean(this.buffer.subarray(pos));\n // we have less than padOffset left in buffer, so we cannot put length in\n // current block, need process it and pad again\n if (this.padOffset > blockLen - pos) {\n this.process(view, 0);\n pos = 0;\n }\n // Pad until full block byte with zeros\n for (let i = pos; i < blockLen; i++) buffer[i] = 0;\n // Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that\n // You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.\n // So we just write lowest 64 bits of that value.\n view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE);\n this.process(view, 0);\n const oview = createView(out);\n const len = this.outputLen;\n // NOTE: we do division by 4 later, which must be fused in single op with modulo by JIT\n if (len % 4) throw new Error('_sha2: outputLen must be aligned to 32bit');\n const outLen = len / 4;\n const state = this.get();\n if (outLen > state.length) throw new Error('_sha2: outputLen bigger than state');\n for (let i = 0; i < outLen; i++) oview.setUint32(4 * i, state[i], isLE);\n }\n digest(): Uint8Array {\n const { buffer, outputLen } = this;\n this.digestInto(buffer);\n const res = buffer.slice(0, outputLen);\n this.destroy();\n return res;\n }\n _cloneInto(to?: T): T {\n to ||= new (this.constructor as any)() as T;\n to.set(...this.get());\n const { blockLen, buffer, length, finished, destroyed, pos } = this;\n to.destroyed = destroyed;\n to.finished = finished;\n to.length = length;\n to.pos = pos;\n if (length % blockLen) to.buffer.set(buffer);\n return to as unknown as any;\n }\n clone(): T {\n return this._cloneInto();\n }\n}\n\n/**\n * Initial SHA-2 state: fractional parts of square roots of first 16 primes 2..53.\n * Check out `test/misc/sha2-gen-iv.js` for recomputation guide.\n */\n\n/** Initial SHA256 state. Bits 0..32 of frac part of sqrt of primes 2..19 */\nexport const SHA256_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,\n]);\n\n/** Initial SHA224 state. Bits 32..64 of frac part of sqrt of primes 23..53 */\nexport const SHA224_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4,\n]);\n\n/** Initial SHA384 state. Bits 0..64 of frac part of sqrt of primes 23..53 */\nexport const SHA384_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0xcbbb9d5d, 0xc1059ed8, 0x629a292a, 0x367cd507, 0x9159015a, 0x3070dd17, 0x152fecd8, 0xf70e5939,\n 0x67332667, 0xffc00b31, 0x8eb44a87, 0x68581511, 0xdb0c2e0d, 0x64f98fa7, 0x47b5481d, 0xbefa4fa4,\n]);\n\n/** Initial SHA512 state. Bits 0..64 of frac part of sqrt of primes 2..19 */\nexport const SHA512_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0x6a09e667, 0xf3bcc908, 0xbb67ae85, 0x84caa73b, 0x3c6ef372, 0xfe94f82b, 0xa54ff53a, 0x5f1d36f1,\n 0x510e527f, 0xade682d1, 0x9b05688c, 0x2b3e6c1f, 0x1f83d9ab, 0xfb41bd6b, 0x5be0cd19, 0x137e2179,\n]);\n","/**\n * SHA2 hash function. A.k.a. sha256, sha384, sha512, sha512_224, sha512_256.\n * SHA256 is the fastest hash implementable in JS, even faster than Blake3.\n * Check out [RFC 4634](https://www.rfc-editor.org/rfc/rfc4634) and\n * [FIPS 180-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).\n * @module\n */\nimport { Chi, HashMD, Maj, SHA224_IV, SHA256_IV, SHA384_IV, SHA512_IV } from './_md.ts';\nimport * as u64 from './_u64.ts';\nimport { type CHash, clean, createHasher, oidNist, rotr } from './utils.ts';\n\n/**\n * Round constants:\n * First 32 bits of fractional parts of the cube roots of the first 64 primes 2..311)\n */\n// prettier-ignore\nconst SHA256_K = /* @__PURE__ */ Uint32Array.from([\n 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2\n]);\n\n/** Reusable temporary buffer. \"W\" comes straight from spec. */\nconst SHA256_W = /* @__PURE__ */ new Uint32Array(64);\n\n/** Internal 32-byte base SHA2 hash class. */\nabstract class SHA2_32B<T extends SHA2_32B<T>> extends HashMD<T> {\n // We cannot use array here since array allows indexing by variable\n // which means optimizer/compiler cannot use registers.\n protected abstract A: number;\n protected abstract B: number;\n protected abstract C: number;\n protected abstract D: number;\n protected abstract E: number;\n protected abstract F: number;\n protected abstract G: number;\n protected abstract H: number;\n\n constructor(outputLen: number) {\n super(64, outputLen, 8, false);\n }\n protected get(): [number, number, number, number, number, number, number, number] {\n const { A, B, C, D, E, F, G, H } = this;\n return [A, B, C, D, E, F, G, H];\n }\n // prettier-ignore\n protected set(\n A: number, B: number, C: number, D: number, E: number, F: number, G: number, H: number\n ): void {\n this.A = A | 0;\n this.B = B | 0;\n this.C = C | 0;\n this.D = D | 0;\n this.E = E | 0;\n this.F = F | 0;\n this.G = G | 0;\n this.H = H | 0;\n }\n protected process(view: DataView, offset: number): void {\n // Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array\n for (let i = 0; i < 16; i++, offset += 4) SHA256_W[i] = view.getUint32(offset, false);\n for (let i = 16; i < 64; i++) {\n const W15 = SHA256_W[i - 15];\n const W2 = SHA256_W[i - 2];\n const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);\n const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);\n SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;\n }\n // Compression function main loop, 64 rounds\n let { A, B, C, D, E, F, G, H } = this;\n for (let i = 0; i < 64; i++) {\n const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);\n const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;\n const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);\n const T2 = (sigma0 + Maj(A, B, C)) | 0;\n H = G;\n G = F;\n F = E;\n E = (D + T1) | 0;\n D = C;\n C = B;\n B = A;\n A = (T1 + T2) | 0;\n }\n // Add the compressed chunk to the current hash value\n A = (A + this.A) | 0;\n B = (B + this.B) | 0;\n C = (C + this.C) | 0;\n D = (D + this.D) | 0;\n E = (E + this.E) | 0;\n F = (F + this.F) | 0;\n G = (G + this.G) | 0;\n H = (H + this.H) | 0;\n this.set(A, B, C, D, E, F, G, H);\n }\n protected roundClean(): void {\n clean(SHA256_W);\n }\n destroy(): void {\n this.set(0, 0, 0, 0, 0, 0, 0, 0);\n clean(this.buffer);\n }\n}\n\n/** Internal SHA2-256 hash class. */\nexport class _SHA256 extends SHA2_32B<_SHA256> {\n // We cannot use array here since array allows indexing by variable\n // which means optimizer/compiler cannot use registers.\n protected A: number = SHA256_IV[0] | 0;\n protected B: number = SHA256_IV[1] | 0;\n protected C: number = SHA256_IV[2] | 0;\n protected D: number = SHA256_IV[3] | 0;\n protected E: number = SHA256_IV[4] | 0;\n protected F: number = SHA256_IV[5] | 0;\n protected G: number = SHA256_IV[6] | 0;\n protected H: number = SHA256_IV[7] | 0;\n constructor() {\n super(32);\n }\n}\n\n/** Internal SHA2-224 hash class. */\nexport class _SHA224 extends SHA2_32B<_SHA224> {\n protected A: number = SHA224_IV[0] | 0;\n protected B: number = SHA224_IV[1] | 0;\n protected C: number = SHA224_IV[2] | 0;\n protected D: number = SHA224_IV[3] | 0;\n protected E: number = SHA224_IV[4] | 0;\n protected F: number = SHA224_IV[5] | 0;\n protected G: number = SHA224_IV[6] | 0;\n protected H: number = SHA224_IV[7] | 0;\n constructor() {\n super(28);\n }\n}\n\n// SHA2-512 is slower than sha256 in js because u64 operations are slow.\n\n// Round contants\n// First 32 bits of the fractional parts of the cube roots of the first 80 primes 2..409\n// prettier-ignore\nconst K512 = /* @__PURE__ */ (() => u64.split([\n '0x428a2f98d728ae22', '0x7137449123ef65cd', '0xb5c0fbcfec4d3b2f', '0xe9b5dba58189dbbc',\n '0x3956c25bf348b538', '0x59f111f1b605d019', '0x923f82a4af194f9b', '0xab1c5ed5da6d8118',\n '0xd807aa98a3030242', '0x12835b0145706fbe', '0x243185be4ee4b28c', '0x550c7dc3d5ffb4e2',\n '0x72be5d74f27b896f', '0x80deb1fe3b1696b1', '0x9bdc06a725c71235', '0xc19bf174cf692694',\n '0xe49b69c19ef14ad2', '0xefbe4786384f25e3', '0x0fc19dc68b8cd5b5', '0x240ca1cc77ac9c65',\n '0x2de92c6f592b0275', '0x4a7484aa6ea6e483', '0x5cb0a9dcbd41fbd4', '0x76f988da831153b5',\n '0x983e5152ee66dfab', '0xa831c66d2db43210', '0xb00327c898fb213f', '0xbf597fc7beef0ee4',\n '0xc6e00bf33da88fc2', '0xd5a79147930aa725', '0x06ca6351e003826f', '0x142929670a0e6e70',\n '0x27b70a8546d22ffc', '0x2e1b21385c26c926', '0x4d2c6dfc5ac42aed', '0x53380d139d95b3df',\n '0x650a73548baf63de', '0x766a0abb3c77b2a8', '0x81c2c92e47edaee6', '0x92722c851482353b',\n '0xa2bfe8a14cf10364', '0xa81a664bbc423001', '0xc24b8b70d0f89791', '0xc76c51a30654be30',\n '0xd192e819d6ef5218', '0xd69906245565a910', '0xf40e35855771202a', '0x106aa07032bbd1b8',\n '0x19a4c116b8d2d0c8', '0x1e376c085141ab53', '0x2748774cdf8eeb99', '0x34b0bcb5e19b48a8',\n '0x391c0cb3c5c95a63', '0x4ed8aa4ae3418acb', '0x5b9cca4f7763e373', '0x682e6ff3d6b2b8a3',\n '0x748f82ee5defb2fc', '0x78a5636f43172f60', '0x84c87814a1f0ab72', '0x8cc702081a6439ec',\n '0x90befffa23631e28', '0xa4506cebde82bde9', '0xbef9a3f7b2c67915', '0xc67178f2e372532b',\n '0xca273eceea26619c', '0xd186b8c721c0c207', '0xeada7dd6cde0eb1e', '0xf57d4f7fee6ed178',\n '0x06f067aa72176fba', '0x0a637dc5a2c898a6', '0x113f9804bef90dae', '0x1b710b35131c471b',\n '0x28db77f523047d84', '0x32caab7b40c72493', '0x3c9ebe0a15c9bebc', '0x431d67c49c100d4c',\n '0x4cc5d4becb3e42b6', '0x597f299cfc657e2a', '0x5fcb6fab3ad6faec', '0x6c44198c4a475817'\n].map(n => BigInt(n))))();\nconst SHA512_Kh = /* @__PURE__ */ (() => K512[0])();\nconst SHA512_Kl = /* @__PURE__ */ (() => K512[1])();\n\n// Reusable temporary buffers\nconst SHA512_W_H = /* @__PURE__ */ new Uint32Array(80);\nconst SHA512_W_L = /* @__PURE__ */ new Uint32Array(80);\n\n/** Internal 64-byte base SHA2 hash class. */\nabstract class SHA2_64B<T extends SHA2_64B<T>> extends HashMD<T> {\n // We cannot use array here since array allows indexing by variable\n // which means optimizer/compiler cannot use registers.\n // h -- high 32 bits, l -- low 32 bits\n protected abstract Ah: number;\n protected abstract Al: number;\n protected abstract Bh: number;\n protected abstract Bl: number;\n protected abstract Ch: number;\n protected abstract Cl: number;\n protected abstract Dh: number;\n protected abstract Dl: number;\n protected abstract Eh: number;\n protected abstract El: number;\n protected abstract Fh: number;\n protected abstract Fl: number;\n protected abstract Gh: number;\n protected abstract Gl: number;\n protected abstract Hh: number;\n protected abstract Hl: number;\n\n constructor(outputLen: number) {\n super(128, outputLen, 16, false);\n }\n // prettier-ignore\n protected get(): [\n number, number, number, number, number, number, number, number,\n number, number, number, number, number, number, number, number\n ] {\n const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;\n return [Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl];\n }\n // prettier-ignore\n protected set(\n Ah: number, Al: number, Bh: number, Bl: number, Ch: number, Cl: number, Dh: number, Dl: number,\n Eh: number, El: number, Fh: number, Fl: number, Gh: number, Gl: number, Hh: number, Hl: number\n ): void {\n this.Ah = Ah | 0;\n this.Al = Al | 0;\n this.Bh = Bh | 0;\n this.Bl = Bl | 0;\n this.Ch = Ch | 0;\n this.Cl = Cl | 0;\n this.Dh = Dh | 0;\n this.Dl = Dl | 0;\n this.Eh = Eh | 0;\n this.El = El | 0;\n this.Fh = Fh | 0;\n this.Fl = Fl | 0;\n this.Gh = Gh | 0;\n this.Gl = Gl | 0;\n this.Hh = Hh | 0;\n this.Hl = Hl | 0;\n }\n protected process(view: DataView, offset: number): void {\n // Extend the first 16 words into the remaining 64 words w[16..79] of the message schedule array\n for (let i = 0; i < 16; i++, offset += 4) {\n SHA512_W_H[i] = view.getUint32(offset);\n SHA512_W_L[i] = view.getUint32((offset += 4));\n }\n for (let i = 16; i < 80; i++) {\n // s0 := (w[i-15] rightrotate 1) xor (w[i-15] rightrotate 8) xor (w[i-15] rightshift 7)\n const W15h = SHA512_W_H[i - 15] | 0;\n const W15l = SHA512_W_L[i - 15] | 0;\n const s0h = u64.rotrSH(W15h, W15l, 1) ^ u64.rotrSH(W15h, W15l, 8) ^ u64.shrSH(W15h, W15l, 7);\n const s0l = u64.rotrSL(W15h, W15l, 1) ^ u64.rotrSL(W15h, W15l, 8) ^ u64.shrSL(W15h, W15l, 7);\n // s1 := (w[i-2] rightrotate 19) xor (w[i-2] rightrotate 61) xor (w[i-2] rightshift 6)\n const W2h = SHA512_W_H[i - 2] | 0;\n const W2l = SHA512_W_L[i - 2] | 0;\n const s1h = u64.rotrSH(W2h, W2l, 19) ^ u64.rotrBH(W2h, W2l, 61) ^ u64.shrSH(W2h, W2l, 6);\n const s1l = u64.rotrSL(W2h, W2l, 19) ^ u64.rotrBL(W2h, W2l, 61) ^ u64.shrSL(W2h, W2l, 6);\n // SHA256_W[i] = s0 + s1 + SHA256_W[i - 7] + SHA256_W[i - 16];\n const SUMl = u64.add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]);\n const SUMh = u64.add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]);\n SHA512_W_H[i] = SUMh | 0;\n SHA512_W_L[i] = SUMl | 0;\n }\n let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;\n // Compression function main loop, 80 rounds\n for (let i = 0; i < 80; i++) {\n // S1 := (e rightrotate 14) xor (e rightrotate 18) xor (e rightrotate 41)\n const sigma1h = u64.rotrSH(Eh, El, 14) ^ u64.rotrSH(Eh, El, 18) ^ u64.rotrBH(Eh, El, 41);\n const sigma1l = u64.rotrSL(Eh, El, 14) ^ u64.rotrSL(Eh, El, 18) ^ u64.rotrBL(Eh, El, 41);\n //const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;\n const CHIh = (Eh & Fh) ^ (~Eh & Gh);\n const CHIl = (El & Fl) ^ (~El & Gl);\n // T1 = H + sigma1 + Chi(E, F, G) + SHA512_K[i] + SHA512_W[i]\n // prettier-ignore\n const T1ll = u64.add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]);\n const T1h = u64.add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]);\n const T1l = T1ll | 0;\n // S0 := (a rightrotate 28) xor (a rightrotate 34) xor (a rightrotate 39)\n const sigma0h = u64.rotrSH(Ah, Al, 28) ^ u64.rotrBH(Ah, Al, 34) ^ u64.rotrBH(Ah, Al, 39);\n const sigma0l = u64.rotrSL(Ah, Al, 28) ^ u64.rotrBL(Ah, Al, 34) ^ u64.rotrBL(Ah, Al, 39);\n const MAJh = (Ah & Bh) ^ (Ah & Ch) ^ (Bh & Ch);\n const MAJl = (Al & Bl) ^ (Al & Cl) ^ (Bl & Cl);\n Hh = Gh | 0;\n Hl = Gl | 0;\n Gh = Fh | 0;\n Gl = Fl | 0;\n Fh = Eh | 0;\n Fl = El | 0;\n ({ h: Eh, l: El } = u64.add(Dh | 0, Dl | 0, T1h | 0, T1l | 0));\n Dh = Ch | 0;\n Dl = Cl | 0;\n Ch = Bh | 0;\n Cl = Bl | 0;\n Bh = Ah | 0;\n Bl = Al | 0;\n const All = u64.add3L(T1l, sigma0l, MAJl);\n Ah = u64.add3H(All, T1h, sigma0h, MAJh);\n Al = All | 0;\n }\n // Add the compressed chunk to the current hash value\n ({ h: Ah, l: Al } = u64.add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0));\n ({ h: Bh, l: Bl } = u64.add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0));\n ({ h: Ch, l: Cl } = u64.add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0));\n ({ h: Dh, l: Dl } = u64.add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0));\n ({ h: Eh, l: El } = u64.add(this.Eh | 0, this.El | 0, Eh | 0, El | 0));\n ({ h: Fh, l: Fl } = u64.add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0));\n ({ h: Gh, l: Gl } = u64.add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0));\n ({ h: Hh, l: Hl } = u64.add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0));\n this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl);\n }\n protected roundClean(): void {\n clean(SHA512_W_H, SHA512_W_L);\n }\n destroy(): void {\n clean(this.buffer);\n this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n }\n}\n\n/** Internal SHA2-512 hash class. */\nexport class _SHA512 extends SHA2_64B<_SHA512> {\n protected Ah: number = SHA512_IV[0] | 0;\n protected Al: number = SHA512_IV[1] | 0;\n protected Bh: number = SHA512_IV[2] | 0;\n protected Bl: number = SHA512_IV[3] | 0;\n protected Ch: number = SHA512_IV[4] | 0;\n protected Cl: number = SHA512_IV[5] | 0;\n protected Dh: number = SHA512_IV[6] | 0;\n protected Dl: number = SHA512_IV[7] | 0;\n protected Eh: number = SHA512_IV[8] | 0;\n protected El: number = SHA512_IV[9] | 0;\n protected Fh: number = SHA512_IV[10] | 0;\n protected Fl: number = SHA512_IV[11] | 0;\n protected Gh: number = SHA512_IV[12] | 0;\n protected Gl: number = SHA512_IV[13] | 0;\n protected Hh: number = SHA512_IV[14] | 0;\n protected Hl: number = SHA512_IV[15] | 0;\n\n constructor() {\n super(64);\n }\n}\n\n/** Internal SHA2-384 hash class. */\nexport class _SHA384 extends SHA2_64B<_SHA384> {\n protected Ah: number = SHA384_IV[0] | 0;\n protected Al: number = SHA384_IV[1] | 0;\n protected Bh: number = SHA384_IV[2] | 0;\n protected Bl: number = SHA384_IV[3] | 0;\n protected Ch: number = SHA384_IV[4] | 0;\n protected Cl: number = SHA384_IV[5] | 0;\n protected Dh: number = SHA384_IV[6] | 0;\n protected Dl: number = SHA384_IV[7] | 0;\n protected Eh: number = SHA384_IV[8] | 0;\n protected El: number = SHA384_IV[9] | 0;\n protected Fh: number = SHA384_IV[10] | 0;\n protected Fl: number = SHA384_IV[11] | 0;\n protected Gh: number = SHA384_IV[12] | 0;\n protected Gl: number = SHA384_IV[13] | 0;\n protected Hh: number = SHA384_IV[14] | 0;\n protected Hl: number = SHA384_IV[15] | 0;\n\n constructor() {\n super(48);\n }\n}\n\n/**\n * Truncated SHA512/256 and SHA512/224.\n * SHA512_IV is XORed with 0xa5a5a5a5a5a5a5a5, then used as \"intermediary\" IV of SHA512/t.\n * Then t hashes string to produce result IV.\n * See `test/misc/sha2-gen-iv.js`.\n */\n\n/** SHA512/224 IV */\nconst T224_IV = /* @__PURE__ */ Uint32Array.from([\n 0x8c3d37c8, 0x19544da2, 0x73e19966, 0x89dcd4d6, 0x1dfab7ae, 0x32ff9c82, 0x679dd514, 0x582f9fcf,\n 0x0f6d2b69, 0x7bd44da8, 0x77e36f73, 0x04c48942, 0x3f9d85a8, 0x6a1d36c8, 0x1112e6ad, 0x91d692a1,\n]);\n\n/** SHA512/256 IV */\nconst T256_IV = /* @__PURE__ */ Uint32Array.from([\n 0x22312194, 0xfc2bf72c, 0x9f555fa3, 0xc84c64c2, 0x2393b86b, 0x6f53b151, 0x96387719, 0x5940eabd,\n 0x96283ee2, 0xa88effe3, 0xbe5e1e25, 0x53863992, 0x2b0199fc, 0x2c85b8aa, 0x0eb72ddc, 0x81c52ca2,\n]);\n\n/** Internal SHA2-512/224 hash class. */\nexport class _SHA512_224 extends SHA2_64B<_SHA512_224> {\n protected Ah: number = T224_IV[0] | 0;\n protected Al: number = T224_IV[1] | 0;\n protected Bh: number = T224_IV[2] | 0;\n protected Bl: number = T224_IV[3] | 0;\n protected Ch: number = T224_IV[4] | 0;\n protected Cl: number = T224_IV[5] | 0;\n protected Dh: number = T224_IV[6] | 0;\n protected Dl: number = T224_IV[7] | 0;\n protected Eh: number = T224_IV[8] | 0;\n protected El: number = T224_IV[9] | 0;\n protected Fh: number = T224_IV[10] | 0;\n protected Fl: number = T224_IV[11] | 0;\n protected Gh: number = T224_IV[12] | 0;\n protected Gl: number = T224_IV[13] | 0;\n protected Hh: number = T224_IV[14] | 0;\n protected Hl: number = T224_IV[15] | 0;\n\n constructor() {\n super(28);\n }\n}\n\n/** Internal SHA2-512/256 hash class. */\nexport class _SHA512_256 extends SHA2_64B<_SHA512_256> {\n protected Ah: number = T256_IV[0] | 0;\n protected Al: number = T256_IV[1] | 0;\n protected Bh: number = T256_IV[2] | 0;\n protected Bl: number = T256_IV[3] | 0;\n protected Ch: number = T256_IV[4] | 0;\n protected Cl: number = T256_IV[5] | 0;\n protected Dh: number = T256_IV[6] | 0;\n protected Dl: number = T256_IV[7] | 0;\n protected Eh: number = T256_IV[8] | 0;\n protected El: number = T256_IV[9] | 0;\n protected Fh: number = T256_IV[10] | 0;\n protected Fl: number = T256_IV[11] | 0;\n protected Gh: number = T256_IV[12] | 0;\n protected Gl: number = T256_IV[13] | 0;\n protected Hh: number = T256_IV[14] | 0;\n protected Hl: number = T256_IV[15] | 0;\n\n constructor() {\n super(32);\n }\n}\n\n/**\n * SHA2-256 hash function from RFC 4634. In JS it's the fastest: even faster than Blake3. Some info:\n *\n * - Trying 2^128 hashes would get 50% chance of collision, using birthday attack.\n * - BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025.\n * - Each sha256 hash is executing 2^18 bit operations.\n * - Good 2024 ASICs can do 200Th/sec with 3500 watts of power, corresponding to 2^36 hashes/joule.\n */\nexport const sha256: CHash<_SHA256> = /* @__PURE__ */ createHasher(\n () => new _SHA256(),\n /* @__PURE__ */ oidNist(0x01)\n);\n/** SHA2-224 hash function from RFC 4634 */\nexport const sha224: CHash<_SHA224> = /* @__PURE__ */ createHasher(\n () => new _SHA224(),\n /* @__PURE__ */ oidNist(0x04)\n);\n\n/** SHA2-512 hash function from RFC 4634. */\nexport const sha512: CHash<_SHA512> = /* @__PURE__ */ createHasher(\n () => new _SHA512(),\n /* @__PURE__ */ oidNist(0x03)\n);\n/** SHA2-384 hash function from RFC 4634. */\nexport const sha384: CHash<_SHA384> = /* @__PURE__ */ createHasher(\n () => new _SHA384(),\n /* @__PURE__ */ oidNist(0x02)\n);\n\n/**\n * SHA2-512/256 \"truncated\" hash function, with improved resistance to length extension attacks.\n * See the paper on [truncated SHA512](https://eprint.iacr.org/2010/548.pdf).\n */\nexport const sha512_256: CHash<_SHA512_256> = /* @__PURE__ */ createHasher(\n () => new _SHA512_256(),\n /* @__PURE__ */ oidNist(0x06)\n);\n/**\n * SHA2-512/224 \"truncated\" hash function, with improved resistance to length extension attacks.\n * See the paper on [truncated SHA512](https://eprint.iacr.org/2010/548.pdf).\n */\nexport const sha512_224: CHash<_SHA512_224> = /* @__PURE__ */ createHasher(\n () => new _SHA512_224(),\n /* @__PURE__ */ oidNist(0x05)\n);\n","/**\n * Cryptographic utilities for SDK2\n *\n * Provides BIP39 mnemonic and BIP32 key derivation functions.\n * Platform-independent - no browser-specific APIs.\n */\n\nimport * as bip39 from 'bip39';\nimport CryptoJS from 'crypto-js';\nimport elliptic from 'elliptic';\nimport { encodeBech32 } from './bech32';\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst ec = new elliptic.ec('secp256k1');\n\n/** secp256k1 curve order */\nconst CURVE_ORDER = BigInt(\n '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141'\n);\n\n/** Default derivation path for Unicity (BIP44) */\nexport const DEFAULT_DERIVATION_PATH = \"m/44'/0'/0'\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface MasterKey {\n privateKey: string;\n chainCode: string;\n}\n\nexport interface DerivedKey {\n privateKey: string;\n chainCode: string;\n}\n\nexport interface KeyPair {\n privateKey: string;\n publicKey: string;\n}\n\nexport interface AddressInfo extends KeyPair {\n address: string;\n path: string;\n index: number;\n}\n\n// =============================================================================\n// BIP39 Mnemonic Functions\n// =============================================================================\n\n/**\n * Generate a new BIP39 mnemonic phrase\n * @param strength - Entropy bits (128 = 12 words, 256 = 24 words)\n */\nexport function generateMnemonic(strength: 128 | 256 = 128): string {\n return bip39.generateMnemonic(strength);\n}\n\n/**\n * Validate a BIP39 mnemonic phrase\n */\nexport function validateMnemonic(mnemonic: string): boolean {\n return bip39.validateMnemonic(mnemonic);\n}\n\n/**\n * Convert mnemonic to seed (64-byte hex string)\n * @param mnemonic - BIP39 mnemonic phrase\n * @param passphrase - Optional passphrase for additional security\n */\nexport async function mnemonicToSeed(\n mnemonic: string,\n passphrase: string = ''\n): Promise<string> {\n const seedBuffer = await bip39.mnemonicToSeed(mnemonic, passphrase);\n return Buffer.from(seedBuffer).toString('hex');\n}\n\n/**\n * Synchronous version of mnemonicToSeed\n */\nexport function mnemonicToSeedSync(\n mnemonic: string,\n passphrase: string = ''\n): string {\n const seedBuffer = bip39.mnemonicToSeedSync(mnemonic, passphrase);\n return Buffer.from(seedBuffer).toString('hex');\n}\n\n/**\n * Convert mnemonic to entropy (for recovery purposes)\n */\nexport function mnemonicToEntropy(mnemonic: string): string {\n return bip39.mnemonicToEntropy(mnemonic);\n}\n\n/**\n * Convert entropy to mnemonic\n */\nexport function entropyToMnemonic(entropy: string): string {\n return bip39.entropyToMnemonic(entropy);\n}\n\n// =============================================================================\n// BIP32 Key Derivation\n// =============================================================================\n\n/**\n * Generate master key from seed (BIP32 standard)\n * Uses HMAC-SHA512 with key \"Bitcoin seed\"\n */\nexport function generateMasterKey(seedHex: string): MasterKey {\n const I = CryptoJS.HmacSHA512(\n CryptoJS.enc.Hex.parse(seedHex),\n CryptoJS.enc.Utf8.parse('Bitcoin seed')\n ).toString();\n\n const IL = I.substring(0, 64); // Left 32 bytes - master private key\n const IR = I.substring(64); // Right 32 bytes - master chain code\n\n // Validate master key\n const masterKeyBigInt = BigInt('0x' + IL);\n if (masterKeyBigInt === 0n || masterKeyBigInt >= CURVE_ORDER) {\n throw new Error('Invalid master key generated');\n }\n\n return {\n privateKey: IL,\n chainCode: IR,\n };\n}\n\n/**\n * Derive child key using BIP32 standard\n * @param parentPrivKey - Parent private key (64 hex chars)\n * @param parentChainCode - Parent chain code (64 hex chars)\n * @param index - Child index (>= 0x80000000 for hardened)\n */\nexport function deriveChildKey(\n parentPrivKey: string,\n parentChainCode: string,\n index: number\n): DerivedKey {\n const isHardened = index >= 0x80000000;\n let data: string;\n\n if (isHardened) {\n // Hardened derivation: 0x00 || parentPrivKey || index\n const indexHex = index.toString(16).padStart(8, '0');\n data = '00' + parentPrivKey + indexHex;\n } else {\n // Non-hardened derivation: compressedPubKey || index\n const keyPair = ec.keyFromPrivate(parentPrivKey, 'hex');\n const compressedPubKey = keyPair.getPublic(true, 'hex');\n const indexHex = index.toString(16).padStart(8, '0');\n data = compressedPubKey + indexHex;\n }\n\n // HMAC-SHA512 with chain code as key\n const I = CryptoJS.HmacSHA512(\n CryptoJS.enc.Hex.parse(data),\n CryptoJS.enc.Hex.parse(parentChainCode)\n ).toString();\n\n const IL = I.substring(0, 64); // Left 32 bytes\n const IR = I.substring(64); // Right 32 bytes (new chain code)\n\n // Add IL to parent key mod n (curve order)\n const ilBigInt = BigInt('0x' + IL);\n const parentKeyBigInt = BigInt('0x' + parentPrivKey);\n\n // Check IL is valid (less than curve order)\n if (ilBigInt >= CURVE_ORDER) {\n throw new Error('Invalid key: IL >= curve order');\n }\n\n const childKeyBigInt = (ilBigInt + parentKeyBigInt) % CURVE_ORDER;\n\n // Check child key is valid (not zero)\n if (childKeyBigInt === 0n) {\n throw new Error('Invalid key: child key is zero');\n }\n\n const childPrivKey = childKeyBigInt.toString(16).padStart(64, '0');\n\n return {\n privateKey: childPrivKey,\n chainCode: IR,\n };\n}\n\n/**\n * Derive key at a full BIP32/BIP44 path\n * @param masterPrivKey - Master private key\n * @param masterChainCode - Master chain code\n * @param path - BIP44 path like \"m/44'/0'/0'/0/0\"\n */\nexport function deriveKeyAtPath(\n masterPrivKey: string,\n masterChainCode: string,\n path: string\n): DerivedKey {\n const pathParts = path.replace('m/', '').split('/');\n\n let currentKey = masterPrivKey;\n let currentChainCode = masterChainCode;\n\n for (const part of pathParts) {\n const isHardened = part.endsWith(\"'\") || part.endsWith('h');\n const indexStr = part.replace(/['h]$/, '');\n let index = parseInt(indexStr, 10);\n\n if (isHardened) {\n index += 0x80000000; // Add hardened offset\n }\n\n const derived = deriveChildKey(currentKey, currentChainCode, index);\n currentKey = derived.privateKey;\n currentChainCode = derived.chainCode;\n }\n\n return {\n privateKey: currentKey,\n chainCode: currentChainCode,\n };\n}\n\n// =============================================================================\n// Key Pair Operations\n// =============================================================================\n\n/**\n * Get public key from private key\n * @param privateKey - Private key as hex string\n * @param compressed - Return compressed public key (default: true)\n */\nexport function getPublicKey(privateKey: string, compressed: boolean = true): string {\n const keyPair = ec.keyFromPrivate(privateKey, 'hex');\n return keyPair.getPublic(compressed, 'hex');\n}\n\n/**\n * Create key pair from private key\n */\nexport function createKeyPair(privateKey: string): KeyPair {\n return {\n privateKey,\n publicKey: getPublicKey(privateKey),\n };\n}\n\n// =============================================================================\n// Hash Functions\n// =============================================================================\n\n/**\n * Compute SHA256 hash\n */\nexport function sha256(data: string, inputEncoding: 'hex' | 'utf8' = 'hex'): string {\n const parsed =\n inputEncoding === 'hex'\n ? CryptoJS.enc.Hex.parse(data)\n : CryptoJS.enc.Utf8.parse(data);\n return CryptoJS.SHA256(parsed).toString();\n}\n\n/**\n * Compute RIPEMD160 hash\n */\nexport function ripemd160(data: string, inputEncoding: 'hex' | 'utf8' = 'hex'): string {\n const parsed =\n inputEncoding === 'hex'\n ? CryptoJS.enc.Hex.parse(data)\n : CryptoJS.enc.Utf8.parse(data);\n return CryptoJS.RIPEMD160(parsed).toString();\n}\n\n/**\n * Compute HASH160 (SHA256 -> RIPEMD160)\n */\nexport function hash160(data: string): string {\n const sha = sha256(data, 'hex');\n return ripemd160(sha, 'hex');\n}\n\n/**\n * Compute double SHA256\n */\nexport function doubleSha256(data: string, inputEncoding: 'hex' | 'utf8' = 'hex'): string {\n const first = sha256(data, inputEncoding);\n return sha256(first, 'hex');\n}\n\n/**\n * Alias for hash160 (L1 SDK compatibility)\n */\nexport const computeHash160 = hash160;\n\n/**\n * Convert hex string to Uint8Array for witness program\n */\nexport function hash160ToBytes(hash160Hex: string): Uint8Array {\n const matches = hash160Hex.match(/../g);\n if (!matches) return new Uint8Array(0);\n return Uint8Array.from(matches.map((x) => parseInt(x, 16)));\n}\n\n/**\n * Generate bech32 address from public key\n * @param publicKey - Compressed public key as hex string\n * @param prefix - Address prefix (default: \"alpha\")\n * @param witnessVersion - Witness version (default: 0 for P2WPKH)\n * @returns Bech32 encoded address\n */\nexport function publicKeyToAddress(\n publicKey: string,\n prefix: string = 'alpha',\n witnessVersion: number = 0\n): string {\n const pubKeyHash = hash160(publicKey);\n const programBytes = hash160ToBytes(pubKeyHash);\n return encodeBech32(prefix, witnessVersion, programBytes);\n}\n\n/**\n * Get address info from private key\n */\nexport function privateKeyToAddressInfo(\n privateKey: string,\n prefix: string = 'alpha'\n): { address: string; publicKey: string } {\n const publicKey = getPublicKey(privateKey);\n const address = publicKeyToAddress(publicKey, prefix);\n return { address, publicKey };\n}\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\n/**\n * Convert hex string to Uint8Array\n */\nexport function hexToBytes(hex: string): Uint8Array {\n const matches = hex.match(/../g);\n if (!matches) {\n return new Uint8Array(0);\n }\n return Uint8Array.from(matches.map((x) => parseInt(x, 16)));\n}\n\n/**\n * Convert Uint8Array to hex string\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Generate random bytes as hex string\n */\nexport function randomBytes(length: number): string {\n const words = CryptoJS.lib.WordArray.random(length);\n return words.toString(CryptoJS.enc.Hex);\n}\n\n// =============================================================================\n// High-Level Functions\n// =============================================================================\n\n/**\n * Generate identity from mnemonic\n * Returns master key derived from mnemonic seed\n */\nexport async function identityFromMnemonic(\n mnemonic: string,\n passphrase: string = ''\n): Promise<MasterKey> {\n if (!validateMnemonic(mnemonic)) {\n throw new Error('Invalid mnemonic phrase');\n }\n const seedHex = await mnemonicToSeed(mnemonic, passphrase);\n return generateMasterKey(seedHex);\n}\n\n/**\n * Synchronous version of identityFromMnemonic\n */\nexport function identityFromMnemonicSync(\n mnemonic: string,\n passphrase: string = ''\n): MasterKey {\n if (!validateMnemonic(mnemonic)) {\n throw new Error('Invalid mnemonic phrase');\n }\n const seedHex = mnemonicToSeedSync(mnemonic, passphrase);\n return generateMasterKey(seedHex);\n}\n\n/**\n * Derive address info at a specific path\n * @param masterKey - Master key with privateKey and chainCode\n * @param basePath - Base derivation path (e.g., \"m/44'/0'/0'\")\n * @param index - Address index\n * @param isChange - Whether this is a change address (chain 1 vs 0)\n * @param prefix - Address prefix (default: \"alpha\")\n */\nexport function deriveAddressInfo(\n masterKey: MasterKey,\n basePath: string,\n index: number,\n isChange: boolean = false,\n prefix: string = 'alpha'\n): AddressInfo {\n const chain = isChange ? 1 : 0;\n const fullPath = `${basePath}/${chain}/${index}`;\n\n const derived = deriveKeyAtPath(masterKey.privateKey, masterKey.chainCode, fullPath);\n const publicKey = getPublicKey(derived.privateKey);\n const address = publicKeyToAddress(publicKey, prefix);\n\n return {\n privateKey: derived.privateKey,\n publicKey,\n address,\n path: fullPath,\n index,\n };\n}\n\n/**\n * Generate full address info from private key with index and path\n * (L1 SDK compatibility)\n */\nexport function generateAddressInfo(\n privateKey: string,\n index: number,\n path: string,\n prefix: string = 'alpha'\n): AddressInfo {\n const { address, publicKey } = privateKeyToAddressInfo(privateKey, prefix);\n return {\n privateKey,\n publicKey,\n address,\n path,\n index,\n };\n}\n\n// Re-export elliptic instance for advanced use cases\nexport { ec };\n","/**\n * Bech32 Encoding/Decoding\n * BIP-173 implementation for address encoding\n */\n\n// =============================================================================\n// Constants\n// =============================================================================\n\n/** Bech32 character set from BIP-173 */\nexport const CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';\n\n/** Generator polynomial for checksum */\nconst GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];\n\n// =============================================================================\n// Bit Conversion\n// =============================================================================\n\n/**\n * Convert between bit arrays (8→5 or 5→8)\n */\nexport function convertBits(\n data: number[],\n fromBits: number,\n toBits: number,\n pad: boolean\n): number[] | null {\n let acc = 0;\n let bits = 0;\n const ret: number[] = [];\n const maxv = (1 << toBits) - 1;\n\n for (let i = 0; i < data.length; i++) {\n const value = data[i];\n if (value < 0 || value >> fromBits !== 0) return null;\n acc = (acc << fromBits) | value;\n bits += fromBits;\n while (bits >= toBits) {\n bits -= toBits;\n ret.push((acc >> bits) & maxv);\n }\n }\n\n if (pad) {\n if (bits > 0) {\n ret.push((acc << (toBits - bits)) & maxv);\n }\n } else if (bits >= fromBits || (acc << (toBits - bits)) & maxv) {\n return null;\n }\n\n return ret;\n}\n\n// =============================================================================\n// Internal Functions\n// =============================================================================\n\n/**\n * Expand HRP for checksum calculation\n */\nfunction hrpExpand(hrp: string): number[] {\n const ret: number[] = [];\n for (let i = 0; i < hrp.length; i++) ret.push(hrp.charCodeAt(i) >> 5);\n ret.push(0);\n for (let i = 0; i < hrp.length; i++) ret.push(hrp.charCodeAt(i) & 31);\n return ret;\n}\n\n/**\n * Calculate polymod checksum\n */\nfunction bech32Polymod(values: number[]): number {\n let chk = 1;\n for (let p = 0; p < values.length; p++) {\n const top = chk >> 25;\n chk = ((chk & 0x1ffffff) << 5) ^ values[p];\n for (let i = 0; i < 5; i++) {\n if ((top >> i) & 1) chk ^= GENERATOR[i];\n }\n }\n return chk;\n}\n\n/**\n * Create checksum for bech32\n */\nfunction bech32Checksum(hrp: string, data: number[]): number[] {\n const values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);\n const mod = bech32Polymod(values) ^ 1;\n\n const ret: number[] = [];\n for (let p = 0; p < 6; p++) {\n ret.push((mod >> (5 * (5 - p))) & 31);\n }\n return ret;\n}\n\n// =============================================================================\n// Public API\n// =============================================================================\n\n/**\n * Encode data to bech32 address\n *\n * @example\n * ```ts\n * const address = encodeBech32('alpha', 1, pubkeyHash);\n * // 'alpha1qw...'\n * ```\n */\nexport function encodeBech32(\n hrp: string,\n version: number,\n program: Uint8Array\n): string {\n if (version < 0 || version > 16) {\n throw new Error('Invalid witness version');\n }\n\n const converted = convertBits(Array.from(program), 8, 5, true);\n if (!converted) {\n throw new Error('Failed to convert bits');\n }\n\n const data = [version].concat(converted);\n const checksum = bech32Checksum(hrp, data);\n const combined = data.concat(checksum);\n\n let out = hrp + '1';\n for (let i = 0; i < combined.length; i++) {\n out += CHARSET[combined[i]];\n }\n\n return out;\n}\n\n/**\n * Decode bech32 address\n *\n * @example\n * ```ts\n * const result = decodeBech32('alpha1qw...');\n * // { hrp: 'alpha', witnessVersion: 1, data: Uint8Array }\n * ```\n */\nexport function decodeBech32(\n addr: string\n): { hrp: string; witnessVersion: number; data: Uint8Array } | null {\n addr = addr.toLowerCase();\n\n const pos = addr.lastIndexOf('1');\n if (pos < 1) return null;\n\n const hrp = addr.substring(0, pos);\n const dataStr = addr.substring(pos + 1);\n\n const data: number[] = [];\n for (let i = 0; i < dataStr.length; i++) {\n const val = CHARSET.indexOf(dataStr[i]);\n if (val === -1) return null;\n data.push(val);\n }\n\n // Validate checksum\n const checksum = bech32Checksum(hrp, data.slice(0, -6));\n for (let i = 0; i < 6; i++) {\n if (checksum[i] !== data[data.length - 6 + i]) {\n return null;\n }\n }\n\n const version = data[0];\n const program = convertBits(data.slice(1, -6), 5, 8, false);\n if (!program) return null;\n\n return {\n hrp,\n witnessVersion: version,\n data: Uint8Array.from(program),\n };\n}\n\n/**\n * Create address from public key hash\n *\n * @example\n * ```ts\n * const address = createAddress('alpha', pubkeyHash);\n * // 'alpha1...'\n * ```\n */\nexport function createAddress(hrp: string, pubkeyHash: Uint8Array | string): string {\n const hashBytes = typeof pubkeyHash === 'string'\n ? Uint8Array.from(Buffer.from(pubkeyHash, 'hex'))\n : pubkeyHash;\n\n return encodeBech32(hrp, 1, hashBytes);\n}\n\n/**\n * Validate bech32 address\n */\nexport function isValidBech32(addr: string): boolean {\n return decodeBech32(addr) !== null;\n}\n\n/**\n * Get HRP from address\n */\nexport function getAddressHrp(addr: string): string | null {\n const result = decodeBech32(addr);\n return result?.hrp ?? null;\n}\n\n// =============================================================================\n// Aliases for L1 SDK compatibility\n// =============================================================================\n\n/**\n * Alias for encodeBech32 (L1 SDK compatibility)\n */\nexport const createBech32 = encodeBech32;\n","/**\n * WebSocket Abstraction\n * Platform-independent WebSocket interface for cross-platform support\n */\n\n// =============================================================================\n// WebSocket Interface\n// =============================================================================\n\n/**\n * Minimal WebSocket interface compatible with browser and Node.js\n */\nexport interface IWebSocket {\n readonly readyState: number;\n\n send(data: string): void;\n close(code?: number, reason?: string): void;\n\n onopen: ((event: unknown) => void) | null;\n onclose: ((event: unknown) => void) | null;\n onerror: ((event: unknown) => void) | null;\n onmessage: ((event: IMessageEvent) => void) | null;\n}\n\nexport interface IMessageEvent {\n data: string;\n}\n\n/**\n * WebSocket ready states (same as native WebSocket)\n */\nexport const WebSocketReadyState = {\n CONNECTING: 0,\n OPEN: 1,\n CLOSING: 2,\n CLOSED: 3,\n} as const;\n\n/**\n * Factory function to create WebSocket instances\n * Different implementations for browser (native) vs Node.js (ws package)\n */\nexport type WebSocketFactory = (url: string) => IWebSocket;\n\n// =============================================================================\n// UUID Generator\n// =============================================================================\n\n/**\n * Generate a unique ID (platform-independent)\n * Browser: crypto.randomUUID()\n * Node: crypto.randomUUID() or uuid package\n */\nexport type UUIDGenerator = () => string;\n\n/**\n * Default UUID generator using crypto.randomUUID\n * Works in modern browsers and Node 19+\n */\nexport function defaultUUIDGenerator(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // Fallback for older environments\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n","/**\n * Browser Transport Exports\n * Re-exports shared transport with browser-specific WebSocket factory\n */\n\nimport {\n NostrTransportProvider,\n type NostrTransportProviderConfig,\n} from '../../../transport/NostrTransportProvider';\nimport type { IWebSocket } from '../../../transport/websocket';\n\n// Re-export shared types and classes\nexport {\n NostrTransportProvider,\n type NostrTransportProviderConfig,\n} from '../../../transport/NostrTransportProvider';\n\nexport {\n type IWebSocket,\n type IMessageEvent,\n type WebSocketFactory,\n type UUIDGenerator,\n WebSocketReadyState,\n defaultUUIDGenerator,\n} from '../../../transport/websocket';\n\n// =============================================================================\n// Browser WebSocket Factory\n// =============================================================================\n\n/**\n * Browser WebSocket factory using native WebSocket\n * Cast to IWebSocket since native WebSocket is a superset\n */\nexport function createBrowserWebSocket(url: string): IWebSocket {\n return new WebSocket(url) as unknown as IWebSocket;\n}\n\n/**\n * Create NostrTransportProvider with browser WebSocket\n * Convenience factory that injects browser-native WebSocket\n */\nexport function createNostrTransportProvider(\n config?: Omit<NostrTransportProviderConfig, 'createWebSocket'>\n): NostrTransportProvider {\n return new NostrTransportProvider({\n ...config,\n createWebSocket: createBrowserWebSocket,\n });\n}\n","/**\n * Unicity Aggregator Provider\n * Platform-independent implementation using @unicitylabs/state-transition-sdk\n *\n * The oracle is a trusted service that provides verifiable truth\n * about token state through cryptographic inclusion proofs.\n *\n * TrustBaseLoader is injected for platform-specific loading:\n * - Browser: fetch from URL\n * - Node.js: read from file\n */\n\nimport type { ProviderStatus } from '../types';\nimport type {\n OracleProvider,\n TransferCommitment,\n SubmitResult,\n InclusionProof,\n WaitOptions,\n ValidationResult,\n TokenState,\n MintParams,\n MintResult,\n OracleEvent,\n OracleEventCallback,\n TrustBaseLoader,\n} from './oracle-provider';\nimport { DEFAULT_AGGREGATOR_TIMEOUT, TIMEOUTS } from '../constants';\n\n// SDK imports - using direct imports from the SDK\nimport { StateTransitionClient } from '@unicitylabs/state-transition-sdk/lib/StateTransitionClient';\nimport { AggregatorClient } from '@unicitylabs/state-transition-sdk/lib/api/AggregatorClient';\nimport { RootTrustBase } from '@unicitylabs/state-transition-sdk/lib/bft/RootTrustBase';\nimport { Token as SdkToken } from '@unicitylabs/state-transition-sdk/lib/token/Token';\nimport { waitInclusionProof } from '@unicitylabs/state-transition-sdk/lib/util/InclusionProofUtils';\nimport type { TransferCommitment as SdkTransferCommitment } from '@unicitylabs/state-transition-sdk/lib/transaction/TransferCommitment';\n\n// SDK MintCommitment type - using interface to avoid generic complexity\ninterface SdkMintCommitment {\n requestId?: { toString(): string };\n [key: string]: unknown;\n}\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\nexport interface UnicityAggregatorProviderConfig {\n /** Aggregator URL */\n url: string;\n /** API key for authentication */\n apiKey?: string;\n /** Request timeout (ms) */\n timeout?: number;\n /** Skip trust base verification (dev only) */\n skipVerification?: boolean;\n /** Enable debug logging */\n debug?: boolean;\n /** Trust base loader (platform-specific) */\n trustBaseLoader?: TrustBaseLoader;\n}\n\n// =============================================================================\n// RPC Response Types\n// =============================================================================\n\ninterface RpcSubmitResponse {\n requestId?: string;\n}\n\ninterface RpcProofResponse {\n proof?: unknown;\n roundNumber?: number;\n}\n\ninterface RpcValidateResponse {\n valid?: boolean;\n spent?: boolean;\n stateHash?: string;\n error?: string;\n}\n\ninterface RpcSpentResponse {\n spent?: boolean;\n}\n\ninterface RpcTokenStateResponse {\n state?: {\n stateHash?: string;\n spent?: boolean;\n roundNumber?: number;\n };\n}\n\ninterface RpcMintResponse {\n requestId?: string;\n tokenId?: string;\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\n/**\n * Unicity Aggregator Provider\n * Concrete implementation of OracleProvider using Unicity's aggregator service\n */\nexport class UnicityAggregatorProvider implements OracleProvider {\n readonly id = 'unicity-aggregator';\n readonly name = 'Unicity Aggregator';\n readonly type = 'network' as const;\n readonly description = 'Unicity state transition aggregator (oracle implementation)';\n\n private config: Required<Omit<UnicityAggregatorProviderConfig, 'trustBaseLoader'>> & {\n trustBaseLoader?: TrustBaseLoader;\n };\n private status: ProviderStatus = 'disconnected';\n private eventCallbacks: Set<OracleEventCallback> = new Set();\n\n // SDK clients\n private aggregatorClient: AggregatorClient | null = null;\n private stateTransitionClient: StateTransitionClient | null = null;\n private trustBase: RootTrustBase | null = null;\n\n /** Get the current trust base */\n getTrustBase(): RootTrustBase | null {\n return this.trustBase;\n }\n\n /** Get the state transition client */\n getStateTransitionClient(): StateTransitionClient | null {\n return this.stateTransitionClient;\n }\n\n /** Get the aggregator client */\n getAggregatorClient(): AggregatorClient | null {\n return this.aggregatorClient;\n }\n\n // Cache for spent states (immutable)\n private spentCache: Map<string, boolean> = new Map();\n\n constructor(config: UnicityAggregatorProviderConfig) {\n this.config = {\n url: config.url,\n apiKey: config.apiKey ?? '',\n timeout: config.timeout ?? DEFAULT_AGGREGATOR_TIMEOUT,\n skipVerification: config.skipVerification ?? false,\n debug: config.debug ?? false,\n trustBaseLoader: config.trustBaseLoader,\n };\n }\n\n // ===========================================================================\n // BaseProvider Implementation\n // ===========================================================================\n\n async connect(): Promise<void> {\n if (this.status === 'connected') return;\n\n this.status = 'connecting';\n\n // Mark as connected - actual connectivity will be verified on first operation\n // The aggregator requires requestId in params even for status checks,\n // which the SDK client doesn't support directly\n this.status = 'connected';\n this.emitEvent({ type: 'oracle:connected', timestamp: Date.now() });\n this.log('Connected to oracle:', this.config.url);\n }\n\n async disconnect(): Promise<void> {\n this.status = 'disconnected';\n this.emitEvent({ type: 'oracle:disconnected', timestamp: Date.now() });\n this.log('Disconnected from oracle');\n }\n\n isConnected(): boolean {\n return this.status === 'connected';\n }\n\n getStatus(): ProviderStatus {\n return this.status;\n }\n\n // ===========================================================================\n // OracleProvider Implementation\n // ===========================================================================\n\n async initialize(trustBase?: RootTrustBase): Promise<void> {\n // Initialize SDK clients with optional API key\n this.aggregatorClient = new AggregatorClient(\n this.config.url,\n this.config.apiKey || null\n );\n this.stateTransitionClient = new StateTransitionClient(this.aggregatorClient);\n\n if (trustBase) {\n this.trustBase = trustBase;\n } else if (!this.config.skipVerification && this.config.trustBaseLoader) {\n // Load trust base using injected loader\n try {\n const trustBaseJson = await this.config.trustBaseLoader.load();\n if (trustBaseJson) {\n this.trustBase = RootTrustBase.fromJSON(trustBaseJson);\n }\n } catch (error) {\n this.log('Failed to load trust base:', error);\n }\n }\n\n await this.connect();\n this.log('Initialized with trust base:', !!this.trustBase);\n }\n\n /**\n * Submit a transfer commitment to the aggregator.\n * Accepts either an SDK TransferCommitment or a simple commitment object.\n */\n async submitCommitment(commitment: TransferCommitment | SdkTransferCommitment): Promise<SubmitResult> {\n this.ensureConnected();\n\n try {\n let requestId: string;\n\n // Check if it's an SDK commitment (has submitTransferCommitment method signature)\n if (this.isSdkTransferCommitment(commitment)) {\n // Use SDK client directly\n const response = await this.stateTransitionClient!.submitTransferCommitment(commitment);\n requestId = commitment.requestId?.toString() ?? response.status;\n } else {\n // Fallback to RPC for simple commitment objects\n const response = await this.rpcCall<RpcSubmitResponse>('submitCommitment', {\n sourceToken: commitment.sourceToken,\n recipient: commitment.recipient,\n salt: Array.from(commitment.salt),\n data: commitment.data,\n });\n requestId = response.requestId ?? '';\n }\n\n this.emitEvent({\n type: 'commitment:submitted',\n timestamp: Date.now(),\n data: { requestId },\n });\n\n return {\n success: true,\n requestId,\n timestamp: Date.now(),\n };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n error: errorMsg,\n timestamp: Date.now(),\n };\n }\n }\n\n /**\n * Submit a mint commitment to the aggregator (SDK only)\n * @param commitment - SDK MintCommitment instance\n */\n async submitMintCommitment(commitment: SdkMintCommitment): Promise<SubmitResult> {\n this.ensureConnected();\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const response = await this.stateTransitionClient!.submitMintCommitment(commitment as any);\n const requestId = commitment.requestId?.toString() ?? response.status;\n\n this.emitEvent({\n type: 'commitment:submitted',\n timestamp: Date.now(),\n data: { requestId },\n });\n\n return {\n success: true,\n requestId,\n timestamp: Date.now(),\n };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n error: errorMsg,\n timestamp: Date.now(),\n };\n }\n }\n\n private isSdkTransferCommitment(commitment: unknown): commitment is SdkTransferCommitment {\n return (\n commitment !== null &&\n typeof commitment === 'object' &&\n 'requestId' in commitment &&\n typeof (commitment as SdkTransferCommitment).requestId?.toString === 'function'\n );\n }\n\n async getProof(requestId: string): Promise<InclusionProof | null> {\n this.ensureConnected();\n\n try {\n const response = await this.rpcCall<RpcProofResponse>('getInclusionProof', { requestId });\n\n if (!response.proof) {\n return null;\n }\n\n return {\n requestId,\n roundNumber: response.roundNumber ?? 0,\n proof: response.proof,\n timestamp: Date.now(),\n };\n } catch {\n return null;\n }\n }\n\n async waitForProof(requestId: string, options?: WaitOptions): Promise<InclusionProof> {\n const timeout = options?.timeout ?? this.config.timeout;\n const pollInterval = options?.pollInterval ?? TIMEOUTS.PROOF_POLL_INTERVAL;\n const startTime = Date.now();\n let attempt = 0;\n\n while (Date.now() - startTime < timeout) {\n options?.onPoll?.(++attempt);\n\n const proof = await this.getProof(requestId);\n if (proof) {\n this.emitEvent({\n type: 'proof:received',\n timestamp: Date.now(),\n data: { requestId, roundNumber: proof.roundNumber },\n });\n return proof;\n }\n\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n }\n\n throw new Error(`Timeout waiting for proof: ${requestId}`);\n }\n\n async validateToken(tokenData: unknown): Promise<ValidationResult> {\n this.ensureConnected();\n\n try {\n // Try SDK validation first if we have trust base\n if (this.trustBase && !this.config.skipVerification) {\n try {\n const sdkToken = await SdkToken.fromJSON(tokenData);\n const verifyResult = await sdkToken.verify(this.trustBase);\n\n // Calculate state hash\n const stateHash = await sdkToken.state.calculateHash();\n const stateHashStr = stateHash.toJSON();\n\n const valid = verifyResult.isSuccessful;\n\n this.emitEvent({\n type: 'validation:completed',\n timestamp: Date.now(),\n data: { valid },\n });\n\n return {\n valid,\n spent: false, // Spend check is separate\n stateHash: stateHashStr,\n error: valid ? undefined : 'SDK verification failed',\n };\n } catch (sdkError) {\n this.log('SDK validation failed, falling back to RPC:', sdkError);\n }\n }\n\n // Fallback to RPC validation\n const response = await this.rpcCall<RpcValidateResponse>('validateToken', { token: tokenData });\n\n const valid = response.valid ?? false;\n const spent = response.spent ?? false;\n\n this.emitEvent({\n type: 'validation:completed',\n timestamp: Date.now(),\n data: { valid },\n });\n\n // Cache spent state if spent\n if (response.stateHash && spent) {\n this.spentCache.set(response.stateHash, true);\n }\n\n return {\n valid,\n spent,\n stateHash: response.stateHash,\n error: response.error,\n };\n } catch (error) {\n return {\n valid: false,\n spent: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n /**\n * Wait for inclusion proof using SDK (for SDK commitments)\n */\n async waitForProofSdk(\n commitment: SdkTransferCommitment | SdkMintCommitment,\n signal?: AbortSignal\n ): Promise<unknown> {\n this.ensureConnected();\n\n if (!this.trustBase) {\n throw new Error('Trust base not initialized');\n }\n\n return await waitInclusionProof(\n this.trustBase,\n this.stateTransitionClient!,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n commitment as any,\n signal\n );\n }\n\n async isSpent(stateHash: string): Promise<boolean> {\n // Check cache first (spent is immutable)\n if (this.spentCache.has(stateHash)) {\n return this.spentCache.get(stateHash)!;\n }\n\n this.ensureConnected();\n\n try {\n const response = await this.rpcCall<RpcSpentResponse>('isSpent', { stateHash });\n const spent = response.spent ?? false;\n\n // Cache result\n if (spent) {\n this.spentCache.set(stateHash, true);\n }\n\n return spent;\n } catch {\n return false;\n }\n }\n\n async getTokenState(tokenId: string): Promise<TokenState | null> {\n this.ensureConnected();\n\n try {\n const response = await this.rpcCall<RpcTokenStateResponse>('getTokenState', { tokenId });\n\n if (!response.state) {\n return null;\n }\n\n return {\n tokenId,\n stateHash: response.state.stateHash ?? '',\n spent: response.state.spent ?? false,\n roundNumber: response.state.roundNumber,\n lastUpdated: Date.now(),\n };\n } catch {\n return null;\n }\n }\n\n async getCurrentRound(): Promise<number> {\n if (this.aggregatorClient) {\n const blockHeight = await this.aggregatorClient.getBlockHeight();\n return Number(blockHeight);\n }\n return 0;\n }\n\n async mint(params: MintParams): Promise<MintResult> {\n this.ensureConnected();\n\n try {\n const response = await this.rpcCall<RpcMintResponse>('mint', {\n coinId: params.coinId,\n amount: params.amount,\n recipientAddress: params.recipientAddress,\n recipientPubkey: params.recipientPubkey,\n });\n\n return {\n success: true,\n requestId: response.requestId,\n tokenId: response.tokenId,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n // ===========================================================================\n // Event Subscription\n // ===========================================================================\n\n onEvent(callback: OracleEventCallback): () => void {\n this.eventCallbacks.add(callback);\n return () => this.eventCallbacks.delete(callback);\n }\n\n // ===========================================================================\n // Private: RPC\n // ===========================================================================\n\n private async rpcCall<T>(method: string, params: unknown): Promise<T> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.timeout);\n\n try {\n const response = await fetch(this.config.url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: Date.now(),\n method,\n params,\n }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const result = await response.json();\n\n if (result.error) {\n throw new Error(result.error.message ?? 'RPC error');\n }\n\n return (result.result ?? {}) as T;\n } finally {\n clearTimeout(timeout);\n }\n }\n\n // ===========================================================================\n // Private: Helpers\n // ===========================================================================\n\n private ensureConnected(): void {\n if (this.status !== 'connected') {\n throw new Error('UnicityAggregatorProvider not connected');\n }\n }\n\n private emitEvent(event: OracleEvent): void {\n for (const callback of this.eventCallbacks) {\n try {\n callback(event);\n } catch (error) {\n this.log('Event callback error:', error);\n }\n }\n }\n\n private log(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[UnicityAggregatorProvider]', ...args);\n }\n }\n}\n\n// =============================================================================\n// Backward Compatibility Aliases (Oracle -> Aggregator)\n// =============================================================================\n\n/** @deprecated Use UnicityAggregatorProvider instead */\nexport const UnicityOracleProvider = UnicityAggregatorProvider;\n/** @deprecated Use UnicityAggregatorProviderConfig instead */\nexport type UnicityOracleProviderConfig = UnicityAggregatorProviderConfig;\n","/**\n * Embedded Trust Base Data\n * Pre-loaded trust base for different networks\n */\n\nexport const TRUSTBASE_TESTNET = {\n version: 1,\n networkId: 3,\n epoch: 1,\n epochStartRound: 1,\n rootNodes: [\n {\n nodeId: '16Uiu2HAkyQRiA7pMgzgLj9GgaBJEJa8zmx9dzqUDa6WxQPJ82ghU',\n sigKey: '0x039afb2acb65f5fbc272d8907f763d0a5d189aadc9b97afdcc5897ea4dd112e68b',\n stake: 1,\n },\n ],\n quorumThreshold: 1,\n stateHash: '',\n changeRecordHash: '',\n previousEntryHash: '',\n signatures: {\n '16Uiu2HAkyQRiA7pMgzgLj9GgaBJEJa8zmx9dzqUDa6WxQPJ82ghU':\n '0xf157c9fdd8a378e3ca70d354ccc4475ab2cd8de360127bc46b0aeab4b453a80f07fd9136a5843b60a8babaff23e20acc8879861f7651440a5e2829f7541b31f100',\n },\n};\n\n// Mainnet trust base (TODO: add when available)\nexport const TRUSTBASE_MAINNET = null;\n\n// Dev trust base (same as testnet for now)\nexport const TRUSTBASE_DEV = TRUSTBASE_TESTNET;\n","/**\n * Shared TrustBase Loader Logic\n * Common embedded trustbase data and base loader\n */\n\nimport { TRUSTBASE_TESTNET, TRUSTBASE_MAINNET, TRUSTBASE_DEV } from '../../assets/trustbase';\nimport type { NetworkType } from '../../constants';\n\nexport interface TrustBaseLoader {\n load(): Promise<unknown | null>;\n}\n\n/**\n * Get embedded trustbase data by network\n */\nexport function getEmbeddedTrustBase(network: NetworkType): unknown | null {\n switch (network) {\n case 'mainnet':\n return TRUSTBASE_MAINNET;\n case 'testnet':\n return TRUSTBASE_TESTNET;\n case 'dev':\n return TRUSTBASE_DEV;\n default:\n return TRUSTBASE_TESTNET;\n }\n}\n\n/**\n * Base TrustBase loader with embedded fallback\n */\nexport abstract class BaseTrustBaseLoader implements TrustBaseLoader {\n protected network: NetworkType;\n\n constructor(network: NetworkType = 'testnet') {\n this.network = network;\n }\n\n /**\n * Try to load from external source (file, URL, etc.)\n * Override in subclass\n */\n protected abstract loadFromExternal(): Promise<unknown | null>;\n\n async load(): Promise<unknown | null> {\n // Try external source first\n const external = await this.loadFromExternal();\n if (external) {\n return external;\n }\n\n // Fallback to embedded data\n return getEmbeddedTrustBase(this.network);\n }\n}\n","/**\n * Browser Oracle Exports\n * Re-exports shared oracle with browser-specific TrustBaseLoader\n */\n\nimport {\n UnicityAggregatorProvider,\n type UnicityAggregatorProviderConfig,\n} from '../../../oracle/UnicityAggregatorProvider';\nimport type { TrustBaseLoader } from '../../../oracle/oracle-provider';\nimport { BaseTrustBaseLoader } from '../../shared/trustbase-loader';\nimport type { NetworkType } from '../../../constants';\n\n// Re-export shared types and classes\nexport {\n UnicityAggregatorProvider,\n type UnicityAggregatorProviderConfig,\n UnicityOracleProvider,\n type UnicityOracleProviderConfig,\n} from '../../../oracle/UnicityAggregatorProvider';\n\nexport type { TrustBaseLoader } from '../../../oracle/oracle-provider';\n\n// =============================================================================\n// Browser TrustBase Loader\n// =============================================================================\n\n/**\n * Browser TrustBase loader - fetches from URL or uses embedded data\n */\nexport class BrowserTrustBaseLoader extends BaseTrustBaseLoader {\n private url?: string;\n\n constructor(networkOrUrl: NetworkType | string = 'testnet') {\n if (networkOrUrl.startsWith('/') || networkOrUrl.startsWith('http')) {\n super('testnet');\n this.url = networkOrUrl;\n } else {\n super(networkOrUrl as NetworkType);\n }\n }\n\n protected async loadFromExternal(): Promise<unknown | null> {\n if (!this.url) return null;\n\n try {\n const response = await fetch(this.url);\n if (response.ok) {\n return await response.json();\n }\n } catch {\n // Fall through to embedded\n }\n return null;\n }\n}\n\n/**\n * Create browser TrustBase loader\n */\nexport function createBrowserTrustBaseLoader(networkOrUrl?: NetworkType | string): TrustBaseLoader {\n return new BrowserTrustBaseLoader(networkOrUrl);\n}\n\n// =============================================================================\n// Browser Factory\n// =============================================================================\n\n/**\n * Create UnicityAggregatorProvider with browser TrustBase loader\n */\nexport function createUnicityAggregatorProvider(\n config: Omit<UnicityAggregatorProviderConfig, 'trustBaseLoader'> & {\n trustBaseUrl?: string;\n network?: NetworkType;\n }\n): UnicityAggregatorProvider {\n const { trustBaseUrl, network, ...restConfig } = config;\n return new UnicityAggregatorProvider({\n ...restConfig,\n trustBaseLoader: createBrowserTrustBaseLoader(trustBaseUrl ?? network ?? 'testnet'),\n });\n}\n\n/** @deprecated Use createUnicityAggregatorProvider instead */\nexport const createUnicityOracleProvider = createUnicityAggregatorProvider;\n","/**\n * Browser Download Utilities\n * Functions for downloading wallet backups as files\n */\n\nimport type { Sphere } from '../../core/Sphere';\nimport type { WalletJSON, WalletJSONExportOptions } from '../../types';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface DownloadTextOptions {\n /** Password for encryption */\n password?: string;\n /** Number of addresses to include */\n addressCount?: number;\n /** Custom filename (without extension) */\n filename?: string;\n}\n\nexport interface DownloadJSONOptions extends WalletJSONExportOptions {\n /** Custom filename (without extension) */\n filename?: string;\n /** Pretty print JSON (default: true) */\n pretty?: boolean;\n}\n\n// =============================================================================\n// Core Download Function\n// =============================================================================\n\n/**\n * Download content as a file in the browser\n */\nexport function downloadFile(\n content: string | Blob,\n filename: string,\n mimeType: string = 'text/plain'\n): void {\n const blob = content instanceof Blob\n ? content\n : new Blob([content], { type: mimeType });\n\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n\n link.href = url;\n link.download = filename;\n link.click();\n\n // Clean up the URL after a short delay\n setTimeout(() => URL.revokeObjectURL(url), 100);\n}\n\n/**\n * Download text content as a .txt file\n */\nexport function downloadTextFile(content: string, filename: string): void {\n downloadFile(content, filename, 'text/plain');\n}\n\n/**\n * Download JSON content as a .json file\n */\nexport function downloadJSONFile(content: object | string, filename: string): void {\n const jsonString = typeof content === 'string'\n ? content\n : JSON.stringify(content, null, 2);\n downloadFile(jsonString, filename, 'application/json');\n}\n\n// =============================================================================\n// Wallet Download Functions\n// =============================================================================\n\n/**\n * Download wallet backup as text file\n *\n * @example\n * ```ts\n * // Download unencrypted backup\n * downloadWalletText(sphere);\n *\n * // Download encrypted backup\n * downloadWalletText(sphere, { password: 'secret' });\n *\n * // Custom filename\n * downloadWalletText(sphere, { filename: 'my-backup' });\n * ```\n */\nexport function downloadWalletText(sphere: Sphere, options: DownloadTextOptions = {}): void {\n const content = sphere.exportToTxt({\n password: options.password,\n addressCount: options.addressCount,\n });\n\n const filename = options.filename\n ? `${options.filename}.txt`\n : `sphere-wallet-${Date.now()}.txt`;\n\n downloadTextFile(content, filename);\n}\n\n/**\n * Download wallet backup as JSON file\n *\n * @example\n * ```ts\n * // Download unencrypted backup\n * downloadWalletJSON(sphere);\n *\n * // Download encrypted backup\n * downloadWalletJSON(sphere, { password: 'secret' });\n *\n * // Include multiple addresses\n * downloadWalletJSON(sphere, { addressCount: 5 });\n * ```\n */\nexport function downloadWalletJSON(sphere: Sphere, options: DownloadJSONOptions = {}): void {\n const json = sphere.exportToJSON({\n password: options.password,\n addressCount: options.addressCount,\n includeMnemonic: options.includeMnemonic,\n });\n\n const filename = options.filename\n ? `${options.filename}.json`\n : `sphere-wallet-${Date.now()}.json`;\n\n const jsonString = options.pretty !== false\n ? JSON.stringify(json, null, 2)\n : JSON.stringify(json);\n\n downloadFile(jsonString, filename, 'application/json');\n}\n\n/**\n * Download pre-built WalletJSON as file\n */\nexport function downloadWalletJSONData(json: WalletJSON, filename?: string): void {\n const name = filename || `sphere-wallet-${Date.now()}.json`;\n downloadJSONFile(json, name.endsWith('.json') ? name : `${name}.json`);\n}\n\n// =============================================================================\n// File Reading Utilities\n// =============================================================================\n\n/**\n * Read a file as text\n */\nexport function readFileAsText(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as string);\n reader.onerror = () => reject(new Error('Failed to read file'));\n reader.readAsText(file);\n });\n}\n\n/**\n * Read a file as ArrayBuffer (for binary files like .dat)\n */\nexport function readFileAsArrayBuffer(file: File): Promise<ArrayBuffer> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as ArrayBuffer);\n reader.onerror = () => reject(new Error('Failed to read file'));\n reader.readAsArrayBuffer(file);\n });\n}\n\n/**\n * Read a file as Uint8Array (for binary files like .dat)\n */\nexport async function readFileAsUint8Array(file: File): Promise<Uint8Array> {\n const buffer = await readFileAsArrayBuffer(file);\n return new Uint8Array(buffer);\n}\n","/**\n * CoinGecko Price Provider\n *\n * Fetches token prices from CoinGecko API with internal caching.\n * Supports both free and pro API tiers.\n */\n\nimport type { PriceProvider, PricePlatform, TokenPrice, PriceProviderConfig } from './price-provider';\n\n// =============================================================================\n// Types\n// =============================================================================\n\ninterface CacheEntry {\n /** Token price, or null if the token was not found on the platform */\n price: TokenPrice | null;\n expiresAt: number;\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\n/**\n * CoinGecko price provider\n *\n * @example\n * ```ts\n * // Free tier (no API key)\n * const provider = new CoinGeckoPriceProvider();\n *\n * // Pro tier\n * const provider = new CoinGeckoPriceProvider({ apiKey: 'CG-xxx' });\n *\n * const prices = await provider.getPrices(['bitcoin', 'ethereum']);\n * console.log(prices.get('bitcoin')?.priceUsd);\n * ```\n */\nexport class CoinGeckoPriceProvider implements PriceProvider {\n readonly platform: PricePlatform = 'coingecko';\n\n private readonly cache: Map<string, CacheEntry> = new Map();\n private readonly apiKey?: string;\n private readonly cacheTtlMs: number;\n private readonly timeout: number;\n private readonly debug: boolean;\n private readonly baseUrl: string;\n\n constructor(config?: Omit<PriceProviderConfig, 'platform'>) {\n this.apiKey = config?.apiKey;\n this.cacheTtlMs = config?.cacheTtlMs ?? 60_000;\n this.timeout = config?.timeout ?? 10_000;\n this.debug = config?.debug ?? false;\n\n this.baseUrl = config?.baseUrl\n ?? (this.apiKey\n ? 'https://pro-api.coingecko.com/api/v3'\n : 'https://api.coingecko.com/api/v3');\n }\n\n async getPrices(tokenNames: string[]): Promise<Map<string, TokenPrice>> {\n if (tokenNames.length === 0) {\n return new Map();\n }\n\n const now = Date.now();\n const result = new Map<string, TokenPrice>();\n const uncachedNames: string[] = [];\n\n // Check cache first\n for (const name of tokenNames) {\n const cached = this.cache.get(name);\n if (cached && cached.expiresAt > now) {\n // null = negative cache (token not found on platform), skip adding to result\n if (cached.price !== null) {\n result.set(name, cached.price);\n }\n } else {\n uncachedNames.push(name);\n }\n }\n\n // All cached — return immediately\n if (uncachedNames.length === 0) {\n return result;\n }\n\n // Fetch uncached prices\n try {\n const ids = uncachedNames.join(',');\n const url = `${this.baseUrl}/simple/price?ids=${encodeURIComponent(ids)}&vs_currencies=usd,eur&include_24hr_change=true`;\n\n const headers: Record<string, string> = { Accept: 'application/json' };\n if (this.apiKey) {\n headers['x-cg-pro-api-key'] = this.apiKey;\n }\n\n if (this.debug) {\n console.log(`[CoinGecko] Fetching prices for: ${uncachedNames.join(', ')}`);\n }\n\n const response = await fetch(url, {\n headers,\n signal: AbortSignal.timeout(this.timeout),\n });\n\n if (!response.ok) {\n throw new Error(`CoinGecko API error: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json() as Record<string, Record<string, number>>;\n\n // Parse and cache response\n for (const [name, values] of Object.entries(data)) {\n if (values && typeof values === 'object') {\n const price: TokenPrice = {\n tokenName: name,\n priceUsd: values.usd ?? 0,\n priceEur: values.eur,\n change24h: values.usd_24h_change,\n timestamp: now,\n };\n this.cache.set(name, { price, expiresAt: now + this.cacheTtlMs });\n result.set(name, price);\n }\n }\n\n // Negative cache: tokens not found on CoinGecko won't be re-requested until TTL expires\n for (const name of uncachedNames) {\n if (!result.has(name)) {\n this.cache.set(name, { price: null, expiresAt: now + this.cacheTtlMs });\n }\n }\n\n if (this.debug) {\n console.log(`[CoinGecko] Fetched ${result.size} prices`);\n }\n } catch (error) {\n if (this.debug) {\n console.warn('[CoinGecko] Fetch failed, using stale cache:', error);\n }\n\n // On error, return stale cached data if available\n for (const name of uncachedNames) {\n const stale = this.cache.get(name);\n if (stale?.price) {\n result.set(name, stale.price);\n }\n }\n }\n\n return result;\n }\n\n async getPrice(tokenName: string): Promise<TokenPrice | null> {\n const prices = await this.getPrices([tokenName]);\n return prices.get(tokenName) ?? null;\n }\n\n clearCache(): void {\n this.cache.clear();\n }\n}\n","/**\n * Price Provider\n *\n * Token market price abstraction with CoinGecko implementation.\n */\n\nexport type {\n PriceProvider,\n PricePlatform,\n TokenPrice,\n PriceProviderConfig,\n} from './price-provider';\n\nexport { CoinGeckoPriceProvider } from './CoinGeckoPriceProvider';\n\n// =============================================================================\n// Factory\n// =============================================================================\n\nimport type { PriceProviderConfig, PriceProvider } from './price-provider';\nimport { CoinGeckoPriceProvider } from './CoinGeckoPriceProvider';\n\n/**\n * Create a price provider based on platform configuration\n *\n * @example\n * ```ts\n * const provider = createPriceProvider({ platform: 'coingecko', apiKey: 'CG-xxx' });\n * ```\n */\nexport function createPriceProvider(config: PriceProviderConfig): PriceProvider {\n switch (config.platform) {\n case 'coingecko':\n return new CoinGeckoPriceProvider(config);\n default:\n throw new Error(`Unsupported price platform: ${String(config.platform)}`);\n }\n}\n","/**\n * Configuration Resolvers\n * Utility functions for resolving provider configurations with extend/override pattern\n */\n\nimport { NETWORKS, DEFAULT_AGGREGATOR_API_KEY, type NetworkType, type NetworkConfig } from '../../constants';\nimport type {\n BaseTransportConfig,\n BaseOracleConfig,\n BasePriceConfig,\n L1Config,\n ResolvedTransportConfig,\n ResolvedOracleConfig,\n} from './config';\nimport type { PriceProviderConfig } from '../../price';\n\n// =============================================================================\n// Network Resolution\n// =============================================================================\n\n/**\n * Get network configuration by type\n */\nexport function getNetworkConfig(network: NetworkType = 'mainnet'): NetworkConfig {\n return NETWORKS[network];\n}\n\n// =============================================================================\n// Transport Resolution\n// =============================================================================\n\n/**\n * Resolve transport configuration with extend/override pattern\n *\n * Priority:\n * 1. `relays` - replaces defaults entirely\n * 2. `additionalRelays` - extends network defaults\n * 3. Network defaults\n *\n * @example\n * ```ts\n * // Use network defaults\n * resolveTransportConfig('testnet', undefined);\n *\n * // Replace relays entirely\n * resolveTransportConfig('testnet', { relays: ['wss://custom.relay'] });\n *\n * // Extend defaults\n * resolveTransportConfig('testnet', { additionalRelays: ['wss://extra.relay'] });\n * ```\n */\nexport function resolveTransportConfig(\n network: NetworkType,\n config?: BaseTransportConfig & { reconnectDelay?: number; maxReconnectAttempts?: number }\n): ResolvedTransportConfig {\n const networkConfig = getNetworkConfig(network);\n\n // Resolve relays with extend/override pattern\n let relays: string[];\n if (config?.relays) {\n // Explicit relays - replace entirely\n relays = config.relays;\n } else {\n // Start with network defaults\n relays = [...networkConfig.nostrRelays] as string[];\n // Add additional relays if specified\n if (config?.additionalRelays) {\n relays = [...relays, ...config.additionalRelays];\n }\n }\n\n return {\n relays,\n timeout: config?.timeout,\n autoReconnect: config?.autoReconnect,\n debug: config?.debug,\n // Browser-specific\n reconnectDelay: config?.reconnectDelay,\n maxReconnectAttempts: config?.maxReconnectAttempts,\n };\n}\n\n// =============================================================================\n// Oracle Resolution\n// =============================================================================\n\n/**\n * Resolve oracle configuration with override pattern\n *\n * Uses network default URL if not explicitly provided\n *\n * @example\n * ```ts\n * // Use network default\n * resolveOracleConfig('testnet', undefined);\n *\n * // Override URL\n * resolveOracleConfig('testnet', { url: 'https://custom.aggregator' });\n * ```\n */\nexport function resolveOracleConfig(\n network: NetworkType,\n config?: BaseOracleConfig & { trustBasePath?: string }\n): ResolvedOracleConfig {\n const networkConfig = getNetworkConfig(network);\n\n return {\n url: config?.url ?? networkConfig.aggregatorUrl,\n apiKey: config?.apiKey ?? DEFAULT_AGGREGATOR_API_KEY,\n timeout: config?.timeout,\n skipVerification: config?.skipVerification,\n debug: config?.debug,\n // Node.js-specific\n trustBasePath: config?.trustBasePath,\n };\n}\n\n// =============================================================================\n// L1 Resolution\n// =============================================================================\n\n/**\n * Resolve L1 configuration with override pattern\n *\n * Only returns config if l1 is explicitly provided (L1 is optional)\n *\n * @example\n * ```ts\n * // No L1 config - returns undefined\n * resolveL1Config('testnet', undefined);\n *\n * // Enable L1 with defaults\n * resolveL1Config('testnet', {});\n *\n * // Override electrum URL\n * resolveL1Config('testnet', { electrumUrl: 'wss://custom.fulcrum:50004' });\n * ```\n */\nexport function resolveL1Config(\n network: NetworkType,\n config?: L1Config\n): L1Config | undefined {\n if (config === undefined) {\n return undefined;\n }\n\n const networkConfig = getNetworkConfig(network);\n\n return {\n electrumUrl: config.electrumUrl ?? networkConfig.electrumUrl,\n defaultFeeRate: config.defaultFeeRate,\n enableVesting: config.enableVesting,\n };\n}\n\n// =============================================================================\n// Price Resolution\n// =============================================================================\n\n/**\n * Resolve price provider configuration\n *\n * Returns undefined if no price config is provided (price is optional).\n *\n * @example\n * ```ts\n * // No price config\n * resolvePriceConfig(undefined); // undefined\n *\n * // Minimal config (defaults to coingecko)\n * resolvePriceConfig({}); // { platform: 'coingecko' }\n *\n * // With API key\n * resolvePriceConfig({ apiKey: 'CG-xxx' }); // { platform: 'coingecko', apiKey: 'CG-xxx' }\n * ```\n */\nexport function resolvePriceConfig(\n config?: BasePriceConfig\n): PriceProviderConfig | undefined {\n if (config === undefined) {\n return undefined;\n }\n\n return {\n platform: config.platform ?? 'coingecko',\n apiKey: config.apiKey,\n baseUrl: config.baseUrl,\n cacheTtlMs: config.cacheTtlMs,\n timeout: config.timeout,\n debug: config.debug,\n };\n}\n\n// =============================================================================\n// Array Extension Helper\n// =============================================================================\n\n/**\n * Resolve array with extend/override pattern\n *\n * @param defaults - Default values from network config\n * @param replace - Values that replace defaults entirely\n * @param additional - Values to add to defaults\n * @returns Resolved array\n *\n * @example\n * ```ts\n * // Use defaults\n * resolveArrayConfig(['a', 'b'], undefined, undefined); // ['a', 'b']\n *\n * // Replace\n * resolveArrayConfig(['a', 'b'], ['x'], undefined); // ['x']\n *\n * // Extend\n * resolveArrayConfig(['a', 'b'], undefined, ['c']); // ['a', 'b', 'c']\n * ```\n */\nexport function resolveArrayConfig<T>(\n defaults: readonly T[],\n replace?: T[],\n additional?: T[]\n): T[] {\n if (replace) {\n return replace;\n }\n\n const result = [...defaults];\n if (additional) {\n return [...result, ...additional];\n }\n\n return result;\n}\n"],"mappings":"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","names":["import_buffer","elliptic","sha256","CryptoJS","NostrEventClass","SdkToken","valid"]}
1
+ {"version":3,"sources":["../../../impl/browser/index.ts","../../../constants.ts","../../../impl/browser/storage/LocalStorageProvider.ts","../../../impl/browser/storage/IndexedDBTokenStorageProvider.ts","../../../transport/NostrTransportProvider.ts","../../../node_modules/@noble/hashes/src/utils.ts","../../../node_modules/@noble/hashes/src/hmac.ts","../../../node_modules/@noble/hashes/src/hkdf.ts","../../../node_modules/@noble/hashes/src/_md.ts","../../../node_modules/@noble/hashes/src/sha2.ts","../../../core/crypto.ts","../../../core/bech32.ts","../../../transport/websocket.ts","../../../impl/browser/transport/index.ts","../../../oracle/UnicityAggregatorProvider.ts","../../../assets/trustbase.ts","../../../impl/shared/trustbase-loader.ts","../../../impl/browser/oracle/index.ts","../../../impl/browser/download.ts","../../../impl/shared/ipfs/ipfs-error-types.ts","../../../impl/shared/ipfs/ipfs-state-persistence.ts","../../../impl/shared/ipfs/ipns-key-derivation.ts","../../../impl/shared/ipfs/ipns-record-manager.ts","../../../impl/shared/ipfs/ipfs-cache.ts","../../../impl/shared/ipfs/ipfs-http-client.ts","../../../impl/shared/ipfs/txf-merge.ts","../../../impl/shared/ipfs/ipns-subscription-client.ts","../../../impl/shared/ipfs/write-behind-buffer.ts","../../../impl/shared/ipfs/ipfs-storage-provider.ts","../../../impl/browser/ipfs/browser-ipfs-state-persistence.ts","../../../impl/browser/ipfs/index.ts","../../../price/CoinGeckoPriceProvider.ts","../../../price/index.ts","../../../impl/shared/resolvers.ts"],"sourcesContent":["/**\n * Browser-specific implementations\n * All platform-dependent code lives here\n */\n\n// Polyfill Buffer for browser environment\n// Many crypto libraries depend on Node.js Buffer API\nimport { Buffer } from 'buffer';\nif (typeof globalThis.Buffer === 'undefined') {\n globalThis.Buffer = Buffer;\n}\n\nexport * from './storage';\nexport * from './transport';\nexport * from './oracle';\nexport * from './download';\n\n// Re-export shared types for convenience\nexport type {\n BaseTransportConfig,\n BaseOracleConfig,\n L1Config,\n BaseProviders,\n} from '../shared';\n\n// =============================================================================\n// Convenience Factory\n// =============================================================================\n\nimport { createLocalStorageProvider, type LocalStorageProviderConfig, createIndexedDBTokenStorageProvider } from './storage';\nimport { createNostrTransportProvider } from './transport';\nimport { createUnicityAggregatorProvider } from './oracle';\nimport { createBrowserIpfsStorageProvider } from './ipfs';\nimport type { StorageProvider, TokenStorageProvider, TxfStorageDataBase } from '../../storage';\nimport type { TransportProvider } from '../../transport';\nimport type { OracleProvider } from '../../oracle';\nimport type { NetworkType } from '../../constants';\nimport type { GroupChatModuleConfig } from '../../modules/groupchat';\nimport type { PriceProvider } from '../../price';\nimport { createPriceProvider } from '../../price';\nimport {\n type BaseTransportConfig,\n type BaseOracleConfig,\n type BasePriceConfig,\n type L1Config,\n type BrowserTransportExtensions,\n resolveTransportConfig,\n resolveOracleConfig,\n resolveL1Config,\n resolvePriceConfig,\n resolveArrayConfig,\n getNetworkConfig,\n resolveGroupChatConfig,\n} from '../shared';\n\n// =============================================================================\n// Browser-Specific Configuration Extensions\n// =============================================================================\n\n/**\n * Browser transport configuration\n * Extends base with browser-specific options\n */\nexport type TransportConfig = BaseTransportConfig & BrowserTransportExtensions;\n\n/**\n * Browser oracle configuration\n * Same as base (no browser-specific extensions)\n */\nexport type OracleConfig = BaseOracleConfig;\n\n// =============================================================================\n// Token Sync Backend Configurations\n// =============================================================================\n\n/**\n * IPFS sync backend configuration\n */\nexport interface IpfsSyncConfig {\n /** Enable IPFS sync (default: false) */\n enabled?: boolean;\n /** Replace default gateways entirely */\n gateways?: string[];\n /** Add gateways to network defaults */\n additionalGateways?: string[];\n /** Replace default bootstrap peers */\n bootstrapPeers?: string[];\n /** Add bootstrap peers to defaults */\n additionalBootstrapPeers?: string[];\n /** Use browser DHT (Helia) vs HTTP-only mode */\n useDht?: boolean;\n}\n\n/**\n * File sync backend configuration (future)\n */\nexport interface FileSyncConfig {\n /** Enable file sync (default: false) */\n enabled?: boolean;\n /** Directory path for token files */\n directory?: string;\n /** File format: 'json' | 'txf' */\n format?: 'json' | 'txf';\n}\n\n/**\n * Cloud sync backend configuration (future)\n */\nexport interface CloudSyncConfig {\n /** Enable cloud sync (default: false) */\n enabled?: boolean;\n /** Cloud provider */\n provider?: 'aws' | 'gcp' | 'azure' | 'custom';\n /** Bucket/container name */\n bucket?: string;\n /** API endpoint (for custom provider) */\n endpoint?: string;\n /** API key or credentials */\n apiKey?: string;\n}\n\n/**\n * MongoDB sync backend configuration\n */\nexport interface MongoDbSyncConfig {\n /** Enable MongoDB sync (default: false) */\n enabled?: boolean;\n /** MongoDB connection URI */\n uri?: string;\n /** Database name */\n database?: string;\n /** Collection name (default: 'tokens') */\n collection?: string;\n /** Enable authentication */\n authEnabled?: boolean;\n /** Username (if authEnabled) */\n username?: string;\n /** Password (if authEnabled) */\n password?: string;\n}\n\n/**\n * Token sync configuration - supports multiple backends\n */\nexport interface TokenSyncConfig {\n /** IPFS sync backend */\n ipfs?: IpfsSyncConfig;\n /** File sync backend (future) */\n file?: FileSyncConfig;\n /** Cloud sync backend (future) */\n cloud?: CloudSyncConfig;\n /** MongoDB sync backend */\n mongodb?: MongoDbSyncConfig;\n}\n\n// =============================================================================\n// Browser Providers Configuration\n// =============================================================================\n\nexport interface BrowserProvidersConfig {\n /** Network preset: mainnet, testnet, or dev. Sets default URLs for all services */\n network?: NetworkType;\n /** Storage configuration (localStorage) */\n storage?: LocalStorageProviderConfig;\n /** Transport (Nostr) configuration - supports extend/override pattern */\n transport?: TransportConfig;\n /** Oracle (Aggregator) configuration - supports extend/override pattern */\n oracle?: OracleConfig;\n /** L1 (ALPHA blockchain) configuration */\n l1?: L1Config;\n /**\n * Token sync backends configuration\n * Supports multiple backends: IPFS, file, cloud (future)\n * Each backend can be enabled/disabled independently\n */\n tokenSync?: TokenSyncConfig;\n /** Price provider configuration (optional — enables fiat value display) */\n price?: BasePriceConfig;\n /** Group chat (NIP-29) configuration. true = enable with defaults, object = custom config */\n groupChat?: { enabled?: boolean; relays?: string[] } | boolean;\n}\n\nexport interface BrowserProviders {\n storage: StorageProvider;\n transport: TransportProvider;\n oracle: OracleProvider;\n /** Token storage provider for local persistence (IndexedDB) */\n tokenStorage: TokenStorageProvider<TxfStorageDataBase>;\n /** L1 configuration (for passing to Sphere.init) */\n l1?: L1Config;\n /** Price provider (optional — enables fiat value display) */\n price?: PriceProvider;\n /** IPFS token storage provider (when tokenSync.ipfs.enabled is true) */\n ipfsTokenStorage?: TokenStorageProvider<TxfStorageDataBase>;\n /** Group chat config (resolved, for passing to Sphere.init) */\n groupChat?: GroupChatModuleConfig | boolean;\n /**\n * Token sync configuration (resolved from tokenSync options)\n * For advanced use cases when additional sync backends are needed\n * @deprecated Use tokenStorage provider instead. For custom sync backends,\n * use Sphere.addTokenStorageProvider() after initialization.\n */\n tokenSyncConfig?: {\n ipfs?: {\n enabled: boolean;\n gateways: string[];\n bootstrapPeers?: string[];\n useDht?: boolean;\n };\n file?: {\n enabled: boolean;\n directory?: string;\n format?: 'json' | 'txf';\n };\n cloud?: {\n enabled: boolean;\n provider?: string;\n bucket?: string;\n endpoint?: string;\n apiKey?: string;\n };\n mongodb?: {\n enabled: boolean;\n uri?: string;\n database?: string;\n collection?: string;\n };\n };\n}\n\n// =============================================================================\n// Token Sync Resolution\n// =============================================================================\n\n/**\n * Resolve IPFS sync configuration with extend/override pattern\n */\nfunction resolveIpfsSyncConfig(\n network: NetworkType,\n config?: IpfsSyncConfig\n): NonNullable<BrowserProviders['tokenSyncConfig']>['ipfs'] | undefined {\n if (!config) return undefined;\n\n const networkConfig = getNetworkConfig(network);\n const gateways = resolveArrayConfig(\n networkConfig.ipfsGateways,\n config.gateways,\n config.additionalGateways\n );\n\n return {\n enabled: config.enabled ?? false,\n gateways,\n bootstrapPeers: config.bootstrapPeers ?? config.additionalBootstrapPeers,\n useDht: config.useDht,\n };\n}\n\n/**\n * Resolve all token sync backends\n */\nfunction resolveTokenSyncConfig(\n network: NetworkType,\n config?: TokenSyncConfig\n): BrowserProviders['tokenSyncConfig'] {\n if (!config) return undefined;\n\n const result: BrowserProviders['tokenSyncConfig'] = {};\n\n // IPFS backend\n const ipfs = resolveIpfsSyncConfig(network, config.ipfs);\n if (ipfs) result.ipfs = ipfs;\n\n // File backend\n if (config.file) {\n result.file = {\n enabled: config.file.enabled ?? false,\n directory: config.file.directory,\n format: config.file.format,\n };\n }\n\n // Cloud backend\n if (config.cloud) {\n result.cloud = {\n enabled: config.cloud.enabled ?? false,\n provider: config.cloud.provider,\n bucket: config.cloud.bucket,\n endpoint: config.cloud.endpoint,\n apiKey: config.cloud.apiKey,\n };\n }\n\n // MongoDB backend\n if (config.mongodb) {\n result.mongodb = {\n enabled: config.mongodb.enabled ?? false,\n uri: config.mongodb.uri,\n database: config.mongodb.database,\n collection: config.mongodb.collection,\n };\n }\n\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\n/**\n * Create all browser providers with default configuration\n *\n * Supports extend/override pattern for flexible configuration:\n * - Use `network` preset for quick setup (mainnet/testnet/dev)\n * - Override specific values (e.g., `oracle.url` replaces default)\n * - Extend arrays with `additional*` (e.g., `additionalRelays` adds to defaults)\n *\n * @example\n * ```ts\n * // Simple - uses mainnet defaults\n * const providers = createBrowserProviders();\n *\n * // Testnet - all services use testnet URLs\n * const providers = createBrowserProviders({ network: 'testnet' });\n *\n * // Add extra relays to testnet defaults\n * const providers = createBrowserProviders({\n * network: 'testnet',\n * transport: {\n * additionalRelays: ['wss://my-relay.com', 'wss://backup-relay.com'],\n * },\n * });\n *\n * // Replace relays entirely (ignores network defaults)\n * const providers = createBrowserProviders({\n * network: 'testnet',\n * transport: {\n * relays: ['wss://only-this-relay.com'],\n * },\n * });\n *\n * // Use with Sphere.init (tokenStorage is automatically included)\n * const { sphere } = await Sphere.init({\n * ...providers,\n * autoGenerate: true,\n * });\n *\n * // Add additional sync backends dynamically after init\n * // await sphere.addTokenStorageProvider(myMongoDbProvider);\n * ```\n */\nexport function createBrowserProviders(config?: BrowserProvidersConfig): BrowserProviders {\n const network = config?.network ?? 'mainnet';\n\n // Resolve configurations using shared utilities\n const transportConfig = resolveTransportConfig(network, config?.transport);\n const oracleConfig = resolveOracleConfig(network, config?.oracle);\n const l1Config = resolveL1Config(network, config?.l1);\n const tokenSyncConfig = resolveTokenSyncConfig(network, config?.tokenSync);\n const priceConfig = resolvePriceConfig(config?.price);\n\n const storage = createLocalStorageProvider(config?.storage);\n\n // Create IPFS storage provider if enabled\n const ipfsConfig = tokenSyncConfig?.ipfs;\n const ipfsTokenStorage = ipfsConfig?.enabled\n ? createBrowserIpfsStorageProvider({\n gateways: ipfsConfig.gateways,\n debug: config?.tokenSync?.ipfs?.useDht, // reuse debug-like flag\n })\n : undefined;\n\n // Resolve group chat config\n const groupChat = resolveGroupChatConfig(network, config?.groupChat);\n\n return {\n storage,\n groupChat,\n transport: createNostrTransportProvider({\n relays: transportConfig.relays,\n timeout: transportConfig.timeout,\n autoReconnect: transportConfig.autoReconnect,\n reconnectDelay: transportConfig.reconnectDelay,\n maxReconnectAttempts: transportConfig.maxReconnectAttempts,\n debug: transportConfig.debug,\n storage,\n }),\n oracle: createUnicityAggregatorProvider({\n url: oracleConfig.url,\n apiKey: oracleConfig.apiKey,\n timeout: oracleConfig.timeout,\n skipVerification: oracleConfig.skipVerification,\n debug: oracleConfig.debug,\n network,\n }),\n tokenStorage: createIndexedDBTokenStorageProvider(),\n l1: l1Config,\n price: priceConfig ? createPriceProvider(priceConfig) : undefined,\n ipfsTokenStorage,\n tokenSyncConfig,\n };\n}\n","/**\n * SDK2 Constants\n * Default configuration values and storage keys\n */\n\n// =============================================================================\n// Storage Keys\n// =============================================================================\n\n/** Default prefix for all storage keys */\nexport const STORAGE_PREFIX = 'sphere_' as const;\n\n/**\n * Default encryption key for wallet data\n * WARNING: This is a placeholder. In production, use user-provided password.\n * This key is used when no password is provided to encrypt/decrypt mnemonic.\n */\nexport const DEFAULT_ENCRYPTION_KEY = 'sphere-default-key' as const;\n\n/**\n * Global storage keys (one per wallet, no address index)\n * Final key format: sphere_{key}\n */\nexport const STORAGE_KEYS_GLOBAL = {\n /** Encrypted BIP39 mnemonic */\n MNEMONIC: 'mnemonic',\n /** Encrypted master private key */\n MASTER_KEY: 'master_key',\n /** BIP32 chain code */\n CHAIN_CODE: 'chain_code',\n /** HD derivation path (full path like m/44'/0'/0'/0/0) */\n DERIVATION_PATH: 'derivation_path',\n /** Base derivation path (like m/44'/0'/0' without chain/index) */\n BASE_PATH: 'base_path',\n /** Derivation mode: bip32, wif_hmac, legacy_hmac */\n DERIVATION_MODE: 'derivation_mode',\n /** Wallet source: mnemonic, file, unknown */\n WALLET_SOURCE: 'wallet_source',\n /** Wallet existence flag */\n WALLET_EXISTS: 'wallet_exists',\n /** Current active address index */\n CURRENT_ADDRESS_INDEX: 'current_address_index',\n /** Nametag cache per address (separate from tracked addresses registry) */\n ADDRESS_NAMETAGS: 'address_nametags',\n /** Active addresses registry (JSON: TrackedAddressesStorage) */\n TRACKED_ADDRESSES: 'tracked_addresses',\n /** Last processed Nostr wallet event timestamp (unix seconds), keyed per pubkey */\n LAST_WALLET_EVENT_TS: 'last_wallet_event_ts',\n /** Group chat: joined groups */\n GROUP_CHAT_GROUPS: 'group_chat_groups',\n /** Group chat: messages */\n GROUP_CHAT_MESSAGES: 'group_chat_messages',\n /** Group chat: members */\n GROUP_CHAT_MEMBERS: 'group_chat_members',\n /** Group chat: processed event IDs for deduplication */\n GROUP_CHAT_PROCESSED_EVENTS: 'group_chat_processed_events',\n /** Group chat: last used relay URL (stale data detection) */\n GROUP_CHAT_RELAY_URL: 'group_chat_relay_url',\n} as const;\n\n/**\n * Per-address storage keys (one per derived address)\n * Final key format: sphere_{DIRECT_xxx_yyy}_{key}\n * Example: sphere_DIRECT_abc123_xyz789_pending_transfers\n *\n * Note: Token data (tokens, tombstones, archived, forked) is stored via\n * TokenStorageProvider, not here. This avoids duplication.\n */\nexport const STORAGE_KEYS_ADDRESS = {\n /** Pending transfers for this address */\n PENDING_TRANSFERS: 'pending_transfers',\n /** Transfer outbox for this address */\n OUTBOX: 'outbox',\n /** Conversations for this address */\n CONVERSATIONS: 'conversations',\n /** Messages for this address */\n MESSAGES: 'messages',\n /** Transaction history for this address */\n TRANSACTION_HISTORY: 'transaction_history',\n /** Pending V5 finalization tokens (unconfirmed instant split tokens) */\n PENDING_V5_TOKENS: 'pending_v5_tokens',\n} as const;\n\n/** @deprecated Use STORAGE_KEYS_GLOBAL and STORAGE_KEYS_ADDRESS instead */\nexport const STORAGE_KEYS = {\n ...STORAGE_KEYS_GLOBAL,\n ...STORAGE_KEYS_ADDRESS,\n} as const;\n\n/**\n * Build a per-address storage key using address identifier\n * @param addressId - Short identifier for the address (e.g., first 8 chars of pubkey hash, or direct address hash)\n * @param key - The key from STORAGE_KEYS_ADDRESS\n * @returns Key in format: \"{addressId}_{key}\" e.g., \"a1b2c3d4_tokens\"\n */\nexport function getAddressStorageKey(addressId: string, key: string): string {\n return `${addressId}_${key}`;\n}\n\n/**\n * Create a readable address identifier from directAddress or chainPubkey\n * Format: DIRECT_first6_last6 (sanitized for filesystem/storage)\n * @param directAddress - The L3 direct address (DIRECT:xxx) or chainPubkey\n * @returns Sanitized identifier like \"DIRECT_abc123_xyz789\"\n */\nexport function getAddressId(directAddress: string): string {\n // Remove DIRECT:// or DIRECT: prefix if present\n let hash = directAddress;\n if (hash.startsWith('DIRECT://')) {\n hash = hash.slice(9);\n } else if (hash.startsWith('DIRECT:')) {\n hash = hash.slice(7);\n }\n // Format: DIRECT_first6_last6 (sanitized)\n const first = hash.slice(0, 6).toLowerCase();\n const last = hash.slice(-6).toLowerCase();\n return `DIRECT_${first}_${last}`;\n}\n\n// =============================================================================\n// Nostr Defaults\n// =============================================================================\n\n/** Default Nostr relays */\nexport const DEFAULT_NOSTR_RELAYS = [\n 'wss://relay.unicity.network',\n 'wss://relay.damus.io',\n 'wss://nos.lol',\n 'wss://relay.nostr.band',\n] as const;\n\n/** Nostr event kinds used by SDK - must match @unicitylabs/nostr-js-sdk */\nexport const NOSTR_EVENT_KINDS = {\n /** NIP-04 encrypted direct message */\n DIRECT_MESSAGE: 4,\n /** Token transfer (Unicity custom - 31113) */\n TOKEN_TRANSFER: 31113,\n /** Payment request (Unicity custom - 31115) */\n PAYMENT_REQUEST: 31115,\n /** Payment request response (Unicity custom - 31116) */\n PAYMENT_REQUEST_RESPONSE: 31116,\n /** Nametag binding (NIP-78 app-specific data) */\n NAMETAG_BINDING: 30078,\n /** Public broadcast */\n BROADCAST: 1,\n} as const;\n\n/**\n * NIP-29 Event Kinds for relay-based group chat\n * https://github.com/nostr-protocol/nips/blob/master/29.md\n */\nexport const NIP29_KINDS = {\n /** Chat message sent to group */\n CHAT_MESSAGE: 9,\n /** Thread root message */\n THREAD_ROOT: 11,\n /** Thread reply message */\n THREAD_REPLY: 12,\n /** User join request */\n JOIN_REQUEST: 9021,\n /** User leave request */\n LEAVE_REQUEST: 9022,\n /** Admin: add/update user */\n PUT_USER: 9000,\n /** Admin: remove user */\n REMOVE_USER: 9001,\n /** Admin: edit group metadata */\n EDIT_METADATA: 9002,\n /** Admin: delete event */\n DELETE_EVENT: 9005,\n /** Admin: create group */\n CREATE_GROUP: 9007,\n /** Admin: delete group */\n DELETE_GROUP: 9008,\n /** Admin: create invite code */\n CREATE_INVITE: 9009,\n /** Relay-signed group metadata */\n GROUP_METADATA: 39000,\n /** Relay-signed group admins */\n GROUP_ADMINS: 39001,\n /** Relay-signed group members */\n GROUP_MEMBERS: 39002,\n /** Relay-signed group roles */\n GROUP_ROLES: 39003,\n} as const;\n\n// =============================================================================\n// Aggregator (Oracle) Defaults\n// =============================================================================\n\n/**\n * Default aggregator URL\n * Note: The aggregator is conceptually an oracle - a trusted service that provides\n * verifiable truth about token state through cryptographic inclusion proofs.\n */\nexport const DEFAULT_AGGREGATOR_URL = 'https://aggregator.unicity.network/rpc' as const;\n\n/** Dev aggregator URL */\nexport const DEV_AGGREGATOR_URL = 'https://dev-aggregator.dyndns.org/rpc' as const;\n\n/** Test aggregator URL (Goggregator) */\nexport const TEST_AGGREGATOR_URL = 'https://goggregator-test.unicity.network' as const;\n\n/** Default aggregator request timeout (ms) */\nexport const DEFAULT_AGGREGATOR_TIMEOUT = 30000;\n\n/** Default API key for aggregator authentication */\nexport const DEFAULT_AGGREGATOR_API_KEY = 'sk_06365a9c44654841a366068bcfc68986' as const;\n\n// =============================================================================\n// IPFS Defaults\n// =============================================================================\n\n/** Default IPFS gateways */\nexport const DEFAULT_IPFS_GATEWAYS = [\n 'https://ipfs.unicity.network',\n 'https://dweb.link',\n 'https://ipfs.io',\n] as const;\n\n/** Unicity IPFS bootstrap peers */\nexport const DEFAULT_IPFS_BOOTSTRAP_PEERS = [\n '/dns4/unicity-ipfs2.dyndns.org/tcp/4001/p2p/12D3KooWLNi5NDPPHbrfJakAQqwBqymYTTwMQXQKEWuCrJNDdmfh',\n '/dns4/unicity-ipfs3.dyndns.org/tcp/4001/p2p/12D3KooWQ4aujVE4ShLjdusNZBdffq3TbzrwT2DuWZY9H1Gxhwn6',\n '/dns4/unicity-ipfs4.dyndns.org/tcp/4001/p2p/12D3KooWJ1ByPfUzUrpYvgxKU8NZrR8i6PU1tUgMEbQX9Hh2DEn1',\n '/dns4/unicity-ipfs5.dyndns.org/tcp/4001/p2p/12D3KooWB1MdZZGHN5B8TvWXntbycfe7Cjcz7n6eZ9eykZadvmDv',\n] as const;\n\n/** Unicity dedicated IPFS nodes (HTTP API access) */\nexport const UNICITY_IPFS_NODES = [\n {\n host: 'unicity-ipfs1.dyndns.org',\n peerId: '12D3KooWDKJqEMAhH4nsSSiKtK1VLcas5coUqSPZAfbWbZpxtL4u',\n httpPort: 9080,\n httpsPort: 443,\n },\n] as const;\n\n/**\n * Get IPFS gateway URLs for HTTP API access.\n * @param isSecure - Use HTTPS (default: true). Set false for development.\n */\nexport function getIpfsGatewayUrls(isSecure?: boolean): string[] {\n return UNICITY_IPFS_NODES.map((node) =>\n isSecure !== false\n ? `https://${node.host}`\n : `http://${node.host}:${node.httpPort}`,\n );\n}\n\n// =============================================================================\n// Wallet Defaults\n// =============================================================================\n\n/** Default BIP32 base path (without chain/index) */\nexport const DEFAULT_BASE_PATH = \"m/44'/0'/0'\" as const;\n\n/** Default BIP32 derivation path (full path with chain/index) */\nexport const DEFAULT_DERIVATION_PATH = `${DEFAULT_BASE_PATH}/0/0` as const;\n\n/** Coin types */\nexport const COIN_TYPES = {\n /** ALPHA token (L1 blockchain) */\n ALPHA: 'ALPHA',\n /** Test token */\n TEST: 'TEST',\n} as const;\n\n// =============================================================================\n// L1 (ALPHA Blockchain) Defaults\n// =============================================================================\n\n/** Default Fulcrum electrum server for mainnet */\nexport const DEFAULT_ELECTRUM_URL = 'wss://fulcrum.alpha.unicity.network:50004' as const;\n\n/** Testnet Fulcrum electrum server */\nexport const TEST_ELECTRUM_URL = 'wss://fulcrum.alpha.testnet.unicity.network:50004' as const;\n\n// =============================================================================\n// Network Defaults\n// =============================================================================\n\n/** Testnet Nostr relays */\nexport const TEST_NOSTR_RELAYS = [\n 'wss://nostr-relay.testnet.unicity.network',\n] as const;\n\n/** Default group chat relays (NIP-29 Zooid relay) */\nexport const DEFAULT_GROUP_RELAYS = [\n 'wss://sphere-relay.unicity.network',\n] as const;\n\n/** Network configurations */\nexport const NETWORKS = {\n mainnet: {\n name: 'Mainnet',\n aggregatorUrl: DEFAULT_AGGREGATOR_URL,\n nostrRelays: DEFAULT_NOSTR_RELAYS,\n ipfsGateways: DEFAULT_IPFS_GATEWAYS,\n electrumUrl: DEFAULT_ELECTRUM_URL,\n groupRelays: DEFAULT_GROUP_RELAYS,\n },\n testnet: {\n name: 'Testnet',\n aggregatorUrl: TEST_AGGREGATOR_URL,\n nostrRelays: TEST_NOSTR_RELAYS,\n ipfsGateways: DEFAULT_IPFS_GATEWAYS,\n electrumUrl: TEST_ELECTRUM_URL,\n groupRelays: DEFAULT_GROUP_RELAYS,\n },\n dev: {\n name: 'Development',\n aggregatorUrl: DEV_AGGREGATOR_URL,\n nostrRelays: TEST_NOSTR_RELAYS,\n ipfsGateways: DEFAULT_IPFS_GATEWAYS,\n electrumUrl: TEST_ELECTRUM_URL,\n groupRelays: DEFAULT_GROUP_RELAYS,\n },\n} as const;\n\nexport type NetworkType = keyof typeof NETWORKS;\nexport type NetworkConfig = (typeof NETWORKS)[NetworkType];\n\n// =============================================================================\n// Timeouts & Limits\n// =============================================================================\n\n/** Default timeouts (ms) */\nexport const TIMEOUTS = {\n /** WebSocket connection timeout */\n WEBSOCKET_CONNECT: 10000,\n /** Nostr relay reconnect delay */\n NOSTR_RECONNECT_DELAY: 3000,\n /** Max reconnect attempts */\n MAX_RECONNECT_ATTEMPTS: 5,\n /** Proof polling interval */\n PROOF_POLL_INTERVAL: 1000,\n /** Sync interval */\n SYNC_INTERVAL: 60000,\n} as const;\n\n/** Validation limits */\nexport const LIMITS = {\n /** Min nametag length */\n NAMETAG_MIN_LENGTH: 3,\n /** Max nametag length */\n NAMETAG_MAX_LENGTH: 20,\n /** Max memo length */\n MEMO_MAX_LENGTH: 500,\n /** Max message length */\n MESSAGE_MAX_LENGTH: 10000,\n} as const;\n","/**\n * Browser LocalStorage Provider\n * Implements StorageProvider using browser localStorage\n */\n\nimport type { ProviderStatus, FullIdentity, TrackedAddressEntry } from '../../../types';\nimport type { StorageProvider } from '../../../storage';\nimport { STORAGE_KEYS_ADDRESS, STORAGE_KEYS_GLOBAL, getAddressId } from '../../../constants';\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\nexport interface LocalStorageProviderConfig {\n /** Key prefix (default: 'sphere_') */\n prefix?: string;\n /** Custom storage instance (for testing/SSR) */\n storage?: Storage;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\nexport class LocalStorageProvider implements StorageProvider {\n readonly id = 'localStorage';\n readonly name = 'Local Storage';\n readonly type = 'local' as const;\n readonly description = 'Browser localStorage for single-device persistence';\n\n private config: Required<Pick<LocalStorageProviderConfig, 'prefix' | 'debug'>> & {\n storage: Storage;\n };\n private identity: FullIdentity | null = null;\n private status: ProviderStatus = 'disconnected';\n\n constructor(config?: LocalStorageProviderConfig) {\n // SSR fallback: use in-memory storage if localStorage unavailable\n const storage = config?.storage ?? this.getStorageSafe();\n\n this.config = {\n prefix: config?.prefix ?? 'sphere_',\n storage,\n debug: config?.debug ?? false,\n };\n }\n\n // ===========================================================================\n // BaseProvider Implementation\n // ===========================================================================\n\n async connect(): Promise<void> {\n if (this.status === 'connected') return;\n\n this.status = 'connecting';\n\n try {\n // Test storage availability\n const testKey = `${this.config.prefix}_test`;\n this.config.storage.setItem(testKey, 'test');\n this.config.storage.removeItem(testKey);\n\n this.status = 'connected';\n this.log('Connected to localStorage');\n } catch (error) {\n this.status = 'error';\n throw new Error(`LocalStorage not available: ${error}`);\n }\n }\n\n async disconnect(): Promise<void> {\n this.status = 'disconnected';\n this.log('Disconnected from localStorage');\n }\n\n isConnected(): boolean {\n return this.status === 'connected';\n }\n\n getStatus(): ProviderStatus {\n return this.status;\n }\n\n // ===========================================================================\n // StorageProvider Implementation\n // ===========================================================================\n\n setIdentity(identity: FullIdentity): void {\n this.identity = identity;\n this.log('Identity set:', identity.l1Address);\n }\n\n async get(key: string): Promise<string | null> {\n this.ensureConnected();\n const fullKey = this.getFullKey(key);\n return this.config.storage.getItem(fullKey);\n }\n\n async set(key: string, value: string): Promise<void> {\n this.ensureConnected();\n const fullKey = this.getFullKey(key);\n this.config.storage.setItem(fullKey, value);\n }\n\n async remove(key: string): Promise<void> {\n this.ensureConnected();\n const fullKey = this.getFullKey(key);\n this.config.storage.removeItem(fullKey);\n }\n\n async has(key: string): Promise<boolean> {\n this.ensureConnected();\n const fullKey = this.getFullKey(key);\n return this.config.storage.getItem(fullKey) !== null;\n }\n\n async keys(prefix?: string): Promise<string[]> {\n this.ensureConnected();\n const basePrefix = this.getFullKey('');\n const searchPrefix = prefix ? this.getFullKey(prefix) : basePrefix;\n const result: string[] = [];\n\n for (let i = 0; i < this.config.storage.length; i++) {\n const key = this.config.storage.key(i);\n if (key?.startsWith(searchPrefix)) {\n // Return key without the base prefix\n result.push(key.slice(basePrefix.length));\n }\n }\n\n return result;\n }\n\n async clear(prefix?: string): Promise<void> {\n this.ensureConnected();\n const keysToRemove = await this.keys(prefix);\n for (const key of keysToRemove) {\n await this.remove(key);\n }\n }\n\n async saveTrackedAddresses(entries: TrackedAddressEntry[]): Promise<void> {\n await this.set(STORAGE_KEYS_GLOBAL.TRACKED_ADDRESSES, JSON.stringify({ version: 1, addresses: entries }));\n }\n\n async loadTrackedAddresses(): Promise<TrackedAddressEntry[]> {\n const data = await this.get(STORAGE_KEYS_GLOBAL.TRACKED_ADDRESSES);\n if (!data) return [];\n try {\n const parsed = JSON.parse(data);\n return parsed.addresses ?? [];\n } catch {\n return [];\n }\n }\n\n // ===========================================================================\n // Helpers\n // ===========================================================================\n\n /**\n * Get JSON data\n */\n async getJSON<T>(key: string): Promise<T | null> {\n const value = await this.get(key);\n if (!value) return null;\n try {\n return JSON.parse(value) as T;\n } catch {\n return null;\n }\n }\n\n /**\n * Set JSON data\n */\n async setJSON<T>(key: string, value: T): Promise<void> {\n await this.set(key, JSON.stringify(value));\n }\n\n // ===========================================================================\n // Private Methods\n // ===========================================================================\n\n private getFullKey(key: string): string {\n // Check if this is a per-address key\n const isPerAddressKey = Object.values(STORAGE_KEYS_ADDRESS).includes(key as typeof STORAGE_KEYS_ADDRESS[keyof typeof STORAGE_KEYS_ADDRESS]);\n\n if (isPerAddressKey && this.identity?.directAddress) {\n // Add address ID prefix for per-address data\n const addressId = getAddressId(this.identity.directAddress);\n return `${this.config.prefix}${addressId}_${key}`;\n }\n\n // Global key - no address prefix\n return `${this.config.prefix}${key}`;\n }\n\n private ensureConnected(): void {\n if (this.status !== 'connected') {\n throw new Error('LocalStorageProvider not connected');\n }\n }\n\n private getStorageSafe(): Storage {\n if (typeof window !== 'undefined' && window.localStorage) {\n return window.localStorage;\n }\n\n // SSR fallback: in-memory storage\n return createInMemoryStorage();\n }\n\n private log(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[LocalStorageProvider]', ...args);\n }\n }\n}\n\n// =============================================================================\n// In-Memory Storage (SSR Fallback)\n// =============================================================================\n\nfunction createInMemoryStorage(): Storage {\n const data = new Map<string, string>();\n\n return {\n get length() {\n return data.size;\n },\n clear() {\n data.clear();\n },\n getItem(key: string) {\n return data.get(key) ?? null;\n },\n setItem(key: string, value: string) {\n data.set(key, value);\n },\n removeItem(key: string) {\n data.delete(key);\n },\n key(index: number) {\n return Array.from(data.keys())[index] ?? null;\n },\n };\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\nexport function createLocalStorageProvider(\n config?: LocalStorageProviderConfig\n): LocalStorageProvider {\n return new LocalStorageProvider(config);\n}\n","/**\n * IndexedDB Token Storage Provider for Browser\n * Stores tokens in IndexedDB for persistent browser storage\n * Each address gets its own database for multi-address support\n */\n\nimport type { TokenStorageProvider, TxfStorageDataBase, SyncResult, SaveResult, LoadResult } from '../../../storage';\nimport type { FullIdentity, ProviderStatus } from '../../../types';\nimport { getAddressId } from '../../../constants';\n\nconst DB_NAME = 'sphere-token-storage';\nconst DB_VERSION = 1;\nconst STORE_TOKENS = 'tokens';\nconst STORE_META = 'meta';\n\nexport interface IndexedDBTokenStorageConfig {\n /** Database name prefix (default: 'sphere-token-storage') */\n dbNamePrefix?: string;\n}\n\nexport class IndexedDBTokenStorageProvider implements TokenStorageProvider<TxfStorageDataBase> {\n readonly id = 'indexeddb-token-storage';\n readonly name = 'IndexedDB Token Storage';\n readonly type = 'local' as const;\n\n private dbNamePrefix: string;\n private dbName: string;\n private db: IDBDatabase | null = null;\n private status: ProviderStatus = 'disconnected';\n private identity: FullIdentity | null = null;\n\n constructor(config?: IndexedDBTokenStorageConfig) {\n this.dbNamePrefix = config?.dbNamePrefix ?? DB_NAME;\n this.dbName = this.dbNamePrefix;\n }\n\n setIdentity(identity: FullIdentity): void {\n this.identity = identity;\n // Scope database to address using consistent addressId format\n if (identity.directAddress) {\n const addressId = getAddressId(identity.directAddress);\n this.dbName = `${this.dbNamePrefix}-${addressId}`;\n }\n }\n\n async initialize(): Promise<boolean> {\n try {\n this.db = await this.openDatabase();\n this.status = 'connected';\n return true;\n } catch (error) {\n console.error('[IndexedDBTokenStorage] Failed to initialize:', error);\n this.status = 'error';\n return false;\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n this.status = 'disconnected';\n }\n\n async connect(): Promise<void> {\n await this.initialize();\n }\n\n async disconnect(): Promise<void> {\n await this.shutdown();\n }\n\n isConnected(): boolean {\n return this.status === 'connected' && this.db !== null;\n }\n\n getStatus(): ProviderStatus {\n return this.status;\n }\n\n async load(): Promise<LoadResult<TxfStorageDataBase>> {\n if (!this.db) {\n return {\n success: false,\n error: 'Database not initialized',\n source: 'local',\n timestamp: Date.now(),\n };\n }\n\n try {\n const data: TxfStorageDataBase = {\n _meta: {\n version: 1,\n address: this.identity?.l1Address ?? '',\n formatVersion: '2.0',\n updatedAt: Date.now(),\n },\n };\n\n // Load meta\n const meta = await this.getFromStore<TxfStorageDataBase['_meta']>(STORE_META, 'meta');\n if (meta) {\n data._meta = meta;\n }\n\n // Load all tokens from store\n const tokens = await this.getAllFromStore<{ id: string; data: unknown }>(STORE_TOKENS);\n for (const token of tokens) {\n // Skip file-format entries (token-, nametag-) - they are loaded via loadTokensFromFileStorage\n if (token.id.startsWith('token-') || token.id.startsWith('nametag-')) {\n continue;\n }\n\n if (token.id.startsWith('archived-')) {\n // Archived tokens: keep as-is (archived-tokenId key)\n data[token.id as keyof TxfStorageDataBase] = token.data;\n } else {\n // Other entries: add _ prefix for TXF format\n const key = `_${token.id}` as `_${string}`;\n data[key] = token.data;\n }\n }\n\n // Load tombstones\n const tombstones = await this.getFromStore<TxfStorageDataBase['_tombstones']>(STORE_META, 'tombstones');\n if (tombstones) {\n data._tombstones = tombstones;\n }\n\n // Load outbox\n const outbox = await this.getFromStore<TxfStorageDataBase['_outbox']>(STORE_META, 'outbox');\n if (outbox) {\n data._outbox = outbox;\n }\n\n // Load sent\n const sent = await this.getFromStore<TxfStorageDataBase['_sent']>(STORE_META, 'sent');\n if (sent) {\n data._sent = sent;\n }\n\n // Load invalid\n const invalid = await this.getFromStore<TxfStorageDataBase['_invalid']>(STORE_META, 'invalid');\n if (invalid) {\n data._invalid = invalid;\n }\n\n return {\n success: true,\n data,\n source: 'local',\n timestamp: Date.now(),\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error',\n source: 'local',\n timestamp: Date.now(),\n };\n }\n }\n\n async save(data: TxfStorageDataBase): Promise<SaveResult> {\n if (!this.db) {\n return {\n success: false,\n error: 'Database not initialized',\n timestamp: Date.now(),\n };\n }\n\n try {\n // Save meta\n await this.putToStore(STORE_META, 'meta', data._meta);\n\n // Save special arrays\n if (data._tombstones) {\n await this.putToStore(STORE_META, 'tombstones', data._tombstones);\n }\n if (data._outbox) {\n await this.putToStore(STORE_META, 'outbox', data._outbox);\n }\n if (data._sent) {\n await this.putToStore(STORE_META, 'sent', data._sent);\n }\n if (data._invalid) {\n await this.putToStore(STORE_META, 'invalid', data._invalid);\n }\n\n // Save each token (active tokens start with _, archived with archived-)\n const reservedKeys = ['_meta', '_tombstones', '_outbox', '_sent', '_invalid'];\n for (const [key, value] of Object.entries(data)) {\n if (reservedKeys.includes(key)) continue;\n\n if (key.startsWith('_')) {\n // Active token: _tokenId -> tokenId\n const tokenId = key.slice(1);\n await this.putToStore(STORE_TOKENS, tokenId, { id: tokenId, data: value });\n } else if (key.startsWith('archived-')) {\n // Archived token: archived-tokenId -> archived-tokenId (keep prefix)\n await this.putToStore(STORE_TOKENS, key, { id: key, data: value });\n }\n }\n\n // Handle tombstones - delete tokens\n if (data._tombstones) {\n for (const tombstone of data._tombstones) {\n await this.deleteFromStore(STORE_TOKENS, tombstone.tokenId);\n }\n }\n\n return {\n success: true,\n timestamp: Date.now(),\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error',\n timestamp: Date.now(),\n };\n }\n }\n\n async sync(localData: TxfStorageDataBase): Promise<SyncResult<TxfStorageDataBase>> {\n // For local IndexedDB storage, just save and return\n const saveResult = await this.save(localData);\n return {\n success: saveResult.success,\n merged: localData,\n added: 0,\n removed: 0,\n conflicts: 0,\n error: saveResult.error,\n };\n }\n\n async exists(): Promise<boolean> {\n if (!this.db) return false;\n const meta = await this.getFromStore(STORE_META, 'meta');\n return meta !== null;\n }\n\n async clear(): Promise<boolean> {\n // Close the open connection so deleteDatabase isn't blocked\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n this.status = 'disconnected';\n\n const CLEAR_TIMEOUT = 1500;\n\n const withTimeout = <T>(promise: Promise<T>, ms: number, label: string): Promise<T> =>\n Promise.race([\n promise,\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms),\n ),\n ]);\n\n const deleteDb = (name: string) =>\n new Promise<void>((resolve) => {\n const req = indexedDB.deleteDatabase(name);\n req.onsuccess = () => resolve();\n req.onerror = () => resolve();\n req.onblocked = () => resolve();\n });\n\n try {\n // Delete all databases matching our prefix (covers all addresses)\n if (typeof indexedDB.databases === 'function') {\n const dbs = await withTimeout(\n indexedDB.databases(),\n CLEAR_TIMEOUT,\n 'indexedDB.databases()',\n );\n await Promise.all(\n dbs\n .filter(db => db.name?.startsWith(this.dbNamePrefix))\n .map(db => deleteDb(db.name!)),\n );\n } else {\n // Fallback: delete only the current database\n await deleteDb(this.dbName);\n }\n return true;\n } catch (err) {\n console.warn('[IndexedDBTokenStorage] clear() failed:', err);\n return false;\n }\n }\n\n // =========================================================================\n // Private IndexedDB helpers\n // =========================================================================\n\n private openDatabase(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(this.dbName, DB_VERSION);\n\n request.onerror = () => {\n reject(request.error);\n };\n\n request.onsuccess = () => {\n resolve(request.result);\n };\n\n request.onupgradeneeded = (event) => {\n const db = (event.target as IDBOpenDBRequest).result;\n\n // Create tokens store\n if (!db.objectStoreNames.contains(STORE_TOKENS)) {\n db.createObjectStore(STORE_TOKENS, { keyPath: 'id' });\n }\n\n // Create meta store\n if (!db.objectStoreNames.contains(STORE_META)) {\n db.createObjectStore(STORE_META);\n }\n };\n });\n }\n\n private getFromStore<T>(storeName: string, key: string): Promise<T | null> {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n resolve(null);\n return;\n }\n\n const transaction = this.db.transaction(storeName, 'readonly');\n const store = transaction.objectStore(storeName);\n const request = store.get(key);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result ?? null);\n });\n }\n\n private getAllFromStore<T>(storeName: string): Promise<T[]> {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n resolve([]);\n return;\n }\n\n const transaction = this.db.transaction(storeName, 'readonly');\n const store = transaction.objectStore(storeName);\n const request = store.getAll();\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result ?? []);\n });\n }\n\n private putToStore(storeName: string, key: string, value: unknown): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n\n const transaction = this.db.transaction(storeName, 'readwrite');\n const store = transaction.objectStore(storeName);\n\n // For meta store, use put with explicit key\n // For tokens store, value contains the key (keyPath: 'id')\n const request = storeName === STORE_META\n ? store.put(value, key)\n : store.put(value);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n });\n }\n\n private deleteFromStore(storeName: string, key: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n resolve();\n return;\n }\n\n const transaction = this.db.transaction(storeName, 'readwrite');\n const store = transaction.objectStore(storeName);\n const request = store.delete(key);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n });\n }\n\n private clearStore(storeName: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n resolve();\n return;\n }\n\n const transaction = this.db.transaction(storeName, 'readwrite');\n const store = transaction.objectStore(storeName);\n const request = store.clear();\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n });\n }\n}\n\nexport function createIndexedDBTokenStorageProvider(\n config?: IndexedDBTokenStorageConfig\n): IndexedDBTokenStorageProvider {\n return new IndexedDBTokenStorageProvider(config);\n}\n","/**\n * Nostr Transport Provider\n * Platform-independent implementation using Nostr protocol for P2P messaging\n *\n * Uses @unicitylabs/nostr-js-sdk for:\n * - Real secp256k1 event signing\n * - NIP-04 encryption/decryption\n * - Event ID calculation\n * - NostrClient for reliable connection management (ping, reconnect, NIP-42)\n *\n * WebSocket is injected via factory for cross-platform support\n */\n\nimport { Buffer } from 'buffer';\nimport { hkdf } from '@noble/hashes/hkdf.js';\nimport { sha256 as sha256Noble } from '@noble/hashes/sha2.js';\nimport {\n NostrKeyManager,\n NIP04,\n NIP17,\n Event as NostrEventClass,\n EventKinds,\n hashNametag,\n NostrClient,\n Filter,\n} from '@unicitylabs/nostr-js-sdk';\nimport { getPublicKey, publicKeyToAddress } from '../core/crypto';\nimport type { ProviderStatus, FullIdentity } from '../types';\nimport type {\n TransportProvider,\n MessageHandler,\n TokenTransferHandler,\n BroadcastHandler,\n PaymentRequestHandler,\n PaymentRequestResponseHandler,\n IncomingMessage,\n IncomingTokenTransfer,\n IncomingBroadcast,\n IncomingPaymentRequest,\n IncomingPaymentRequestResponse,\n TokenTransferPayload,\n PaymentRequestPayload,\n PaymentRequestResponsePayload,\n TransportEvent,\n TransportEventCallback,\n PeerInfo,\n} from './transport-provider';\nimport type { WebSocketFactory, UUIDGenerator } from './websocket';\nimport { defaultUUIDGenerator } from './websocket';\nimport {\n DEFAULT_NOSTR_RELAYS,\n NOSTR_EVENT_KINDS,\n STORAGE_KEYS_GLOBAL,\n TIMEOUTS,\n} from '../constants';\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\n/**\n * Minimal key-value storage interface for transport persistence.\n * Used to persist the last processed event timestamp across sessions.\n */\nexport interface TransportStorageAdapter {\n get(key: string): Promise<string | null>;\n set(key: string, value: string): Promise<void>;\n}\n\nexport interface NostrTransportProviderConfig {\n /** Nostr relay URLs */\n relays?: string[];\n /** Connection timeout (ms) */\n timeout?: number;\n /** Auto-reconnect on disconnect */\n autoReconnect?: boolean;\n /** Reconnect delay (ms) */\n reconnectDelay?: number;\n /** Max reconnect attempts */\n maxReconnectAttempts?: number;\n /** Enable debug logging */\n debug?: boolean;\n /** WebSocket factory (required for platform support) */\n createWebSocket: WebSocketFactory;\n /** UUID generator (optional, defaults to crypto.randomUUID) */\n generateUUID?: UUIDGenerator;\n /** Optional storage adapter for persisting subscription timestamps */\n storage?: TransportStorageAdapter;\n}\n\n// Alias for backward compatibility\nconst EVENT_KINDS = NOSTR_EVENT_KINDS;\n\n// =============================================================================\n// Address Hashing Utility\n// =============================================================================\n\n/**\n * Hash an address (DIRECT:// or PROXY://) for use as indexed 't' tag value.\n * Enables reverse lookup: address → binding event → transport pubkey.\n * @param address - Address string (e.g., DIRECT://... or PROXY://...)\n * @returns Hex-encoded SHA-256 hash\n */\nfunction hashAddressForTag(address: string): string {\n const bytes = new TextEncoder().encode('unicity:address:' + address);\n return Buffer.from(sha256Noble(bytes)).toString('hex');\n}\n\n// =============================================================================\n// Nametag Encryption Utilities\n// =============================================================================\n\n/**\n * Derive encryption key from private key using HKDF\n * @param privateKeyHex - 32-byte private key as hex\n * @returns 32-byte derived key as Uint8Array\n */\nfunction deriveNametagEncryptionKey(privateKeyHex: string): Uint8Array {\n const privateKeyBytes = Buffer.from(privateKeyHex, 'hex');\n // Use HKDF with SHA-256, salt derived from constant, info = \"nametag-encryption\"\n const saltInput = new TextEncoder().encode('sphere-nametag-salt');\n const salt = sha256Noble(saltInput);\n const info = new TextEncoder().encode('nametag-encryption');\n return hkdf(sha256Noble, privateKeyBytes, salt, info, 32);\n}\n\n/**\n * Encrypt nametag with AES-GCM using derived key\n * @param nametag - Plain text nametag\n * @param privateKeyHex - Private key for key derivation\n * @returns Base64 encoded encrypted data (iv + ciphertext + tag)\n */\nasync function encryptNametag(nametag: string, privateKeyHex: string): Promise<string> {\n const key = deriveNametagEncryptionKey(privateKeyHex);\n const iv = crypto.getRandomValues(new Uint8Array(12)); // 96-bit IV for AES-GCM\n const encoder = new TextEncoder();\n const data = encoder.encode(nametag);\n\n const cryptoKey = await crypto.subtle.importKey(\n 'raw',\n new Uint8Array(key).buffer as ArrayBuffer,\n { name: 'AES-GCM' },\n false,\n ['encrypt']\n );\n\n const encrypted = await crypto.subtle.encrypt(\n { name: 'AES-GCM', iv: new Uint8Array(iv).buffer as ArrayBuffer },\n cryptoKey,\n new Uint8Array(data).buffer as ArrayBuffer\n );\n\n // Combine IV + ciphertext (includes auth tag)\n const combined = new Uint8Array(iv.length + encrypted.byteLength);\n combined.set(iv, 0);\n combined.set(new Uint8Array(encrypted), iv.length);\n\n return Buffer.from(combined).toString('base64');\n}\n\n/**\n * Decrypt nametag with AES-GCM using derived key\n * @param encryptedBase64 - Base64 encoded encrypted data (iv + ciphertext + tag)\n * @param privateKeyHex - Private key for key derivation\n * @returns Decrypted nametag or null if decryption fails\n */\nasync function decryptNametag(encryptedBase64: string, privateKeyHex: string): Promise<string | null> {\n try {\n const key = deriveNametagEncryptionKey(privateKeyHex);\n const combined = Buffer.from(encryptedBase64, 'base64');\n\n const iv = combined.slice(0, 12);\n const ciphertext = combined.slice(12);\n\n const cryptoKey = await crypto.subtle.importKey(\n 'raw',\n new Uint8Array(key).buffer as ArrayBuffer,\n { name: 'AES-GCM' },\n false,\n ['decrypt']\n );\n\n const decrypted = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv: new Uint8Array(iv).buffer as ArrayBuffer },\n cryptoKey,\n new Uint8Array(ciphertext).buffer as ArrayBuffer\n );\n\n const decoder = new TextDecoder();\n return decoder.decode(decrypted);\n } catch {\n return null;\n }\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\nexport class NostrTransportProvider implements TransportProvider {\n readonly id = 'nostr';\n readonly name = 'Nostr Transport';\n readonly type = 'p2p' as const;\n readonly description = 'P2P messaging via Nostr protocol';\n\n private config: Required<Omit<NostrTransportProviderConfig, 'createWebSocket' | 'generateUUID' | 'storage'>> & {\n createWebSocket: WebSocketFactory;\n generateUUID: UUIDGenerator;\n };\n private storage: TransportStorageAdapter | null = null;\n /** In-memory max event timestamp to avoid read-before-write races in updateLastEventTimestamp. */\n private lastEventTs: number = 0;\n private identity: FullIdentity | null = null;\n private keyManager: NostrKeyManager | null = null;\n private status: ProviderStatus = 'disconnected';\n\n // NostrClient from nostr-js-sdk handles all WebSocket management,\n // keepalive pings, reconnection, and NIP-42 authentication\n private nostrClient: NostrClient | null = null;\n private mainSubscriptionId: string | null = null;\n\n // Event handlers\n private processedEventIds = new Set<string>();\n private messageHandlers: Set<MessageHandler> = new Set();\n private transferHandlers: Set<TokenTransferHandler> = new Set();\n private paymentRequestHandlers: Set<PaymentRequestHandler> = new Set();\n private paymentRequestResponseHandlers: Set<PaymentRequestResponseHandler> = new Set();\n private broadcastHandlers: Map<string, Set<BroadcastHandler>> = new Map();\n private eventCallbacks: Set<TransportEventCallback> = new Set();\n\n constructor(config: NostrTransportProviderConfig) {\n this.config = {\n relays: config.relays ?? [...DEFAULT_NOSTR_RELAYS],\n timeout: config.timeout ?? TIMEOUTS.WEBSOCKET_CONNECT,\n autoReconnect: config.autoReconnect ?? true,\n reconnectDelay: config.reconnectDelay ?? TIMEOUTS.NOSTR_RECONNECT_DELAY,\n maxReconnectAttempts: config.maxReconnectAttempts ?? TIMEOUTS.MAX_RECONNECT_ATTEMPTS,\n debug: config.debug ?? false,\n createWebSocket: config.createWebSocket,\n generateUUID: config.generateUUID ?? defaultUUIDGenerator,\n };\n this.storage = config.storage ?? null;\n }\n\n // ===========================================================================\n // BaseProvider Implementation\n // ===========================================================================\n\n async connect(): Promise<void> {\n if (this.status === 'connected') return;\n\n this.status = 'connecting';\n\n try {\n // Ensure keyManager exists for NostrClient\n if (!this.keyManager) {\n // Create a temporary key manager - will be replaced when setIdentity is called\n const tempKey = Buffer.alloc(32);\n crypto.getRandomValues(tempKey);\n this.keyManager = NostrKeyManager.fromPrivateKey(tempKey);\n }\n\n // Create NostrClient with robust connection handling:\n // - autoReconnect: automatic reconnection with exponential backoff\n // - pingIntervalMs: keepalive pings to detect stale connections\n // - NIP-42 AUTH handling built-in\n this.nostrClient = new NostrClient(this.keyManager, {\n autoReconnect: this.config.autoReconnect,\n reconnectIntervalMs: this.config.reconnectDelay,\n maxReconnectIntervalMs: this.config.reconnectDelay * 16, // exponential backoff cap\n pingIntervalMs: 15000, // 15 second keepalive pings (more aggressive to prevent drops)\n });\n\n // Add connection event listener for logging\n this.nostrClient.addConnectionListener({\n onConnect: (url) => {\n this.log('NostrClient connected to relay:', url);\n this.emitEvent({ type: 'transport:connected', timestamp: Date.now() });\n },\n onDisconnect: (url, reason) => {\n this.log('NostrClient disconnected from relay:', url, 'reason:', reason);\n },\n onReconnecting: (url, attempt) => {\n this.log('NostrClient reconnecting to relay:', url, 'attempt:', attempt);\n this.emitEvent({ type: 'transport:reconnecting', timestamp: Date.now() });\n },\n onReconnected: (url) => {\n this.log('NostrClient reconnected to relay:', url);\n this.emitEvent({ type: 'transport:connected', timestamp: Date.now() });\n },\n });\n\n // Connect to all relays (with timeout to prevent indefinite hang)\n await Promise.race([\n this.nostrClient.connect(...this.config.relays),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(\n `Transport connection timed out after ${this.config.timeout}ms`\n )), this.config.timeout)\n ),\n ]);\n\n // Need at least one successful connection\n if (!this.nostrClient.isConnected()) {\n throw new Error('Failed to connect to any relay');\n }\n\n this.status = 'connected';\n this.emitEvent({ type: 'transport:connected', timestamp: Date.now() });\n this.log('Connected to', this.nostrClient.getConnectedRelays().size, 'relays');\n\n // Set up subscriptions\n if (this.identity) {\n await this.subscribeToEvents();\n }\n } catch (error) {\n this.status = 'error';\n throw error;\n }\n }\n\n async disconnect(): Promise<void> {\n if (this.nostrClient) {\n this.nostrClient.disconnect();\n this.nostrClient = null;\n }\n this.mainSubscriptionId = null;\n this.walletSubscriptionId = null;\n this.chatSubscriptionId = null;\n this.status = 'disconnected';\n this.emitEvent({ type: 'transport:disconnected', timestamp: Date.now() });\n this.log('Disconnected from all relays');\n }\n\n isConnected(): boolean {\n return this.status === 'connected' && this.nostrClient?.isConnected() === true;\n }\n\n getStatus(): ProviderStatus {\n return this.status;\n }\n\n // ===========================================================================\n // Dynamic Relay Management\n // ===========================================================================\n\n /**\n * Get list of configured relay URLs\n */\n getRelays(): string[] {\n return [...this.config.relays];\n }\n\n /**\n * Get list of currently connected relay URLs\n */\n getConnectedRelays(): string[] {\n if (!this.nostrClient) return [];\n return Array.from(this.nostrClient.getConnectedRelays());\n }\n\n /**\n * Add a new relay dynamically\n * Will connect immediately if provider is already connected\n */\n async addRelay(relayUrl: string): Promise<boolean> {\n // Check if already configured\n if (this.config.relays.includes(relayUrl)) {\n this.log('Relay already configured:', relayUrl);\n return false;\n }\n\n // Add to config\n this.config.relays.push(relayUrl);\n\n // Connect if provider is connected\n if (this.status === 'connected' && this.nostrClient) {\n try {\n await this.nostrClient.connect(relayUrl);\n this.log('Added and connected to relay:', relayUrl);\n this.emitEvent({\n type: 'transport:relay_added',\n timestamp: Date.now(),\n data: { relay: relayUrl, connected: true },\n });\n return true;\n } catch (error) {\n this.log('Failed to connect to new relay:', relayUrl, error);\n this.emitEvent({\n type: 'transport:relay_added',\n timestamp: Date.now(),\n data: { relay: relayUrl, connected: false, error: String(error) },\n });\n return false;\n }\n }\n\n this.emitEvent({\n type: 'transport:relay_added',\n timestamp: Date.now(),\n data: { relay: relayUrl, connected: false },\n });\n return true;\n }\n\n /**\n * Remove a relay dynamically\n * Will disconnect from the relay if connected\n * NOTE: NostrClient doesn't support removing individual relays at runtime.\n * We remove from config so it won't be used on next connect().\n */\n async removeRelay(relayUrl: string): Promise<boolean> {\n const index = this.config.relays.indexOf(relayUrl);\n if (index === -1) {\n this.log('Relay not found:', relayUrl);\n return false;\n }\n\n // Remove from config\n this.config.relays.splice(index, 1);\n this.log('Removed relay from config:', relayUrl);\n\n this.emitEvent({\n type: 'transport:relay_removed',\n timestamp: Date.now(),\n data: { relay: relayUrl },\n });\n\n // Check if we still have connections\n if (this.nostrClient && !this.nostrClient.isConnected() && this.status === 'connected') {\n this.status = 'error';\n this.emitEvent({\n type: 'transport:error',\n timestamp: Date.now(),\n data: { error: 'No connected relays remaining' },\n });\n }\n\n return true;\n }\n\n /**\n * Check if a relay is configured\n */\n hasRelay(relayUrl: string): boolean {\n return this.config.relays.includes(relayUrl);\n }\n\n /**\n * Check if a relay is currently connected\n */\n isRelayConnected(relayUrl: string): boolean {\n if (!this.nostrClient) return false;\n return this.nostrClient.getConnectedRelays().has(relayUrl);\n }\n\n // ===========================================================================\n // TransportProvider Implementation\n // ===========================================================================\n\n async setIdentity(identity: FullIdentity): Promise<void> {\n this.identity = identity;\n\n // Create NostrKeyManager from private key\n const secretKey = Buffer.from(identity.privateKey, 'hex');\n this.keyManager = NostrKeyManager.fromPrivateKey(secretKey);\n\n // Use Nostr-format pubkey (32 bytes / 64 hex chars) from keyManager\n const nostrPubkey = this.keyManager.getPublicKeyHex();\n this.log('Identity set, Nostr pubkey:', nostrPubkey.slice(0, 16) + '...');\n\n // If we already have a NostrClient with a temp key, we need to reconnect with the real key\n // NostrClient doesn't support changing key at runtime\n if (this.nostrClient && this.status === 'connected') {\n this.log('Identity changed while connected - recreating NostrClient');\n const oldClient = this.nostrClient;\n\n // Create new client with real identity\n this.nostrClient = new NostrClient(this.keyManager, {\n autoReconnect: this.config.autoReconnect,\n reconnectIntervalMs: this.config.reconnectDelay,\n maxReconnectIntervalMs: this.config.reconnectDelay * 16,\n pingIntervalMs: 15000, // 15 second keepalive pings\n });\n\n // Add connection event listener\n this.nostrClient.addConnectionListener({\n onConnect: (url) => {\n this.log('NostrClient connected to relay:', url);\n },\n onDisconnect: (url, reason) => {\n this.log('NostrClient disconnected from relay:', url, 'reason:', reason);\n },\n onReconnecting: (url, attempt) => {\n this.log('NostrClient reconnecting to relay:', url, 'attempt:', attempt);\n },\n onReconnected: (url) => {\n this.log('NostrClient reconnected to relay:', url);\n },\n });\n\n // Connect with new identity, set up subscriptions, then disconnect old client\n await Promise.race([\n this.nostrClient.connect(...this.config.relays),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(\n `Transport reconnection timed out after ${this.config.timeout}ms`\n )), this.config.timeout)\n ),\n ]);\n await this.subscribeToEvents();\n oldClient.disconnect();\n } else if (this.isConnected()) {\n // Already connected with right key, just subscribe\n await this.subscribeToEvents();\n }\n }\n\n /**\n * Get the Nostr-format public key (32 bytes / 64 hex chars)\n * This is the x-coordinate only, without the 02/03 prefix.\n */\n getNostrPubkey(): string {\n if (!this.keyManager) {\n throw new Error('KeyManager not initialized - call setIdentity first');\n }\n return this.keyManager.getPublicKeyHex();\n }\n\n async sendMessage(recipientPubkey: string, content: string): Promise<string> {\n this.ensureReady();\n\n // NIP-17 requires 32-byte x-only pubkey; strip 02/03 prefix if present\n const nostrRecipient = recipientPubkey.length === 66 && (recipientPubkey.startsWith('02') || recipientPubkey.startsWith('03'))\n ? recipientPubkey.slice(2)\n : recipientPubkey;\n\n // Wrap content with sender nametag for Sphere app compatibility\n const senderNametag = this.identity?.nametag;\n const wrappedContent = senderNametag\n ? JSON.stringify({ senderNametag, text: content })\n : content;\n\n // Create NIP-17 gift-wrapped message (kind 1059)\n const giftWrap = NIP17.createGiftWrap(this.keyManager!, nostrRecipient, wrappedContent);\n\n await this.publishEvent(giftWrap);\n\n this.emitEvent({\n type: 'message:sent',\n timestamp: Date.now(),\n data: { recipient: recipientPubkey },\n });\n\n return giftWrap.id;\n }\n\n onMessage(handler: MessageHandler): () => void {\n this.messageHandlers.add(handler);\n return () => this.messageHandlers.delete(handler);\n }\n\n async sendTokenTransfer(\n recipientPubkey: string,\n payload: TokenTransferPayload\n ): Promise<string> {\n this.ensureReady();\n\n // Create encrypted token transfer event\n // Content must have \"token_transfer:\" prefix for nostr-js-sdk compatibility\n const content = 'token_transfer:' + JSON.stringify(payload);\n const event = await this.createEncryptedEvent(\n EVENT_KINDS.TOKEN_TRANSFER,\n content,\n [\n ['p', recipientPubkey],\n ['d', 'token-transfer'],\n ['type', 'token_transfer'],\n ]\n );\n\n await this.publishEvent(event);\n\n this.emitEvent({\n type: 'transfer:sent',\n timestamp: Date.now(),\n data: { recipient: recipientPubkey },\n });\n\n return event.id;\n }\n\n onTokenTransfer(handler: TokenTransferHandler): () => void {\n this.transferHandlers.add(handler);\n return () => this.transferHandlers.delete(handler);\n }\n\n async sendPaymentRequest(\n recipientPubkey: string,\n payload: PaymentRequestPayload\n ): Promise<string> {\n this.ensureReady();\n\n const requestId = this.config.generateUUID();\n const amount = typeof payload.amount === 'bigint' ? payload.amount.toString() : payload.amount;\n\n // Build request content matching nostr-js-sdk format\n const requestContent = {\n requestId,\n amount,\n coinId: payload.coinId,\n message: payload.message,\n recipientNametag: payload.recipientNametag,\n deadline: Date.now() + 5 * 60 * 1000, // 5 minutes default\n };\n\n // Content must have \"payment_request:\" prefix for nostr-js-sdk compatibility\n const content = 'payment_request:' + JSON.stringify(requestContent);\n\n // Build tags matching nostr-js-sdk format\n const tags: string[][] = [\n ['p', recipientPubkey],\n ['type', 'payment_request'],\n ['amount', amount],\n ];\n if (payload.recipientNametag) {\n tags.push(['recipient', payload.recipientNametag]);\n }\n\n const event = await this.createEncryptedEvent(\n EVENT_KINDS.PAYMENT_REQUEST,\n content,\n tags\n );\n\n await this.publishEvent(event);\n\n this.log('Sent payment request:', event.id);\n\n return event.id;\n }\n\n onPaymentRequest(handler: PaymentRequestHandler): () => void {\n this.paymentRequestHandlers.add(handler);\n return () => this.paymentRequestHandlers.delete(handler);\n }\n\n async sendPaymentRequestResponse(\n recipientPubkey: string,\n payload: PaymentRequestResponsePayload\n ): Promise<string> {\n this.ensureReady();\n\n // Build response content\n const responseContent = {\n requestId: payload.requestId,\n responseType: payload.responseType,\n message: payload.message,\n transferId: payload.transferId,\n };\n\n // Create encrypted payment request response event\n // Content must have \"payment_response:\" prefix for nostr-js-sdk compatibility\n const content = 'payment_response:' + JSON.stringify(responseContent);\n const event = await this.createEncryptedEvent(\n EVENT_KINDS.PAYMENT_REQUEST_RESPONSE,\n content,\n [\n ['p', recipientPubkey],\n ['e', payload.requestId], // Reference to original request\n ['d', 'payment-request-response'],\n ['type', 'payment_response'],\n ]\n );\n\n await this.publishEvent(event);\n\n this.log('Sent payment request response:', event.id, 'type:', payload.responseType);\n\n return event.id;\n }\n\n onPaymentRequestResponse(handler: PaymentRequestResponseHandler): () => void {\n this.paymentRequestResponseHandlers.add(handler);\n return () => this.paymentRequestResponseHandlers.delete(handler);\n }\n\n /**\n * Resolve any identifier to full peer information.\n * Routes to the appropriate specific resolve method based on identifier format.\n */\n async resolve(identifier: string): Promise<PeerInfo | null> {\n // @nametag\n if (identifier.startsWith('@')) {\n return this.resolveNametagInfo(identifier.slice(1));\n }\n\n // DIRECT:// or PROXY:// address\n if (identifier.startsWith('DIRECT:') || identifier.startsWith('PROXY:')) {\n return this.resolveAddressInfo(identifier);\n }\n\n // L1 address (alpha1... or alphat1...)\n if (identifier.startsWith('alpha1') || identifier.startsWith('alphat1')) {\n return this.resolveAddressInfo(identifier);\n }\n\n // 66-char hex starting with 02/03 → compressed chain pubkey (33 bytes)\n if (/^0[23][0-9a-f]{64}$/i.test(identifier)) {\n return this.resolveAddressInfo(identifier);\n }\n\n // 64-char hex string → transport pubkey\n if (/^[0-9a-f]{64}$/i.test(identifier)) {\n return this.resolveTransportPubkeyInfo(identifier);\n }\n\n // Fallback: treat as bare nametag\n return this.resolveNametagInfo(identifier);\n }\n\n async resolveNametag(nametag: string): Promise<string | null> {\n this.ensureConnected();\n\n // Query for nametag binding events using hashed nametag (privacy-preserving)\n // Try both '#d' and '#t' filters for compatibility with nostr-js-sdk\n const hashedNametag = hashNametag(nametag);\n\n // First try '#t' tag (nostr-js-sdk format)\n let events = await this.queryEvents({\n kinds: [EVENT_KINDS.NAMETAG_BINDING],\n '#t': [hashedNametag],\n limit: 1,\n });\n\n // Fallback to '#d' tag (legacy format)\n if (events.length === 0) {\n events = await this.queryEvents({\n kinds: [EVENT_KINDS.NAMETAG_BINDING],\n '#d': [hashedNametag],\n limit: 1,\n });\n }\n\n if (events.length === 0) return null;\n\n // Parse binding event\n const bindingEvent = events[0];\n\n // For Nostr messaging (NIP-04 encryption), we MUST use the event author's pubkey.\n // The 'address' tag contains the Unicity blockchain address (not a hex pubkey),\n // which cannot be used for Nostr encryption.\n // The event.pubkey is always the hex pubkey of the nametag owner.\n if (bindingEvent.pubkey) {\n return bindingEvent.pubkey;\n }\n\n // Fallback: try 'p' tag (our SDK format uses hex pubkey here)\n const pubkeyTag = bindingEvent.tags.find((t: string[]) => t[0] === 'p');\n if (pubkeyTag?.[1]) return pubkeyTag[1];\n\n return null;\n }\n\n async resolveNametagInfo(nametag: string): Promise<PeerInfo | null> {\n this.ensureConnected();\n\n // Query for nametag binding events using hashed nametag (privacy-preserving)\n const hashedNametag = hashNametag(nametag);\n\n // First try '#t' tag (nostr-js-sdk format)\n let events = await this.queryEvents({\n kinds: [EVENT_KINDS.NAMETAG_BINDING],\n '#t': [hashedNametag],\n limit: 1,\n });\n\n // Fallback to '#d' tag (legacy format)\n if (events.length === 0) {\n events = await this.queryEvents({\n kinds: [EVENT_KINDS.NAMETAG_BINDING],\n '#d': [hashedNametag],\n limit: 1,\n });\n }\n\n if (events.length === 0) return null;\n\n const bindingEvent = events[0];\n\n try {\n const content = JSON.parse(bindingEvent.content);\n\n // Compute proper PROXY address using state-transition-sdk\n const { ProxyAddress } = await import('@unicitylabs/state-transition-sdk/lib/address/ProxyAddress');\n const proxyAddr = await ProxyAddress.fromNameTag(nametag);\n const proxyAddress = proxyAddr.toString();\n\n // Check if event has extended fields\n if (content.public_key && content.l1_address) {\n return {\n nametag,\n transportPubkey: bindingEvent.pubkey,\n chainPubkey: content.public_key,\n l1Address: content.l1_address,\n directAddress: content.direct_address || '',\n proxyAddress,\n timestamp: bindingEvent.created_at * 1000,\n };\n }\n\n // Legacy event - only has Nostr pubkey\n // Cannot derive l1_address or l3_address without 33-byte pubkey\n this.log('Legacy nametag event without extended fields:', nametag);\n\n // Try to get info from tags as fallback\n const pubkeyTag = bindingEvent.tags.find((t: string[]) => t[0] === 'pubkey');\n const l1Tag = bindingEvent.tags.find((t: string[]) => t[0] === 'l1');\n\n if (pubkeyTag?.[1] && l1Tag?.[1]) {\n return {\n nametag,\n transportPubkey: bindingEvent.pubkey,\n chainPubkey: pubkeyTag[1],\n l1Address: l1Tag[1],\n directAddress: '',\n proxyAddress,\n timestamp: bindingEvent.created_at * 1000,\n };\n }\n\n // Return partial info with empty addresses for legacy events\n return {\n nametag,\n transportPubkey: bindingEvent.pubkey,\n chainPubkey: '', // Cannot derive from 32-byte Nostr pubkey\n l1Address: '', // Cannot derive without 33-byte pubkey\n directAddress: '',\n proxyAddress,\n timestamp: bindingEvent.created_at * 1000,\n };\n } catch {\n // If content is not JSON, try legacy format\n const { ProxyAddress } = await import('@unicitylabs/state-transition-sdk/lib/address/ProxyAddress');\n const proxyAddr = await ProxyAddress.fromNameTag(nametag);\n return {\n nametag,\n transportPubkey: bindingEvent.pubkey,\n chainPubkey: '',\n l1Address: '',\n directAddress: '',\n proxyAddress: proxyAddr.toString(),\n timestamp: bindingEvent.created_at * 1000,\n };\n }\n }\n\n /**\n * Resolve a DIRECT://, PROXY://, or L1 address to full peer info.\n * Performs reverse lookup: hash(address) → query '#t' tag → parse binding event.\n * Works with both new identity binding events and legacy nametag binding events.\n */\n async resolveAddressInfo(address: string): Promise<PeerInfo | null> {\n this.ensureConnected();\n\n const addressHash = hashAddressForTag(address);\n\n const events = await this.queryEvents({\n kinds: [EVENT_KINDS.NAMETAG_BINDING],\n '#t': [addressHash],\n limit: 1,\n });\n\n if (events.length === 0) return null;\n\n const bindingEvent = events[0];\n\n try {\n const content = JSON.parse(bindingEvent.content);\n\n return {\n nametag: content.nametag || undefined,\n transportPubkey: bindingEvent.pubkey,\n chainPubkey: content.public_key || '',\n l1Address: content.l1_address || '',\n directAddress: content.direct_address || '',\n proxyAddress: content.proxy_address || undefined,\n timestamp: bindingEvent.created_at * 1000,\n };\n } catch {\n return {\n transportPubkey: bindingEvent.pubkey,\n chainPubkey: '',\n l1Address: '',\n directAddress: '',\n timestamp: bindingEvent.created_at * 1000,\n };\n }\n }\n\n /**\n * Resolve transport pubkey (Nostr pubkey) to full peer info.\n * Queries binding events authored by the given pubkey.\n */\n async resolveTransportPubkeyInfo(transportPubkey: string): Promise<PeerInfo | null> {\n this.ensureConnected();\n\n const events = await this.queryEvents({\n kinds: [EVENT_KINDS.NAMETAG_BINDING],\n authors: [transportPubkey],\n limit: 5,\n });\n\n if (events.length === 0) return null;\n\n // Sort by timestamp descending and take the most recent\n events.sort((a, b) => b.created_at - a.created_at);\n const bindingEvent = events[0];\n\n try {\n const content = JSON.parse(bindingEvent.content);\n\n return {\n nametag: content.nametag || undefined,\n transportPubkey: bindingEvent.pubkey,\n chainPubkey: content.public_key || '',\n l1Address: content.l1_address || '',\n directAddress: content.direct_address || '',\n proxyAddress: content.proxy_address || undefined,\n timestamp: bindingEvent.created_at * 1000,\n };\n } catch {\n return {\n transportPubkey: bindingEvent.pubkey,\n chainPubkey: '',\n l1Address: '',\n directAddress: '',\n timestamp: bindingEvent.created_at * 1000,\n };\n }\n }\n\n /**\n * Recover nametag for the current identity by searching for encrypted nametag events\n * Used after wallet import to recover associated nametag\n * @returns Decrypted nametag or null if none found\n */\n async recoverNametag(): Promise<string | null> {\n this.ensureReady();\n\n if (!this.identity || !this.keyManager) {\n throw new Error('Identity not set');\n }\n\n const nostrPubkey = this.getNostrPubkey();\n this.log('Searching for nametag events for pubkey:', nostrPubkey.slice(0, 16) + '...');\n\n // Query for nametag binding events authored by this pubkey\n const events = await this.queryEvents({\n kinds: [EVENT_KINDS.NAMETAG_BINDING],\n authors: [nostrPubkey],\n limit: 10, // Get recent events in case of updates\n });\n\n if (events.length === 0) {\n this.log('No nametag events found for this pubkey');\n return null;\n }\n\n // Sort by timestamp descending to get most recent\n events.sort((a, b) => b.created_at - a.created_at);\n\n // Try to decrypt nametag from events\n for (const event of events) {\n try {\n const content = JSON.parse(event.content);\n if (content.encrypted_nametag) {\n const decrypted = await decryptNametag(\n content.encrypted_nametag,\n this.identity.privateKey\n );\n if (decrypted) {\n this.log('Recovered nametag:', decrypted);\n return decrypted;\n }\n }\n } catch {\n // Try next event\n continue;\n }\n }\n\n this.log('Could not decrypt nametag from any event');\n return null;\n }\n\n /**\n * Publish identity binding event on Nostr.\n * Without nametag: publishes base binding (chainPubkey, l1Address, directAddress).\n * With nametag: also publishes nametag hash, proxy address, encrypted nametag for recovery.\n *\n * Uses kind 30078 parameterized replaceable event with d=SHA256('unicity:identity:' + nostrPubkey).\n * Each HD address index has its own Nostr key → its own binding event.\n *\n * @returns true if successful, false if nametag is taken by another pubkey\n */\n async publishIdentityBinding(\n chainPubkey: string,\n l1Address: string,\n directAddress: string,\n nametag?: string,\n ): Promise<boolean> {\n this.ensureReady();\n\n if (!this.identity) {\n throw new Error('Identity not set');\n }\n\n const nostrPubkey = this.getNostrPubkey();\n\n // Deterministic d-tag: SHA256('unicity:identity:' + nostrPubkey) — privacy-preserving\n const dTagBytes = new TextEncoder().encode('unicity:identity:' + nostrPubkey);\n const dTag = Buffer.from(sha256Noble(dTagBytes)).toString('hex');\n\n // Content — event.pubkey already identifies the author, event.created_at provides timestamp\n const contentObj: Record<string, unknown> = {\n public_key: chainPubkey,\n l1_address: l1Address,\n direct_address: directAddress,\n };\n\n // Tags — 'd' for replacement, 't' for indexed lookups\n const tags: string[][] = [\n ['d', dTag],\n ['t', hashAddressForTag(chainPubkey)],\n ['t', hashAddressForTag(directAddress)],\n ['t', hashAddressForTag(l1Address)],\n ];\n\n // If nametag provided, check availability and add nametag-specific fields\n if (nametag) {\n const existing = await this.resolveNametag(nametag);\n if (existing && existing !== nostrPubkey) {\n this.log('Nametag already taken:', nametag, '- owner:', existing);\n return false;\n }\n\n // Compute proxy address\n const { ProxyAddress } = await import('@unicitylabs/state-transition-sdk/lib/address/ProxyAddress');\n const proxyAddr = await ProxyAddress.fromNameTag(nametag);\n const proxyAddress = proxyAddr.toString();\n\n // Encrypt nametag for recovery\n const encryptedNametag = await encryptNametag(nametag, this.identity.privateKey);\n const hashedNametag = hashNametag(nametag);\n\n // Add nametag fields to content\n contentObj.nametag = nametag;\n contentObj.encrypted_nametag = encryptedNametag;\n contentObj.proxy_address = proxyAddress;\n\n // Add nametag-specific 't' tags for indexed lookup\n tags.push(['t', hashedNametag]);\n tags.push(['t', hashAddressForTag(proxyAddress)]);\n }\n\n const content = JSON.stringify(contentObj);\n const event = await this.createEvent(EVENT_KINDS.NAMETAG_BINDING, content, tags);\n await this.publishEvent(event);\n\n if (nametag) {\n this.log('Published identity binding with nametag:', nametag, 'for pubkey:', nostrPubkey.slice(0, 16) + '...');\n } else {\n this.log('Published identity binding (no nametag) for pubkey:', nostrPubkey.slice(0, 16) + '...');\n }\n\n return true;\n }\n\n /** @deprecated Use publishIdentityBinding instead */\n async publishNametag(nametag: string, address: string): Promise<void> {\n this.ensureReady();\n\n // Use hashed nametag (privacy-preserving)\n const hashedNametag = hashNametag(nametag);\n const event = await this.createEvent(EVENT_KINDS.NAMETAG_BINDING, address, [\n ['d', hashedNametag],\n ['a', address],\n ]);\n\n await this.publishEvent(event);\n this.log('Published nametag binding:', nametag);\n }\n\n async registerNametag(nametag: string, _publicKey: string, directAddress: string = ''): Promise<boolean> {\n this.ensureReady();\n\n if (!this.identity) {\n throw new Error('Identity not set');\n }\n\n // Always use 32-byte Nostr-format pubkey from keyManager (not the 33-byte compressed key)\n const nostrPubkey = this.getNostrPubkey();\n\n // Check if nametag is already taken by someone else\n const existing = await this.resolveNametag(nametag);\n\n this.log('registerNametag:', nametag, 'existing:', existing, 'myPubkey:', nostrPubkey);\n\n if (existing && existing !== nostrPubkey) {\n this.log('Nametag already taken:', nametag, '- owner:', existing);\n return false;\n }\n\n // Always (re)publish to ensure event has correct format with all required tags\n // This is a parameterized replaceable event (kind 30078), so publishing with same 'd' tag\n // will replace any old event. This ensures the event has ['t', hash] tag for nostr-js-sdk.\n\n // Derive extended address info for full nametag support:\n // - encrypted_nametag: AES-GCM encrypted nametag for recovery\n // - public_key: 33-byte compressed public key for L3 operations\n // - l1_address: L1 address (alpha1...) for L1 transfers\n const privateKeyHex = this.identity.privateKey;\n const compressedPubkey = getPublicKey(privateKeyHex, true); // 33-byte compressed\n const l1Address = publicKeyToAddress(compressedPubkey, 'alpha'); // alpha1...\n const encryptedNametag = await encryptNametag(nametag, privateKeyHex);\n\n // Compute PROXY address for reverse lookup\n const { ProxyAddress } = await import('@unicitylabs/state-transition-sdk/lib/address/ProxyAddress');\n const proxyAddr = await ProxyAddress.fromNameTag(nametag);\n const proxyAddress = proxyAddr.toString();\n\n // Publish nametag binding with extended info\n const hashedNametag = hashNametag(nametag);\n const content = JSON.stringify({\n nametag_hash: hashedNametag,\n address: nostrPubkey,\n verified: Date.now(),\n // Extended fields for nametag recovery and address lookup\n encrypted_nametag: encryptedNametag,\n public_key: compressedPubkey,\n l1_address: l1Address,\n direct_address: directAddress,\n proxy_address: proxyAddress,\n });\n\n // Build tags with indexed 't' tags for reverse lookup by nametag and address\n const tags: string[][] = [\n ['d', hashedNametag],\n ['nametag', hashedNametag],\n ['t', hashedNametag],\n ['t', hashAddressForTag(directAddress)],\n ['t', hashAddressForTag(proxyAddress)],\n ['address', nostrPubkey],\n ['pubkey', compressedPubkey],\n ['l1', l1Address],\n ];\n\n const event = await this.createEvent(EVENT_KINDS.NAMETAG_BINDING, content, tags);\n\n await this.publishEvent(event);\n this.log('Registered nametag:', nametag, 'for pubkey:', nostrPubkey.slice(0, 16) + '...', 'l1:', l1Address.slice(0, 12) + '...');\n return true;\n }\n\n // Track broadcast subscriptions\n private broadcastSubscriptions: Map<string, string> = new Map(); // key -> subId\n\n subscribeToBroadcast(tags: string[], handler: BroadcastHandler): () => void {\n const key = tags.sort().join(':');\n\n if (!this.broadcastHandlers.has(key)) {\n this.broadcastHandlers.set(key, new Set());\n\n // Subscribe to relay\n if (this.isConnected() && this.nostrClient) {\n this.subscribeToTags(tags);\n }\n }\n\n this.broadcastHandlers.get(key)!.add(handler);\n\n return () => {\n this.broadcastHandlers.get(key)?.delete(handler);\n if (this.broadcastHandlers.get(key)?.size === 0) {\n this.broadcastHandlers.delete(key);\n // Unsubscribe from relay\n const subId = this.broadcastSubscriptions.get(key);\n if (subId && this.nostrClient) {\n this.nostrClient.unsubscribe(subId);\n this.broadcastSubscriptions.delete(key);\n }\n }\n };\n }\n\n async publishBroadcast(content: string, tags?: string[]): Promise<string> {\n this.ensureReady();\n\n const eventTags = tags?.map((t) => ['t', t]) ?? [];\n const event = await this.createEvent(EVENT_KINDS.BROADCAST, content, eventTags);\n\n await this.publishEvent(event);\n return event.id;\n }\n\n // ===========================================================================\n // Event Subscription\n // ===========================================================================\n\n onEvent(callback: TransportEventCallback): () => void {\n this.eventCallbacks.add(callback);\n return () => this.eventCallbacks.delete(callback);\n }\n\n // ===========================================================================\n // Private: Message Handling\n // ===========================================================================\n\n private async handleEvent(event: NostrEvent): Promise<void> {\n // Dedup: skip events already processed by another subscription\n if (event.id && this.processedEventIds.has(event.id)) {\n return;\n }\n if (event.id) {\n this.processedEventIds.add(event.id);\n }\n\n this.log('Processing event kind:', event.kind, 'id:', event.id?.slice(0, 12));\n try {\n switch (event.kind) {\n case EVENT_KINDS.DIRECT_MESSAGE:\n await this.handleDirectMessage(event);\n break;\n case EventKinds.GIFT_WRAP:\n this.log('Handling gift wrap (NIP-17 DM)');\n await this.handleGiftWrap(event);\n break;\n case EVENT_KINDS.TOKEN_TRANSFER:\n await this.handleTokenTransfer(event);\n break;\n case EVENT_KINDS.PAYMENT_REQUEST:\n await this.handlePaymentRequest(event);\n break;\n case EVENT_KINDS.PAYMENT_REQUEST_RESPONSE:\n await this.handlePaymentRequestResponse(event);\n break;\n case EVENT_KINDS.BROADCAST:\n this.handleBroadcast(event);\n break;\n }\n\n // Persist the latest event timestamp for resumption on reconnect.\n // Only update for wallet event kinds (not chat/broadcast).\n if (event.created_at && this.storage && this.keyManager) {\n const kind = event.kind;\n if (\n kind === EVENT_KINDS.DIRECT_MESSAGE ||\n kind === EVENT_KINDS.TOKEN_TRANSFER ||\n kind === EVENT_KINDS.PAYMENT_REQUEST ||\n kind === EVENT_KINDS.PAYMENT_REQUEST_RESPONSE\n ) {\n this.updateLastEventTimestamp(event.created_at);\n }\n }\n } catch (error) {\n this.log('Failed to handle event:', error);\n }\n }\n\n /**\n * Save the max event timestamp to storage (fire-and-forget, no await needed by caller).\n * Uses in-memory `lastEventTs` to avoid read-before-write race conditions\n * when multiple events arrive in quick succession.\n */\n private updateLastEventTimestamp(createdAt: number): void {\n if (!this.storage || !this.keyManager) return;\n if (createdAt <= this.lastEventTs) return;\n\n this.lastEventTs = createdAt;\n const pubkey = this.keyManager.getPublicKeyHex();\n const storageKey = `${STORAGE_KEYS_GLOBAL.LAST_WALLET_EVENT_TS}_${pubkey.slice(0, 16)}`;\n\n this.storage.set(storageKey, createdAt.toString()).catch(err => {\n this.log('Failed to save last event timestamp:', err);\n });\n }\n\n private async handleDirectMessage(event: NostrEvent): Promise<void> {\n // NIP-04 (kind 4) is deprecated for DMs - only used for legacy token transfers\n // DMs should come through NIP-17 (kind 1059 gift wrap) via handleGiftWrap\n // This handler is kept for backwards compatibility but does NOT dispatch to messageHandlers\n this.log('Ignoring NIP-04 kind 4 event (DMs use NIP-17):', event.id?.slice(0, 12));\n }\n\n private async handleGiftWrap(event: NostrEvent): Promise<void> {\n if (!this.identity || !this.keyManager) {\n this.log('handleGiftWrap: no identity/keyManager');\n return;\n }\n\n try {\n const pm = NIP17.unwrap(event as any, this.keyManager);\n this.log('Gift wrap unwrapped, sender:', pm.senderPubkey?.slice(0, 16), 'kind:', pm.kind);\n if (pm.senderPubkey === this.keyManager.getPublicKeyHex()) {\n this.log('Skipping own message');\n return;\n }\n if (pm.kind !== EventKinds.CHAT_MESSAGE) {\n this.log('Skipping non-chat message, kind:', pm.kind);\n return;\n }\n\n // Sphere app wraps DM content as JSON: {senderNametag, text}\n let content = pm.content;\n let senderNametag: string | undefined;\n try {\n const parsed = JSON.parse(content);\n if (typeof parsed === 'object' && parsed.text !== undefined) {\n content = parsed.text;\n senderNametag = parsed.senderNametag || undefined;\n }\n } catch {\n // Plain text — use as-is\n }\n\n this.log('DM received from:', senderNametag || pm.senderPubkey?.slice(0, 16), 'content:', content?.slice(0, 50));\n\n const message: IncomingMessage = {\n id: pm.eventId,\n senderTransportPubkey: pm.senderPubkey,\n senderNametag,\n content,\n timestamp: pm.timestamp * 1000,\n encrypted: true,\n };\n\n this.emitEvent({ type: 'message:received', timestamp: Date.now() });\n\n this.log('Dispatching to', this.messageHandlers.size, 'handlers');\n for (const handler of this.messageHandlers) {\n try {\n handler(message);\n } catch (error) {\n this.log('Message handler error:', error);\n }\n }\n } catch (err) {\n // Expected for gift wraps meant for other recipients\n this.log('Gift wrap decrypt failed (expected if not for us):', (err as Error)?.message?.slice(0, 50));\n }\n }\n\n private async handleTokenTransfer(event: NostrEvent): Promise<void> {\n if (!this.identity) return;\n\n // Decrypt content\n const content = await this.decryptContent(event.content, event.pubkey);\n const payload = JSON.parse(content) as TokenTransferPayload;\n\n const transfer: IncomingTokenTransfer = {\n id: event.id,\n senderTransportPubkey: event.pubkey,\n payload,\n timestamp: event.created_at * 1000,\n };\n\n this.emitEvent({ type: 'transfer:received', timestamp: Date.now() });\n\n for (const handler of this.transferHandlers) {\n try {\n await handler(transfer);\n } catch (error) {\n this.log('Transfer handler error:', error);\n }\n }\n }\n\n private async handlePaymentRequest(event: NostrEvent): Promise<void> {\n if (!this.identity) return;\n\n try {\n // Decrypt content\n const content = await this.decryptContent(event.content, event.pubkey);\n const requestData = JSON.parse(content) as {\n requestId: string;\n amount: string;\n coinId: string;\n message?: string;\n recipientNametag?: string;\n metadata?: Record<string, unknown>;\n };\n\n const request: IncomingPaymentRequest = {\n id: event.id,\n senderTransportPubkey: event.pubkey,\n senderNametag: requestData.recipientNametag,\n request: {\n requestId: requestData.requestId,\n amount: requestData.amount,\n coinId: requestData.coinId,\n message: requestData.message,\n recipientNametag: requestData.recipientNametag,\n metadata: requestData.metadata,\n },\n timestamp: event.created_at * 1000,\n };\n\n this.log('Received payment request:', request.id);\n\n for (const handler of this.paymentRequestHandlers) {\n try {\n handler(request);\n } catch (error) {\n this.log('Payment request handler error:', error);\n }\n }\n } catch (error) {\n this.log('Failed to handle payment request:', error);\n }\n }\n\n private async handlePaymentRequestResponse(event: NostrEvent): Promise<void> {\n if (!this.identity) return;\n\n try {\n // Decrypt content\n const content = await this.decryptContent(event.content, event.pubkey);\n const responseData = JSON.parse(content) as {\n requestId: string;\n responseType: 'accepted' | 'rejected' | 'paid';\n message?: string;\n transferId?: string;\n };\n\n const response: IncomingPaymentRequestResponse = {\n id: event.id,\n responderTransportPubkey: event.pubkey,\n response: {\n requestId: responseData.requestId,\n responseType: responseData.responseType,\n message: responseData.message,\n transferId: responseData.transferId,\n },\n timestamp: event.created_at * 1000,\n };\n\n this.log('Received payment request response:', response.id, 'type:', responseData.responseType);\n\n for (const handler of this.paymentRequestResponseHandlers) {\n try {\n handler(response);\n } catch (error) {\n this.log('Payment request response handler error:', error);\n }\n }\n } catch (error) {\n this.log('Failed to handle payment request response:', error);\n }\n }\n\n private handleBroadcast(event: NostrEvent): void {\n const tags = event.tags\n .filter((t: string[]) => t[0] === 't')\n .map((t: string[]) => t[1]);\n\n const broadcast: IncomingBroadcast = {\n id: event.id,\n authorTransportPubkey: event.pubkey,\n content: event.content,\n tags,\n timestamp: event.created_at * 1000,\n };\n\n // Find matching handlers\n for (const [key, handlers] of this.broadcastHandlers) {\n const subscribedTags = key.split(':');\n if (tags.some((t) => subscribedTags.includes(t))) {\n for (const handler of handlers) {\n try {\n handler(broadcast);\n } catch (error) {\n this.log('Broadcast handler error:', error);\n }\n }\n }\n }\n }\n\n // ===========================================================================\n // Private: Event Creation & Publishing\n // ===========================================================================\n\n private async createEvent(\n kind: number,\n content: string,\n tags: string[][]\n ): Promise<NostrEvent> {\n if (!this.identity) throw new Error('Identity not set');\n if (!this.keyManager) throw new Error('KeyManager not initialized');\n\n // Create and sign event using SDK\n const signedEvent = NostrEventClass.create(this.keyManager, {\n kind,\n content,\n tags,\n });\n\n // Convert to our interface\n const event: NostrEvent = {\n id: signedEvent.id,\n kind: signedEvent.kind,\n content: signedEvent.content,\n tags: signedEvent.tags,\n pubkey: signedEvent.pubkey,\n created_at: signedEvent.created_at,\n sig: signedEvent.sig,\n };\n\n return event;\n }\n\n private async createEncryptedEvent(\n kind: number,\n content: string,\n tags: string[][]\n ): Promise<NostrEvent> {\n if (!this.keyManager) throw new Error('KeyManager not initialized');\n\n // Extract recipient pubkey from tags (first 'p' tag)\n const recipientTag = tags.find((t) => t[0] === 'p');\n if (!recipientTag || !recipientTag[1]) {\n throw new Error('No recipient pubkey in tags for encryption');\n }\n const recipientPubkey = recipientTag[1];\n\n // Encrypt content with NIP-04 (using hex variant for string keys)\n const encrypted = await NIP04.encryptHex(\n content,\n this.keyManager.getPrivateKeyHex(),\n recipientPubkey\n );\n\n return this.createEvent(kind, encrypted, tags);\n }\n\n private async publishEvent(event: NostrEvent): Promise<void> {\n if (!this.nostrClient) {\n throw new Error('NostrClient not initialized');\n }\n\n // Convert to nostr-js-sdk Event and publish\n const sdkEvent = NostrEventClass.fromJSON(event);\n await this.nostrClient.publishEvent(sdkEvent);\n }\n\n async fetchPendingEvents(): Promise<void> {\n if (!this.nostrClient?.isConnected() || !this.keyManager) {\n throw new Error('Transport not connected');\n }\n\n const nostrPubkey = this.keyManager.getPublicKeyHex();\n\n const walletFilter = new Filter();\n walletFilter.kinds = [\n EVENT_KINDS.DIRECT_MESSAGE,\n EVENT_KINDS.TOKEN_TRANSFER,\n EVENT_KINDS.PAYMENT_REQUEST,\n EVENT_KINDS.PAYMENT_REQUEST_RESPONSE,\n ];\n walletFilter['#p'] = [nostrPubkey];\n walletFilter.since = Math.floor(Date.now() / 1000) - 86400;\n\n // Collect events first, then process after EOSE\n const events: NostrEvent[] = [];\n\n await new Promise<void>((resolve) => {\n const timeout = setTimeout(() => {\n if (subId) this.nostrClient?.unsubscribe(subId);\n resolve();\n }, 5000);\n\n const subId = this.nostrClient!.subscribe(walletFilter, {\n onEvent: (event) => {\n events.push({\n id: event.id,\n kind: event.kind,\n content: event.content,\n tags: event.tags,\n pubkey: event.pubkey,\n created_at: event.created_at,\n sig: event.sig,\n });\n },\n onEndOfStoredEvents: () => {\n clearTimeout(timeout);\n this.nostrClient?.unsubscribe(subId);\n resolve();\n },\n });\n });\n\n // Process collected events sequentially (dedup skips already-processed ones)\n for (const event of events) {\n await this.handleEvent(event);\n }\n }\n\n private async queryEvents(filterObj: NostrFilter): Promise<NostrEvent[]> {\n if (!this.nostrClient || !this.nostrClient.isConnected()) {\n throw new Error('No connected relays');\n }\n\n const events: NostrEvent[] = [];\n const filter = new Filter(filterObj);\n\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n if (subId) {\n this.nostrClient?.unsubscribe(subId);\n }\n resolve(events);\n }, 5000);\n\n const subId = this.nostrClient!.subscribe(filter, {\n onEvent: (event) => {\n events.push({\n id: event.id,\n kind: event.kind,\n content: event.content,\n tags: event.tags,\n pubkey: event.pubkey,\n created_at: event.created_at,\n sig: event.sig,\n });\n },\n onEndOfStoredEvents: () => {\n clearTimeout(timeout);\n this.nostrClient?.unsubscribe(subId);\n resolve(events);\n },\n });\n });\n }\n\n // ===========================================================================\n // Private: Subscriptions\n // ===========================================================================\n\n // Track subscription IDs for cleanup\n private walletSubscriptionId: string | null = null;\n private chatSubscriptionId: string | null = null;\n\n private async subscribeToEvents(): Promise<void> {\n this.log('subscribeToEvents called, identity:', !!this.identity, 'keyManager:', !!this.keyManager, 'nostrClient:', !!this.nostrClient);\n if (!this.identity || !this.keyManager || !this.nostrClient) {\n this.log('subscribeToEvents: skipped - no identity, keyManager, or nostrClient');\n return;\n }\n\n // Unsubscribe from previous subscriptions if any\n if (this.walletSubscriptionId) {\n this.nostrClient.unsubscribe(this.walletSubscriptionId);\n this.walletSubscriptionId = null;\n }\n if (this.chatSubscriptionId) {\n this.nostrClient.unsubscribe(this.chatSubscriptionId);\n this.chatSubscriptionId = null;\n }\n if (this.mainSubscriptionId) {\n this.nostrClient.unsubscribe(this.mainSubscriptionId);\n this.mainSubscriptionId = null;\n }\n\n // Use 32-byte Nostr pubkey (x-coordinate only), not 33-byte compressed key\n const nostrPubkey = this.keyManager.getPublicKeyHex();\n this.log('Subscribing with Nostr pubkey:', nostrPubkey);\n\n // Determine 'since' filter from persisted last event timestamp.\n // - Existing wallet: resume from last processed event (inclusive >=, dedup handles replays)\n // - Fresh wallet / no storage: use current time (no historical replay)\n let since: number;\n if (this.storage) {\n const storageKey = `${STORAGE_KEYS_GLOBAL.LAST_WALLET_EVENT_TS}_${nostrPubkey.slice(0, 16)}`;\n try {\n const stored = await this.storage.get(storageKey);\n if (stored) {\n since = parseInt(stored, 10);\n this.lastEventTs = since; // Seed in-memory tracker from storage\n this.log('Resuming from stored event timestamp:', since);\n } else {\n // No stored timestamp = fresh wallet, start from now\n since = Math.floor(Date.now() / 1000);\n this.log('No stored timestamp, starting from now:', since);\n }\n } catch (err) {\n this.log('Failed to read last event timestamp, falling back to now:', err);\n since = Math.floor(Date.now() / 1000);\n }\n } else {\n // No storage adapter — fallback to last 24h (legacy behavior)\n since = Math.floor(Date.now() / 1000) - 86400;\n this.log('No storage adapter, using 24h fallback');\n }\n\n // Subscribe to wallet events (token transfers, payment requests) with since filter\n const walletFilter = new Filter();\n walletFilter.kinds = [\n EVENT_KINDS.DIRECT_MESSAGE,\n EVENT_KINDS.TOKEN_TRANSFER,\n EVENT_KINDS.PAYMENT_REQUEST,\n EVENT_KINDS.PAYMENT_REQUEST_RESPONSE,\n ];\n walletFilter['#p'] = [nostrPubkey];\n walletFilter.since = since;\n\n this.walletSubscriptionId = this.nostrClient.subscribe(walletFilter, {\n onEvent: (event) => {\n this.log('Received wallet event kind:', event.kind, 'id:', event.id?.slice(0, 12));\n this.handleEvent({\n id: event.id,\n kind: event.kind,\n content: event.content,\n tags: event.tags,\n pubkey: event.pubkey,\n created_at: event.created_at,\n sig: event.sig,\n });\n },\n onEndOfStoredEvents: () => {\n this.log('Wallet subscription ready (EOSE)');\n },\n onError: (_subId, error) => {\n this.log('Wallet subscription error:', error);\n },\n });\n this.log('Wallet subscription created, subId:', this.walletSubscriptionId);\n\n // Subscribe to chat events (NIP-17 gift wrap) WITHOUT since filter\n // This matches Sphere app's approach - chat messages rely on deduplication\n const chatFilter = new Filter();\n chatFilter.kinds = [EventKinds.GIFT_WRAP];\n chatFilter['#p'] = [nostrPubkey];\n // NO since filter for chat - we want real-time messages\n\n this.chatSubscriptionId = this.nostrClient.subscribe(chatFilter, {\n onEvent: (event) => {\n this.log('Received chat event kind:', event.kind, 'id:', event.id?.slice(0, 12));\n this.handleEvent({\n id: event.id,\n kind: event.kind,\n content: event.content,\n tags: event.tags,\n pubkey: event.pubkey,\n created_at: event.created_at,\n sig: event.sig,\n });\n },\n onEndOfStoredEvents: () => {\n this.log('Chat subscription ready (EOSE)');\n },\n onError: (_subId, error) => {\n this.log('Chat subscription error:', error);\n },\n });\n this.log('Chat subscription created, subId:', this.chatSubscriptionId);\n }\n\n private subscribeToTags(tags: string[]): void {\n if (!this.nostrClient) return;\n\n const key = tags.sort().join(':');\n const filter = new Filter({\n kinds: [EVENT_KINDS.BROADCAST],\n '#t': tags,\n since: Math.floor(Date.now() / 1000) - 3600, // Last hour\n });\n\n const subId = this.nostrClient.subscribe(filter, {\n onEvent: (event) => {\n this.handleBroadcast({\n id: event.id,\n kind: event.kind,\n content: event.content,\n tags: event.tags,\n pubkey: event.pubkey,\n created_at: event.created_at,\n sig: event.sig,\n });\n },\n });\n\n this.broadcastSubscriptions.set(key, subId);\n }\n\n // ===========================================================================\n // Private: Encryption\n // ===========================================================================\n\n private async decryptContent(content: string, senderPubkey: string): Promise<string> {\n if (!this.keyManager) throw new Error('KeyManager not initialized');\n\n // Decrypt content using NIP-04 (using hex variant for string keys)\n const decrypted = await NIP04.decryptHex(\n content,\n this.keyManager.getPrivateKeyHex(),\n senderPubkey\n );\n\n // Strip known prefixes for compatibility with nostr-js-sdk\n return this.stripContentPrefix(decrypted);\n }\n\n /**\n * Strip known content prefixes (nostr-js-sdk compatibility)\n * Handles: payment_request:, token_transfer:, etc.\n */\n private stripContentPrefix(content: string): string {\n const prefixes = [\n 'payment_request:',\n 'token_transfer:',\n 'payment_response:',\n ];\n\n for (const prefix of prefixes) {\n if (content.startsWith(prefix)) {\n return content.slice(prefix.length);\n }\n }\n\n return content;\n }\n\n // ===========================================================================\n // Private: Helpers\n // ===========================================================================\n\n private ensureConnected(): void {\n if (!this.isConnected()) {\n throw new Error('NostrTransportProvider not connected');\n }\n }\n\n private ensureReady(): void {\n this.ensureConnected();\n if (!this.identity) {\n throw new Error('Identity not set');\n }\n }\n\n private emitEvent(event: TransportEvent): void {\n for (const callback of this.eventCallbacks) {\n try {\n callback(event);\n } catch (error) {\n this.log('Event callback error:', error);\n }\n }\n }\n\n private log(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[NostrTransportProvider]', ...args);\n }\n }\n}\n\n// =============================================================================\n// Types\n// =============================================================================\n\ninterface NostrEvent {\n id: string;\n kind: number;\n content: string;\n tags: string[][];\n pubkey: string;\n created_at: number;\n sig: string;\n}\n\ninterface NostrFilter {\n ids?: string[];\n authors?: string[];\n kinds?: number[];\n '#p'?: string[];\n '#t'?: string[];\n '#d'?: string[];\n since?: number;\n until?: number;\n limit?: number;\n}\n","/**\n * Utilities for hex, bytes, CSPRNG.\n * @module\n */\n/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */\n/** Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. */\nexport function isBytes(a: unknown): a is Uint8Array {\n return a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');\n}\n\n/** Asserts something is positive integer. */\nexport function anumber(n: number, title: string = ''): void {\n if (!Number.isSafeInteger(n) || n < 0) {\n const prefix = title && `\"${title}\" `;\n throw new Error(`${prefix}expected integer >= 0, got ${n}`);\n }\n}\n\n/** Asserts something is Uint8Array. */\nexport function abytes(value: Uint8Array, length?: number, title: string = ''): Uint8Array {\n const bytes = isBytes(value);\n const len = value?.length;\n const needsLen = length !== undefined;\n if (!bytes || (needsLen && len !== length)) {\n const prefix = title && `\"${title}\" `;\n const ofLen = needsLen ? ` of length ${length}` : '';\n const got = bytes ? `length=${len}` : `type=${typeof value}`;\n throw new Error(prefix + 'expected Uint8Array' + ofLen + ', got ' + got);\n }\n return value;\n}\n\n/** Asserts something is hash */\nexport function ahash(h: CHash): void {\n if (typeof h !== 'function' || typeof h.create !== 'function')\n throw new Error('Hash must wrapped by utils.createHasher');\n anumber(h.outputLen);\n anumber(h.blockLen);\n}\n\n/** Asserts a hash instance has not been destroyed / finished */\nexport function aexists(instance: any, checkFinished = true): void {\n if (instance.destroyed) throw new Error('Hash instance has been destroyed');\n if (checkFinished && instance.finished) throw new Error('Hash#digest() has already been called');\n}\n\n/** Asserts output is properly-sized byte array */\nexport function aoutput(out: any, instance: any): void {\n abytes(out, undefined, 'digestInto() output');\n const min = instance.outputLen;\n if (out.length < min) {\n throw new Error('\"digestInto() output\" expected to be of length >=' + min);\n }\n}\n\n/** Generic type encompassing 8/16/32-byte arrays - but not 64-byte. */\n// prettier-ignore\nexport type TypedArray = Int8Array | Uint8ClampedArray | Uint8Array |\n Uint16Array | Int16Array | Uint32Array | Int32Array;\n\n/** Cast u8 / u16 / u32 to u8. */\nexport function u8(arr: TypedArray): Uint8Array {\n return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);\n}\n\n/** Cast u8 / u16 / u32 to u32. */\nexport function u32(arr: TypedArray): Uint32Array {\n return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));\n}\n\n/** Zeroize a byte array. Warning: JS provides no guarantees. */\nexport function clean(...arrays: TypedArray[]): void {\n for (let i = 0; i < arrays.length; i++) {\n arrays[i].fill(0);\n }\n}\n\n/** Create DataView of an array for easy byte-level manipulation. */\nexport function createView(arr: TypedArray): DataView {\n return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);\n}\n\n/** The rotate right (circular right shift) operation for uint32 */\nexport function rotr(word: number, shift: number): number {\n return (word << (32 - shift)) | (word >>> shift);\n}\n\n/** The rotate left (circular left shift) operation for uint32 */\nexport function rotl(word: number, shift: number): number {\n return (word << shift) | ((word >>> (32 - shift)) >>> 0);\n}\n\n/** Is current platform little-endian? Most are. Big-Endian platform: IBM */\nexport const isLE: boolean = /* @__PURE__ */ (() =>\n new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44)();\n\n/** The byte swap operation for uint32 */\nexport function byteSwap(word: number): number {\n return (\n ((word << 24) & 0xff000000) |\n ((word << 8) & 0xff0000) |\n ((word >>> 8) & 0xff00) |\n ((word >>> 24) & 0xff)\n );\n}\n/** Conditionally byte swap if on a big-endian platform */\nexport const swap8IfBE: (n: number) => number = isLE\n ? (n: number) => n\n : (n: number) => byteSwap(n);\n\n/** In place byte swap for Uint32Array */\nexport function byteSwap32(arr: Uint32Array): Uint32Array {\n for (let i = 0; i < arr.length; i++) {\n arr[i] = byteSwap(arr[i]);\n }\n return arr;\n}\n\nexport const swap32IfBE: (u: Uint32Array) => Uint32Array = isLE\n ? (u: Uint32Array) => u\n : byteSwap32;\n\n// Built-in hex conversion https://caniuse.com/mdn-javascript_builtins_uint8array_fromhex\nconst hasHexBuiltin: boolean = /* @__PURE__ */ (() =>\n // @ts-ignore\n typeof Uint8Array.from([]).toHex === 'function' && typeof Uint8Array.fromHex === 'function')();\n\n// Array where index 0xf0 (240) is mapped to string 'f0'\nconst hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>\n i.toString(16).padStart(2, '0')\n);\n\n/**\n * Convert byte array to hex string. Uses built-in function, when available.\n * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n abytes(bytes);\n // @ts-ignore\n if (hasHexBuiltin) return bytes.toHex();\n // pre-caching improves the speed 6x\n let hex = '';\n for (let i = 0; i < bytes.length; i++) {\n hex += hexes[bytes[i]];\n }\n return hex;\n}\n\n// We use optimized technique to convert hex string to byte array\nconst asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 } as const;\nfunction asciiToBase16(ch: number): number | undefined {\n if (ch >= asciis._0 && ch <= asciis._9) return ch - asciis._0; // '2' => 50-48\n if (ch >= asciis.A && ch <= asciis.F) return ch - (asciis.A - 10); // 'B' => 66-(65-10)\n if (ch >= asciis.a && ch <= asciis.f) return ch - (asciis.a - 10); // 'b' => 98-(97-10)\n return;\n}\n\n/**\n * Convert hex string to byte array. Uses built-in function, when available.\n * @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])\n */\nexport function hexToBytes(hex: string): Uint8Array {\n if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);\n // @ts-ignore\n if (hasHexBuiltin) return Uint8Array.fromHex(hex);\n const hl = hex.length;\n const al = hl / 2;\n if (hl % 2) throw new Error('hex string expected, got unpadded hex of length ' + hl);\n const array = new Uint8Array(al);\n for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {\n const n1 = asciiToBase16(hex.charCodeAt(hi));\n const n2 = asciiToBase16(hex.charCodeAt(hi + 1));\n if (n1 === undefined || n2 === undefined) {\n const char = hex[hi] + hex[hi + 1];\n throw new Error('hex string expected, got non-hex character \"' + char + '\" at index ' + hi);\n }\n array[ai] = n1 * 16 + n2; // multiply first octet, e.g. 'a3' => 10*16+3 => 160 + 3 => 163\n }\n return array;\n}\n\n/**\n * There is no setImmediate in browser and setTimeout is slow.\n * Call of async fn will return Promise, which will be fullfiled only on\n * next scheduler queue processing step and this is exactly what we need.\n */\nexport const nextTick = async (): Promise<void> => {};\n\n/** Returns control to thread each 'tick' ms to avoid blocking. */\nexport async function asyncLoop(\n iters: number,\n tick: number,\n cb: (i: number) => void\n): Promise<void> {\n let ts = Date.now();\n for (let i = 0; i < iters; i++) {\n cb(i);\n // Date.now() is not monotonic, so in case if clock goes backwards we return return control too\n const diff = Date.now() - ts;\n if (diff >= 0 && diff < tick) continue;\n await nextTick();\n ts += diff;\n }\n}\n\n// Global symbols, but ts doesn't see them: https://github.com/microsoft/TypeScript/issues/31535\ndeclare const TextEncoder: any;\n\n/**\n * Converts string to bytes using UTF8 encoding.\n * Built-in doesn't validate input to be string: we do the check.\n * @example utf8ToBytes('abc') // Uint8Array.from([97, 98, 99])\n */\nexport function utf8ToBytes(str: string): Uint8Array {\n if (typeof str !== 'string') throw new Error('string expected');\n return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809\n}\n\n/** KDFs can accept string or Uint8Array for user convenience. */\nexport type KDFInput = string | Uint8Array;\n\n/**\n * Helper for KDFs: consumes uint8array or string.\n * When string is passed, does utf8 decoding, using TextDecoder.\n */\nexport function kdfInputToBytes(data: KDFInput, errorTitle = ''): Uint8Array {\n if (typeof data === 'string') return utf8ToBytes(data);\n return abytes(data, undefined, errorTitle);\n}\n\n/** Copies several Uint8Arrays into one. */\nexport function concatBytes(...arrays: Uint8Array[]): Uint8Array {\n let sum = 0;\n for (let i = 0; i < arrays.length; i++) {\n const a = arrays[i];\n abytes(a);\n sum += a.length;\n }\n const res = new Uint8Array(sum);\n for (let i = 0, pad = 0; i < arrays.length; i++) {\n const a = arrays[i];\n res.set(a, pad);\n pad += a.length;\n }\n return res;\n}\n\ntype EmptyObj = {};\n/** Merges default options and passed options. */\nexport function checkOpts<T1 extends EmptyObj, T2 extends EmptyObj>(\n defaults: T1,\n opts?: T2\n): T1 & T2 {\n if (opts !== undefined && {}.toString.call(opts) !== '[object Object]')\n throw new Error('options must be object or undefined');\n const merged = Object.assign(defaults, opts);\n return merged as T1 & T2;\n}\n\n/** Common interface for all hashes. */\nexport interface Hash<T> {\n blockLen: number; // Bytes per block\n outputLen: number; // Bytes in output\n update(buf: Uint8Array): this;\n digestInto(buf: Uint8Array): void;\n digest(): Uint8Array;\n destroy(): void;\n _cloneInto(to?: T): T;\n clone(): T;\n}\n\n/** PseudoRandom (number) Generator */\nexport interface PRG {\n addEntropy(seed: Uint8Array): void;\n randomBytes(length: number): Uint8Array;\n clean(): void;\n}\n\n/**\n * XOF: streaming API to read digest in chunks.\n * Same as 'squeeze' in keccak/k12 and 'seek' in blake3, but more generic name.\n * When hash used in XOF mode it is up to user to call '.destroy' afterwards, since we cannot\n * destroy state, next call can require more bytes.\n */\nexport type HashXOF<T extends Hash<T>> = Hash<T> & {\n xof(bytes: number): Uint8Array; // Read 'bytes' bytes from digest stream\n xofInto(buf: Uint8Array): Uint8Array; // read buf.length bytes from digest stream into buf\n};\n\n/** Hash constructor */\nexport type HasherCons<T, Opts = undefined> = Opts extends undefined ? () => T : (opts?: Opts) => T;\n/** Optional hash params. */\nexport type HashInfo = {\n oid?: Uint8Array; // DER encoded OID in bytes\n};\n/** Hash function */\nexport type CHash<T extends Hash<T> = Hash<any>, Opts = undefined> = {\n outputLen: number;\n blockLen: number;\n} & HashInfo &\n (Opts extends undefined\n ? {\n (msg: Uint8Array): Uint8Array;\n create(): T;\n }\n : {\n (msg: Uint8Array, opts?: Opts): Uint8Array;\n create(opts?: Opts): T;\n });\n/** XOF with output */\nexport type CHashXOF<T extends HashXOF<T> = HashXOF<any>, Opts = undefined> = CHash<T, Opts>;\n\n/** Creates function with outputLen, blockLen, create properties from a class constructor. */\nexport function createHasher<T extends Hash<T>, Opts = undefined>(\n hashCons: HasherCons<T, Opts>,\n info: HashInfo = {}\n): CHash<T, Opts> {\n const hashC: any = (msg: Uint8Array, opts?: Opts) => hashCons(opts).update(msg).digest();\n const tmp = hashCons(undefined);\n hashC.outputLen = tmp.outputLen;\n hashC.blockLen = tmp.blockLen;\n hashC.create = (opts?: Opts) => hashCons(opts);\n Object.assign(hashC, info);\n return Object.freeze(hashC);\n}\n\n/** Cryptographically secure PRNG. Uses internal OS-level `crypto.getRandomValues`. */\nexport function randomBytes(bytesLength = 32): Uint8Array {\n const cr = typeof globalThis === 'object' ? (globalThis as any).crypto : null;\n if (typeof cr?.getRandomValues !== 'function')\n throw new Error('crypto.getRandomValues must be defined');\n return cr.getRandomValues(new Uint8Array(bytesLength));\n}\n\n/** Creates OID opts for NIST hashes, with prefix 06 09 60 86 48 01 65 03 04 02. */\nexport const oidNist = (suffix: number): Required<HashInfo> => ({\n oid: Uint8Array.from([0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, suffix]),\n});\n","/**\n * HMAC: RFC2104 message authentication code.\n * @module\n */\nimport { abytes, aexists, ahash, clean, type CHash, type Hash } from './utils.ts';\n\n/** Internal class for HMAC. */\nexport class _HMAC<T extends Hash<T>> implements Hash<_HMAC<T>> {\n oHash: T;\n iHash: T;\n blockLen: number;\n outputLen: number;\n private finished = false;\n private destroyed = false;\n\n constructor(hash: CHash, key: Uint8Array) {\n ahash(hash);\n abytes(key, undefined, 'key');\n this.iHash = hash.create() as T;\n if (typeof this.iHash.update !== 'function')\n throw new Error('Expected instance of class which extends utils.Hash');\n this.blockLen = this.iHash.blockLen;\n this.outputLen = this.iHash.outputLen;\n const blockLen = this.blockLen;\n const pad = new Uint8Array(blockLen);\n // blockLen can be bigger than outputLen\n pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);\n for (let i = 0; i < pad.length; i++) pad[i] ^= 0x36;\n this.iHash.update(pad);\n // By doing update (processing of first block) of outer hash here we can re-use it between multiple calls via clone\n this.oHash = hash.create() as T;\n // Undo internal XOR && apply outer XOR\n for (let i = 0; i < pad.length; i++) pad[i] ^= 0x36 ^ 0x5c;\n this.oHash.update(pad);\n clean(pad);\n }\n update(buf: Uint8Array): this {\n aexists(this);\n this.iHash.update(buf);\n return this;\n }\n digestInto(out: Uint8Array): void {\n aexists(this);\n abytes(out, this.outputLen, 'output');\n this.finished = true;\n this.iHash.digestInto(out);\n this.oHash.update(out);\n this.oHash.digestInto(out);\n this.destroy();\n }\n digest(): Uint8Array {\n const out = new Uint8Array(this.oHash.outputLen);\n this.digestInto(out);\n return out;\n }\n _cloneInto(to?: _HMAC<T>): _HMAC<T> {\n // Create new instance without calling constructor since key already in state and we don't know it.\n to ||= Object.create(Object.getPrototypeOf(this), {});\n const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;\n to = to as this;\n to.finished = finished;\n to.destroyed = destroyed;\n to.blockLen = blockLen;\n to.outputLen = outputLen;\n to.oHash = oHash._cloneInto(to.oHash);\n to.iHash = iHash._cloneInto(to.iHash);\n return to;\n }\n clone(): _HMAC<T> {\n return this._cloneInto();\n }\n destroy(): void {\n this.destroyed = true;\n this.oHash.destroy();\n this.iHash.destroy();\n }\n}\n\n/**\n * HMAC: RFC2104 message authentication code.\n * @param hash - function that would be used e.g. sha256\n * @param key - message key\n * @param message - message data\n * @example\n * import { hmac } from '@noble/hashes/hmac';\n * import { sha256 } from '@noble/hashes/sha2';\n * const mac1 = hmac(sha256, 'key', 'message');\n */\nexport const hmac: {\n (hash: CHash, key: Uint8Array, message: Uint8Array): Uint8Array;\n create(hash: CHash, key: Uint8Array): _HMAC<any>;\n} = (hash: CHash, key: Uint8Array, message: Uint8Array): Uint8Array =>\n new _HMAC<any>(hash, key).update(message).digest();\nhmac.create = (hash: CHash, key: Uint8Array) => new _HMAC<any>(hash, key);\n","/**\n * HKDF (RFC 5869): extract + expand in one step.\n * See https://soatok.blog/2021/11/17/understanding-hkdf/.\n * @module\n */\nimport { hmac } from './hmac.ts';\nimport { abytes, ahash, anumber, type CHash, clean } from './utils.ts';\n\n/**\n * HKDF-extract from spec. Less important part. `HKDF-Extract(IKM, salt) -> PRK`\n * Arguments position differs from spec (IKM is first one, since it is not optional)\n * @param hash - hash function that would be used (e.g. sha256)\n * @param ikm - input keying material, the initial key\n * @param salt - optional salt value (a non-secret random value)\n */\nexport function extract(hash: CHash, ikm: Uint8Array, salt?: Uint8Array): Uint8Array {\n ahash(hash);\n // NOTE: some libraries treat zero-length array as 'not provided';\n // we don't, since we have undefined as 'not provided'\n // https://github.com/RustCrypto/KDFs/issues/15\n if (salt === undefined) salt = new Uint8Array(hash.outputLen);\n return hmac(hash, salt, ikm);\n}\n\nconst HKDF_COUNTER = /* @__PURE__ */ Uint8Array.of(0);\nconst EMPTY_BUFFER = /* @__PURE__ */ Uint8Array.of();\n\n/**\n * HKDF-expand from the spec. The most important part. `HKDF-Expand(PRK, info, L) -> OKM`\n * @param hash - hash function that would be used (e.g. sha256)\n * @param prk - a pseudorandom key of at least HashLen octets (usually, the output from the extract step)\n * @param info - optional context and application specific information (can be a zero-length string)\n * @param length - length of output keying material in bytes\n */\nexport function expand(\n hash: CHash,\n prk: Uint8Array,\n info?: Uint8Array,\n length: number = 32\n): Uint8Array {\n ahash(hash);\n anumber(length, 'length');\n const olen = hash.outputLen;\n if (length > 255 * olen) throw new Error('Length must be <= 255*HashLen');\n const blocks = Math.ceil(length / olen);\n if (info === undefined) info = EMPTY_BUFFER;\n else abytes(info, undefined, 'info');\n // first L(ength) octets of T\n const okm = new Uint8Array(blocks * olen);\n // Re-use HMAC instance between blocks\n const HMAC = hmac.create(hash, prk);\n const HMACTmp = HMAC._cloneInto();\n const T = new Uint8Array(HMAC.outputLen);\n for (let counter = 0; counter < blocks; counter++) {\n HKDF_COUNTER[0] = counter + 1;\n // T(0) = empty string (zero length)\n // T(N) = HMAC-Hash(PRK, T(N-1) | info | N)\n HMACTmp.update(counter === 0 ? EMPTY_BUFFER : T)\n .update(info)\n .update(HKDF_COUNTER)\n .digestInto(T);\n okm.set(T, olen * counter);\n HMAC._cloneInto(HMACTmp);\n }\n HMAC.destroy();\n HMACTmp.destroy();\n clean(T, HKDF_COUNTER);\n return okm.slice(0, length);\n}\n\n/**\n * HKDF (RFC 5869): derive keys from an initial input.\n * Combines hkdf_extract + hkdf_expand in one step\n * @param hash - hash function that would be used (e.g. sha256)\n * @param ikm - input keying material, the initial key\n * @param salt - optional salt value (a non-secret random value)\n * @param info - optional context and application specific information (can be a zero-length string)\n * @param length - length of output keying material in bytes\n * @example\n * import { hkdf } from '@noble/hashes/hkdf';\n * import { sha256 } from '@noble/hashes/sha2';\n * import { randomBytes } from '@noble/hashes/utils';\n * const inputKey = randomBytes(32);\n * const salt = randomBytes(32);\n * const info = 'application-key';\n * const hk1 = hkdf(sha256, inputKey, salt, info, 32);\n */\nexport const hkdf = (\n hash: CHash,\n ikm: Uint8Array,\n salt: Uint8Array | undefined,\n info: Uint8Array | undefined,\n length: number\n): Uint8Array => expand(hash, extract(hash, ikm, salt), info, length);\n","/**\n * Internal Merkle-Damgard hash utils.\n * @module\n */\nimport { abytes, aexists, aoutput, clean, createView, type Hash } from './utils.ts';\n\n/** Choice: a ? b : c */\nexport function Chi(a: number, b: number, c: number): number {\n return (a & b) ^ (~a & c);\n}\n\n/** Majority function, true if any two inputs is true. */\nexport function Maj(a: number, b: number, c: number): number {\n return (a & b) ^ (a & c) ^ (b & c);\n}\n\n/**\n * Merkle-Damgard hash construction base class.\n * Could be used to create MD5, RIPEMD, SHA1, SHA2.\n */\nexport abstract class HashMD<T extends HashMD<T>> implements Hash<T> {\n protected abstract process(buf: DataView, offset: number): void;\n protected abstract get(): number[];\n protected abstract set(...args: number[]): void;\n abstract destroy(): void;\n protected abstract roundClean(): void;\n\n readonly blockLen: number;\n readonly outputLen: number;\n readonly padOffset: number;\n readonly isLE: boolean;\n\n // For partial updates less than block size\n protected buffer: Uint8Array;\n protected view: DataView;\n protected finished = false;\n protected length = 0;\n protected pos = 0;\n protected destroyed = false;\n\n constructor(blockLen: number, outputLen: number, padOffset: number, isLE: boolean) {\n this.blockLen = blockLen;\n this.outputLen = outputLen;\n this.padOffset = padOffset;\n this.isLE = isLE;\n this.buffer = new Uint8Array(blockLen);\n this.view = createView(this.buffer);\n }\n update(data: Uint8Array): this {\n aexists(this);\n abytes(data);\n const { view, buffer, blockLen } = this;\n const len = data.length;\n for (let pos = 0; pos < len; ) {\n const take = Math.min(blockLen - this.pos, len - pos);\n // Fast path: we have at least one block in input, cast it to view and process\n if (take === blockLen) {\n const dataView = createView(data);\n for (; blockLen <= len - pos; pos += blockLen) this.process(dataView, pos);\n continue;\n }\n buffer.set(data.subarray(pos, pos + take), this.pos);\n this.pos += take;\n pos += take;\n if (this.pos === blockLen) {\n this.process(view, 0);\n this.pos = 0;\n }\n }\n this.length += data.length;\n this.roundClean();\n return this;\n }\n digestInto(out: Uint8Array): void {\n aexists(this);\n aoutput(out, this);\n this.finished = true;\n // Padding\n // We can avoid allocation of buffer for padding completely if it\n // was previously not allocated here. But it won't change performance.\n const { buffer, view, blockLen, isLE } = this;\n let { pos } = this;\n // append the bit '1' to the message\n buffer[pos++] = 0b10000000;\n clean(this.buffer.subarray(pos));\n // we have less than padOffset left in buffer, so we cannot put length in\n // current block, need process it and pad again\n if (this.padOffset > blockLen - pos) {\n this.process(view, 0);\n pos = 0;\n }\n // Pad until full block byte with zeros\n for (let i = pos; i < blockLen; i++) buffer[i] = 0;\n // Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that\n // You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.\n // So we just write lowest 64 bits of that value.\n view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE);\n this.process(view, 0);\n const oview = createView(out);\n const len = this.outputLen;\n // NOTE: we do division by 4 later, which must be fused in single op with modulo by JIT\n if (len % 4) throw new Error('_sha2: outputLen must be aligned to 32bit');\n const outLen = len / 4;\n const state = this.get();\n if (outLen > state.length) throw new Error('_sha2: outputLen bigger than state');\n for (let i = 0; i < outLen; i++) oview.setUint32(4 * i, state[i], isLE);\n }\n digest(): Uint8Array {\n const { buffer, outputLen } = this;\n this.digestInto(buffer);\n const res = buffer.slice(0, outputLen);\n this.destroy();\n return res;\n }\n _cloneInto(to?: T): T {\n to ||= new (this.constructor as any)() as T;\n to.set(...this.get());\n const { blockLen, buffer, length, finished, destroyed, pos } = this;\n to.destroyed = destroyed;\n to.finished = finished;\n to.length = length;\n to.pos = pos;\n if (length % blockLen) to.buffer.set(buffer);\n return to as unknown as any;\n }\n clone(): T {\n return this._cloneInto();\n }\n}\n\n/**\n * Initial SHA-2 state: fractional parts of square roots of first 16 primes 2..53.\n * Check out `test/misc/sha2-gen-iv.js` for recomputation guide.\n */\n\n/** Initial SHA256 state. Bits 0..32 of frac part of sqrt of primes 2..19 */\nexport const SHA256_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,\n]);\n\n/** Initial SHA224 state. Bits 32..64 of frac part of sqrt of primes 23..53 */\nexport const SHA224_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4,\n]);\n\n/** Initial SHA384 state. Bits 0..64 of frac part of sqrt of primes 23..53 */\nexport const SHA384_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0xcbbb9d5d, 0xc1059ed8, 0x629a292a, 0x367cd507, 0x9159015a, 0x3070dd17, 0x152fecd8, 0xf70e5939,\n 0x67332667, 0xffc00b31, 0x8eb44a87, 0x68581511, 0xdb0c2e0d, 0x64f98fa7, 0x47b5481d, 0xbefa4fa4,\n]);\n\n/** Initial SHA512 state. Bits 0..64 of frac part of sqrt of primes 2..19 */\nexport const SHA512_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0x6a09e667, 0xf3bcc908, 0xbb67ae85, 0x84caa73b, 0x3c6ef372, 0xfe94f82b, 0xa54ff53a, 0x5f1d36f1,\n 0x510e527f, 0xade682d1, 0x9b05688c, 0x2b3e6c1f, 0x1f83d9ab, 0xfb41bd6b, 0x5be0cd19, 0x137e2179,\n]);\n","/**\n * SHA2 hash function. A.k.a. sha256, sha384, sha512, sha512_224, sha512_256.\n * SHA256 is the fastest hash implementable in JS, even faster than Blake3.\n * Check out [RFC 4634](https://www.rfc-editor.org/rfc/rfc4634) and\n * [FIPS 180-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).\n * @module\n */\nimport { Chi, HashMD, Maj, SHA224_IV, SHA256_IV, SHA384_IV, SHA512_IV } from './_md.ts';\nimport * as u64 from './_u64.ts';\nimport { type CHash, clean, createHasher, oidNist, rotr } from './utils.ts';\n\n/**\n * Round constants:\n * First 32 bits of fractional parts of the cube roots of the first 64 primes 2..311)\n */\n// prettier-ignore\nconst SHA256_K = /* @__PURE__ */ Uint32Array.from([\n 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2\n]);\n\n/** Reusable temporary buffer. \"W\" comes straight from spec. */\nconst SHA256_W = /* @__PURE__ */ new Uint32Array(64);\n\n/** Internal 32-byte base SHA2 hash class. */\nabstract class SHA2_32B<T extends SHA2_32B<T>> extends HashMD<T> {\n // We cannot use array here since array allows indexing by variable\n // which means optimizer/compiler cannot use registers.\n protected abstract A: number;\n protected abstract B: number;\n protected abstract C: number;\n protected abstract D: number;\n protected abstract E: number;\n protected abstract F: number;\n protected abstract G: number;\n protected abstract H: number;\n\n constructor(outputLen: number) {\n super(64, outputLen, 8, false);\n }\n protected get(): [number, number, number, number, number, number, number, number] {\n const { A, B, C, D, E, F, G, H } = this;\n return [A, B, C, D, E, F, G, H];\n }\n // prettier-ignore\n protected set(\n A: number, B: number, C: number, D: number, E: number, F: number, G: number, H: number\n ): void {\n this.A = A | 0;\n this.B = B | 0;\n this.C = C | 0;\n this.D = D | 0;\n this.E = E | 0;\n this.F = F | 0;\n this.G = G | 0;\n this.H = H | 0;\n }\n protected process(view: DataView, offset: number): void {\n // Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array\n for (let i = 0; i < 16; i++, offset += 4) SHA256_W[i] = view.getUint32(offset, false);\n for (let i = 16; i < 64; i++) {\n const W15 = SHA256_W[i - 15];\n const W2 = SHA256_W[i - 2];\n const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);\n const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);\n SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;\n }\n // Compression function main loop, 64 rounds\n let { A, B, C, D, E, F, G, H } = this;\n for (let i = 0; i < 64; i++) {\n const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);\n const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;\n const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);\n const T2 = (sigma0 + Maj(A, B, C)) | 0;\n H = G;\n G = F;\n F = E;\n E = (D + T1) | 0;\n D = C;\n C = B;\n B = A;\n A = (T1 + T2) | 0;\n }\n // Add the compressed chunk to the current hash value\n A = (A + this.A) | 0;\n B = (B + this.B) | 0;\n C = (C + this.C) | 0;\n D = (D + this.D) | 0;\n E = (E + this.E) | 0;\n F = (F + this.F) | 0;\n G = (G + this.G) | 0;\n H = (H + this.H) | 0;\n this.set(A, B, C, D, E, F, G, H);\n }\n protected roundClean(): void {\n clean(SHA256_W);\n }\n destroy(): void {\n this.set(0, 0, 0, 0, 0, 0, 0, 0);\n clean(this.buffer);\n }\n}\n\n/** Internal SHA2-256 hash class. */\nexport class _SHA256 extends SHA2_32B<_SHA256> {\n // We cannot use array here since array allows indexing by variable\n // which means optimizer/compiler cannot use registers.\n protected A: number = SHA256_IV[0] | 0;\n protected B: number = SHA256_IV[1] | 0;\n protected C: number = SHA256_IV[2] | 0;\n protected D: number = SHA256_IV[3] | 0;\n protected E: number = SHA256_IV[4] | 0;\n protected F: number = SHA256_IV[5] | 0;\n protected G: number = SHA256_IV[6] | 0;\n protected H: number = SHA256_IV[7] | 0;\n constructor() {\n super(32);\n }\n}\n\n/** Internal SHA2-224 hash class. */\nexport class _SHA224 extends SHA2_32B<_SHA224> {\n protected A: number = SHA224_IV[0] | 0;\n protected B: number = SHA224_IV[1] | 0;\n protected C: number = SHA224_IV[2] | 0;\n protected D: number = SHA224_IV[3] | 0;\n protected E: number = SHA224_IV[4] | 0;\n protected F: number = SHA224_IV[5] | 0;\n protected G: number = SHA224_IV[6] | 0;\n protected H: number = SHA224_IV[7] | 0;\n constructor() {\n super(28);\n }\n}\n\n// SHA2-512 is slower than sha256 in js because u64 operations are slow.\n\n// Round contants\n// First 32 bits of the fractional parts of the cube roots of the first 80 primes 2..409\n// prettier-ignore\nconst K512 = /* @__PURE__ */ (() => u64.split([\n '0x428a2f98d728ae22', '0x7137449123ef65cd', '0xb5c0fbcfec4d3b2f', '0xe9b5dba58189dbbc',\n '0x3956c25bf348b538', '0x59f111f1b605d019', '0x923f82a4af194f9b', '0xab1c5ed5da6d8118',\n '0xd807aa98a3030242', '0x12835b0145706fbe', '0x243185be4ee4b28c', '0x550c7dc3d5ffb4e2',\n '0x72be5d74f27b896f', '0x80deb1fe3b1696b1', '0x9bdc06a725c71235', '0xc19bf174cf692694',\n '0xe49b69c19ef14ad2', '0xefbe4786384f25e3', '0x0fc19dc68b8cd5b5', '0x240ca1cc77ac9c65',\n '0x2de92c6f592b0275', '0x4a7484aa6ea6e483', '0x5cb0a9dcbd41fbd4', '0x76f988da831153b5',\n '0x983e5152ee66dfab', '0xa831c66d2db43210', '0xb00327c898fb213f', '0xbf597fc7beef0ee4',\n '0xc6e00bf33da88fc2', '0xd5a79147930aa725', '0x06ca6351e003826f', '0x142929670a0e6e70',\n '0x27b70a8546d22ffc', '0x2e1b21385c26c926', '0x4d2c6dfc5ac42aed', '0x53380d139d95b3df',\n '0x650a73548baf63de', '0x766a0abb3c77b2a8', '0x81c2c92e47edaee6', '0x92722c851482353b',\n '0xa2bfe8a14cf10364', '0xa81a664bbc423001', '0xc24b8b70d0f89791', '0xc76c51a30654be30',\n '0xd192e819d6ef5218', '0xd69906245565a910', '0xf40e35855771202a', '0x106aa07032bbd1b8',\n '0x19a4c116b8d2d0c8', '0x1e376c085141ab53', '0x2748774cdf8eeb99', '0x34b0bcb5e19b48a8',\n '0x391c0cb3c5c95a63', '0x4ed8aa4ae3418acb', '0x5b9cca4f7763e373', '0x682e6ff3d6b2b8a3',\n '0x748f82ee5defb2fc', '0x78a5636f43172f60', '0x84c87814a1f0ab72', '0x8cc702081a6439ec',\n '0x90befffa23631e28', '0xa4506cebde82bde9', '0xbef9a3f7b2c67915', '0xc67178f2e372532b',\n '0xca273eceea26619c', '0xd186b8c721c0c207', '0xeada7dd6cde0eb1e', '0xf57d4f7fee6ed178',\n '0x06f067aa72176fba', '0x0a637dc5a2c898a6', '0x113f9804bef90dae', '0x1b710b35131c471b',\n '0x28db77f523047d84', '0x32caab7b40c72493', '0x3c9ebe0a15c9bebc', '0x431d67c49c100d4c',\n '0x4cc5d4becb3e42b6', '0x597f299cfc657e2a', '0x5fcb6fab3ad6faec', '0x6c44198c4a475817'\n].map(n => BigInt(n))))();\nconst SHA512_Kh = /* @__PURE__ */ (() => K512[0])();\nconst SHA512_Kl = /* @__PURE__ */ (() => K512[1])();\n\n// Reusable temporary buffers\nconst SHA512_W_H = /* @__PURE__ */ new Uint32Array(80);\nconst SHA512_W_L = /* @__PURE__ */ new Uint32Array(80);\n\n/** Internal 64-byte base SHA2 hash class. */\nabstract class SHA2_64B<T extends SHA2_64B<T>> extends HashMD<T> {\n // We cannot use array here since array allows indexing by variable\n // which means optimizer/compiler cannot use registers.\n // h -- high 32 bits, l -- low 32 bits\n protected abstract Ah: number;\n protected abstract Al: number;\n protected abstract Bh: number;\n protected abstract Bl: number;\n protected abstract Ch: number;\n protected abstract Cl: number;\n protected abstract Dh: number;\n protected abstract Dl: number;\n protected abstract Eh: number;\n protected abstract El: number;\n protected abstract Fh: number;\n protected abstract Fl: number;\n protected abstract Gh: number;\n protected abstract Gl: number;\n protected abstract Hh: number;\n protected abstract Hl: number;\n\n constructor(outputLen: number) {\n super(128, outputLen, 16, false);\n }\n // prettier-ignore\n protected get(): [\n number, number, number, number, number, number, number, number,\n number, number, number, number, number, number, number, number\n ] {\n const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;\n return [Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl];\n }\n // prettier-ignore\n protected set(\n Ah: number, Al: number, Bh: number, Bl: number, Ch: number, Cl: number, Dh: number, Dl: number,\n Eh: number, El: number, Fh: number, Fl: number, Gh: number, Gl: number, Hh: number, Hl: number\n ): void {\n this.Ah = Ah | 0;\n this.Al = Al | 0;\n this.Bh = Bh | 0;\n this.Bl = Bl | 0;\n this.Ch = Ch | 0;\n this.Cl = Cl | 0;\n this.Dh = Dh | 0;\n this.Dl = Dl | 0;\n this.Eh = Eh | 0;\n this.El = El | 0;\n this.Fh = Fh | 0;\n this.Fl = Fl | 0;\n this.Gh = Gh | 0;\n this.Gl = Gl | 0;\n this.Hh = Hh | 0;\n this.Hl = Hl | 0;\n }\n protected process(view: DataView, offset: number): void {\n // Extend the first 16 words into the remaining 64 words w[16..79] of the message schedule array\n for (let i = 0; i < 16; i++, offset += 4) {\n SHA512_W_H[i] = view.getUint32(offset);\n SHA512_W_L[i] = view.getUint32((offset += 4));\n }\n for (let i = 16; i < 80; i++) {\n // s0 := (w[i-15] rightrotate 1) xor (w[i-15] rightrotate 8) xor (w[i-15] rightshift 7)\n const W15h = SHA512_W_H[i - 15] | 0;\n const W15l = SHA512_W_L[i - 15] | 0;\n const s0h = u64.rotrSH(W15h, W15l, 1) ^ u64.rotrSH(W15h, W15l, 8) ^ u64.shrSH(W15h, W15l, 7);\n const s0l = u64.rotrSL(W15h, W15l, 1) ^ u64.rotrSL(W15h, W15l, 8) ^ u64.shrSL(W15h, W15l, 7);\n // s1 := (w[i-2] rightrotate 19) xor (w[i-2] rightrotate 61) xor (w[i-2] rightshift 6)\n const W2h = SHA512_W_H[i - 2] | 0;\n const W2l = SHA512_W_L[i - 2] | 0;\n const s1h = u64.rotrSH(W2h, W2l, 19) ^ u64.rotrBH(W2h, W2l, 61) ^ u64.shrSH(W2h, W2l, 6);\n const s1l = u64.rotrSL(W2h, W2l, 19) ^ u64.rotrBL(W2h, W2l, 61) ^ u64.shrSL(W2h, W2l, 6);\n // SHA256_W[i] = s0 + s1 + SHA256_W[i - 7] + SHA256_W[i - 16];\n const SUMl = u64.add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]);\n const SUMh = u64.add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]);\n SHA512_W_H[i] = SUMh | 0;\n SHA512_W_L[i] = SUMl | 0;\n }\n let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;\n // Compression function main loop, 80 rounds\n for (let i = 0; i < 80; i++) {\n // S1 := (e rightrotate 14) xor (e rightrotate 18) xor (e rightrotate 41)\n const sigma1h = u64.rotrSH(Eh, El, 14) ^ u64.rotrSH(Eh, El, 18) ^ u64.rotrBH(Eh, El, 41);\n const sigma1l = u64.rotrSL(Eh, El, 14) ^ u64.rotrSL(Eh, El, 18) ^ u64.rotrBL(Eh, El, 41);\n //const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;\n const CHIh = (Eh & Fh) ^ (~Eh & Gh);\n const CHIl = (El & Fl) ^ (~El & Gl);\n // T1 = H + sigma1 + Chi(E, F, G) + SHA512_K[i] + SHA512_W[i]\n // prettier-ignore\n const T1ll = u64.add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]);\n const T1h = u64.add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]);\n const T1l = T1ll | 0;\n // S0 := (a rightrotate 28) xor (a rightrotate 34) xor (a rightrotate 39)\n const sigma0h = u64.rotrSH(Ah, Al, 28) ^ u64.rotrBH(Ah, Al, 34) ^ u64.rotrBH(Ah, Al, 39);\n const sigma0l = u64.rotrSL(Ah, Al, 28) ^ u64.rotrBL(Ah, Al, 34) ^ u64.rotrBL(Ah, Al, 39);\n const MAJh = (Ah & Bh) ^ (Ah & Ch) ^ (Bh & Ch);\n const MAJl = (Al & Bl) ^ (Al & Cl) ^ (Bl & Cl);\n Hh = Gh | 0;\n Hl = Gl | 0;\n Gh = Fh | 0;\n Gl = Fl | 0;\n Fh = Eh | 0;\n Fl = El | 0;\n ({ h: Eh, l: El } = u64.add(Dh | 0, Dl | 0, T1h | 0, T1l | 0));\n Dh = Ch | 0;\n Dl = Cl | 0;\n Ch = Bh | 0;\n Cl = Bl | 0;\n Bh = Ah | 0;\n Bl = Al | 0;\n const All = u64.add3L(T1l, sigma0l, MAJl);\n Ah = u64.add3H(All, T1h, sigma0h, MAJh);\n Al = All | 0;\n }\n // Add the compressed chunk to the current hash value\n ({ h: Ah, l: Al } = u64.add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0));\n ({ h: Bh, l: Bl } = u64.add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0));\n ({ h: Ch, l: Cl } = u64.add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0));\n ({ h: Dh, l: Dl } = u64.add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0));\n ({ h: Eh, l: El } = u64.add(this.Eh | 0, this.El | 0, Eh | 0, El | 0));\n ({ h: Fh, l: Fl } = u64.add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0));\n ({ h: Gh, l: Gl } = u64.add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0));\n ({ h: Hh, l: Hl } = u64.add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0));\n this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl);\n }\n protected roundClean(): void {\n clean(SHA512_W_H, SHA512_W_L);\n }\n destroy(): void {\n clean(this.buffer);\n this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n }\n}\n\n/** Internal SHA2-512 hash class. */\nexport class _SHA512 extends SHA2_64B<_SHA512> {\n protected Ah: number = SHA512_IV[0] | 0;\n protected Al: number = SHA512_IV[1] | 0;\n protected Bh: number = SHA512_IV[2] | 0;\n protected Bl: number = SHA512_IV[3] | 0;\n protected Ch: number = SHA512_IV[4] | 0;\n protected Cl: number = SHA512_IV[5] | 0;\n protected Dh: number = SHA512_IV[6] | 0;\n protected Dl: number = SHA512_IV[7] | 0;\n protected Eh: number = SHA512_IV[8] | 0;\n protected El: number = SHA512_IV[9] | 0;\n protected Fh: number = SHA512_IV[10] | 0;\n protected Fl: number = SHA512_IV[11] | 0;\n protected Gh: number = SHA512_IV[12] | 0;\n protected Gl: number = SHA512_IV[13] | 0;\n protected Hh: number = SHA512_IV[14] | 0;\n protected Hl: number = SHA512_IV[15] | 0;\n\n constructor() {\n super(64);\n }\n}\n\n/** Internal SHA2-384 hash class. */\nexport class _SHA384 extends SHA2_64B<_SHA384> {\n protected Ah: number = SHA384_IV[0] | 0;\n protected Al: number = SHA384_IV[1] | 0;\n protected Bh: number = SHA384_IV[2] | 0;\n protected Bl: number = SHA384_IV[3] | 0;\n protected Ch: number = SHA384_IV[4] | 0;\n protected Cl: number = SHA384_IV[5] | 0;\n protected Dh: number = SHA384_IV[6] | 0;\n protected Dl: number = SHA384_IV[7] | 0;\n protected Eh: number = SHA384_IV[8] | 0;\n protected El: number = SHA384_IV[9] | 0;\n protected Fh: number = SHA384_IV[10] | 0;\n protected Fl: number = SHA384_IV[11] | 0;\n protected Gh: number = SHA384_IV[12] | 0;\n protected Gl: number = SHA384_IV[13] | 0;\n protected Hh: number = SHA384_IV[14] | 0;\n protected Hl: number = SHA384_IV[15] | 0;\n\n constructor() {\n super(48);\n }\n}\n\n/**\n * Truncated SHA512/256 and SHA512/224.\n * SHA512_IV is XORed with 0xa5a5a5a5a5a5a5a5, then used as \"intermediary\" IV of SHA512/t.\n * Then t hashes string to produce result IV.\n * See `test/misc/sha2-gen-iv.js`.\n */\n\n/** SHA512/224 IV */\nconst T224_IV = /* @__PURE__ */ Uint32Array.from([\n 0x8c3d37c8, 0x19544da2, 0x73e19966, 0x89dcd4d6, 0x1dfab7ae, 0x32ff9c82, 0x679dd514, 0x582f9fcf,\n 0x0f6d2b69, 0x7bd44da8, 0x77e36f73, 0x04c48942, 0x3f9d85a8, 0x6a1d36c8, 0x1112e6ad, 0x91d692a1,\n]);\n\n/** SHA512/256 IV */\nconst T256_IV = /* @__PURE__ */ Uint32Array.from([\n 0x22312194, 0xfc2bf72c, 0x9f555fa3, 0xc84c64c2, 0x2393b86b, 0x6f53b151, 0x96387719, 0x5940eabd,\n 0x96283ee2, 0xa88effe3, 0xbe5e1e25, 0x53863992, 0x2b0199fc, 0x2c85b8aa, 0x0eb72ddc, 0x81c52ca2,\n]);\n\n/** Internal SHA2-512/224 hash class. */\nexport class _SHA512_224 extends SHA2_64B<_SHA512_224> {\n protected Ah: number = T224_IV[0] | 0;\n protected Al: number = T224_IV[1] | 0;\n protected Bh: number = T224_IV[2] | 0;\n protected Bl: number = T224_IV[3] | 0;\n protected Ch: number = T224_IV[4] | 0;\n protected Cl: number = T224_IV[5] | 0;\n protected Dh: number = T224_IV[6] | 0;\n protected Dl: number = T224_IV[7] | 0;\n protected Eh: number = T224_IV[8] | 0;\n protected El: number = T224_IV[9] | 0;\n protected Fh: number = T224_IV[10] | 0;\n protected Fl: number = T224_IV[11] | 0;\n protected Gh: number = T224_IV[12] | 0;\n protected Gl: number = T224_IV[13] | 0;\n protected Hh: number = T224_IV[14] | 0;\n protected Hl: number = T224_IV[15] | 0;\n\n constructor() {\n super(28);\n }\n}\n\n/** Internal SHA2-512/256 hash class. */\nexport class _SHA512_256 extends SHA2_64B<_SHA512_256> {\n protected Ah: number = T256_IV[0] | 0;\n protected Al: number = T256_IV[1] | 0;\n protected Bh: number = T256_IV[2] | 0;\n protected Bl: number = T256_IV[3] | 0;\n protected Ch: number = T256_IV[4] | 0;\n protected Cl: number = T256_IV[5] | 0;\n protected Dh: number = T256_IV[6] | 0;\n protected Dl: number = T256_IV[7] | 0;\n protected Eh: number = T256_IV[8] | 0;\n protected El: number = T256_IV[9] | 0;\n protected Fh: number = T256_IV[10] | 0;\n protected Fl: number = T256_IV[11] | 0;\n protected Gh: number = T256_IV[12] | 0;\n protected Gl: number = T256_IV[13] | 0;\n protected Hh: number = T256_IV[14] | 0;\n protected Hl: number = T256_IV[15] | 0;\n\n constructor() {\n super(32);\n }\n}\n\n/**\n * SHA2-256 hash function from RFC 4634. In JS it's the fastest: even faster than Blake3. Some info:\n *\n * - Trying 2^128 hashes would get 50% chance of collision, using birthday attack.\n * - BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025.\n * - Each sha256 hash is executing 2^18 bit operations.\n * - Good 2024 ASICs can do 200Th/sec with 3500 watts of power, corresponding to 2^36 hashes/joule.\n */\nexport const sha256: CHash<_SHA256> = /* @__PURE__ */ createHasher(\n () => new _SHA256(),\n /* @__PURE__ */ oidNist(0x01)\n);\n/** SHA2-224 hash function from RFC 4634 */\nexport const sha224: CHash<_SHA224> = /* @__PURE__ */ createHasher(\n () => new _SHA224(),\n /* @__PURE__ */ oidNist(0x04)\n);\n\n/** SHA2-512 hash function from RFC 4634. */\nexport const sha512: CHash<_SHA512> = /* @__PURE__ */ createHasher(\n () => new _SHA512(),\n /* @__PURE__ */ oidNist(0x03)\n);\n/** SHA2-384 hash function from RFC 4634. */\nexport const sha384: CHash<_SHA384> = /* @__PURE__ */ createHasher(\n () => new _SHA384(),\n /* @__PURE__ */ oidNist(0x02)\n);\n\n/**\n * SHA2-512/256 \"truncated\" hash function, with improved resistance to length extension attacks.\n * See the paper on [truncated SHA512](https://eprint.iacr.org/2010/548.pdf).\n */\nexport const sha512_256: CHash<_SHA512_256> = /* @__PURE__ */ createHasher(\n () => new _SHA512_256(),\n /* @__PURE__ */ oidNist(0x06)\n);\n/**\n * SHA2-512/224 \"truncated\" hash function, with improved resistance to length extension attacks.\n * See the paper on [truncated SHA512](https://eprint.iacr.org/2010/548.pdf).\n */\nexport const sha512_224: CHash<_SHA512_224> = /* @__PURE__ */ createHasher(\n () => new _SHA512_224(),\n /* @__PURE__ */ oidNist(0x05)\n);\n","/**\n * Cryptographic utilities for SDK2\n *\n * Provides BIP39 mnemonic and BIP32 key derivation functions.\n * Platform-independent - no browser-specific APIs.\n */\n\nimport * as bip39 from 'bip39';\nimport CryptoJS from 'crypto-js';\nimport elliptic from 'elliptic';\nimport { encodeBech32 } from './bech32';\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst ec = new elliptic.ec('secp256k1');\n\n/** secp256k1 curve order */\nconst CURVE_ORDER = BigInt(\n '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141'\n);\n\n/** Default derivation path for Unicity (BIP44) */\nexport const DEFAULT_DERIVATION_PATH = \"m/44'/0'/0'\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface MasterKey {\n privateKey: string;\n chainCode: string;\n}\n\nexport interface DerivedKey {\n privateKey: string;\n chainCode: string;\n}\n\nexport interface KeyPair {\n privateKey: string;\n publicKey: string;\n}\n\nexport interface AddressInfo extends KeyPair {\n address: string;\n path: string;\n index: number;\n}\n\n// =============================================================================\n// BIP39 Mnemonic Functions\n// =============================================================================\n\n/**\n * Generate a new BIP39 mnemonic phrase\n * @param strength - Entropy bits (128 = 12 words, 256 = 24 words)\n */\nexport function generateMnemonic(strength: 128 | 256 = 128): string {\n return bip39.generateMnemonic(strength);\n}\n\n/**\n * Validate a BIP39 mnemonic phrase\n */\nexport function validateMnemonic(mnemonic: string): boolean {\n return bip39.validateMnemonic(mnemonic);\n}\n\n/**\n * Convert mnemonic to seed (64-byte hex string)\n * @param mnemonic - BIP39 mnemonic phrase\n * @param passphrase - Optional passphrase for additional security\n */\nexport async function mnemonicToSeed(\n mnemonic: string,\n passphrase: string = ''\n): Promise<string> {\n const seedBuffer = await bip39.mnemonicToSeed(mnemonic, passphrase);\n return Buffer.from(seedBuffer).toString('hex');\n}\n\n/**\n * Synchronous version of mnemonicToSeed\n */\nexport function mnemonicToSeedSync(\n mnemonic: string,\n passphrase: string = ''\n): string {\n const seedBuffer = bip39.mnemonicToSeedSync(mnemonic, passphrase);\n return Buffer.from(seedBuffer).toString('hex');\n}\n\n/**\n * Convert mnemonic to entropy (for recovery purposes)\n */\nexport function mnemonicToEntropy(mnemonic: string): string {\n return bip39.mnemonicToEntropy(mnemonic);\n}\n\n/**\n * Convert entropy to mnemonic\n */\nexport function entropyToMnemonic(entropy: string): string {\n return bip39.entropyToMnemonic(entropy);\n}\n\n// =============================================================================\n// BIP32 Key Derivation\n// =============================================================================\n\n/**\n * Generate master key from seed (BIP32 standard)\n * Uses HMAC-SHA512 with key \"Bitcoin seed\"\n */\nexport function generateMasterKey(seedHex: string): MasterKey {\n const I = CryptoJS.HmacSHA512(\n CryptoJS.enc.Hex.parse(seedHex),\n CryptoJS.enc.Utf8.parse('Bitcoin seed')\n ).toString();\n\n const IL = I.substring(0, 64); // Left 32 bytes - master private key\n const IR = I.substring(64); // Right 32 bytes - master chain code\n\n // Validate master key\n const masterKeyBigInt = BigInt('0x' + IL);\n if (masterKeyBigInt === 0n || masterKeyBigInt >= CURVE_ORDER) {\n throw new Error('Invalid master key generated');\n }\n\n return {\n privateKey: IL,\n chainCode: IR,\n };\n}\n\n/**\n * Derive child key using BIP32 standard\n * @param parentPrivKey - Parent private key (64 hex chars)\n * @param parentChainCode - Parent chain code (64 hex chars)\n * @param index - Child index (>= 0x80000000 for hardened)\n */\nexport function deriveChildKey(\n parentPrivKey: string,\n parentChainCode: string,\n index: number\n): DerivedKey {\n const isHardened = index >= 0x80000000;\n let data: string;\n\n if (isHardened) {\n // Hardened derivation: 0x00 || parentPrivKey || index\n const indexHex = index.toString(16).padStart(8, '0');\n data = '00' + parentPrivKey + indexHex;\n } else {\n // Non-hardened derivation: compressedPubKey || index\n const keyPair = ec.keyFromPrivate(parentPrivKey, 'hex');\n const compressedPubKey = keyPair.getPublic(true, 'hex');\n const indexHex = index.toString(16).padStart(8, '0');\n data = compressedPubKey + indexHex;\n }\n\n // HMAC-SHA512 with chain code as key\n const I = CryptoJS.HmacSHA512(\n CryptoJS.enc.Hex.parse(data),\n CryptoJS.enc.Hex.parse(parentChainCode)\n ).toString();\n\n const IL = I.substring(0, 64); // Left 32 bytes\n const IR = I.substring(64); // Right 32 bytes (new chain code)\n\n // Add IL to parent key mod n (curve order)\n const ilBigInt = BigInt('0x' + IL);\n const parentKeyBigInt = BigInt('0x' + parentPrivKey);\n\n // Check IL is valid (less than curve order)\n if (ilBigInt >= CURVE_ORDER) {\n throw new Error('Invalid key: IL >= curve order');\n }\n\n const childKeyBigInt = (ilBigInt + parentKeyBigInt) % CURVE_ORDER;\n\n // Check child key is valid (not zero)\n if (childKeyBigInt === 0n) {\n throw new Error('Invalid key: child key is zero');\n }\n\n const childPrivKey = childKeyBigInt.toString(16).padStart(64, '0');\n\n return {\n privateKey: childPrivKey,\n chainCode: IR,\n };\n}\n\n/**\n * Derive key at a full BIP32/BIP44 path\n * @param masterPrivKey - Master private key\n * @param masterChainCode - Master chain code\n * @param path - BIP44 path like \"m/44'/0'/0'/0/0\"\n */\nexport function deriveKeyAtPath(\n masterPrivKey: string,\n masterChainCode: string,\n path: string\n): DerivedKey {\n const pathParts = path.replace('m/', '').split('/');\n\n let currentKey = masterPrivKey;\n let currentChainCode = masterChainCode;\n\n for (const part of pathParts) {\n const isHardened = part.endsWith(\"'\") || part.endsWith('h');\n const indexStr = part.replace(/['h]$/, '');\n let index = parseInt(indexStr, 10);\n\n if (isHardened) {\n index += 0x80000000; // Add hardened offset\n }\n\n const derived = deriveChildKey(currentKey, currentChainCode, index);\n currentKey = derived.privateKey;\n currentChainCode = derived.chainCode;\n }\n\n return {\n privateKey: currentKey,\n chainCode: currentChainCode,\n };\n}\n\n// =============================================================================\n// Key Pair Operations\n// =============================================================================\n\n/**\n * Get public key from private key\n * @param privateKey - Private key as hex string\n * @param compressed - Return compressed public key (default: true)\n */\nexport function getPublicKey(privateKey: string, compressed: boolean = true): string {\n const keyPair = ec.keyFromPrivate(privateKey, 'hex');\n return keyPair.getPublic(compressed, 'hex');\n}\n\n/**\n * Create key pair from private key\n */\nexport function createKeyPair(privateKey: string): KeyPair {\n return {\n privateKey,\n publicKey: getPublicKey(privateKey),\n };\n}\n\n// =============================================================================\n// Hash Functions\n// =============================================================================\n\n/**\n * Compute SHA256 hash\n */\nexport function sha256(data: string, inputEncoding: 'hex' | 'utf8' = 'hex'): string {\n const parsed =\n inputEncoding === 'hex'\n ? CryptoJS.enc.Hex.parse(data)\n : CryptoJS.enc.Utf8.parse(data);\n return CryptoJS.SHA256(parsed).toString();\n}\n\n/**\n * Compute RIPEMD160 hash\n */\nexport function ripemd160(data: string, inputEncoding: 'hex' | 'utf8' = 'hex'): string {\n const parsed =\n inputEncoding === 'hex'\n ? CryptoJS.enc.Hex.parse(data)\n : CryptoJS.enc.Utf8.parse(data);\n return CryptoJS.RIPEMD160(parsed).toString();\n}\n\n/**\n * Compute HASH160 (SHA256 -> RIPEMD160)\n */\nexport function hash160(data: string): string {\n const sha = sha256(data, 'hex');\n return ripemd160(sha, 'hex');\n}\n\n/**\n * Compute double SHA256\n */\nexport function doubleSha256(data: string, inputEncoding: 'hex' | 'utf8' = 'hex'): string {\n const first = sha256(data, inputEncoding);\n return sha256(first, 'hex');\n}\n\n/**\n * Alias for hash160 (L1 SDK compatibility)\n */\nexport const computeHash160 = hash160;\n\n/**\n * Convert hex string to Uint8Array for witness program\n */\nexport function hash160ToBytes(hash160Hex: string): Uint8Array {\n const matches = hash160Hex.match(/../g);\n if (!matches) return new Uint8Array(0);\n return Uint8Array.from(matches.map((x) => parseInt(x, 16)));\n}\n\n/**\n * Generate bech32 address from public key\n * @param publicKey - Compressed public key as hex string\n * @param prefix - Address prefix (default: \"alpha\")\n * @param witnessVersion - Witness version (default: 0 for P2WPKH)\n * @returns Bech32 encoded address\n */\nexport function publicKeyToAddress(\n publicKey: string,\n prefix: string = 'alpha',\n witnessVersion: number = 0\n): string {\n const pubKeyHash = hash160(publicKey);\n const programBytes = hash160ToBytes(pubKeyHash);\n return encodeBech32(prefix, witnessVersion, programBytes);\n}\n\n/**\n * Get address info from private key\n */\nexport function privateKeyToAddressInfo(\n privateKey: string,\n prefix: string = 'alpha'\n): { address: string; publicKey: string } {\n const publicKey = getPublicKey(privateKey);\n const address = publicKeyToAddress(publicKey, prefix);\n return { address, publicKey };\n}\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\n/**\n * Convert hex string to Uint8Array\n */\nexport function hexToBytes(hex: string): Uint8Array {\n const matches = hex.match(/../g);\n if (!matches) {\n return new Uint8Array(0);\n }\n return Uint8Array.from(matches.map((x) => parseInt(x, 16)));\n}\n\n/**\n * Convert Uint8Array to hex string\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Generate random bytes as hex string\n */\nexport function randomBytes(length: number): string {\n const words = CryptoJS.lib.WordArray.random(length);\n return words.toString(CryptoJS.enc.Hex);\n}\n\n// =============================================================================\n// High-Level Functions\n// =============================================================================\n\n/**\n * Generate identity from mnemonic\n * Returns master key derived from mnemonic seed\n */\nexport async function identityFromMnemonic(\n mnemonic: string,\n passphrase: string = ''\n): Promise<MasterKey> {\n if (!validateMnemonic(mnemonic)) {\n throw new Error('Invalid mnemonic phrase');\n }\n const seedHex = await mnemonicToSeed(mnemonic, passphrase);\n return generateMasterKey(seedHex);\n}\n\n/**\n * Synchronous version of identityFromMnemonic\n */\nexport function identityFromMnemonicSync(\n mnemonic: string,\n passphrase: string = ''\n): MasterKey {\n if (!validateMnemonic(mnemonic)) {\n throw new Error('Invalid mnemonic phrase');\n }\n const seedHex = mnemonicToSeedSync(mnemonic, passphrase);\n return generateMasterKey(seedHex);\n}\n\n/**\n * Derive address info at a specific path\n * @param masterKey - Master key with privateKey and chainCode\n * @param basePath - Base derivation path (e.g., \"m/44'/0'/0'\")\n * @param index - Address index\n * @param isChange - Whether this is a change address (chain 1 vs 0)\n * @param prefix - Address prefix (default: \"alpha\")\n */\nexport function deriveAddressInfo(\n masterKey: MasterKey,\n basePath: string,\n index: number,\n isChange: boolean = false,\n prefix: string = 'alpha'\n): AddressInfo {\n const chain = isChange ? 1 : 0;\n const fullPath = `${basePath}/${chain}/${index}`;\n\n const derived = deriveKeyAtPath(masterKey.privateKey, masterKey.chainCode, fullPath);\n const publicKey = getPublicKey(derived.privateKey);\n const address = publicKeyToAddress(publicKey, prefix);\n\n return {\n privateKey: derived.privateKey,\n publicKey,\n address,\n path: fullPath,\n index,\n };\n}\n\n/**\n * Generate full address info from private key with index and path\n * (L1 SDK compatibility)\n */\nexport function generateAddressInfo(\n privateKey: string,\n index: number,\n path: string,\n prefix: string = 'alpha'\n): AddressInfo {\n const { address, publicKey } = privateKeyToAddressInfo(privateKey, prefix);\n return {\n privateKey,\n publicKey,\n address,\n path,\n index,\n };\n}\n\n// Re-export elliptic instance for advanced use cases\nexport { ec };\n","/**\n * Bech32 Encoding/Decoding\n * BIP-173 implementation for address encoding\n */\n\n// =============================================================================\n// Constants\n// =============================================================================\n\n/** Bech32 character set from BIP-173 */\nexport const CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';\n\n/** Generator polynomial for checksum */\nconst GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];\n\n// =============================================================================\n// Bit Conversion\n// =============================================================================\n\n/**\n * Convert between bit arrays (8→5 or 5→8)\n */\nexport function convertBits(\n data: number[],\n fromBits: number,\n toBits: number,\n pad: boolean\n): number[] | null {\n let acc = 0;\n let bits = 0;\n const ret: number[] = [];\n const maxv = (1 << toBits) - 1;\n\n for (let i = 0; i < data.length; i++) {\n const value = data[i];\n if (value < 0 || value >> fromBits !== 0) return null;\n acc = (acc << fromBits) | value;\n bits += fromBits;\n while (bits >= toBits) {\n bits -= toBits;\n ret.push((acc >> bits) & maxv);\n }\n }\n\n if (pad) {\n if (bits > 0) {\n ret.push((acc << (toBits - bits)) & maxv);\n }\n } else if (bits >= fromBits || (acc << (toBits - bits)) & maxv) {\n return null;\n }\n\n return ret;\n}\n\n// =============================================================================\n// Internal Functions\n// =============================================================================\n\n/**\n * Expand HRP for checksum calculation\n */\nfunction hrpExpand(hrp: string): number[] {\n const ret: number[] = [];\n for (let i = 0; i < hrp.length; i++) ret.push(hrp.charCodeAt(i) >> 5);\n ret.push(0);\n for (let i = 0; i < hrp.length; i++) ret.push(hrp.charCodeAt(i) & 31);\n return ret;\n}\n\n/**\n * Calculate polymod checksum\n */\nfunction bech32Polymod(values: number[]): number {\n let chk = 1;\n for (let p = 0; p < values.length; p++) {\n const top = chk >> 25;\n chk = ((chk & 0x1ffffff) << 5) ^ values[p];\n for (let i = 0; i < 5; i++) {\n if ((top >> i) & 1) chk ^= GENERATOR[i];\n }\n }\n return chk;\n}\n\n/**\n * Create checksum for bech32\n */\nfunction bech32Checksum(hrp: string, data: number[]): number[] {\n const values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);\n const mod = bech32Polymod(values) ^ 1;\n\n const ret: number[] = [];\n for (let p = 0; p < 6; p++) {\n ret.push((mod >> (5 * (5 - p))) & 31);\n }\n return ret;\n}\n\n// =============================================================================\n// Public API\n// =============================================================================\n\n/**\n * Encode data to bech32 address\n *\n * @example\n * ```ts\n * const address = encodeBech32('alpha', 1, pubkeyHash);\n * // 'alpha1qw...'\n * ```\n */\nexport function encodeBech32(\n hrp: string,\n version: number,\n program: Uint8Array\n): string {\n if (version < 0 || version > 16) {\n throw new Error('Invalid witness version');\n }\n\n const converted = convertBits(Array.from(program), 8, 5, true);\n if (!converted) {\n throw new Error('Failed to convert bits');\n }\n\n const data = [version].concat(converted);\n const checksum = bech32Checksum(hrp, data);\n const combined = data.concat(checksum);\n\n let out = hrp + '1';\n for (let i = 0; i < combined.length; i++) {\n out += CHARSET[combined[i]];\n }\n\n return out;\n}\n\n/**\n * Decode bech32 address\n *\n * @example\n * ```ts\n * const result = decodeBech32('alpha1qw...');\n * // { hrp: 'alpha', witnessVersion: 1, data: Uint8Array }\n * ```\n */\nexport function decodeBech32(\n addr: string\n): { hrp: string; witnessVersion: number; data: Uint8Array } | null {\n addr = addr.toLowerCase();\n\n const pos = addr.lastIndexOf('1');\n if (pos < 1) return null;\n\n const hrp = addr.substring(0, pos);\n const dataStr = addr.substring(pos + 1);\n\n const data: number[] = [];\n for (let i = 0; i < dataStr.length; i++) {\n const val = CHARSET.indexOf(dataStr[i]);\n if (val === -1) return null;\n data.push(val);\n }\n\n // Validate checksum\n const checksum = bech32Checksum(hrp, data.slice(0, -6));\n for (let i = 0; i < 6; i++) {\n if (checksum[i] !== data[data.length - 6 + i]) {\n return null;\n }\n }\n\n const version = data[0];\n const program = convertBits(data.slice(1, -6), 5, 8, false);\n if (!program) return null;\n\n return {\n hrp,\n witnessVersion: version,\n data: Uint8Array.from(program),\n };\n}\n\n/**\n * Create address from public key hash\n *\n * @example\n * ```ts\n * const address = createAddress('alpha', pubkeyHash);\n * // 'alpha1...'\n * ```\n */\nexport function createAddress(hrp: string, pubkeyHash: Uint8Array | string): string {\n const hashBytes = typeof pubkeyHash === 'string'\n ? Uint8Array.from(Buffer.from(pubkeyHash, 'hex'))\n : pubkeyHash;\n\n return encodeBech32(hrp, 1, hashBytes);\n}\n\n/**\n * Validate bech32 address\n */\nexport function isValidBech32(addr: string): boolean {\n return decodeBech32(addr) !== null;\n}\n\n/**\n * Get HRP from address\n */\nexport function getAddressHrp(addr: string): string | null {\n const result = decodeBech32(addr);\n return result?.hrp ?? null;\n}\n\n// =============================================================================\n// Aliases for L1 SDK compatibility\n// =============================================================================\n\n/**\n * Alias for encodeBech32 (L1 SDK compatibility)\n */\nexport const createBech32 = encodeBech32;\n","/**\n * WebSocket Abstraction\n * Platform-independent WebSocket interface for cross-platform support\n */\n\n// =============================================================================\n// WebSocket Interface\n// =============================================================================\n\n/**\n * Minimal WebSocket interface compatible with browser and Node.js\n */\nexport interface IWebSocket {\n readonly readyState: number;\n\n send(data: string): void;\n close(code?: number, reason?: string): void;\n\n onopen: ((event: unknown) => void) | null;\n onclose: ((event: unknown) => void) | null;\n onerror: ((event: unknown) => void) | null;\n onmessage: ((event: IMessageEvent) => void) | null;\n}\n\nexport interface IMessageEvent {\n data: string;\n}\n\n/**\n * WebSocket ready states (same as native WebSocket)\n */\nexport const WebSocketReadyState = {\n CONNECTING: 0,\n OPEN: 1,\n CLOSING: 2,\n CLOSED: 3,\n} as const;\n\n/**\n * Factory function to create WebSocket instances\n * Different implementations for browser (native) vs Node.js (ws package)\n */\nexport type WebSocketFactory = (url: string) => IWebSocket;\n\n// =============================================================================\n// UUID Generator\n// =============================================================================\n\n/**\n * Generate a unique ID (platform-independent)\n * Browser: crypto.randomUUID()\n * Node: crypto.randomUUID() or uuid package\n */\nexport type UUIDGenerator = () => string;\n\n/**\n * Default UUID generator using crypto.randomUUID\n * Works in modern browsers and Node 19+\n */\nexport function defaultUUIDGenerator(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // Fallback for older environments\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n","/**\n * Browser Transport Exports\n * Re-exports shared transport with browser-specific WebSocket factory\n */\n\nimport {\n NostrTransportProvider,\n type NostrTransportProviderConfig,\n} from '../../../transport/NostrTransportProvider';\nimport type { IWebSocket } from '../../../transport/websocket';\n\n// Re-export shared types and classes\nexport {\n NostrTransportProvider,\n type NostrTransportProviderConfig,\n} from '../../../transport/NostrTransportProvider';\n\nexport {\n type IWebSocket,\n type IMessageEvent,\n type WebSocketFactory,\n type UUIDGenerator,\n WebSocketReadyState,\n defaultUUIDGenerator,\n} from '../../../transport/websocket';\n\n// =============================================================================\n// Browser WebSocket Factory\n// =============================================================================\n\n/**\n * Browser WebSocket factory using native WebSocket\n * Cast to IWebSocket since native WebSocket is a superset\n */\nexport function createBrowserWebSocket(url: string): IWebSocket {\n return new WebSocket(url) as unknown as IWebSocket;\n}\n\n/**\n * Create NostrTransportProvider with browser WebSocket\n * Convenience factory that injects browser-native WebSocket\n */\nexport function createNostrTransportProvider(\n config?: Omit<NostrTransportProviderConfig, 'createWebSocket'>\n): NostrTransportProvider {\n return new NostrTransportProvider({\n ...config,\n createWebSocket: createBrowserWebSocket,\n });\n}\n","/**\n * Unicity Aggregator Provider\n * Platform-independent implementation using @unicitylabs/state-transition-sdk\n *\n * The oracle is a trusted service that provides verifiable truth\n * about token state through cryptographic inclusion proofs.\n *\n * TrustBaseLoader is injected for platform-specific loading:\n * - Browser: fetch from URL\n * - Node.js: read from file\n */\n\nimport type { ProviderStatus } from '../types';\nimport type {\n OracleProvider,\n TransferCommitment,\n SubmitResult,\n InclusionProof,\n WaitOptions,\n ValidationResult,\n TokenState,\n MintParams,\n MintResult,\n OracleEvent,\n OracleEventCallback,\n TrustBaseLoader,\n} from './oracle-provider';\nimport { DEFAULT_AGGREGATOR_TIMEOUT, TIMEOUTS } from '../constants';\n\n// SDK imports - using direct imports from the SDK\nimport { StateTransitionClient } from '@unicitylabs/state-transition-sdk/lib/StateTransitionClient';\nimport { AggregatorClient } from '@unicitylabs/state-transition-sdk/lib/api/AggregatorClient';\nimport { RootTrustBase } from '@unicitylabs/state-transition-sdk/lib/bft/RootTrustBase';\nimport { Token as SdkToken } from '@unicitylabs/state-transition-sdk/lib/token/Token';\nimport { waitInclusionProof } from '@unicitylabs/state-transition-sdk/lib/util/InclusionProofUtils';\nimport type { TransferCommitment as SdkTransferCommitment } from '@unicitylabs/state-transition-sdk/lib/transaction/TransferCommitment';\n\n// SDK MintCommitment type - using interface to avoid generic complexity\ninterface SdkMintCommitment {\n requestId?: { toString(): string };\n [key: string]: unknown;\n}\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\nexport interface UnicityAggregatorProviderConfig {\n /** Aggregator URL */\n url: string;\n /** API key for authentication */\n apiKey?: string;\n /** Request timeout (ms) */\n timeout?: number;\n /** Skip trust base verification (dev only) */\n skipVerification?: boolean;\n /** Enable debug logging */\n debug?: boolean;\n /** Trust base loader (platform-specific) */\n trustBaseLoader?: TrustBaseLoader;\n}\n\n// =============================================================================\n// RPC Response Types\n// =============================================================================\n\ninterface RpcSubmitResponse {\n requestId?: string;\n}\n\ninterface RpcProofResponse {\n proof?: unknown;\n roundNumber?: number;\n}\n\ninterface RpcValidateResponse {\n valid?: boolean;\n spent?: boolean;\n stateHash?: string;\n error?: string;\n}\n\ninterface RpcSpentResponse {\n spent?: boolean;\n}\n\ninterface RpcTokenStateResponse {\n state?: {\n stateHash?: string;\n spent?: boolean;\n roundNumber?: number;\n };\n}\n\ninterface RpcMintResponse {\n requestId?: string;\n tokenId?: string;\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\n/**\n * Unicity Aggregator Provider\n * Concrete implementation of OracleProvider using Unicity's aggregator service\n */\nexport class UnicityAggregatorProvider implements OracleProvider {\n readonly id = 'unicity-aggregator';\n readonly name = 'Unicity Aggregator';\n readonly type = 'network' as const;\n readonly description = 'Unicity state transition aggregator (oracle implementation)';\n\n private config: Required<Omit<UnicityAggregatorProviderConfig, 'trustBaseLoader'>> & {\n trustBaseLoader?: TrustBaseLoader;\n };\n private status: ProviderStatus = 'disconnected';\n private eventCallbacks: Set<OracleEventCallback> = new Set();\n\n // SDK clients\n private aggregatorClient: AggregatorClient | null = null;\n private stateTransitionClient: StateTransitionClient | null = null;\n private trustBase: RootTrustBase | null = null;\n\n /** Get the current trust base */\n getTrustBase(): RootTrustBase | null {\n return this.trustBase;\n }\n\n /** Get the state transition client */\n getStateTransitionClient(): StateTransitionClient | null {\n return this.stateTransitionClient;\n }\n\n /** Get the aggregator client */\n getAggregatorClient(): AggregatorClient | null {\n return this.aggregatorClient;\n }\n\n // Cache for spent states (immutable)\n private spentCache: Map<string, boolean> = new Map();\n\n constructor(config: UnicityAggregatorProviderConfig) {\n this.config = {\n url: config.url,\n apiKey: config.apiKey ?? '',\n timeout: config.timeout ?? DEFAULT_AGGREGATOR_TIMEOUT,\n skipVerification: config.skipVerification ?? false,\n debug: config.debug ?? false,\n trustBaseLoader: config.trustBaseLoader,\n };\n }\n\n // ===========================================================================\n // BaseProvider Implementation\n // ===========================================================================\n\n async connect(): Promise<void> {\n if (this.status === 'connected') return;\n\n this.status = 'connecting';\n\n // Mark as connected - actual connectivity will be verified on first operation\n // The aggregator requires requestId in params even for status checks,\n // which the SDK client doesn't support directly\n this.status = 'connected';\n this.emitEvent({ type: 'oracle:connected', timestamp: Date.now() });\n this.log('Connected to oracle:', this.config.url);\n }\n\n async disconnect(): Promise<void> {\n this.status = 'disconnected';\n this.emitEvent({ type: 'oracle:disconnected', timestamp: Date.now() });\n this.log('Disconnected from oracle');\n }\n\n isConnected(): boolean {\n return this.status === 'connected';\n }\n\n getStatus(): ProviderStatus {\n return this.status;\n }\n\n // ===========================================================================\n // OracleProvider Implementation\n // ===========================================================================\n\n async initialize(trustBase?: RootTrustBase): Promise<void> {\n // Initialize SDK clients with optional API key\n this.aggregatorClient = new AggregatorClient(\n this.config.url,\n this.config.apiKey || null\n );\n this.stateTransitionClient = new StateTransitionClient(this.aggregatorClient);\n\n if (trustBase) {\n this.trustBase = trustBase;\n } else if (!this.config.skipVerification && this.config.trustBaseLoader) {\n // Load trust base using injected loader\n try {\n const trustBaseJson = await this.config.trustBaseLoader.load();\n if (trustBaseJson) {\n this.trustBase = RootTrustBase.fromJSON(trustBaseJson);\n }\n } catch (error) {\n this.log('Failed to load trust base:', error);\n }\n }\n\n await this.connect();\n this.log('Initialized with trust base:', !!this.trustBase);\n }\n\n /**\n * Submit a transfer commitment to the aggregator.\n * Accepts either an SDK TransferCommitment or a simple commitment object.\n */\n async submitCommitment(commitment: TransferCommitment | SdkTransferCommitment): Promise<SubmitResult> {\n this.ensureConnected();\n\n try {\n let requestId: string;\n\n // Check if it's an SDK commitment (has submitTransferCommitment method signature)\n if (this.isSdkTransferCommitment(commitment)) {\n // Use SDK client directly\n const response = await this.stateTransitionClient!.submitTransferCommitment(commitment);\n requestId = commitment.requestId?.toString() ?? response.status;\n } else {\n // Fallback to RPC for simple commitment objects\n const response = await this.rpcCall<RpcSubmitResponse>('submitCommitment', {\n sourceToken: commitment.sourceToken,\n recipient: commitment.recipient,\n salt: Array.from(commitment.salt),\n data: commitment.data,\n });\n requestId = response.requestId ?? '';\n }\n\n this.emitEvent({\n type: 'commitment:submitted',\n timestamp: Date.now(),\n data: { requestId },\n });\n\n return {\n success: true,\n requestId,\n timestamp: Date.now(),\n };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n error: errorMsg,\n timestamp: Date.now(),\n };\n }\n }\n\n /**\n * Submit a mint commitment to the aggregator (SDK only)\n * @param commitment - SDK MintCommitment instance\n */\n async submitMintCommitment(commitment: SdkMintCommitment): Promise<SubmitResult> {\n this.ensureConnected();\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const response = await this.stateTransitionClient!.submitMintCommitment(commitment as any);\n const requestId = commitment.requestId?.toString() ?? response.status;\n\n this.emitEvent({\n type: 'commitment:submitted',\n timestamp: Date.now(),\n data: { requestId },\n });\n\n return {\n success: true,\n requestId,\n timestamp: Date.now(),\n };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n error: errorMsg,\n timestamp: Date.now(),\n };\n }\n }\n\n private isSdkTransferCommitment(commitment: unknown): commitment is SdkTransferCommitment {\n return (\n commitment !== null &&\n typeof commitment === 'object' &&\n 'requestId' in commitment &&\n typeof (commitment as SdkTransferCommitment).requestId?.toString === 'function'\n );\n }\n\n async getProof(requestId: string): Promise<InclusionProof | null> {\n this.ensureConnected();\n\n try {\n const response = await this.rpcCall<RpcProofResponse>('getInclusionProof', { requestId });\n\n if (!response.proof) {\n return null;\n }\n\n return {\n requestId,\n roundNumber: response.roundNumber ?? 0,\n proof: response.proof,\n timestamp: Date.now(),\n };\n } catch {\n return null;\n }\n }\n\n async waitForProof(requestId: string, options?: WaitOptions): Promise<InclusionProof> {\n const timeout = options?.timeout ?? this.config.timeout;\n const pollInterval = options?.pollInterval ?? TIMEOUTS.PROOF_POLL_INTERVAL;\n const startTime = Date.now();\n let attempt = 0;\n\n while (Date.now() - startTime < timeout) {\n options?.onPoll?.(++attempt);\n\n const proof = await this.getProof(requestId);\n if (proof) {\n this.emitEvent({\n type: 'proof:received',\n timestamp: Date.now(),\n data: { requestId, roundNumber: proof.roundNumber },\n });\n return proof;\n }\n\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n }\n\n throw new Error(`Timeout waiting for proof: ${requestId}`);\n }\n\n async validateToken(tokenData: unknown): Promise<ValidationResult> {\n this.ensureConnected();\n\n try {\n // Try SDK validation first if we have trust base\n if (this.trustBase && !this.config.skipVerification) {\n try {\n const sdkToken = await SdkToken.fromJSON(tokenData);\n const verifyResult = await sdkToken.verify(this.trustBase);\n\n // Calculate state hash\n const stateHash = await sdkToken.state.calculateHash();\n const stateHashStr = stateHash.toJSON();\n\n const valid = verifyResult.isSuccessful;\n\n this.emitEvent({\n type: 'validation:completed',\n timestamp: Date.now(),\n data: { valid },\n });\n\n return {\n valid,\n spent: false, // Spend check is separate\n stateHash: stateHashStr,\n error: valid ? undefined : 'SDK verification failed',\n };\n } catch (sdkError) {\n this.log('SDK validation failed, falling back to RPC:', sdkError);\n }\n }\n\n // Fallback to RPC validation\n const response = await this.rpcCall<RpcValidateResponse>('validateToken', { token: tokenData });\n\n const valid = response.valid ?? false;\n const spent = response.spent ?? false;\n\n this.emitEvent({\n type: 'validation:completed',\n timestamp: Date.now(),\n data: { valid },\n });\n\n // Cache spent state if spent\n if (response.stateHash && spent) {\n this.spentCache.set(response.stateHash, true);\n }\n\n return {\n valid,\n spent,\n stateHash: response.stateHash,\n error: response.error,\n };\n } catch (error) {\n return {\n valid: false,\n spent: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n /**\n * Wait for inclusion proof using SDK (for SDK commitments)\n */\n async waitForProofSdk(\n commitment: SdkTransferCommitment | SdkMintCommitment,\n signal?: AbortSignal\n ): Promise<unknown> {\n this.ensureConnected();\n\n if (!this.trustBase) {\n throw new Error('Trust base not initialized');\n }\n\n return await waitInclusionProof(\n this.trustBase,\n this.stateTransitionClient!,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n commitment as any,\n signal\n );\n }\n\n async isSpent(stateHash: string): Promise<boolean> {\n // Check cache first (spent is immutable)\n if (this.spentCache.has(stateHash)) {\n return this.spentCache.get(stateHash)!;\n }\n\n this.ensureConnected();\n\n try {\n const response = await this.rpcCall<RpcSpentResponse>('isSpent', { stateHash });\n const spent = response.spent ?? false;\n\n // Cache result\n if (spent) {\n this.spentCache.set(stateHash, true);\n }\n\n return spent;\n } catch {\n return false;\n }\n }\n\n async getTokenState(tokenId: string): Promise<TokenState | null> {\n this.ensureConnected();\n\n try {\n const response = await this.rpcCall<RpcTokenStateResponse>('getTokenState', { tokenId });\n\n if (!response.state) {\n return null;\n }\n\n return {\n tokenId,\n stateHash: response.state.stateHash ?? '',\n spent: response.state.spent ?? false,\n roundNumber: response.state.roundNumber,\n lastUpdated: Date.now(),\n };\n } catch {\n return null;\n }\n }\n\n async getCurrentRound(): Promise<number> {\n if (this.aggregatorClient) {\n const blockHeight = await this.aggregatorClient.getBlockHeight();\n return Number(blockHeight);\n }\n return 0;\n }\n\n async mint(params: MintParams): Promise<MintResult> {\n this.ensureConnected();\n\n try {\n const response = await this.rpcCall<RpcMintResponse>('mint', {\n coinId: params.coinId,\n amount: params.amount,\n recipientAddress: params.recipientAddress,\n recipientPubkey: params.recipientPubkey,\n });\n\n return {\n success: true,\n requestId: response.requestId,\n tokenId: response.tokenId,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n // ===========================================================================\n // Event Subscription\n // ===========================================================================\n\n onEvent(callback: OracleEventCallback): () => void {\n this.eventCallbacks.add(callback);\n return () => this.eventCallbacks.delete(callback);\n }\n\n // ===========================================================================\n // Private: RPC\n // ===========================================================================\n\n private async rpcCall<T>(method: string, params: unknown): Promise<T> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.timeout);\n\n try {\n const response = await fetch(this.config.url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: Date.now(),\n method,\n params,\n }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const result = await response.json();\n\n if (result.error) {\n throw new Error(result.error.message ?? 'RPC error');\n }\n\n return (result.result ?? {}) as T;\n } finally {\n clearTimeout(timeout);\n }\n }\n\n // ===========================================================================\n // Private: Helpers\n // ===========================================================================\n\n private ensureConnected(): void {\n if (this.status !== 'connected') {\n throw new Error('UnicityAggregatorProvider not connected');\n }\n }\n\n private emitEvent(event: OracleEvent): void {\n for (const callback of this.eventCallbacks) {\n try {\n callback(event);\n } catch (error) {\n this.log('Event callback error:', error);\n }\n }\n }\n\n private log(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[UnicityAggregatorProvider]', ...args);\n }\n }\n}\n\n// =============================================================================\n// Backward Compatibility Aliases (Oracle -> Aggregator)\n// =============================================================================\n\n/** @deprecated Use UnicityAggregatorProvider instead */\nexport const UnicityOracleProvider = UnicityAggregatorProvider;\n/** @deprecated Use UnicityAggregatorProviderConfig instead */\nexport type UnicityOracleProviderConfig = UnicityAggregatorProviderConfig;\n","/**\n * Embedded Trust Base Data\n * Pre-loaded trust base for different networks\n */\n\nexport const TRUSTBASE_TESTNET = {\n version: 1,\n networkId: 3,\n epoch: 1,\n epochStartRound: 1,\n rootNodes: [\n {\n nodeId: '16Uiu2HAkyQRiA7pMgzgLj9GgaBJEJa8zmx9dzqUDa6WxQPJ82ghU',\n sigKey: '0x039afb2acb65f5fbc272d8907f763d0a5d189aadc9b97afdcc5897ea4dd112e68b',\n stake: 1,\n },\n ],\n quorumThreshold: 1,\n stateHash: '',\n changeRecordHash: '',\n previousEntryHash: '',\n signatures: {\n '16Uiu2HAkyQRiA7pMgzgLj9GgaBJEJa8zmx9dzqUDa6WxQPJ82ghU':\n '0xf157c9fdd8a378e3ca70d354ccc4475ab2cd8de360127bc46b0aeab4b453a80f07fd9136a5843b60a8babaff23e20acc8879861f7651440a5e2829f7541b31f100',\n },\n};\n\n// Mainnet trust base (TODO: add when available)\nexport const TRUSTBASE_MAINNET = null;\n\n// Dev trust base (same as testnet for now)\nexport const TRUSTBASE_DEV = TRUSTBASE_TESTNET;\n","/**\n * Shared TrustBase Loader Logic\n * Common embedded trustbase data and base loader\n */\n\nimport { TRUSTBASE_TESTNET, TRUSTBASE_MAINNET, TRUSTBASE_DEV } from '../../assets/trustbase';\nimport type { NetworkType } from '../../constants';\n\nexport interface TrustBaseLoader {\n load(): Promise<unknown | null>;\n}\n\n/**\n * Get embedded trustbase data by network\n */\nexport function getEmbeddedTrustBase(network: NetworkType): unknown | null {\n switch (network) {\n case 'mainnet':\n return TRUSTBASE_MAINNET;\n case 'testnet':\n return TRUSTBASE_TESTNET;\n case 'dev':\n return TRUSTBASE_DEV;\n default:\n return TRUSTBASE_TESTNET;\n }\n}\n\n/**\n * Base TrustBase loader with embedded fallback\n */\nexport abstract class BaseTrustBaseLoader implements TrustBaseLoader {\n protected network: NetworkType;\n\n constructor(network: NetworkType = 'testnet') {\n this.network = network;\n }\n\n /**\n * Try to load from external source (file, URL, etc.)\n * Override in subclass\n */\n protected abstract loadFromExternal(): Promise<unknown | null>;\n\n async load(): Promise<unknown | null> {\n // Try external source first\n const external = await this.loadFromExternal();\n if (external) {\n return external;\n }\n\n // Fallback to embedded data\n return getEmbeddedTrustBase(this.network);\n }\n}\n","/**\n * Browser Oracle Exports\n * Re-exports shared oracle with browser-specific TrustBaseLoader\n */\n\nimport {\n UnicityAggregatorProvider,\n type UnicityAggregatorProviderConfig,\n} from '../../../oracle/UnicityAggregatorProvider';\nimport type { TrustBaseLoader } from '../../../oracle/oracle-provider';\nimport { BaseTrustBaseLoader } from '../../shared/trustbase-loader';\nimport type { NetworkType } from '../../../constants';\n\n// Re-export shared types and classes\nexport {\n UnicityAggregatorProvider,\n type UnicityAggregatorProviderConfig,\n UnicityOracleProvider,\n type UnicityOracleProviderConfig,\n} from '../../../oracle/UnicityAggregatorProvider';\n\nexport type { TrustBaseLoader } from '../../../oracle/oracle-provider';\n\n// =============================================================================\n// Browser TrustBase Loader\n// =============================================================================\n\n/**\n * Browser TrustBase loader - fetches from URL or uses embedded data\n */\nexport class BrowserTrustBaseLoader extends BaseTrustBaseLoader {\n private url?: string;\n\n constructor(networkOrUrl: NetworkType | string = 'testnet') {\n if (networkOrUrl.startsWith('/') || networkOrUrl.startsWith('http')) {\n super('testnet');\n this.url = networkOrUrl;\n } else {\n super(networkOrUrl as NetworkType);\n }\n }\n\n protected async loadFromExternal(): Promise<unknown | null> {\n if (!this.url) return null;\n\n try {\n const response = await fetch(this.url);\n if (response.ok) {\n return await response.json();\n }\n } catch {\n // Fall through to embedded\n }\n return null;\n }\n}\n\n/**\n * Create browser TrustBase loader\n */\nexport function createBrowserTrustBaseLoader(networkOrUrl?: NetworkType | string): TrustBaseLoader {\n return new BrowserTrustBaseLoader(networkOrUrl);\n}\n\n// =============================================================================\n// Browser Factory\n// =============================================================================\n\n/**\n * Create UnicityAggregatorProvider with browser TrustBase loader\n */\nexport function createUnicityAggregatorProvider(\n config: Omit<UnicityAggregatorProviderConfig, 'trustBaseLoader'> & {\n trustBaseUrl?: string;\n network?: NetworkType;\n }\n): UnicityAggregatorProvider {\n const { trustBaseUrl, network, ...restConfig } = config;\n return new UnicityAggregatorProvider({\n ...restConfig,\n trustBaseLoader: createBrowserTrustBaseLoader(trustBaseUrl ?? network ?? 'testnet'),\n });\n}\n\n/** @deprecated Use createUnicityAggregatorProvider instead */\nexport const createUnicityOracleProvider = createUnicityAggregatorProvider;\n","/**\n * Browser Download Utilities\n * Functions for downloading wallet backups as files\n */\n\nimport type { Sphere } from '../../core/Sphere';\nimport type { WalletJSON, WalletJSONExportOptions } from '../../types';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface DownloadTextOptions {\n /** Password for encryption */\n password?: string;\n /** Number of addresses to include */\n addressCount?: number;\n /** Custom filename (without extension) */\n filename?: string;\n}\n\nexport interface DownloadJSONOptions extends WalletJSONExportOptions {\n /** Custom filename (without extension) */\n filename?: string;\n /** Pretty print JSON (default: true) */\n pretty?: boolean;\n}\n\n// =============================================================================\n// Core Download Function\n// =============================================================================\n\n/**\n * Download content as a file in the browser\n */\nexport function downloadFile(\n content: string | Blob,\n filename: string,\n mimeType: string = 'text/plain'\n): void {\n const blob = content instanceof Blob\n ? content\n : new Blob([content], { type: mimeType });\n\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n\n link.href = url;\n link.download = filename;\n link.click();\n\n // Clean up the URL after a short delay\n setTimeout(() => URL.revokeObjectURL(url), 100);\n}\n\n/**\n * Download text content as a .txt file\n */\nexport function downloadTextFile(content: string, filename: string): void {\n downloadFile(content, filename, 'text/plain');\n}\n\n/**\n * Download JSON content as a .json file\n */\nexport function downloadJSONFile(content: object | string, filename: string): void {\n const jsonString = typeof content === 'string'\n ? content\n : JSON.stringify(content, null, 2);\n downloadFile(jsonString, filename, 'application/json');\n}\n\n// =============================================================================\n// Wallet Download Functions\n// =============================================================================\n\n/**\n * Download wallet backup as text file\n *\n * @example\n * ```ts\n * // Download unencrypted backup\n * downloadWalletText(sphere);\n *\n * // Download encrypted backup\n * downloadWalletText(sphere, { password: 'secret' });\n *\n * // Custom filename\n * downloadWalletText(sphere, { filename: 'my-backup' });\n * ```\n */\nexport function downloadWalletText(sphere: Sphere, options: DownloadTextOptions = {}): void {\n const content = sphere.exportToTxt({\n password: options.password,\n addressCount: options.addressCount,\n });\n\n const filename = options.filename\n ? `${options.filename}.txt`\n : `sphere-wallet-${Date.now()}.txt`;\n\n downloadTextFile(content, filename);\n}\n\n/**\n * Download wallet backup as JSON file\n *\n * @example\n * ```ts\n * // Download unencrypted backup\n * downloadWalletJSON(sphere);\n *\n * // Download encrypted backup\n * downloadWalletJSON(sphere, { password: 'secret' });\n *\n * // Include multiple addresses\n * downloadWalletJSON(sphere, { addressCount: 5 });\n * ```\n */\nexport function downloadWalletJSON(sphere: Sphere, options: DownloadJSONOptions = {}): void {\n const json = sphere.exportToJSON({\n password: options.password,\n addressCount: options.addressCount,\n includeMnemonic: options.includeMnemonic,\n });\n\n const filename = options.filename\n ? `${options.filename}.json`\n : `sphere-wallet-${Date.now()}.json`;\n\n const jsonString = options.pretty !== false\n ? JSON.stringify(json, null, 2)\n : JSON.stringify(json);\n\n downloadFile(jsonString, filename, 'application/json');\n}\n\n/**\n * Download pre-built WalletJSON as file\n */\nexport function downloadWalletJSONData(json: WalletJSON, filename?: string): void {\n const name = filename || `sphere-wallet-${Date.now()}.json`;\n downloadJSONFile(json, name.endsWith('.json') ? name : `${name}.json`);\n}\n\n// =============================================================================\n// File Reading Utilities\n// =============================================================================\n\n/**\n * Read a file as text\n */\nexport function readFileAsText(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as string);\n reader.onerror = () => reject(new Error('Failed to read file'));\n reader.readAsText(file);\n });\n}\n\n/**\n * Read a file as ArrayBuffer (for binary files like .dat)\n */\nexport function readFileAsArrayBuffer(file: File): Promise<ArrayBuffer> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as ArrayBuffer);\n reader.onerror = () => reject(new Error('Failed to read file'));\n reader.readAsArrayBuffer(file);\n });\n}\n\n/**\n * Read a file as Uint8Array (for binary files like .dat)\n */\nexport async function readFileAsUint8Array(file: File): Promise<Uint8Array> {\n const buffer = await readFileAsArrayBuffer(file);\n return new Uint8Array(buffer);\n}\n","/**\n * IPFS Error Classification\n * Categorizes errors for proper handling (e.g., NOT_FOUND should not trigger circuit breaker)\n */\n\n// =============================================================================\n// Error Categories\n// =============================================================================\n\nexport type IpfsErrorCategory =\n | 'NOT_FOUND' // IPNS record never published (expected for new wallets)\n | 'NETWORK_ERROR' // Connectivity / server issues\n | 'TIMEOUT' // Request timed out\n | 'GATEWAY_ERROR' // Gateway returned error (5xx, etc.)\n | 'INVALID_RESPONSE' // Response parsing failed\n | 'CID_MISMATCH' // Content hash doesn't match CID\n | 'SEQUENCE_DOWNGRADE'; // Remote sequence < local (stale data)\n\n// =============================================================================\n// Error Class\n// =============================================================================\n\nexport class IpfsError extends Error {\n readonly category: IpfsErrorCategory;\n readonly gateway?: string;\n readonly cause?: Error;\n\n constructor(\n message: string,\n category: IpfsErrorCategory,\n gateway?: string,\n cause?: Error,\n ) {\n super(message);\n this.name = 'IpfsError';\n this.category = category;\n this.gateway = gateway;\n this.cause = cause;\n }\n\n /** Whether this error should trigger the circuit breaker */\n get shouldTriggerCircuitBreaker(): boolean {\n // NOT_FOUND is expected for new wallets, don't penalize the gateway\n return this.category !== 'NOT_FOUND' && this.category !== 'SEQUENCE_DOWNGRADE';\n }\n}\n\n// =============================================================================\n// Error Classification Helpers\n// =============================================================================\n\n/**\n * Classify a fetch exception into an IpfsErrorCategory\n */\nexport function classifyFetchError(error: unknown): IpfsErrorCategory {\n if (error instanceof DOMException && error.name === 'AbortError') {\n return 'TIMEOUT';\n }\n if (error instanceof TypeError) {\n // TypeError typically means network failure (DNS, connection refused, etc.)\n return 'NETWORK_ERROR';\n }\n if (error instanceof Error && error.name === 'TimeoutError') {\n return 'TIMEOUT';\n }\n return 'NETWORK_ERROR';\n}\n\n/**\n * Classify an HTTP status code into an IpfsErrorCategory\n * @param status - HTTP status code\n * @param responseBody - Optional response body for additional context\n */\nexport function classifyHttpStatus(\n status: number,\n responseBody?: string,\n): IpfsErrorCategory {\n if (status === 404) {\n return 'NOT_FOUND';\n }\n\n if (status === 500 && responseBody) {\n // Kubo returns 500 with \"routing: not found\" for IPNS records that don't exist\n if (/routing:\\s*not\\s*found/i.test(responseBody)) {\n return 'NOT_FOUND';\n }\n }\n\n if (status >= 500) {\n return 'GATEWAY_ERROR';\n }\n\n if (status >= 400) {\n return 'GATEWAY_ERROR';\n }\n\n return 'GATEWAY_ERROR';\n}\n","/**\n * IPFS State Persistence\n * Interface and in-memory implementation for persisting IPFS/IPNS state\n */\n\nimport type { IpfsStatePersistence, IpfsPersistedState } from './ipfs-types';\n\n// Re-export for convenience\nexport type { IpfsStatePersistence, IpfsPersistedState };\n\n// =============================================================================\n// In-Memory Implementation (for testing)\n// =============================================================================\n\nexport class InMemoryIpfsStatePersistence implements IpfsStatePersistence {\n private readonly states = new Map<string, IpfsPersistedState>();\n\n async load(ipnsName: string): Promise<IpfsPersistedState | null> {\n return this.states.get(ipnsName) ?? null;\n }\n\n async save(ipnsName: string, state: IpfsPersistedState): Promise<void> {\n this.states.set(ipnsName, { ...state });\n }\n\n async clear(ipnsName: string): Promise<void> {\n this.states.delete(ipnsName);\n }\n}\n","/**\n * IPNS Key Derivation\n * Deterministic IPNS identity from secp256k1 private key using HKDF\n *\n * Derivation path:\n * secp256k1 privateKey (hex)\n * -> HKDF(sha256, key, info=\"ipfs-storage-ed25519-v1\", 32 bytes)\n * -> Ed25519 key pair\n * -> libp2p PeerId\n * -> IPNS name (e.g., \"12D3KooW...\")\n */\n\nimport { hkdf } from '@noble/hashes/hkdf.js';\nimport { sha256 } from '@noble/hashes/sha2.js';\nimport { hexToBytes } from '../../../core/crypto';\n\n// =============================================================================\n// Constants\n// =============================================================================\n\n/**\n * HKDF info string for deriving Ed25519 keys from wallet keys.\n * Must match sphere webapp for cross-device compatibility.\n */\nexport const IPNS_HKDF_INFO = 'ipfs-storage-ed25519-v1';\n\n// =============================================================================\n// Dynamic Import Cache\n// =============================================================================\n\nlet libp2pCryptoModule: typeof import('@libp2p/crypto/keys') | null = null;\nlet libp2pPeerIdModule: typeof import('@libp2p/peer-id') | null = null;\n\nasync function loadLibp2pModules() {\n if (!libp2pCryptoModule) {\n [libp2pCryptoModule, libp2pPeerIdModule] = await Promise.all([\n import('@libp2p/crypto/keys'),\n import('@libp2p/peer-id'),\n ]);\n }\n return {\n generateKeyPairFromSeed: libp2pCryptoModule!.generateKeyPairFromSeed,\n peerIdFromPrivateKey: libp2pPeerIdModule!.peerIdFromPrivateKey,\n };\n}\n\n// =============================================================================\n// Key Derivation\n// =============================================================================\n\n/**\n * Derive Ed25519 key material from a secp256k1 private key using HKDF.\n *\n * @param privateKeyHex - secp256k1 private key in hex format\n * @param info - HKDF info string (default: IPNS_HKDF_INFO)\n * @returns 32-byte derived key material suitable for Ed25519 seed\n */\nexport function deriveEd25519KeyMaterial(\n privateKeyHex: string,\n info: string = IPNS_HKDF_INFO,\n): Uint8Array {\n const walletSecret = hexToBytes(privateKeyHex);\n const infoBytes = new TextEncoder().encode(info);\n return hkdf(sha256, walletSecret, undefined, infoBytes, 32);\n}\n\n/**\n * Derive full IPNS identity (key pair + IPNS name) from a secp256k1 private key.\n *\n * @param privateKeyHex - secp256k1 private key in hex format\n * @returns Object with keyPair and ipnsName\n */\nexport async function deriveIpnsIdentity(\n privateKeyHex: string,\n): Promise<{ keyPair: unknown; ipnsName: string }> {\n const { generateKeyPairFromSeed, peerIdFromPrivateKey } = await loadLibp2pModules();\n\n const derivedKey = deriveEd25519KeyMaterial(privateKeyHex);\n const keyPair = await generateKeyPairFromSeed('Ed25519', derivedKey);\n const peerId = peerIdFromPrivateKey(keyPair);\n\n return {\n keyPair,\n ipnsName: peerId.toString(),\n };\n}\n\n/**\n * Derive just the IPNS name from a secp256k1 private key.\n * Lighter than deriveIpnsIdentity when you don't need the key pair.\n *\n * @param privateKeyHex - secp256k1 private key in hex format\n * @returns IPNS name string (e.g., \"12D3KooW...\")\n */\nexport async function deriveIpnsName(\n privateKeyHex: string,\n): Promise<string> {\n const { ipnsName } = await deriveIpnsIdentity(privateKeyHex);\n return ipnsName;\n}\n","/**\n * IPNS Record Manager\n * Creates, marshals, and parses IPNS records for publishing and resolution\n */\n\n// =============================================================================\n// Constants\n// =============================================================================\n\n/** Default IPNS record lifetime: 99 years (effectively permanent) */\nconst DEFAULT_LIFETIME_MS = 99 * 365 * 24 * 60 * 60 * 1000;\n\n// =============================================================================\n// Dynamic Import Cache\n// =============================================================================\n\nlet ipnsModule: {\n createIPNSRecord: typeof import('ipns')['createIPNSRecord'];\n marshalIPNSRecord: typeof import('ipns')['marshalIPNSRecord'];\n unmarshalIPNSRecord: typeof import('ipns')['unmarshalIPNSRecord'];\n} | null = null;\n\nasync function loadIpnsModule() {\n if (!ipnsModule) {\n const mod = await import('ipns');\n ipnsModule = {\n createIPNSRecord: mod.createIPNSRecord,\n marshalIPNSRecord: mod.marshalIPNSRecord,\n unmarshalIPNSRecord: mod.unmarshalIPNSRecord,\n };\n }\n return ipnsModule;\n}\n\n// =============================================================================\n// Record Creation\n// =============================================================================\n\n/**\n * Create a signed IPNS record and marshal it to bytes.\n *\n * @param keyPair - Ed25519 private key (from deriveIpnsIdentity)\n * @param cid - CID to point the IPNS record at\n * @param sequenceNumber - Monotonically increasing sequence number\n * @param lifetimeMs - Record validity period (default: 99 years)\n * @returns Marshalled IPNS record bytes\n */\nexport async function createSignedRecord(\n keyPair: unknown,\n cid: string,\n sequenceNumber: bigint,\n lifetimeMs: number = DEFAULT_LIFETIME_MS,\n): Promise<Uint8Array> {\n const { createIPNSRecord, marshalIPNSRecord } = await loadIpnsModule();\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const record = await createIPNSRecord(\n keyPair as any,\n `/ipfs/${cid}`,\n sequenceNumber,\n lifetimeMs,\n );\n\n return marshalIPNSRecord(record);\n}\n\n// =============================================================================\n// Record Parsing\n// =============================================================================\n\n/**\n * Parse a routing API response (NDJSON) to extract CID and sequence number.\n * The routing API returns newline-delimited JSON with an \"Extra\" field\n * containing a base64-encoded marshalled IPNS record.\n *\n * @param responseText - Raw text from the routing API response\n * @returns Parsed result with cid, sequence, and recordData, or null\n */\nexport async function parseRoutingApiResponse(\n responseText: string,\n): Promise<{ cid: string; sequence: bigint; recordData: Uint8Array } | null> {\n const { unmarshalIPNSRecord } = await loadIpnsModule();\n\n const lines = responseText.trim().split('\\n');\n\n for (const line of lines) {\n if (!line.trim()) continue;\n\n try {\n const obj = JSON.parse(line);\n\n if (obj.Extra) {\n const recordData = base64ToUint8Array(obj.Extra);\n const record = unmarshalIPNSRecord(recordData);\n\n // Extract CID from the value field\n const valueBytes = typeof record.value === 'string'\n ? new TextEncoder().encode(record.value)\n : record.value as Uint8Array;\n const valueStr = new TextDecoder().decode(valueBytes);\n const cidMatch = valueStr.match(/\\/ipfs\\/([a-zA-Z0-9]+)/);\n\n if (cidMatch) {\n return {\n cid: cidMatch[1],\n sequence: record.sequence,\n recordData,\n };\n }\n }\n } catch {\n // Skip malformed lines\n continue;\n }\n }\n\n return null;\n}\n\n/**\n * Verify that a new sequence number represents a valid progression.\n *\n * @param newSeq - Proposed new sequence number\n * @param lastKnownSeq - Last known sequence number\n * @returns true if the new sequence is valid (greater than last known)\n */\nexport function verifySequenceProgression(\n newSeq: bigint,\n lastKnownSeq: bigint,\n): boolean {\n return newSeq > lastKnownSeq;\n}\n\n// =============================================================================\n// Utilities\n// =============================================================================\n\nfunction base64ToUint8Array(base64: string): Uint8Array {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n","/**\n * IPFS Multi-Tier Cache\n * Caches IPNS records, content by CID, and tracks gateway failures\n */\n\nimport type { IpnsGatewayResult } from './ipfs-types';\nimport type { TxfStorageDataBase } from '../../../storage';\n\n// =============================================================================\n// Cache Entry Type\n// =============================================================================\n\ninterface CacheEntry<T> {\n data: T;\n timestamp: number;\n}\n\n// =============================================================================\n// Default Config\n// =============================================================================\n\nconst DEFAULT_IPNS_TTL_MS = 60_000; // 60s for IPNS records\nconst DEFAULT_FAILURE_COOLDOWN_MS = 60_000; // 60s circuit breaker cooldown\nconst DEFAULT_FAILURE_THRESHOLD = 3; // 3 consecutive failures\nconst DEFAULT_KNOWN_FRESH_WINDOW_MS = 30_000; // 30s after publish\n\n// =============================================================================\n// Cache Implementation\n// =============================================================================\n\nexport interface IpfsCacheConfig {\n ipnsTtlMs?: number;\n failureCooldownMs?: number;\n failureThreshold?: number;\n knownFreshWindowMs?: number;\n}\n\nexport class IpfsCache {\n private readonly ipnsRecords = new Map<string, CacheEntry<IpnsGatewayResult>>();\n private readonly content = new Map<string, CacheEntry<TxfStorageDataBase>>();\n private readonly gatewayFailures = new Map<string, { count: number; lastFailure: number }>();\n private readonly knownFreshTimestamps = new Map<string, number>();\n\n private readonly ipnsTtlMs: number;\n private readonly failureCooldownMs: number;\n private readonly failureThreshold: number;\n private readonly knownFreshWindowMs: number;\n\n constructor(config?: IpfsCacheConfig) {\n this.ipnsTtlMs = config?.ipnsTtlMs ?? DEFAULT_IPNS_TTL_MS;\n this.failureCooldownMs = config?.failureCooldownMs ?? DEFAULT_FAILURE_COOLDOWN_MS;\n this.failureThreshold = config?.failureThreshold ?? DEFAULT_FAILURE_THRESHOLD;\n this.knownFreshWindowMs = config?.knownFreshWindowMs ?? DEFAULT_KNOWN_FRESH_WINDOW_MS;\n }\n\n // ---------------------------------------------------------------------------\n // IPNS Record Cache (60s TTL)\n // ---------------------------------------------------------------------------\n\n getIpnsRecord(ipnsName: string): IpnsGatewayResult | null {\n const entry = this.ipnsRecords.get(ipnsName);\n if (!entry) return null;\n\n if (Date.now() - entry.timestamp > this.ipnsTtlMs) {\n this.ipnsRecords.delete(ipnsName);\n return null;\n }\n\n return entry.data;\n }\n\n /**\n * Get cached IPNS record ignoring TTL (for known-fresh optimization).\n */\n getIpnsRecordIgnoreTtl(ipnsName: string): IpnsGatewayResult | null {\n const entry = this.ipnsRecords.get(ipnsName);\n return entry?.data ?? null;\n }\n\n setIpnsRecord(ipnsName: string, result: IpnsGatewayResult): void {\n this.ipnsRecords.set(ipnsName, {\n data: result,\n timestamp: Date.now(),\n });\n }\n\n invalidateIpns(ipnsName: string): void {\n this.ipnsRecords.delete(ipnsName);\n }\n\n // ---------------------------------------------------------------------------\n // Content Cache (infinite TTL - content is immutable by CID)\n // ---------------------------------------------------------------------------\n\n getContent(cid: string): TxfStorageDataBase | null {\n const entry = this.content.get(cid);\n return entry?.data ?? null;\n }\n\n setContent(cid: string, data: TxfStorageDataBase): void {\n this.content.set(cid, {\n data,\n timestamp: Date.now(),\n });\n }\n\n // ---------------------------------------------------------------------------\n // Gateway Failure Tracking (Circuit Breaker)\n // ---------------------------------------------------------------------------\n\n /**\n * Record a gateway failure. After threshold consecutive failures,\n * the gateway enters cooldown and is considered unhealthy.\n */\n recordGatewayFailure(gateway: string): void {\n const existing = this.gatewayFailures.get(gateway);\n this.gatewayFailures.set(gateway, {\n count: (existing?.count ?? 0) + 1,\n lastFailure: Date.now(),\n });\n }\n\n /** Reset failure count for a gateway (on successful request) */\n recordGatewaySuccess(gateway: string): void {\n this.gatewayFailures.delete(gateway);\n }\n\n /**\n * Check if a gateway is currently in circuit breaker cooldown.\n * A gateway is considered unhealthy if it has had >= threshold\n * consecutive failures and the cooldown period hasn't elapsed.\n */\n isGatewayInCooldown(gateway: string): boolean {\n const failure = this.gatewayFailures.get(gateway);\n if (!failure) return false;\n\n if (failure.count < this.failureThreshold) return false;\n\n const elapsed = Date.now() - failure.lastFailure;\n if (elapsed >= this.failureCooldownMs) {\n // Cooldown expired, reset\n this.gatewayFailures.delete(gateway);\n return false;\n }\n\n return true;\n }\n\n // ---------------------------------------------------------------------------\n // Known-Fresh Flag (FAST mode optimization)\n // ---------------------------------------------------------------------------\n\n /**\n * Mark IPNS cache as \"known-fresh\" (after local publish or push notification).\n * Within the fresh window, we can skip network resolution.\n */\n markIpnsFresh(ipnsName: string): void {\n this.knownFreshTimestamps.set(ipnsName, Date.now());\n }\n\n /**\n * Check if the cache is known-fresh (within the fresh window).\n */\n isIpnsKnownFresh(ipnsName: string): boolean {\n const timestamp = this.knownFreshTimestamps.get(ipnsName);\n if (!timestamp) return false;\n\n if (Date.now() - timestamp > this.knownFreshWindowMs) {\n this.knownFreshTimestamps.delete(ipnsName);\n return false;\n }\n\n return true;\n }\n\n // ---------------------------------------------------------------------------\n // Cache Management\n // ---------------------------------------------------------------------------\n\n clear(): void {\n this.ipnsRecords.clear();\n this.content.clear();\n this.gatewayFailures.clear();\n this.knownFreshTimestamps.clear();\n }\n}\n","/**\n * IPFS HTTP Client\n * Fetch-based HTTP API client for IPFS gateway operations.\n * Works in both browser and Node.js (native fetch available since Node 18+).\n */\n\nimport type {\n IpnsGatewayResult,\n IpnsProgressiveResult,\n IpnsPublishResult,\n GatewayHealthResult,\n} from './ipfs-types';\nimport type { TxfStorageDataBase } from '../../../storage';\nimport {\n IpfsError,\n classifyFetchError,\n classifyHttpStatus,\n} from './ipfs-error-types';\nimport { IpfsCache } from './ipfs-cache';\nimport { parseRoutingApiResponse } from './ipns-record-manager';\n\n// =============================================================================\n// Default Timeouts\n// =============================================================================\n\nconst DEFAULT_CONNECTIVITY_TIMEOUT_MS = 5000;\nconst DEFAULT_FETCH_TIMEOUT_MS = 15000;\nconst DEFAULT_RESOLVE_TIMEOUT_MS = 10000;\nconst DEFAULT_PUBLISH_TIMEOUT_MS = 30000;\nconst DEFAULT_GATEWAY_PATH_TIMEOUT_MS = 3000;\nconst DEFAULT_ROUTING_API_TIMEOUT_MS = 2000;\n\n// =============================================================================\n// HTTP Client\n// =============================================================================\n\nexport interface IpfsHttpClientConfig {\n gateways: string[];\n fetchTimeoutMs?: number;\n resolveTimeoutMs?: number;\n publishTimeoutMs?: number;\n connectivityTimeoutMs?: number;\n debug?: boolean;\n}\n\nexport class IpfsHttpClient {\n private readonly gateways: string[];\n private readonly fetchTimeoutMs: number;\n private readonly resolveTimeoutMs: number;\n private readonly publishTimeoutMs: number;\n private readonly connectivityTimeoutMs: number;\n private readonly debug: boolean;\n private readonly cache: IpfsCache;\n\n constructor(config: IpfsHttpClientConfig, cache: IpfsCache) {\n this.gateways = config.gateways;\n this.fetchTimeoutMs = config.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;\n this.resolveTimeoutMs = config.resolveTimeoutMs ?? DEFAULT_RESOLVE_TIMEOUT_MS;\n this.publishTimeoutMs = config.publishTimeoutMs ?? DEFAULT_PUBLISH_TIMEOUT_MS;\n this.connectivityTimeoutMs = config.connectivityTimeoutMs ?? DEFAULT_CONNECTIVITY_TIMEOUT_MS;\n this.debug = config.debug ?? false;\n this.cache = cache;\n }\n\n // ---------------------------------------------------------------------------\n // Public Accessors\n // ---------------------------------------------------------------------------\n\n /**\n * Get configured gateway URLs.\n */\n getGateways(): string[] {\n return [...this.gateways];\n }\n\n // ---------------------------------------------------------------------------\n // Gateway Health\n // ---------------------------------------------------------------------------\n\n /**\n * Test connectivity to a single gateway.\n */\n async testConnectivity(gateway: string): Promise<GatewayHealthResult> {\n const start = Date.now();\n try {\n const response = await this.fetchWithTimeout(\n `${gateway}/api/v0/version`,\n this.connectivityTimeoutMs,\n { method: 'POST' },\n );\n\n if (!response.ok) {\n return { gateway, healthy: false, error: `HTTP ${response.status}` };\n }\n\n return {\n gateway,\n healthy: true,\n responseTimeMs: Date.now() - start,\n };\n } catch (error) {\n return {\n gateway,\n healthy: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n /**\n * Find healthy gateways from the configured list.\n */\n async findHealthyGateways(): Promise<string[]> {\n const results = await Promise.allSettled(\n this.gateways.map((gw) => this.testConnectivity(gw)),\n );\n\n return results\n .filter((r): r is PromiseFulfilledResult<GatewayHealthResult> =>\n r.status === 'fulfilled' && r.value.healthy)\n .map((r) => r.value.gateway);\n }\n\n /**\n * Get gateways that are not in circuit breaker cooldown.\n */\n getAvailableGateways(): string[] {\n return this.gateways.filter((gw) => !this.cache.isGatewayInCooldown(gw));\n }\n\n // ---------------------------------------------------------------------------\n // Content Upload\n // ---------------------------------------------------------------------------\n\n /**\n * Upload JSON content to IPFS.\n * Tries all gateways in parallel, returns first success.\n */\n async upload(data: unknown, gateways?: string[]): Promise<{ cid: string }> {\n const targets = gateways ?? this.getAvailableGateways();\n if (targets.length === 0) {\n throw new IpfsError('No gateways available for upload', 'NETWORK_ERROR');\n }\n\n const jsonBytes = new TextEncoder().encode(JSON.stringify(data));\n\n const promises = targets.map(async (gateway) => {\n try {\n const formData = new FormData();\n formData.append('file', new Blob([jsonBytes], { type: 'application/json' }), 'data.json');\n\n const response = await this.fetchWithTimeout(\n `${gateway}/api/v0/add?pin=true&cid-version=1`,\n this.publishTimeoutMs,\n { method: 'POST', body: formData },\n );\n\n if (!response.ok) {\n throw new IpfsError(\n `Upload failed: HTTP ${response.status}`,\n classifyHttpStatus(response.status),\n gateway,\n );\n }\n\n const result = await response.json();\n this.cache.recordGatewaySuccess(gateway);\n this.log(`Uploaded to ${gateway}: CID=${result.Hash}`);\n return { cid: result.Hash as string, gateway };\n } catch (error) {\n if (error instanceof IpfsError && error.shouldTriggerCircuitBreaker) {\n this.cache.recordGatewayFailure(gateway);\n }\n throw error;\n }\n });\n\n try {\n const result = await Promise.any(promises);\n return { cid: result.cid };\n } catch (error) {\n if (error instanceof AggregateError) {\n throw new IpfsError(\n `Upload failed on all gateways: ${error.errors.map(e => e.message).join('; ')}`,\n 'NETWORK_ERROR',\n );\n }\n throw error;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Content Fetch\n // ---------------------------------------------------------------------------\n\n /**\n * Fetch content by CID from IPFS gateways.\n * Checks content cache first. Races all gateways for fastest response.\n */\n async fetchContent<T extends TxfStorageDataBase>(\n cid: string,\n gateways?: string[],\n ): Promise<T> {\n // Check content cache (infinite TTL for immutable content)\n const cached = this.cache.getContent(cid);\n if (cached) {\n this.log(`Content cache hit for CID=${cid}`);\n return cached as T;\n }\n\n const targets = gateways ?? this.getAvailableGateways();\n if (targets.length === 0) {\n throw new IpfsError('No gateways available for fetch', 'NETWORK_ERROR');\n }\n\n const promises = targets.map(async (gateway) => {\n try {\n const response = await this.fetchWithTimeout(\n `${gateway}/ipfs/${cid}`,\n this.fetchTimeoutMs,\n { headers: { Accept: 'application/octet-stream' } },\n );\n\n if (!response.ok) {\n const body = await response.text().catch(() => '');\n throw new IpfsError(\n `Fetch failed: HTTP ${response.status}`,\n classifyHttpStatus(response.status, body),\n gateway,\n );\n }\n\n const data = await response.json() as T;\n this.cache.recordGatewaySuccess(gateway);\n this.cache.setContent(cid, data);\n this.log(`Fetched from ${gateway}: CID=${cid}`);\n return data;\n } catch (error) {\n if (error instanceof IpfsError && error.shouldTriggerCircuitBreaker) {\n this.cache.recordGatewayFailure(gateway);\n }\n throw error;\n }\n });\n\n try {\n return await Promise.any(promises);\n } catch (error) {\n if (error instanceof AggregateError) {\n throw new IpfsError(\n `Fetch failed on all gateways for CID=${cid}`,\n 'NETWORK_ERROR',\n );\n }\n throw error;\n }\n }\n\n // ---------------------------------------------------------------------------\n // IPNS Resolution\n // ---------------------------------------------------------------------------\n\n /**\n * Resolve IPNS via Routing API (returns record with sequence number).\n * POST /api/v0/routing/get?arg=/ipns/{name}\n */\n async resolveIpnsViaRoutingApi(\n gateway: string,\n ipnsName: string,\n timeoutMs: number = DEFAULT_ROUTING_API_TIMEOUT_MS,\n ): Promise<IpnsGatewayResult | null> {\n try {\n const response = await this.fetchWithTimeout(\n `${gateway}/api/v0/routing/get?arg=/ipns/${ipnsName}`,\n timeoutMs,\n { method: 'POST' },\n );\n\n if (!response.ok) {\n const body = await response.text().catch(() => '');\n const category = classifyHttpStatus(response.status, body);\n if (category === 'NOT_FOUND') return null;\n throw new IpfsError(`Routing API: HTTP ${response.status}`, category, gateway);\n }\n\n const text = await response.text();\n const parsed = await parseRoutingApiResponse(text);\n\n if (!parsed) return null;\n\n this.cache.recordGatewaySuccess(gateway);\n return {\n cid: parsed.cid,\n sequence: parsed.sequence,\n gateway,\n recordData: parsed.recordData,\n };\n } catch (error) {\n if (error instanceof IpfsError) throw error;\n const category = classifyFetchError(error);\n if (category !== 'NOT_FOUND') {\n this.cache.recordGatewayFailure(gateway);\n }\n return null;\n }\n }\n\n /**\n * Resolve IPNS via gateway path (simpler, no sequence number).\n * GET /ipns/{name}?format=dag-json\n */\n async resolveIpnsViaGatewayPath(\n gateway: string,\n ipnsName: string,\n timeoutMs: number = DEFAULT_GATEWAY_PATH_TIMEOUT_MS,\n ): Promise<{ cid: string; content?: unknown } | null> {\n try {\n const response = await this.fetchWithTimeout(\n `${gateway}/ipns/${ipnsName}`,\n timeoutMs,\n { headers: { Accept: 'application/json' } },\n );\n\n if (!response.ok) return null;\n\n const content = await response.json();\n const cidHeader = response.headers.get('X-Ipfs-Path');\n if (cidHeader) {\n const match = cidHeader.match(/\\/ipfs\\/([a-zA-Z0-9]+)/);\n if (match) {\n this.cache.recordGatewaySuccess(gateway);\n return { cid: match[1], content };\n }\n }\n\n return { cid: '', content };\n } catch {\n return null;\n }\n }\n\n /**\n * Progressive IPNS resolution across all gateways.\n * Queries all gateways in parallel, returns highest sequence number.\n */\n async resolveIpns(\n ipnsName: string,\n gateways?: string[],\n ): Promise<IpnsProgressiveResult> {\n const targets = gateways ?? this.getAvailableGateways();\n if (targets.length === 0) {\n return { best: null, allResults: [], respondedCount: 0, totalGateways: 0 };\n }\n\n const results: IpnsGatewayResult[] = [];\n let respondedCount = 0;\n\n const promises = targets.map(async (gateway) => {\n const result = await this.resolveIpnsViaRoutingApi(\n gateway,\n ipnsName,\n this.resolveTimeoutMs,\n );\n if (result) results.push(result);\n respondedCount++;\n return result;\n });\n\n // Wait for all to complete (with overall timeout)\n await Promise.race([\n Promise.allSettled(promises),\n new Promise<void>((resolve) =>\n setTimeout(resolve, this.resolveTimeoutMs + 1000)),\n ]);\n\n // Find best result (highest sequence)\n let best: IpnsGatewayResult | null = null;\n for (const result of results) {\n if (!best || result.sequence > best.sequence) {\n best = result;\n }\n }\n\n if (best) {\n this.cache.setIpnsRecord(ipnsName, best);\n }\n\n return {\n best,\n allResults: results,\n respondedCount,\n totalGateways: targets.length,\n };\n }\n\n // ---------------------------------------------------------------------------\n // IPNS Publishing\n // ---------------------------------------------------------------------------\n\n /**\n * Publish IPNS record to a single gateway via routing API.\n */\n async publishIpnsViaRoutingApi(\n gateway: string,\n ipnsName: string,\n marshalledRecord: Uint8Array,\n timeoutMs: number = DEFAULT_PUBLISH_TIMEOUT_MS,\n ): Promise<boolean> {\n try {\n const formData = new FormData();\n formData.append(\n 'file',\n new Blob([new Uint8Array(marshalledRecord)]),\n 'record',\n );\n\n const response = await this.fetchWithTimeout(\n `${gateway}/api/v0/routing/put?arg=/ipns/${ipnsName}&allow-offline=true`,\n timeoutMs,\n { method: 'POST', body: formData },\n );\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => '');\n throw new IpfsError(\n `IPNS publish: HTTP ${response.status}: ${errorText.slice(0, 100)}`,\n classifyHttpStatus(response.status, errorText),\n gateway,\n );\n }\n\n this.cache.recordGatewaySuccess(gateway);\n this.log(`IPNS published to ${gateway}: ${ipnsName}`);\n return true;\n } catch (error) {\n if (error instanceof IpfsError && error.shouldTriggerCircuitBreaker) {\n this.cache.recordGatewayFailure(gateway);\n }\n this.log(`IPNS publish to ${gateway} failed: ${error}`);\n return false;\n }\n }\n\n /**\n * Publish IPNS record to all gateways in parallel.\n */\n async publishIpns(\n ipnsName: string,\n marshalledRecord: Uint8Array,\n gateways?: string[],\n ): Promise<IpnsPublishResult> {\n const targets = gateways ?? this.getAvailableGateways();\n if (targets.length === 0) {\n return { success: false, error: 'No gateways available' };\n }\n\n const results = await Promise.allSettled(\n targets.map((gw) =>\n this.publishIpnsViaRoutingApi(gw, ipnsName, marshalledRecord, this.publishTimeoutMs)),\n );\n\n const successfulGateways: string[] = [];\n results.forEach((result, index) => {\n if (result.status === 'fulfilled' && result.value) {\n successfulGateways.push(targets[index]);\n }\n });\n\n return {\n success: successfulGateways.length > 0,\n ipnsName,\n successfulGateways,\n error: successfulGateways.length === 0 ? 'All gateways failed' : undefined,\n };\n }\n\n // ---------------------------------------------------------------------------\n // IPNS Verification\n // ---------------------------------------------------------------------------\n\n /**\n * Verify IPNS record persistence after publishing.\n * Retries resolution to confirm the record was accepted.\n */\n async verifyIpnsRecord(\n ipnsName: string,\n expectedSeq: bigint,\n expectedCid: string,\n retries: number = 3,\n delayMs: number = 1000,\n ): Promise<boolean> {\n for (let i = 0; i < retries; i++) {\n if (i > 0) {\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n }\n\n const { best } = await this.resolveIpns(ipnsName);\n if (best && best.sequence >= expectedSeq && best.cid === expectedCid) {\n return true;\n }\n }\n return false;\n }\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n private async fetchWithTimeout(\n url: string,\n timeoutMs: number,\n options?: RequestInit,\n ): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n return await fetch(url, {\n ...options,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n }\n\n private log(message: string): void {\n if (this.debug) {\n console.log(`[IPFS-HTTP] ${message}`);\n }\n }\n}\n","/**\n * TXF Data Merge / Conflict Resolution\n * Merges local and remote TXF storage data with proper conflict handling\n */\n\nimport type { TxfStorageDataBase, TxfTombstone } from '../../../storage';\nimport type { MergeResult } from './ipfs-types';\n\n// =============================================================================\n// Merge Logic\n// =============================================================================\n\n/**\n * Merge local and remote TXF data.\n *\n * Rules:\n * 1. Meta: Higher version wins as base; increment by 1\n * 2. Tombstones: Union by composite key (tokenId, stateHash)\n * 3. Token entries: present in only one source -> add; both -> local wins\n * 4. Tombstone filtering: exclude tokens present in merged tombstones\n * 5. Outbox/Sent: Union with dedup by id/tokenId\n */\nexport function mergeTxfData<T extends TxfStorageDataBase>(\n local: T,\n remote: T,\n): MergeResult<T> {\n let added = 0;\n let removed = 0;\n let conflicts = 0;\n\n // 1. Merge meta — use higher version as base, increment\n const localVersion = local._meta?.version ?? 0;\n const remoteVersion = remote._meta?.version ?? 0;\n const baseMeta = localVersion >= remoteVersion ? local._meta : remote._meta;\n const mergedMeta = {\n ...baseMeta,\n version: Math.max(localVersion, remoteVersion) + 1,\n updatedAt: Date.now(),\n };\n\n // 2. Merge tombstones — union by composite key (tokenId + stateHash)\n const mergedTombstones = mergeTombstones(\n local._tombstones ?? [],\n remote._tombstones ?? [],\n );\n const tombstoneKeys = new Set(\n mergedTombstones.map((t) => `${t.tokenId}:${t.stateHash}`),\n );\n\n // 3. Merge token entries\n const localTokenKeys = getTokenKeys(local);\n const remoteTokenKeys = getTokenKeys(remote);\n const allTokenKeys = new Set([...localTokenKeys, ...remoteTokenKeys]);\n\n const mergedTokens: Record<string, unknown> = {};\n\n for (const key of allTokenKeys) {\n const tokenId = key.startsWith('_') ? key.slice(1) : key;\n const localToken = (local as Record<string, unknown>)[key];\n const remoteToken = (remote as Record<string, unknown>)[key];\n\n // Check tombstone filter\n if (isTokenTombstoned(tokenId, localToken, remoteToken, tombstoneKeys)) {\n if (localTokenKeys.has(key)) removed++;\n continue;\n }\n\n if (localToken && !remoteToken) {\n // Only in local\n mergedTokens[key] = localToken;\n } else if (!localToken && remoteToken) {\n // Only in remote\n mergedTokens[key] = remoteToken;\n added++;\n } else if (localToken && remoteToken) {\n // In both — local wins (with conflict count)\n mergedTokens[key] = localToken;\n conflicts++;\n }\n }\n\n // 4. Merge outbox — union with dedup by id\n const mergedOutbox = mergeArrayById(\n local._outbox ?? [],\n remote._outbox ?? [],\n 'id',\n );\n\n // 5. Merge sent — union with dedup by tokenId\n const mergedSent = mergeArrayById(\n local._sent ?? [],\n remote._sent ?? [],\n 'tokenId',\n );\n\n // 6. Merge invalid — union with dedup by tokenId\n const mergedInvalid = mergeArrayById(\n local._invalid ?? [],\n remote._invalid ?? [],\n 'tokenId',\n );\n\n // 7. Merge nametags — union by name, local wins on conflict\n type NametagEntry = { name: string; [key: string]: unknown };\n const localNametags = (local._nametags ?? []) as NametagEntry[];\n const remoteNametags = (remote._nametags ?? []) as NametagEntry[];\n const mergedNametags = mergeNametagsByName(localNametags, remoteNametags);\n\n // Build merged result\n const merged = {\n _meta: mergedMeta,\n _tombstones: mergedTombstones.length > 0 ? mergedTombstones : undefined,\n _nametags: mergedNametags.length > 0 ? mergedNametags : undefined,\n _outbox: mergedOutbox.length > 0 ? mergedOutbox : undefined,\n _sent: mergedSent.length > 0 ? mergedSent : undefined,\n _invalid: mergedInvalid.length > 0 ? mergedInvalid : undefined,\n ...mergedTokens,\n } as unknown as T;\n\n return { merged, added, removed, conflicts };\n}\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\n/**\n * Merge tombstone arrays by composite key (tokenId + stateHash).\n * On duplicates, keep the one with the newer timestamp.\n */\nfunction mergeTombstones(\n local: TxfTombstone[],\n remote: TxfTombstone[],\n): TxfTombstone[] {\n const merged = new Map<string, TxfTombstone>();\n\n for (const tombstone of [...local, ...remote]) {\n const key = `${tombstone.tokenId}:${tombstone.stateHash}`;\n const existing = merged.get(key);\n if (!existing || tombstone.timestamp > existing.timestamp) {\n merged.set(key, tombstone);\n }\n }\n\n return Array.from(merged.values());\n}\n\n/**\n * Get all token entry keys from TXF data.\n * Token keys start with '_' but are not meta fields.\n */\nfunction getTokenKeys(data: TxfStorageDataBase): Set<string> {\n const reservedKeys = new Set([\n '_meta', '_tombstones', '_outbox', '_sent', '_invalid',\n '_nametag', '_nametags', '_mintOutbox', '_invalidatedNametags', '_integrity',\n ]);\n const keys = new Set<string>();\n\n for (const key of Object.keys(data)) {\n if (reservedKeys.has(key)) continue;\n // Exclude archived and forked entries from token merge\n if (key.startsWith('archived-') || key.startsWith('_forked_')) continue;\n keys.add(key);\n }\n\n return keys;\n}\n\n/**\n * Check if a token should be filtered by tombstones.\n */\nfunction isTokenTombstoned(\n tokenId: string,\n localToken: unknown,\n remoteToken: unknown,\n tombstoneKeys: Set<string>,\n): boolean {\n // Check if any variant of this token is tombstoned\n // We check generic tokenId matching since we may not have the stateHash here\n for (const key of tombstoneKeys) {\n if (key.startsWith(`${tokenId}:`)) {\n return true;\n }\n }\n // Keep token if not tombstoned\n void localToken;\n void remoteToken;\n return false;\n}\n\n/**\n * Merge nametag arrays by name, deduplicating.\n * On duplicates, keep the local entry.\n */\nfunction mergeNametagsByName(\n local: Array<{ name: string; [key: string]: unknown }>,\n remote: Array<{ name: string; [key: string]: unknown }>,\n): Array<{ name: string; [key: string]: unknown }> {\n const seen = new Map<string, { name: string; [key: string]: unknown }>();\n\n for (const item of local) {\n if (item.name) seen.set(item.name, item);\n }\n for (const item of remote) {\n if (item.name && !seen.has(item.name)) {\n seen.set(item.name, item);\n }\n }\n\n return Array.from(seen.values());\n}\n\n/**\n * Merge arrays by a key field, deduplicating.\n * On duplicates, keep the one from the first array (local).\n */\nfunction mergeArrayById<T>(\n local: T[],\n remote: T[],\n idField: keyof T,\n): T[] {\n const seen = new Map<unknown, T>();\n\n for (const item of local) {\n const id = item[idField];\n if (id !== undefined) {\n seen.set(id, item);\n }\n }\n\n for (const item of remote) {\n const id = item[idField];\n if (id !== undefined && !seen.has(id)) {\n seen.set(id, item);\n }\n }\n\n return Array.from(seen.values());\n}\n","/**\n * WebSocket client for IPNS subscription updates.\n * Connects to IPFS sidecar and receives push notifications for IPNS changes.\n *\n * Architecture:\n * - Connects to /ws/ipns endpoint on IPFS gateway\n * - Clients subscribe to specific IPNS names\n * - Server pushes updates when IPNS records change\n * - Auto-reconnects on connection loss with exponential backoff\n * - Falls back to polling when WebSocket is unavailable\n *\n * Ported from Sphere webapp's IpnsSubscriptionClient.\n */\n\nimport type { IWebSocket, WebSocketFactory } from '../../../transport/websocket';\nimport { WebSocketReadyState } from '../../../transport/websocket';\nimport type { IpnsUpdateEvent } from './ipfs-types';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface IpnsSubscriptionClientConfig {\n /** WebSocket URL (e.g., wss://host/ws/ipns) */\n wsUrl: string;\n /** Platform-specific WebSocket factory */\n createWebSocket: WebSocketFactory;\n /** Ping interval in ms (default: 30000) */\n pingIntervalMs?: number;\n /** Initial reconnect delay in ms (default: 5000) */\n reconnectDelayMs?: number;\n /** Max reconnect delay in ms (default: 60000) */\n maxReconnectDelayMs?: number;\n /** Enable debug logging (default: false) */\n debug?: boolean;\n}\n\ntype UpdateCallback = (update: IpnsUpdateEvent) => void;\n\ninterface WebSocketMessage {\n type: string;\n name?: string;\n names?: string[];\n sequence?: number;\n cid?: string | null;\n timestamp?: string;\n message?: string;\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\nexport class IpnsSubscriptionClient {\n private ws: IWebSocket | null = null;\n private readonly subscriptions: Map<string, Set<UpdateCallback>> = new Map();\n private reconnectTimeout: ReturnType<typeof setTimeout> | null = null;\n private pingInterval: ReturnType<typeof setInterval> | null = null;\n private fallbackPollInterval: ReturnType<typeof setInterval> | null = null;\n\n private readonly wsUrl: string;\n private readonly createWebSocket: WebSocketFactory;\n private readonly pingIntervalMs: number;\n private readonly initialReconnectDelayMs: number;\n private readonly maxReconnectDelayMs: number;\n private readonly debugEnabled: boolean;\n\n private reconnectAttempts = 0;\n private isConnecting = false;\n private connectionOpenedAt = 0;\n private destroyed = false;\n\n /** Minimum stable connection time before resetting backoff (30 seconds) */\n private readonly minStableConnectionMs = 30000;\n\n private fallbackPollFn: (() => Promise<void>) | null = null;\n private fallbackPollIntervalMs = 0;\n\n constructor(config: IpnsSubscriptionClientConfig) {\n this.wsUrl = config.wsUrl;\n this.createWebSocket = config.createWebSocket;\n this.pingIntervalMs = config.pingIntervalMs ?? 30000;\n this.initialReconnectDelayMs = config.reconnectDelayMs ?? 5000;\n this.maxReconnectDelayMs = config.maxReconnectDelayMs ?? 60000;\n this.debugEnabled = config.debug ?? false;\n }\n\n // ---------------------------------------------------------------------------\n // Public API\n // ---------------------------------------------------------------------------\n\n /**\n * Subscribe to IPNS updates for a specific name.\n * Automatically connects the WebSocket if not already connected.\n * If WebSocket is connecting, the name will be subscribed once connected.\n */\n subscribe(ipnsName: string, callback: UpdateCallback): () => void {\n if (!ipnsName || typeof ipnsName !== 'string') {\n this.log('Invalid IPNS name for subscription');\n return () => { /* noop */ };\n }\n\n const isNewSubscription = !this.subscriptions.has(ipnsName);\n\n if (isNewSubscription) {\n this.subscriptions.set(ipnsName, new Set());\n }\n\n this.subscriptions.get(ipnsName)!.add(callback);\n\n // Send subscription to server if already connected and this is a new name\n if (isNewSubscription && this.ws?.readyState === WebSocketReadyState.OPEN) {\n this.sendSubscribe([ipnsName]);\n }\n\n // Connect if not already connected\n if (!this.ws || this.ws.readyState !== WebSocketReadyState.OPEN) {\n this.connect();\n }\n\n // Return unsubscribe function\n return () => {\n const callbacks = this.subscriptions.get(ipnsName);\n if (callbacks) {\n callbacks.delete(callback);\n if (callbacks.size === 0) {\n this.subscriptions.delete(ipnsName);\n if (this.ws?.readyState === WebSocketReadyState.OPEN) {\n this.sendUnsubscribe([ipnsName]);\n }\n // Disconnect if no more subscriptions\n if (this.subscriptions.size === 0) {\n this.disconnect();\n }\n }\n }\n };\n }\n\n /**\n * Register a convenience update callback for all subscriptions.\n * Returns an unsubscribe function.\n */\n onUpdate(callback: UpdateCallback): () => void {\n // Store as a special \"global\" callback keyed by '*'\n if (!this.subscriptions.has('*')) {\n this.subscriptions.set('*', new Set());\n }\n this.subscriptions.get('*')!.add(callback);\n\n return () => {\n const callbacks = this.subscriptions.get('*');\n if (callbacks) {\n callbacks.delete(callback);\n if (callbacks.size === 0) {\n this.subscriptions.delete('*');\n }\n }\n };\n }\n\n /**\n * Set a fallback poll function to use when WebSocket is disconnected.\n * The poll function will be called at the specified interval while WS is down.\n */\n setFallbackPoll(fn: () => Promise<void>, intervalMs: number): void {\n this.fallbackPollFn = fn;\n this.fallbackPollIntervalMs = intervalMs;\n // Start polling if WS is not connected\n if (!this.isConnected()) {\n this.startFallbackPolling();\n }\n }\n\n /**\n * Connect to the WebSocket server.\n */\n connect(): void {\n if (this.destroyed) return;\n if (this.ws?.readyState === WebSocketReadyState.OPEN || this.isConnecting) {\n return;\n }\n\n this.isConnecting = true;\n\n try {\n this.log(`Connecting to ${this.wsUrl}...`);\n this.ws = this.createWebSocket(this.wsUrl);\n\n this.ws.onopen = () => {\n this.log('WebSocket connected');\n this.isConnecting = false;\n this.connectionOpenedAt = Date.now();\n\n // Resubscribe to all IPNS names (excluding '*' global key)\n const names = Array.from(this.subscriptions.keys()).filter(n => n !== '*');\n if (names.length > 0) {\n this.sendSubscribe(names);\n }\n\n // Start ping interval to keep connection alive\n this.startPingInterval();\n\n // Stop fallback polling — WS is live\n this.stopFallbackPolling();\n };\n\n this.ws.onmessage = (event) => {\n this.handleMessage(event.data);\n };\n\n this.ws.onclose = () => {\n const connectionDuration = this.connectionOpenedAt > 0\n ? Date.now() - this.connectionOpenedAt\n : 0;\n const wasStable = connectionDuration >= this.minStableConnectionMs;\n\n this.log(`WebSocket closed (duration: ${Math.round(connectionDuration / 1000)}s)`);\n\n this.isConnecting = false;\n this.connectionOpenedAt = 0;\n this.stopPingInterval();\n\n // Only reset backoff if connection was stable\n if (wasStable) {\n this.reconnectAttempts = 0;\n }\n\n // Start fallback polling while WS is down\n this.startFallbackPolling();\n\n this.scheduleReconnect();\n };\n\n this.ws.onerror = () => {\n this.log('WebSocket error');\n this.isConnecting = false;\n };\n } catch (e) {\n this.log(`Failed to connect: ${e}`);\n this.isConnecting = false;\n this.startFallbackPolling();\n this.scheduleReconnect();\n }\n }\n\n /**\n * Disconnect from the WebSocket server and clean up.\n */\n disconnect(): void {\n this.destroyed = true;\n\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = null;\n }\n this.stopPingInterval();\n this.stopFallbackPolling();\n\n if (this.ws) {\n this.ws.onopen = null;\n this.ws.onclose = null;\n this.ws.onerror = null;\n this.ws.onmessage = null;\n this.ws.close();\n this.ws = null;\n }\n this.isConnecting = false;\n this.reconnectAttempts = 0;\n }\n\n /**\n * Check if connected to the WebSocket server.\n */\n isConnected(): boolean {\n return this.ws?.readyState === WebSocketReadyState.OPEN;\n }\n\n // ---------------------------------------------------------------------------\n // Internal: Message Handling\n // ---------------------------------------------------------------------------\n\n private handleMessage(data: string): void {\n try {\n const message = JSON.parse(data) as WebSocketMessage;\n\n switch (message.type) {\n case 'update':\n if (message.name && message.sequence !== undefined) {\n this.notifySubscribers({\n type: 'update',\n name: message.name,\n sequence: message.sequence,\n cid: message.cid ?? '',\n timestamp: message.timestamp || new Date().toISOString(),\n });\n }\n break;\n\n case 'subscribed':\n this.log(`Subscribed to ${message.names?.length || 0} names`);\n break;\n\n case 'unsubscribed':\n this.log(`Unsubscribed from ${message.names?.length || 0} names`);\n break;\n\n case 'pong':\n // Keepalive response received\n break;\n\n case 'error':\n this.log(`Server error: ${message.message}`);\n break;\n\n default:\n // Unknown message type — ignore\n break;\n }\n } catch {\n this.log('Failed to parse message');\n }\n }\n\n private notifySubscribers(update: IpnsUpdateEvent & { type: string }): void {\n // Notify name-specific subscribers\n const callbacks = this.subscriptions.get(update.name);\n if (callbacks) {\n this.log(`Update: ${update.name.slice(0, 16)}... seq=${update.sequence}`);\n for (const callback of callbacks) {\n try {\n callback(update);\n } catch {\n // Don't let callback errors break the client\n }\n }\n }\n\n // Notify global subscribers\n const globalCallbacks = this.subscriptions.get('*');\n if (globalCallbacks) {\n for (const callback of globalCallbacks) {\n try {\n callback(update);\n } catch {\n // Don't let callback errors break the client\n }\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Internal: WebSocket Send\n // ---------------------------------------------------------------------------\n\n private sendSubscribe(names: string[]): void {\n if (this.ws?.readyState === WebSocketReadyState.OPEN) {\n this.ws.send(JSON.stringify({ action: 'subscribe', names }));\n }\n }\n\n private sendUnsubscribe(names: string[]): void {\n if (this.ws?.readyState === WebSocketReadyState.OPEN) {\n this.ws.send(JSON.stringify({ action: 'unsubscribe', names }));\n }\n }\n\n // ---------------------------------------------------------------------------\n // Internal: Reconnection\n // ---------------------------------------------------------------------------\n\n /**\n * Schedule reconnection with exponential backoff.\n * Sequence: 5s, 10s, 20s, 40s, 60s (capped)\n */\n private scheduleReconnect(): void {\n if (this.destroyed || this.reconnectTimeout) return;\n\n // Don't reconnect if no subscriptions (excluding '*')\n const realSubscriptions = Array.from(this.subscriptions.keys()).filter(n => n !== '*');\n if (realSubscriptions.length === 0) return;\n\n this.reconnectAttempts++;\n const delay = Math.min(\n this.initialReconnectDelayMs * Math.pow(2, this.reconnectAttempts - 1),\n this.maxReconnectDelayMs,\n );\n\n this.log(`Reconnecting in ${(delay / 1000).toFixed(1)}s (attempt ${this.reconnectAttempts})...`);\n\n this.reconnectTimeout = setTimeout(() => {\n this.reconnectTimeout = null;\n this.connect();\n }, delay);\n }\n\n // ---------------------------------------------------------------------------\n // Internal: Keepalive\n // ---------------------------------------------------------------------------\n\n private startPingInterval(): void {\n this.stopPingInterval();\n this.pingInterval = setInterval(() => {\n if (this.ws?.readyState === WebSocketReadyState.OPEN) {\n this.ws.send(JSON.stringify({ action: 'ping' }));\n }\n }, this.pingIntervalMs);\n }\n\n private stopPingInterval(): void {\n if (this.pingInterval) {\n clearInterval(this.pingInterval);\n this.pingInterval = null;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Internal: Fallback Polling\n // ---------------------------------------------------------------------------\n\n private startFallbackPolling(): void {\n if (this.fallbackPollInterval || !this.fallbackPollFn || this.destroyed) return;\n\n this.log(`Starting fallback polling (${this.fallbackPollIntervalMs / 1000}s interval)`);\n\n // Run poll immediately once\n this.fallbackPollFn().catch(() => { /* ignore */ });\n\n this.fallbackPollInterval = setInterval(() => {\n this.fallbackPollFn?.().catch(() => { /* ignore */ });\n }, this.fallbackPollIntervalMs);\n }\n\n private stopFallbackPolling(): void {\n if (this.fallbackPollInterval) {\n clearInterval(this.fallbackPollInterval);\n this.fallbackPollInterval = null;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Internal: Logging\n // ---------------------------------------------------------------------------\n\n private log(message: string): void {\n if (this.debugEnabled) {\n console.log(`[IPNS-WS] ${message}`);\n }\n }\n}\n","/**\n * Write-Behind Buffer for IpfsStorageProvider\n *\n * Provides non-blocking writes via double-buffering and a promise-chain\n * serial queue. Writes are accepted immediately into a pending buffer\n * and flushed to IPFS asynchronously in the background.\n */\n\nimport type { TxfStorageDataBase } from '../../../storage';\n\n// =============================================================================\n// AsyncSerialQueue\n// =============================================================================\n\n/**\n * Promise-chain-based async mutex. Serializes async operations\n * without external dependencies. Each enqueued operation waits for\n * the previous one to complete before starting.\n */\nexport class AsyncSerialQueue {\n private tail: Promise<void> = Promise.resolve();\n\n /** Enqueue an async operation. Returns when it completes. */\n enqueue<T>(fn: () => Promise<T>): Promise<T> {\n let resolve: (value: T) => void;\n let reject: (reason: unknown) => void;\n const promise = new Promise<T>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n\n this.tail = this.tail.then(\n () => fn().then(resolve!, reject!),\n () => fn().then(resolve!, reject!),\n );\n\n return promise;\n }\n}\n\n// =============================================================================\n// WriteBuffer\n// =============================================================================\n\n/**\n * Collects mutations (token saves/deletes + full TXF data)\n * between flush cycles. Acts as a staging area for changes\n * that haven't been persisted to IPFS yet.\n */\nexport class WriteBuffer {\n /** Full TXF data from save() calls — latest wins */\n txfData: TxfStorageDataBase | null = null;\n\n get isEmpty(): boolean {\n return this.txfData === null;\n }\n\n clear(): void {\n this.txfData = null;\n }\n\n /**\n * Merge another buffer's contents into this one (for rollback).\n * Existing (newer) mutations in `this` take precedence over `other`.\n */\n mergeFrom(other: WriteBuffer): void {\n if (other.txfData && !this.txfData) {\n this.txfData = other.txfData;\n }\n }\n}\n","/**\n * IPFS Storage Provider\n * Main TokenStorageProvider implementation using IPFS/IPNS.\n * Shared cross-platform module (browser + Node.js via native fetch).\n *\n * Uses a write-behind buffer for non-blocking save() operations.\n * Writes are accepted immediately and flushed to IPFS asynchronously.\n */\n\nimport type { ProviderStatus, FullIdentity } from '../../../types';\nimport type {\n TokenStorageProvider,\n TxfStorageDataBase,\n SaveResult,\n LoadResult,\n SyncResult,\n StorageEventCallback,\n StorageEvent,\n} from '../../../storage';\nimport type {\n IpfsStorageConfig,\n IpfsStatePersistence,\n} from './ipfs-types';\nimport type { WebSocketFactory } from '../../../transport/websocket';\nimport { getIpfsGatewayUrls } from '../../../constants';\nimport { IpfsCache } from './ipfs-cache';\nimport { IpfsHttpClient } from './ipfs-http-client';\nimport { IpnsSubscriptionClient } from './ipns-subscription-client';\nimport { deriveIpnsIdentity } from './ipns-key-derivation';\nimport { createSignedRecord } from './ipns-record-manager';\nimport { mergeTxfData } from './txf-merge';\nimport { InMemoryIpfsStatePersistence } from './ipfs-state-persistence';\nimport { AsyncSerialQueue, WriteBuffer } from './write-behind-buffer';\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\nexport class IpfsStorageProvider<TData extends TxfStorageDataBase = TxfStorageDataBase>\n implements TokenStorageProvider<TData>\n{\n readonly id = 'ipfs';\n readonly name = 'IPFS Storage';\n readonly type = 'p2p' as const;\n\n private status: ProviderStatus = 'disconnected';\n private identity: FullIdentity | null = null;\n private ipnsKeyPair: unknown = null;\n private ipnsName: string | null = null;\n private ipnsSequenceNumber: bigint = 0n;\n private lastCid: string | null = null;\n private lastKnownRemoteSequence: bigint = 0n;\n private dataVersion = 0;\n\n /**\n * The CID currently stored on the sidecar for this IPNS name.\n * Used as `_meta.lastCid` in the next save to satisfy chain validation.\n * - null for bootstrap (first-ever save)\n * - set after every successful save() or load()\n */\n private remoteCid: string | null = null;\n\n private readonly cache: IpfsCache;\n private readonly httpClient: IpfsHttpClient;\n private readonly statePersistence: IpfsStatePersistence;\n private readonly eventCallbacks: Set<StorageEventCallback> = new Set();\n private readonly debug: boolean;\n private readonly ipnsLifetimeMs: number;\n\n /** WebSocket factory for push subscriptions */\n private readonly createWebSocket: WebSocketFactory | undefined;\n /** Override WS URL */\n private readonly wsUrl: string | undefined;\n /** Fallback poll interval (default: 90000) */\n private readonly fallbackPollIntervalMs: number;\n /** IPNS subscription client for push notifications */\n private subscriptionClient: IpnsSubscriptionClient | null = null;\n /** Unsubscribe function from subscription client */\n private subscriptionUnsubscribe: (() => void) | null = null;\n\n /** Write-behind buffer: serializes flush / sync / shutdown */\n private readonly flushQueue = new AsyncSerialQueue();\n /** Pending mutations not yet flushed to IPFS */\n private pendingBuffer = new WriteBuffer();\n /** Debounce timer for background flush */\n private flushTimer: ReturnType<typeof setTimeout> | null = null;\n /** Debounce interval in ms */\n private readonly flushDebounceMs: number;\n /** Set to true during shutdown to prevent new flushes */\n private isShuttingDown = false;\n\n constructor(\n config?: IpfsStorageConfig,\n statePersistence?: IpfsStatePersistence,\n ) {\n const gateways = config?.gateways ?? getIpfsGatewayUrls();\n this.debug = config?.debug ?? false;\n this.ipnsLifetimeMs = config?.ipnsLifetimeMs ?? (99 * 365 * 24 * 60 * 60 * 1000);\n this.flushDebounceMs = config?.flushDebounceMs ?? 2000;\n\n this.cache = new IpfsCache({\n ipnsTtlMs: config?.ipnsCacheTtlMs,\n failureCooldownMs: config?.circuitBreakerCooldownMs,\n failureThreshold: config?.circuitBreakerThreshold,\n knownFreshWindowMs: config?.knownFreshWindowMs,\n });\n\n this.httpClient = new IpfsHttpClient({\n gateways,\n fetchTimeoutMs: config?.fetchTimeoutMs,\n resolveTimeoutMs: config?.resolveTimeoutMs,\n publishTimeoutMs: config?.publishTimeoutMs,\n connectivityTimeoutMs: config?.connectivityTimeoutMs,\n debug: this.debug,\n }, this.cache);\n\n this.statePersistence = statePersistence ?? new InMemoryIpfsStatePersistence();\n this.createWebSocket = config?.createWebSocket;\n this.wsUrl = config?.wsUrl;\n this.fallbackPollIntervalMs = config?.fallbackPollIntervalMs ?? 90000;\n }\n\n // ---------------------------------------------------------------------------\n // BaseProvider interface\n // ---------------------------------------------------------------------------\n\n async connect(): Promise<void> {\n await this.initialize();\n }\n\n async disconnect(): Promise<void> {\n await this.shutdown();\n }\n\n isConnected(): boolean {\n return this.status === 'connected';\n }\n\n getStatus(): ProviderStatus {\n return this.status;\n }\n\n // ---------------------------------------------------------------------------\n // Identity & Initialization\n // ---------------------------------------------------------------------------\n\n setIdentity(identity: FullIdentity): void {\n this.identity = identity;\n }\n\n async initialize(): Promise<boolean> {\n if (!this.identity) {\n this.log('Cannot initialize: no identity set');\n return false;\n }\n\n this.status = 'connecting';\n this.emitEvent({ type: 'storage:loading', timestamp: Date.now() });\n\n try {\n // Derive IPNS key pair and name from wallet private key\n const { keyPair, ipnsName } = await deriveIpnsIdentity(this.identity.privateKey);\n this.ipnsKeyPair = keyPair;\n this.ipnsName = ipnsName;\n this.log(`IPNS name derived: ${ipnsName}`);\n\n // Load persisted state\n const persisted = await this.statePersistence.load(ipnsName);\n if (persisted) {\n this.ipnsSequenceNumber = BigInt(persisted.sequenceNumber);\n this.lastCid = persisted.lastCid;\n this.remoteCid = persisted.lastCid; // chain link for next save\n this.dataVersion = persisted.version;\n this.log(`Loaded persisted state: seq=${this.ipnsSequenceNumber}, cid=${this.lastCid}`);\n }\n\n // Set up IPNS push subscription if WebSocket factory is available\n if (this.createWebSocket) {\n try {\n const wsUrlFinal = this.wsUrl ?? this.deriveWsUrl();\n if (wsUrlFinal) {\n this.subscriptionClient = new IpnsSubscriptionClient({\n wsUrl: wsUrlFinal,\n createWebSocket: this.createWebSocket,\n debug: this.debug,\n });\n\n // Subscribe to own IPNS name\n this.subscriptionUnsubscribe = this.subscriptionClient.subscribe(\n ipnsName,\n (update) => {\n this.log(`Push update: seq=${update.sequence}, cid=${update.cid}`);\n this.emitEvent({\n type: 'storage:remote-updated',\n timestamp: Date.now(),\n data: { name: update.name, sequence: update.sequence, cid: update.cid },\n });\n },\n );\n\n // Set fallback poll for when WS is disconnected\n this.subscriptionClient.setFallbackPoll(\n () => this.pollForRemoteChanges(),\n this.fallbackPollIntervalMs,\n );\n\n // Connect (non-blocking)\n this.subscriptionClient.connect();\n }\n } catch (wsError) {\n this.log(`Failed to set up IPNS subscription: ${wsError}`);\n // Non-fatal — provider works without push notifications\n }\n }\n\n // Test gateway connectivity (non-blocking, don't fail on it)\n this.httpClient.findHealthyGateways().then((healthy) => {\n if (healthy.length > 0) {\n this.log(`${healthy.length} healthy gateway(s) found`);\n } else {\n this.log('Warning: no healthy gateways found');\n }\n }).catch(() => {\n // Non-fatal\n });\n\n this.isShuttingDown = false;\n this.status = 'connected';\n this.emitEvent({ type: 'storage:loaded', timestamp: Date.now() });\n return true;\n } catch (error) {\n this.status = 'error';\n this.emitEvent({\n type: 'storage:error',\n timestamp: Date.now(),\n error: error instanceof Error ? error.message : String(error),\n });\n return false;\n }\n }\n\n async shutdown(): Promise<void> {\n this.isShuttingDown = true;\n\n // Cancel any pending debounced flush\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n\n // Final flush — drain any pending writes\n await this.flushQueue.enqueue(async () => {\n if (!this.pendingBuffer.isEmpty) {\n try {\n await this.executeFlush();\n } catch {\n this.log('Final flush on shutdown failed (data may be lost)');\n }\n }\n });\n\n // Disconnect subscription client\n if (this.subscriptionUnsubscribe) {\n this.subscriptionUnsubscribe();\n this.subscriptionUnsubscribe = null;\n }\n if (this.subscriptionClient) {\n this.subscriptionClient.disconnect();\n this.subscriptionClient = null;\n }\n\n this.cache.clear();\n this.status = 'disconnected';\n }\n\n // ---------------------------------------------------------------------------\n // Save (non-blocking — buffers data for async flush)\n // ---------------------------------------------------------------------------\n\n async save(data: TData): Promise<SaveResult> {\n if (!this.ipnsKeyPair || !this.ipnsName) {\n return { success: false, error: 'Not initialized', timestamp: Date.now() };\n }\n\n // Buffer the data for async flush\n this.pendingBuffer.txfData = data;\n this.scheduleFlush();\n\n // Return immediately — flush happens in background\n return { success: true, timestamp: Date.now() };\n }\n\n // ---------------------------------------------------------------------------\n // Internal: Blocking save (used by sync and executeFlush)\n // ---------------------------------------------------------------------------\n\n /**\n * Perform the actual upload + IPNS publish synchronously.\n * Called by executeFlush() and sync() — never by public save().\n */\n private async _doSave(data: TData): Promise<SaveResult> {\n if (!this.ipnsKeyPair || !this.ipnsName) {\n return { success: false, error: 'Not initialized', timestamp: Date.now() };\n }\n\n this.emitEvent({ type: 'storage:saving', timestamp: Date.now() });\n\n try {\n // Update meta with chain-validation fields required by sidecar:\n // - lastCid: must equal the CID currently stored on sidecar (null for bootstrap)\n // - version: must be exactly current_version + 1 (for normal updates)\n this.dataVersion++;\n const metaUpdate: Record<string, unknown> = {\n ...data._meta,\n version: this.dataVersion,\n ipnsName: this.ipnsName,\n updatedAt: Date.now(),\n };\n if (this.remoteCid) {\n // Normal update: chain to previous CID\n metaUpdate.lastCid = this.remoteCid;\n }\n // Bootstrap (remoteCid is null): do NOT include lastCid field at all\n const updatedData = { ...data, _meta: metaUpdate } as unknown as Record<string, unknown>;\n\n // Upload to IPFS\n const { cid } = await this.httpClient.upload(updatedData);\n this.log(`Content uploaded: CID=${cid}`);\n\n // Compute new sequence: max(local, remote) + 1\n const baseSeq = this.ipnsSequenceNumber > this.lastKnownRemoteSequence\n ? this.ipnsSequenceNumber\n : this.lastKnownRemoteSequence;\n const newSeq = baseSeq + 1n;\n\n // Create signed IPNS record\n const marshalledRecord = await createSignedRecord(\n this.ipnsKeyPair,\n cid,\n newSeq,\n this.ipnsLifetimeMs,\n );\n\n // Publish to all gateways\n const publishResult = await this.httpClient.publishIpns(\n this.ipnsName,\n marshalledRecord,\n );\n\n if (!publishResult.success) {\n // Rollback version (sequence was not yet updated)\n this.dataVersion--;\n this.log(`IPNS publish failed: ${publishResult.error}`);\n return {\n success: false,\n error: publishResult.error ?? 'IPNS publish failed',\n timestamp: Date.now(),\n };\n }\n\n // Update local state\n this.ipnsSequenceNumber = newSeq;\n this.lastCid = cid;\n this.remoteCid = cid; // next save chains to this CID\n\n // Update cache\n this.cache.setIpnsRecord(this.ipnsName, {\n cid,\n sequence: newSeq,\n gateway: 'local',\n });\n this.cache.setContent(cid, updatedData as unknown as TxfStorageDataBase);\n this.cache.markIpnsFresh(this.ipnsName);\n\n // Persist state\n await this.statePersistence.save(this.ipnsName, {\n sequenceNumber: newSeq.toString(),\n lastCid: cid,\n version: this.dataVersion,\n });\n\n this.emitEvent({\n type: 'storage:saved',\n timestamp: Date.now(),\n data: { cid, sequence: newSeq.toString() },\n });\n\n this.log(`Saved: CID=${cid}, seq=${newSeq}`);\n return { success: true, cid, timestamp: Date.now() };\n } catch (error) {\n // Rollback version on any error\n this.dataVersion--;\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.emitEvent({\n type: 'storage:error',\n timestamp: Date.now(),\n error: errorMessage,\n });\n return { success: false, error: errorMessage, timestamp: Date.now() };\n }\n }\n\n // ---------------------------------------------------------------------------\n // Write-behind buffer: scheduling and flushing\n // ---------------------------------------------------------------------------\n\n /**\n * Schedule a debounced background flush.\n * Resets the timer on each call so rapid mutations coalesce.\n */\n private scheduleFlush(): void {\n if (this.isShuttingDown) return;\n if (this.flushTimer) clearTimeout(this.flushTimer);\n this.flushTimer = setTimeout(() => {\n this.flushTimer = null;\n this.flushQueue.enqueue(() => this.executeFlush()).catch((err) => {\n this.log(`Background flush failed: ${err}`);\n });\n }, this.flushDebounceMs);\n }\n\n /**\n * Execute a flush of the pending buffer to IPFS.\n * Runs inside AsyncSerialQueue for concurrency safety.\n */\n private async executeFlush(): Promise<void> {\n if (this.pendingBuffer.isEmpty) return;\n\n // 1. Swap: take pending → active, create new empty pending\n const active = this.pendingBuffer;\n this.pendingBuffer = new WriteBuffer();\n\n try {\n // 2. Build the data to save\n // Use buffered TXF data if available, otherwise build minimal payload\n const baseData = (active.txfData ?? {\n _meta: { version: 0, address: this.identity?.directAddress ?? '', formatVersion: '2.0', updatedAt: 0 },\n }) as TData;\n\n // 3. Perform the actual blocking save\n const result = await this._doSave(baseData);\n\n if (!result.success) {\n throw new Error(result.error ?? 'Save failed');\n }\n\n this.log(`Flushed successfully: CID=${result.cid}`);\n } catch (error) {\n // 4. Rollback: merge active back into pending\n this.pendingBuffer.mergeFrom(active);\n\n const msg = error instanceof Error ? error.message : String(error);\n this.log(`Flush failed (will retry): ${msg}`);\n\n // Schedule retry\n this.scheduleFlush();\n\n throw error; // re-throw so callers (e.g. shutdown) know it failed\n }\n }\n\n // ---------------------------------------------------------------------------\n // Load\n // ---------------------------------------------------------------------------\n\n async load(identifier?: string): Promise<LoadResult<TData>> {\n if (!this.ipnsName && !identifier) {\n return { success: false, error: 'Not initialized', source: 'local', timestamp: Date.now() };\n }\n\n this.emitEvent({ type: 'storage:loading', timestamp: Date.now() });\n\n try {\n // If a specific CID is given, fetch directly\n if (identifier) {\n const data = await this.httpClient.fetchContent<TData>(identifier);\n return { success: true, data, source: 'remote', timestamp: Date.now() };\n }\n\n const ipnsName = this.ipnsName!;\n\n // Check known-fresh cache\n if (this.cache.isIpnsKnownFresh(ipnsName)) {\n const cached = this.cache.getIpnsRecordIgnoreTtl(ipnsName);\n if (cached) {\n const content = this.cache.getContent(cached.cid);\n if (content) {\n this.log('Using known-fresh cached data');\n return { success: true, data: content as TData, source: 'cache', timestamp: Date.now() };\n }\n }\n }\n\n // Check IPNS cache (60s TTL)\n const cachedRecord = this.cache.getIpnsRecord(ipnsName);\n if (cachedRecord) {\n const content = this.cache.getContent(cachedRecord.cid);\n if (content) {\n this.log('IPNS cache hit');\n return { success: true, data: content as TData, source: 'cache', timestamp: Date.now() };\n }\n // Have CID but not content — fetch content\n try {\n const data = await this.httpClient.fetchContent<TData>(cachedRecord.cid);\n return { success: true, data, source: 'remote', timestamp: Date.now() };\n } catch {\n // Fall through to full resolution\n }\n }\n\n // Resolve IPNS from network\n const { best } = await this.httpClient.resolveIpns(ipnsName);\n\n if (!best) {\n // Not found — could be a new wallet\n this.log('IPNS record not found (new wallet?)');\n return { success: false, error: 'IPNS record not found', source: 'remote', timestamp: Date.now() };\n }\n\n // Track remote sequence and CID for chain validation\n if (best.sequence > this.lastKnownRemoteSequence) {\n this.lastKnownRemoteSequence = best.sequence;\n }\n this.remoteCid = best.cid;\n\n // Fetch content\n const data = await this.httpClient.fetchContent<TData>(best.cid);\n\n // Track remote version for correct version chaining\n const remoteVersion = (data as TxfStorageDataBase)?._meta?.version;\n if (typeof remoteVersion === 'number' && remoteVersion > this.dataVersion) {\n this.dataVersion = remoteVersion;\n }\n\n this.emitEvent({\n type: 'storage:loaded',\n timestamp: Date.now(),\n data: { cid: best.cid, sequence: best.sequence.toString() },\n });\n\n return { success: true, data, source: 'remote', timestamp: Date.now() };\n } catch (error) {\n // On network error, try to return cached data\n if (this.ipnsName) {\n const cached = this.cache.getIpnsRecordIgnoreTtl(this.ipnsName);\n if (cached) {\n const content = this.cache.getContent(cached.cid);\n if (content) {\n this.log('Network error, returning stale cache');\n return { success: true, data: content as TData, source: 'cache', timestamp: Date.now() };\n }\n }\n }\n\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.emitEvent({\n type: 'storage:error',\n timestamp: Date.now(),\n error: errorMessage,\n });\n return { success: false, error: errorMessage, source: 'remote', timestamp: Date.now() };\n }\n }\n\n // ---------------------------------------------------------------------------\n // Sync (enters serial queue to avoid concurrent IPNS conflicts)\n // ---------------------------------------------------------------------------\n\n async sync(localData: TData): Promise<SyncResult<TData>> {\n return this.flushQueue.enqueue(async () => {\n // Cancel any pending debounced flush (we'll save as part of sync)\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n\n this.emitEvent({ type: 'sync:started', timestamp: Date.now() });\n\n try {\n // Drain pending buffer — its data will be included via the sync save\n this.pendingBuffer.clear();\n\n // Load remote data\n const remoteResult = await this.load();\n\n if (!remoteResult.success || !remoteResult.data) {\n // No remote data — save local as initial\n this.log('No remote data found, uploading local data');\n const saveResult = await this._doSave(localData);\n this.emitEvent({ type: 'sync:completed', timestamp: Date.now() });\n return {\n success: saveResult.success,\n merged: localData,\n added: 0,\n removed: 0,\n conflicts: 0,\n error: saveResult.error,\n };\n }\n\n const remoteData = remoteResult.data;\n\n // Check if merge is needed\n const localVersion = localData._meta?.version ?? 0;\n const remoteVersion = remoteData._meta?.version ?? 0;\n\n if (localVersion === remoteVersion && this.lastCid) {\n // Same version — no merge needed\n this.log('Data is in sync (same version)');\n this.emitEvent({ type: 'sync:completed', timestamp: Date.now() });\n return {\n success: true,\n merged: localData,\n added: 0,\n removed: 0,\n conflicts: 0,\n };\n }\n\n // Merge\n this.log(`Merging: local v${localVersion} <-> remote v${remoteVersion}`);\n const { merged, added, removed, conflicts } = mergeTxfData(localData, remoteData);\n\n if (conflicts > 0) {\n this.emitEvent({\n type: 'sync:conflict',\n timestamp: Date.now(),\n data: { conflicts },\n });\n }\n\n // Save merged result\n const saveResult = await this._doSave(merged);\n\n this.emitEvent({\n type: 'sync:completed',\n timestamp: Date.now(),\n data: { added, removed, conflicts },\n });\n\n return {\n success: saveResult.success,\n merged: merged,\n added,\n removed,\n conflicts,\n error: saveResult.error,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.emitEvent({\n type: 'sync:error',\n timestamp: Date.now(),\n error: errorMessage,\n });\n return {\n success: false,\n added: 0,\n removed: 0,\n conflicts: 0,\n error: errorMessage,\n };\n }\n });\n }\n\n // ---------------------------------------------------------------------------\n // Private Helpers\n // ---------------------------------------------------------------------------\n\n // ---------------------------------------------------------------------------\n // Optional Methods\n // ---------------------------------------------------------------------------\n\n async exists(): Promise<boolean> {\n if (!this.ipnsName) return false;\n\n // Check cache first\n const cached = this.cache.getIpnsRecord(this.ipnsName);\n if (cached) return true;\n\n // Resolve from network\n const { best } = await this.httpClient.resolveIpns(this.ipnsName);\n return best !== null;\n }\n\n async clear(): Promise<boolean> {\n if (!this.ipnsKeyPair || !this.ipnsName) return false;\n\n // Clear pending buffer\n this.pendingBuffer.clear();\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n\n const emptyData = {\n _meta: {\n version: 0,\n address: this.identity?.directAddress ?? '',\n ipnsName: this.ipnsName,\n formatVersion: '2.0',\n updatedAt: Date.now(),\n },\n } as TData;\n\n const result = await this._doSave(emptyData);\n if (result.success) {\n this.cache.clear();\n await this.statePersistence.clear(this.ipnsName);\n }\n return result.success;\n }\n\n onEvent(callback: StorageEventCallback): () => void {\n this.eventCallbacks.add(callback);\n return () => {\n this.eventCallbacks.delete(callback);\n };\n }\n\n // ---------------------------------------------------------------------------\n // Public Accessors\n // ---------------------------------------------------------------------------\n\n getIpnsName(): string | null {\n return this.ipnsName;\n }\n\n getLastCid(): string | null {\n return this.lastCid;\n }\n\n getSequenceNumber(): bigint {\n return this.ipnsSequenceNumber;\n }\n\n getDataVersion(): number {\n return this.dataVersion;\n }\n\n getRemoteCid(): string | null {\n return this.remoteCid;\n }\n\n // ---------------------------------------------------------------------------\n // Testing helper: wait for pending flush to complete\n // ---------------------------------------------------------------------------\n\n /**\n * Wait for the pending flush timer to fire and the flush operation to\n * complete. Useful in tests to await background writes.\n * Returns immediately if no flush is pending.\n */\n async waitForFlush(): Promise<void> {\n if (this.flushTimer) {\n // Force the timer to fire now\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n await this.flushQueue.enqueue(() => this.executeFlush()).catch(() => {});\n } else if (!this.pendingBuffer.isEmpty) {\n // No timer but pending data — flush now\n await this.flushQueue.enqueue(() => this.executeFlush()).catch(() => {});\n } else {\n // Ensure any in-flight flush completes\n await this.flushQueue.enqueue(async () => {});\n }\n }\n\n // ---------------------------------------------------------------------------\n // Internal: Push Subscription Helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Derive WebSocket URL from the first configured gateway.\n * Converts https://host → wss://host/ws/ipns\n */\n private deriveWsUrl(): string | null {\n const gateways = this.httpClient.getGateways();\n if (gateways.length === 0) return null;\n\n const gateway = gateways[0];\n const wsProtocol = gateway.startsWith('https://') ? 'wss://' : 'ws://';\n const host = gateway.replace(/^https?:\\/\\//, '');\n return `${wsProtocol}${host}/ws/ipns`;\n }\n\n /**\n * Poll for remote IPNS changes (fallback when WS is unavailable).\n * Compares remote sequence number with last known and emits event if changed.\n */\n private async pollForRemoteChanges(): Promise<void> {\n if (!this.ipnsName) return;\n\n try {\n const { best } = await this.httpClient.resolveIpns(this.ipnsName);\n if (best && best.sequence > this.lastKnownRemoteSequence) {\n this.log(`Poll detected remote change: seq=${best.sequence} (was ${this.lastKnownRemoteSequence})`);\n this.lastKnownRemoteSequence = best.sequence;\n this.emitEvent({\n type: 'storage:remote-updated',\n timestamp: Date.now(),\n data: { name: this.ipnsName, sequence: Number(best.sequence), cid: best.cid },\n });\n }\n } catch {\n // Non-fatal — poll will retry on next interval\n }\n }\n\n // ---------------------------------------------------------------------------\n // Internal\n // ---------------------------------------------------------------------------\n\n private emitEvent(event: StorageEvent): void {\n for (const callback of this.eventCallbacks) {\n try {\n callback(event);\n } catch {\n // Don't let event handler errors break the provider\n }\n }\n }\n\n private log(message: string): void {\n if (this.debug) {\n console.log(`[IPFS-Storage] ${message}`);\n }\n }\n\n}\n","/**\n * Browser IPFS State Persistence\n * Uses localStorage for persisting IPFS/IPNS state between sessions\n */\n\nimport type { IpfsStatePersistence, IpfsPersistedState } from '../../shared/ipfs';\n\nconst KEY_PREFIX = 'sphere_ipfs_';\n\nfunction seqKey(ipnsName: string): string {\n return `${KEY_PREFIX}seq_${ipnsName}`;\n}\n\nfunction cidKey(ipnsName: string): string {\n return `${KEY_PREFIX}cid_${ipnsName}`;\n}\n\nfunction verKey(ipnsName: string): string {\n return `${KEY_PREFIX}ver_${ipnsName}`;\n}\n\nexport class BrowserIpfsStatePersistence implements IpfsStatePersistence {\n async load(ipnsName: string): Promise<IpfsPersistedState | null> {\n try {\n const seq = localStorage.getItem(seqKey(ipnsName));\n if (!seq) return null;\n\n return {\n sequenceNumber: seq,\n lastCid: localStorage.getItem(cidKey(ipnsName)),\n version: parseInt(localStorage.getItem(verKey(ipnsName)) ?? '0', 10),\n };\n } catch {\n return null;\n }\n }\n\n async save(ipnsName: string, state: IpfsPersistedState): Promise<void> {\n try {\n localStorage.setItem(seqKey(ipnsName), state.sequenceNumber);\n if (state.lastCid) {\n localStorage.setItem(cidKey(ipnsName), state.lastCid);\n } else {\n localStorage.removeItem(cidKey(ipnsName));\n }\n localStorage.setItem(verKey(ipnsName), String(state.version));\n } catch {\n // localStorage might be full or unavailable\n }\n }\n\n async clear(ipnsName: string): Promise<void> {\n try {\n localStorage.removeItem(seqKey(ipnsName));\n localStorage.removeItem(cidKey(ipnsName));\n localStorage.removeItem(verKey(ipnsName));\n } catch {\n // Ignore cleanup errors\n }\n }\n}\n","/**\n * Browser IPFS Storage Module\n * Factory function for browser-specific IPFS storage provider\n */\n\nimport { IpfsStorageProvider, type IpfsStorageConfig } from '../../shared/ipfs';\nimport { BrowserIpfsStatePersistence } from './browser-ipfs-state-persistence';\nimport type { IWebSocket } from '../../../transport/websocket';\n\n// Re-export for convenience\nexport { IpfsStorageProvider } from '../../shared/ipfs';\nexport { BrowserIpfsStatePersistence } from './browser-ipfs-state-persistence';\nexport type { IpfsStorageConfig as IpfsStorageProviderConfig } from '../../shared/ipfs';\n\n/**\n * Create a browser WebSocket that conforms to the IWebSocket interface.\n */\nfunction createBrowserWebSocket(url: string): IWebSocket {\n return new WebSocket(url) as unknown as IWebSocket;\n}\n\n/**\n * Create a browser IPFS storage provider with localStorage-based state persistence.\n * Automatically injects the browser WebSocket factory for IPNS push subscriptions.\n */\nexport function createBrowserIpfsStorageProvider(config?: IpfsStorageConfig): IpfsStorageProvider {\n return new IpfsStorageProvider(\n { ...config, createWebSocket: config?.createWebSocket ?? createBrowserWebSocket },\n new BrowserIpfsStatePersistence(),\n );\n}\n\n/** @deprecated Use createBrowserIpfsStorageProvider instead */\nexport const createIpfsStorageProvider = createBrowserIpfsStorageProvider;\n","/**\n * CoinGecko Price Provider\n *\n * Fetches token prices from CoinGecko API with internal caching.\n * Supports both free and pro API tiers.\n */\n\nimport type { PriceProvider, PricePlatform, TokenPrice, PriceProviderConfig } from './price-provider';\n\n// =============================================================================\n// Types\n// =============================================================================\n\ninterface CacheEntry {\n /** Token price, or null if the token was not found on the platform */\n price: TokenPrice | null;\n expiresAt: number;\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\n/**\n * CoinGecko price provider\n *\n * @example\n * ```ts\n * // Free tier (no API key)\n * const provider = new CoinGeckoPriceProvider();\n *\n * // Pro tier\n * const provider = new CoinGeckoPriceProvider({ apiKey: 'CG-xxx' });\n *\n * const prices = await provider.getPrices(['bitcoin', 'ethereum']);\n * console.log(prices.get('bitcoin')?.priceUsd);\n * ```\n */\nexport class CoinGeckoPriceProvider implements PriceProvider {\n readonly platform: PricePlatform = 'coingecko';\n\n private readonly cache: Map<string, CacheEntry> = new Map();\n private readonly apiKey?: string;\n private readonly cacheTtlMs: number;\n private readonly timeout: number;\n private readonly debug: boolean;\n private readonly baseUrl: string;\n\n constructor(config?: Omit<PriceProviderConfig, 'platform'>) {\n this.apiKey = config?.apiKey;\n this.cacheTtlMs = config?.cacheTtlMs ?? 60_000;\n this.timeout = config?.timeout ?? 10_000;\n this.debug = config?.debug ?? false;\n\n this.baseUrl = config?.baseUrl\n ?? (this.apiKey\n ? 'https://pro-api.coingecko.com/api/v3'\n : 'https://api.coingecko.com/api/v3');\n }\n\n async getPrices(tokenNames: string[]): Promise<Map<string, TokenPrice>> {\n if (tokenNames.length === 0) {\n return new Map();\n }\n\n const now = Date.now();\n const result = new Map<string, TokenPrice>();\n const uncachedNames: string[] = [];\n\n // Check cache first\n for (const name of tokenNames) {\n const cached = this.cache.get(name);\n if (cached && cached.expiresAt > now) {\n // null = negative cache (token not found on platform), skip adding to result\n if (cached.price !== null) {\n result.set(name, cached.price);\n }\n } else {\n uncachedNames.push(name);\n }\n }\n\n // All cached — return immediately\n if (uncachedNames.length === 0) {\n return result;\n }\n\n // Fetch uncached prices\n try {\n const ids = uncachedNames.join(',');\n const url = `${this.baseUrl}/simple/price?ids=${encodeURIComponent(ids)}&vs_currencies=usd,eur&include_24hr_change=true`;\n\n const headers: Record<string, string> = { Accept: 'application/json' };\n if (this.apiKey) {\n headers['x-cg-pro-api-key'] = this.apiKey;\n }\n\n if (this.debug) {\n console.log(`[CoinGecko] Fetching prices for: ${uncachedNames.join(', ')}`);\n }\n\n const response = await fetch(url, {\n headers,\n signal: AbortSignal.timeout(this.timeout),\n });\n\n if (!response.ok) {\n throw new Error(`CoinGecko API error: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json() as Record<string, Record<string, number>>;\n\n // Parse and cache response\n for (const [name, values] of Object.entries(data)) {\n if (values && typeof values === 'object') {\n const price: TokenPrice = {\n tokenName: name,\n priceUsd: values.usd ?? 0,\n priceEur: values.eur,\n change24h: values.usd_24h_change,\n timestamp: now,\n };\n this.cache.set(name, { price, expiresAt: now + this.cacheTtlMs });\n result.set(name, price);\n }\n }\n\n // Negative cache: tokens not found on CoinGecko won't be re-requested until TTL expires\n for (const name of uncachedNames) {\n if (!result.has(name)) {\n this.cache.set(name, { price: null, expiresAt: now + this.cacheTtlMs });\n }\n }\n\n if (this.debug) {\n console.log(`[CoinGecko] Fetched ${result.size} prices`);\n }\n } catch (error) {\n if (this.debug) {\n console.warn('[CoinGecko] Fetch failed, using stale cache:', error);\n }\n\n // On error, return stale cached data if available\n for (const name of uncachedNames) {\n const stale = this.cache.get(name);\n if (stale?.price) {\n result.set(name, stale.price);\n }\n }\n }\n\n return result;\n }\n\n async getPrice(tokenName: string): Promise<TokenPrice | null> {\n const prices = await this.getPrices([tokenName]);\n return prices.get(tokenName) ?? null;\n }\n\n clearCache(): void {\n this.cache.clear();\n }\n}\n","/**\n * Price Provider\n *\n * Token market price abstraction with CoinGecko implementation.\n */\n\nexport type {\n PriceProvider,\n PricePlatform,\n TokenPrice,\n PriceProviderConfig,\n} from './price-provider';\n\nexport { CoinGeckoPriceProvider } from './CoinGeckoPriceProvider';\n\n// =============================================================================\n// Factory\n// =============================================================================\n\nimport type { PriceProviderConfig, PriceProvider } from './price-provider';\nimport { CoinGeckoPriceProvider } from './CoinGeckoPriceProvider';\n\n/**\n * Create a price provider based on platform configuration\n *\n * @example\n * ```ts\n * const provider = createPriceProvider({ platform: 'coingecko', apiKey: 'CG-xxx' });\n * ```\n */\nexport function createPriceProvider(config: PriceProviderConfig): PriceProvider {\n switch (config.platform) {\n case 'coingecko':\n return new CoinGeckoPriceProvider(config);\n default:\n throw new Error(`Unsupported price platform: ${String(config.platform)}`);\n }\n}\n","/**\n * Configuration Resolvers\n * Utility functions for resolving provider configurations with extend/override pattern\n */\n\nimport { NETWORKS, DEFAULT_AGGREGATOR_API_KEY, type NetworkType, type NetworkConfig } from '../../constants';\nimport type {\n BaseTransportConfig,\n BaseOracleConfig,\n BasePriceConfig,\n L1Config,\n ResolvedTransportConfig,\n ResolvedOracleConfig,\n} from './config';\nimport type { PriceProviderConfig } from '../../price';\nimport type { GroupChatModuleConfig } from '../../modules/groupchat';\n\n// =============================================================================\n// Network Resolution\n// =============================================================================\n\n/**\n * Get network configuration by type\n */\nexport function getNetworkConfig(network: NetworkType = 'mainnet'): NetworkConfig {\n return NETWORKS[network];\n}\n\n// =============================================================================\n// Transport Resolution\n// =============================================================================\n\n/**\n * Resolve transport configuration with extend/override pattern\n *\n * Priority:\n * 1. `relays` - replaces defaults entirely\n * 2. `additionalRelays` - extends network defaults\n * 3. Network defaults\n *\n * @example\n * ```ts\n * // Use network defaults\n * resolveTransportConfig('testnet', undefined);\n *\n * // Replace relays entirely\n * resolveTransportConfig('testnet', { relays: ['wss://custom.relay'] });\n *\n * // Extend defaults\n * resolveTransportConfig('testnet', { additionalRelays: ['wss://extra.relay'] });\n * ```\n */\nexport function resolveTransportConfig(\n network: NetworkType,\n config?: BaseTransportConfig & { reconnectDelay?: number; maxReconnectAttempts?: number }\n): ResolvedTransportConfig {\n const networkConfig = getNetworkConfig(network);\n\n // Resolve relays with extend/override pattern\n let relays: string[];\n if (config?.relays) {\n // Explicit relays - replace entirely\n relays = config.relays;\n } else {\n // Start with network defaults\n relays = [...networkConfig.nostrRelays] as string[];\n // Add additional relays if specified\n if (config?.additionalRelays) {\n relays = [...relays, ...config.additionalRelays];\n }\n }\n\n return {\n relays,\n timeout: config?.timeout,\n autoReconnect: config?.autoReconnect,\n debug: config?.debug,\n // Browser-specific\n reconnectDelay: config?.reconnectDelay,\n maxReconnectAttempts: config?.maxReconnectAttempts,\n };\n}\n\n// =============================================================================\n// Oracle Resolution\n// =============================================================================\n\n/**\n * Resolve oracle configuration with override pattern\n *\n * Uses network default URL if not explicitly provided\n *\n * @example\n * ```ts\n * // Use network default\n * resolveOracleConfig('testnet', undefined);\n *\n * // Override URL\n * resolveOracleConfig('testnet', { url: 'https://custom.aggregator' });\n * ```\n */\nexport function resolveOracleConfig(\n network: NetworkType,\n config?: BaseOracleConfig & { trustBasePath?: string }\n): ResolvedOracleConfig {\n const networkConfig = getNetworkConfig(network);\n\n return {\n url: config?.url ?? networkConfig.aggregatorUrl,\n apiKey: config?.apiKey ?? DEFAULT_AGGREGATOR_API_KEY,\n timeout: config?.timeout,\n skipVerification: config?.skipVerification,\n debug: config?.debug,\n // Node.js-specific\n trustBasePath: config?.trustBasePath,\n };\n}\n\n// =============================================================================\n// L1 Resolution\n// =============================================================================\n\n/**\n * Resolve L1 configuration with override pattern\n *\n * Only returns config if l1 is explicitly provided (L1 is optional)\n *\n * @example\n * ```ts\n * // No L1 config - returns undefined\n * resolveL1Config('testnet', undefined);\n *\n * // Enable L1 with defaults\n * resolveL1Config('testnet', {});\n *\n * // Override electrum URL\n * resolveL1Config('testnet', { electrumUrl: 'wss://custom.fulcrum:50004' });\n * ```\n */\nexport function resolveL1Config(\n network: NetworkType,\n config?: L1Config\n): L1Config | undefined {\n if (config === undefined) {\n return undefined;\n }\n\n const networkConfig = getNetworkConfig(network);\n\n return {\n electrumUrl: config.electrumUrl ?? networkConfig.electrumUrl,\n defaultFeeRate: config.defaultFeeRate,\n enableVesting: config.enableVesting,\n };\n}\n\n// =============================================================================\n// Price Resolution\n// =============================================================================\n\n/**\n * Resolve price provider configuration\n *\n * Returns undefined if no price config is provided (price is optional).\n *\n * @example\n * ```ts\n * // No price config\n * resolvePriceConfig(undefined); // undefined\n *\n * // Minimal config (defaults to coingecko)\n * resolvePriceConfig({}); // { platform: 'coingecko' }\n *\n * // With API key\n * resolvePriceConfig({ apiKey: 'CG-xxx' }); // { platform: 'coingecko', apiKey: 'CG-xxx' }\n * ```\n */\nexport function resolvePriceConfig(\n config?: BasePriceConfig\n): PriceProviderConfig | undefined {\n if (config === undefined) {\n return undefined;\n }\n\n return {\n platform: config.platform ?? 'coingecko',\n apiKey: config.apiKey,\n baseUrl: config.baseUrl,\n cacheTtlMs: config.cacheTtlMs,\n timeout: config.timeout,\n debug: config.debug,\n };\n}\n\n// =============================================================================\n// Array Extension Helper\n// =============================================================================\n\n/**\n * Resolve array with extend/override pattern\n *\n * @param defaults - Default values from network config\n * @param replace - Values that replace defaults entirely\n * @param additional - Values to add to defaults\n * @returns Resolved array\n *\n * @example\n * ```ts\n * // Use defaults\n * resolveArrayConfig(['a', 'b'], undefined, undefined); // ['a', 'b']\n *\n * // Replace\n * resolveArrayConfig(['a', 'b'], ['x'], undefined); // ['x']\n *\n * // Extend\n * resolveArrayConfig(['a', 'b'], undefined, ['c']); // ['a', 'b', 'c']\n * ```\n */\nexport function resolveArrayConfig<T>(\n defaults: readonly T[],\n replace?: T[],\n additional?: T[]\n): T[] {\n if (replace) {\n return replace;\n }\n\n const result = [...defaults];\n if (additional) {\n return [...result, ...additional];\n }\n\n return result;\n}\n\n// =============================================================================\n// Group Chat Resolution\n// =============================================================================\n\n/**\n * Resolve group chat configuration for provider factories.\n * @param network - Network type for default relay URLs\n * @param config - User-provided group chat config (true, object, or undefined)\n * @returns Resolved GroupChatModuleConfig or undefined if disabled\n */\nexport function resolveGroupChatConfig(\n network: NetworkType,\n config?: { enabled?: boolean; relays?: string[] } | boolean,\n): GroupChatModuleConfig | undefined {\n if (!config) return undefined;\n\n if (config === true) {\n const netConfig = getNetworkConfig(network);\n return { relays: [...netConfig.groupRelays] };\n }\n\n if (typeof config === 'object' && config.enabled === false) {\n return undefined;\n }\n\n const netConfig = getNetworkConfig(network);\n return {\n relays: config.relays ?? [...netConfig.groupRelays],\n };\n}\n"],"mappings":"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","names":["import_buffer","elliptic","sha256","CryptoJS","NostrEventClass","SdkToken","valid","data","saveResult","createBrowserWebSocket","netConfig"]}