/** * Orbis1 SDK * * Main SDK class for interacting with RGB assets * * @module Orbis1SDK */ import { Wallet } from './core/Wallet'; import type { IFeatureModule } from './types/IFeatureModule'; import type { SDKConfig } from './types/SDKConfig'; import { validateSDKConfig, mergeWithDefaults, Environment, } from './types/SDKConfig'; import { Feature } from './types/Feature'; import { ConfigurationError } from './errors/ConfigurationError'; import { OrbisError, OrbisErrorCode } from './errors/OrbisError'; import { FeatureRegistry } from './utils/FeatureRegistry'; import { Logger, createLogger } from './utils/logger'; import { WatchTowerModule } from './features/watch-tower'; import { GasFreeModule } from './features/gas-free'; import { BitcoinNetwork } from './core/Interfaces'; /** * Orbis1SDK class * * Main entry point for the Orbis1 SDK. * Provides access to RGB operations and enabled features. */ export class Orbis1SDK { private config: SDKConfig; private wallet?: Wallet; private featureRegistry: FeatureRegistry; private logger: Logger; private initialized = false; /** * Create an Orbis1SDK instance * * @param config - SDK configuration */ constructor(config: SDKConfig) { // Validate and merge config with defaults try { validateSDKConfig(config); this.config = mergeWithDefaults(config); } catch (error) { throw ConfigurationError.validationFailed([ error instanceof Error ? error.message : String(error), ]); } // Initialize logger this.logger = createLogger({ level: this.config.logging?.level, customLogger: this.config.logging?.logger, }); // Initialize wallet from config (if enabled) if (this.config.wallet?.enabled) { // Determine network from environment const network = this.config.environment === Environment.MAINNET ? BitcoinNetwork.MAINNET : this.config.environment === Environment.REGTEST ? BitcoinNetwork.REGTEST : BitcoinNetwork.TESTNET4; this.wallet = new Wallet(this.config.wallet.keys, { dataDir: this.config.wallet.dataDir, network, supportedSchemas: this.config.wallet.supportedSchemas, maxAllocationsPerUtxo: this.config.wallet.maxAllocationsPerUtxo, vanillaKeychain: this.config.wallet.vanillaKeychain, }); this.logger.info( `Wallet initialized for ${this.config.environment} environment` ); } // Initialize feature registry this.featureRegistry = new FeatureRegistry(); this.logger.info('Orbis1SDK instance created'); } /** * Initialize the SDK * * This method must be called before using any SDK features. * It initializes the RGB binding and all enabled features. */ async initialize(): Promise { if (this.initialized) { this.logger.warn('SDK already initialized'); return; } this.logger.info('Initializing SDK...'); try { // Register and initialize enabled features await this.initializeFeatures(); // Mark registry as initialized (prevents further registration) this.featureRegistry.markInitialized(); // Mark SDK as initialized this.initialized = true; this.logger.info('SDK initialized successfully'); } catch (error) { this.logger.error('SDK initialization failed', error); throw OrbisError.fromError( error instanceof Error ? error : new Error(String(error)), OrbisErrorCode.INITIALIZATION ); } } /** * Initialize enabled features */ private async initializeFeatures(): Promise { const { features } = this.config; // Initialize Gas-Free feature if (features?.gasFree?.enabled) { // Gas-Free is not available in REGTEST yet if (this.config.environment === Environment.REGTEST) { throw new OrbisError( 'Gas-Free is not available in REGTEST yet. Disable gasFree for REGTEST environment or use a different environment.', OrbisErrorCode.CONFIGURATION ); } // Gas-Free requires Wallet if (!this.wallet) { throw new OrbisError( 'Gas-Free feature requires Wallet instance. Pass wallet to SDK constructor.', OrbisErrorCode.CONFIGURATION ); } const gasFreeModule = new GasFreeModule({ name: Feature.GAS_FREE, enabled: true, environment: this.config.environment, apiKey: this.config.apiKey, timeout: features.gasFree.timeout, }); this.featureRegistry.register(Feature.GAS_FREE, gasFreeModule); await gasFreeModule.initialize(this.wallet, this.logger); } // Initialize Watch Tower feature if (features?.watchTower?.enabled) { const watchTowerModule = new WatchTowerModule({ name: Feature.WATCH_TOWER, enabled: true, environment: this.config.environment, apiKey: this.config.apiKey, }); this.featureRegistry.register(Feature.WATCH_TOWER, watchTowerModule); await watchTowerModule.initialize(this.wallet, this.logger); // Wallet parameter ignored by Watch Tower } this.logger.info(`Initialized ${this.featureRegistry.count()} feature(s)`); } /** * Cleanup and release resources * * Should be called when the SDK is no longer needed. */ async cleanup(): Promise { if (!this.initialized) { return; } this.logger.info('Cleaning up SDK...'); try { // Cleanup all features const features = this.featureRegistry.getAllModules(); await Promise.all(features.map((feature) => feature.cleanup())); this.initialized = false; this.logger.info('SDK cleaned up successfully'); } catch (error) { this.logger.error('SDK cleanup failed', error); throw OrbisError.fromError( error instanceof Error ? error : new Error(String(error)), OrbisErrorCode.UNKNOWN ); } } /** * Get a feature module * * @param feature - Feature enum value * @returns Feature module instance * @throws {FeatureNotEnabledError} If feature is not enabled */ getFeature(feature: Feature): T { this.ensureInitialized(); return this.featureRegistry.get(feature, true)!; } /** * Access Watch Tower feature (add invoice to watchtower, set FCM token). * * @throws {FeatureNotEnabledError} If Watch Tower is not enabled */ watchTower(): WatchTowerModule { return this.getFeature(Feature.WATCH_TOWER); } /** * Access Gas-Free transfer feature. * * @throws {FeatureNotEnabledError} If Gas-Free is not enabled */ gasFree(): GasFreeModule { return this.getFeature(Feature.GAS_FREE); } /** * Check if a feature is enabled * * @param feature - Feature enum value * @returns True if enabled, false otherwise */ hasFeature(feature: Feature): boolean { return this.featureRegistry.has(feature); } /** * Get Wallet instance * * @returns Wallet instance (if provided) */ getWallet(): Wallet | undefined { this.ensureInitialized(); return this.wallet; } /** * Get SDK configuration * * @returns SDK configuration (readonly) */ getConfig(): Readonly { return this.config; } /** * Get SDK status * * @returns SDK status information */ getStatus(): { initialized: boolean; features: Record>; } { return { initialized: this.initialized, features: this.featureRegistry.getStatus(), }; } /** * Check if SDK is initialized * * @returns True if initialized, false otherwise */ isInitialized(): boolean { return this.initialized; } /** * Ensure SDK is initialized * * @throws {OrbisError} If SDK is not initialized */ private ensureInitialized(): void { if (!this.initialized) { throw new OrbisError( 'SDK is not initialized. Call initialize() first.', OrbisErrorCode.INITIALIZATION ); } } /** * Get logger instance * * @returns Logger instance */ getLogger(): Logger { return this.logger; } }