All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
cacheMessagesoption for CommunicationsModule —communications: { cacheMessages: false }inSphereInitOptionsdisables DM caching in memory and storage. Messages still flow throughonDirectMessage()handlers andmessage:dmevents, but are never stored. Useful for anonymous/ephemeral agents (e.g. LLM bots) that only need streaming DM reception.sendDM()still works but doesn't cache the sent message. Deduplication is skipped when caching is disabled.- Message signing —
signMessage(),verifySignedMessage(),hashSignMessage()crypto functions for secp256k1 ECDSA with recoverable signatures (Bitcoin-like double-SHA256 withSphere Signed Message:\nprefix).Sphere.signMessage(message)instance method encapsulates private key access.SIGNING_ERRORadded toSphereErrorCode.SphereInstanceinterface in ConnectHost extended withsignMessage. 22 unit tests covering signing, verification, round-trips, tampering detection, and edge cases. - Centralized logger —
loggersingleton withdebug/warn/errorlevels,globalThis-based state sharing across tsup bundles, per-tag control (logger.setTagDebug('Nostr', true)), and custom handler support SphereErrorwith typed error codes — All SDK methods throwSphereErrorwith a typed.codefield (SphereErrorCode). 15 error codes:NOT_INITIALIZED,ALREADY_INITIALIZED,INVALID_CONFIG,INVALID_IDENTITY,INSUFFICIENT_BALANCE,INVALID_RECIPIENT,TRANSFER_FAILED,STORAGE_ERROR,TRANSPORT_ERROR,AGGREGATOR_ERROR,VALIDATION_ERROR,NETWORK_ERROR,TIMEOUT,DECRYPTION_ERROR,MODULE_NOT_AVAILABLEisSphereError()type guard — Helper function for typed error handling in catch blocks- Silent failure logging — All previously silent
.catch(() => {}), empty catch blocks, and timeout-based silent failures now log vialogger.warn(operational issues) orlogger.debug(expected/non-critical) - 20 unit tests for logger module
- IPNS push-based sync via WebSocket —
IpnsSubscriptionClientconnects to/ws/ipnson IPFS gateways for real-time IPNS update notifications, with exponential backoff reconnection (5s→60s capped) and 30s keepalive pings - Fallback HTTP polling — When WebSocket is unavailable, the IPFS provider automatically polls for IPNS changes at a configurable interval (default: 90s)
- Auto-sync on import —
Sphere.import()automatically syncs with all registered token storage providers after initialization to recover tokens from IPFS - Debounced auto-sync on remote updates —
PaymentsModulesubscribes tostorage:remote-updatedevents from token storage providers and performs a debounced (500ms) sync, emitting a newsync:remote-updatesphere event storage:remote-updatedstorage event type — New event emitted byIpfsStorageProviderwhen a remote IPNS change is detected via WebSocket push or HTTP pollingsync:remote-updatesphere event — New top-level event with{ providerId, name, sequence, cid, added, removed }payload, emitted after a push-triggered sync completes- WebSocket factory injection in platform factories —
createNodeIpfsStorageProvider()andcreateBrowserIpfsStorageProvider()now automatically inject platform-appropriate WebSocket factories IpfsHttpClient.getGateways()— New public accessor returning configured gateway URLsIpfsStorageConfigextensions — New optional fields:createWebSocket,wsUrl,fallbackPollIntervalMs,syncDebounceMsIpnsUpdateEventtype — Exported fromimpl/shared/ipfsfor consumers- 24 unit tests for
IpnsSubscriptionClientcovering subscribe, message handling, reconnection, keepalive, fallback polling, and disconnect
- IPFS token recovery via TXF merge —
mergeTxfData()now recognizes individual token entries (token-*keys) stored viasaveToken(), not just_-prefixed TXF keys; previously IPFS sync returnedadded: 0because merge couldn't find tokens in the blob - TXF parser handles individual file format —
parseTxfStorageData()now extracts tokens from{ token, meta }wrapper format used by IPFS individual token storage - Sync coalescing —
PaymentsModule.sync()now coalesces concurrent calls, preventing race conditions when multiple syncs overlap
- All
throw new Error()in production code replaced withthrow new SphereError()— zero plain errors remaining - All
console.log/warn/errorin production code replaced withlogger.debug/warn/error— console output controlled by debug flag logger.warn()andlogger.error()are always shown regardless of debug flag;logger.debug()is hidden whendebug=falsePaymentsModule.updateTokenStorageProviders()now re-subscribes to storage events when providers changePaymentsModule.destroy()now cleans up storage event subscriptions and debounce timersIpfsStorageProvider.shutdown()now disconnects the subscription client