@unicitylabs/sphere-sdk 0.3.1 → 0.3.3

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.
@@ -718,6 +718,9 @@ interface SphereEventMap {
718
718
  'connection:changed': {
719
719
  provider: string;
720
720
  connected: boolean;
721
+ status?: ProviderStatus;
722
+ enabled?: boolean;
723
+ error?: string;
721
724
  };
722
725
  'nametag:registered': {
723
726
  nametag: string;
@@ -832,6 +835,74 @@ interface WalletJSONExportOptions {
832
835
  addressCount?: number;
833
836
  }
834
837
 
838
+ /**
839
+ * Result of a single service health check
840
+ */
841
+ interface ServiceHealthResult {
842
+ /** Whether the service is reachable */
843
+ healthy: boolean;
844
+ /** URL that was checked */
845
+ url: string;
846
+ /** Response time in ms (null if unreachable) */
847
+ responseTimeMs: number | null;
848
+ /** Error message if unhealthy */
849
+ error?: string;
850
+ }
851
+ /**
852
+ * User-provided health check function for custom services.
853
+ * Receives the configured timeout and should return a ServiceHealthResult.
854
+ */
855
+ type HealthCheckFn = (timeoutMs: number) => Promise<ServiceHealthResult>;
856
+ /**
857
+ * Result of checking all network services (pre-init)
858
+ */
859
+ interface NetworkHealthResult {
860
+ /** Overall health: true if all checked services are reachable */
861
+ healthy: boolean;
862
+ /** Per-service results (built-in + custom) */
863
+ services: {
864
+ relay?: ServiceHealthResult;
865
+ oracle?: ServiceHealthResult;
866
+ l1?: ServiceHealthResult;
867
+ /** Custom service results keyed by user-provided name */
868
+ [key: string]: ServiceHealthResult | undefined;
869
+ };
870
+ /** Total time to complete all checks (ms) */
871
+ totalTimeMs: number;
872
+ }
873
+ /** Role of a provider in the system */
874
+ type ProviderRole = 'storage' | 'token-storage' | 'transport' | 'oracle' | 'l1' | 'price';
875
+ /**
876
+ * Rich status information for a single provider (used in getStatus())
877
+ */
878
+ interface ProviderStatusInfo {
879
+ /** Provider unique ID */
880
+ id: string;
881
+ /** Display name */
882
+ name: string;
883
+ /** Role in the system */
884
+ role: ProviderRole;
885
+ /** Detailed status */
886
+ status: ProviderStatus;
887
+ /** Shorthand for status === 'connected' */
888
+ connected: boolean;
889
+ /** Whether the provider is enabled (can be toggled at runtime) */
890
+ enabled: boolean;
891
+ /** Provider-specific metadata (e.g., relay count for transport) */
892
+ metadata?: Record<string, unknown>;
893
+ }
894
+ /**
895
+ * Aggregated status of all providers, grouped by role
896
+ */
897
+ interface SphereStatus {
898
+ storage: ProviderStatusInfo[];
899
+ tokenStorage: ProviderStatusInfo[];
900
+ transport: ProviderStatusInfo[];
901
+ oracle: ProviderStatusInfo[];
902
+ l1: ProviderStatusInfo[];
903
+ price: ProviderStatusInfo[];
904
+ }
905
+
835
906
  /**
836
907
  * Transport Provider Interface
837
908
  * Platform-independent P2P messaging abstraction
@@ -1235,6 +1306,7 @@ interface L1PaymentsModuleDependencies {
1235
1306
  */
1236
1307
  declare class L1PaymentsModule {
1237
1308
  private _initialized;
1309
+ private _disabled;
1238
1310
  private _config;
1239
1311
  private _identity?;
1240
1312
  private _addresses;
@@ -1249,6 +1321,15 @@ declare class L1PaymentsModule {
1249
1321
  */
1250
1322
  private ensureConnected;
1251
1323
  destroy(): void;
1324
+ /**
1325
+ * Disable this module — disconnect WebSocket and block operations until re-enabled.
1326
+ */
1327
+ disable(): void;
1328
+ /**
1329
+ * Re-enable this module. Connection will be established lazily on next operation.
1330
+ */
1331
+ enable(): void;
1332
+ get disabled(): boolean;
1252
1333
  /**
1253
1334
  * Check if a string looks like an L1 address (alpha1... or alphat1...)
1254
1335
  */
@@ -1725,6 +1806,8 @@ interface PaymentsModuleDependencies {
1725
1806
  l1Addresses?: string[];
1726
1807
  /** Price provider (optional — enables fiat value display) */
1727
1808
  price?: PriceProvider;
1809
+ /** Set of disabled provider IDs — disabled providers are skipped during sync/save */
1810
+ disabledProviderIds?: ReadonlySet<string>;
1728
1811
  }
1729
1812
  declare class PaymentsModule {
1730
1813
  private readonly moduleConfig;
@@ -2307,9 +2390,13 @@ declare class PaymentsModule {
2307
2390
  */
2308
2391
  private debouncedSyncFromRemoteUpdate;
2309
2392
  /**
2310
- * Get all active token storage providers
2393
+ * Get all active (non-disabled) token storage providers
2311
2394
  */
2312
2395
  private getTokenStorageProviders;
2396
+ /**
2397
+ * Check if the price provider is disabled via the disabled providers set.
2398
+ */
2399
+ private isPriceDisabled;
2313
2400
  /**
2314
2401
  * Replace the set of token storage providers at runtime.
2315
2402
  *
@@ -2623,7 +2710,7 @@ declare const NETWORKS: {
2623
2710
  readonly name: "Mainnet";
2624
2711
  readonly aggregatorUrl: "https://aggregator.unicity.network/rpc";
2625
2712
  readonly nostrRelays: readonly ["wss://relay.unicity.network", "wss://relay.damus.io", "wss://nos.lol", "wss://relay.nostr.band"];
2626
- readonly ipfsGateways: readonly ["https://ipfs.unicity.network", "https://dweb.link", "https://ipfs.io"];
2713
+ readonly ipfsGateways: readonly ["https://unicity-ipfs1.dyndns.org"];
2627
2714
  readonly electrumUrl: "wss://fulcrum.alpha.unicity.network:50004";
2628
2715
  readonly groupRelays: readonly ["wss://sphere-relay.unicity.network"];
2629
2716
  };
@@ -2631,7 +2718,7 @@ declare const NETWORKS: {
2631
2718
  readonly name: "Testnet";
2632
2719
  readonly aggregatorUrl: "https://goggregator-test.unicity.network";
2633
2720
  readonly nostrRelays: readonly ["wss://nostr-relay.testnet.unicity.network"];
2634
- readonly ipfsGateways: readonly ["https://ipfs.unicity.network", "https://dweb.link", "https://ipfs.io"];
2721
+ readonly ipfsGateways: readonly ["https://unicity-ipfs1.dyndns.org"];
2635
2722
  readonly electrumUrl: "wss://fulcrum.alpha.testnet.unicity.network:50004";
2636
2723
  readonly groupRelays: readonly ["wss://sphere-relay.unicity.network"];
2637
2724
  };
@@ -2639,7 +2726,7 @@ declare const NETWORKS: {
2639
2726
  readonly name: "Development";
2640
2727
  readonly aggregatorUrl: "https://dev-aggregator.dyndns.org/rpc";
2641
2728
  readonly nostrRelays: readonly ["wss://nostr-relay.testnet.unicity.network"];
2642
- readonly ipfsGateways: readonly ["https://ipfs.unicity.network", "https://dweb.link", "https://ipfs.io"];
2729
+ readonly ipfsGateways: readonly ["https://unicity-ipfs1.dyndns.org"];
2643
2730
  readonly electrumUrl: "wss://fulcrum.alpha.testnet.unicity.network:50004";
2644
2731
  readonly groupRelays: readonly ["wss://sphere-relay.unicity.network"];
2645
2732
  };
@@ -2893,6 +2980,9 @@ declare class Sphere {
2893
2980
  private _communications;
2894
2981
  private _groupChat;
2895
2982
  private eventHandlers;
2983
+ private _disabledProviders;
2984
+ private _providerEventCleanups;
2985
+ private _lastProviderConnected;
2896
2986
  private constructor();
2897
2987
  /**
2898
2988
  * Check if wallet exists in storage
@@ -3356,18 +3446,48 @@ declare class Sphere {
3356
3446
  hidden: boolean;
3357
3447
  nametag?: string;
3358
3448
  }>): Promise<void>;
3359
- getStatus(): {
3360
- storage: {
3361
- connected: boolean;
3362
- };
3363
- transport: {
3364
- connected: boolean;
3365
- };
3366
- oracle: {
3367
- connected: boolean;
3368
- };
3369
- };
3449
+ /**
3450
+ * Get aggregated status of all providers, grouped by role.
3451
+ *
3452
+ * @example
3453
+ * ```ts
3454
+ * const status = sphere.getStatus();
3455
+ * // status.transport[0].connected // true/false
3456
+ * // status.transport[0].metadata?.relays // { total: 3, connected: 2 }
3457
+ * // status.tokenStorage // all registered token storage providers
3458
+ * ```
3459
+ */
3460
+ getStatus(): SphereStatus;
3370
3461
  reconnect(): Promise<void>;
3462
+ /**
3463
+ * Disable a provider at runtime. The provider stays registered but is disconnected
3464
+ * and skipped during operations (e.g., sync).
3465
+ *
3466
+ * Main storage provider cannot be disabled.
3467
+ *
3468
+ * @returns true if successfully disabled, false if provider not found
3469
+ */
3470
+ disableProvider(providerId: string): Promise<boolean>;
3471
+ /**
3472
+ * Re-enable a previously disabled provider. Reconnects and resumes operations.
3473
+ *
3474
+ * @returns true if successfully enabled, false if provider not found
3475
+ */
3476
+ enableProvider(providerId: string): Promise<boolean>;
3477
+ /**
3478
+ * Check if a provider is currently enabled
3479
+ */
3480
+ isProviderEnabled(providerId: string): boolean;
3481
+ /**
3482
+ * Get the set of disabled provider IDs (for passing to modules)
3483
+ */
3484
+ getDisabledProviderIds(): ReadonlySet<string>;
3485
+ /** Get the price provider's ID (implementation detail — not on PriceProvider interface) */
3486
+ private get _priceProviderId();
3487
+ /**
3488
+ * Find a provider by ID across all provider collections
3489
+ */
3490
+ private findProviderById;
3371
3491
  on<T extends SphereEventType>(type: T, handler: SphereEventHandler<T>): () => void;
3372
3492
  off<T extends SphereEventType>(type: T, handler: SphereEventHandler<T>): void;
3373
3493
  sync(): Promise<void>;
@@ -3503,6 +3623,16 @@ declare class Sphere {
3503
3623
  private initializeIdentityFromMnemonic;
3504
3624
  private initializeIdentityFromMasterKey;
3505
3625
  private initializeProviders;
3626
+ /**
3627
+ * Subscribe to provider-level events and bridge them to Sphere connection:changed events.
3628
+ * Uses deduplication to avoid emitting duplicate events.
3629
+ */
3630
+ private subscribeToProviderEvents;
3631
+ /**
3632
+ * Emit connection:changed with deduplication — only emits if status actually changed.
3633
+ */
3634
+ private emitConnectionChanged;
3635
+ private cleanupProviderEventSubscriptions;
3506
3636
  private initializeModules;
3507
3637
  private ensureReady;
3508
3638
  private emitEvent;
@@ -3770,4 +3900,101 @@ declare function randomHex(byteLength: number): string;
3770
3900
  */
3771
3901
  declare function randomUUID(): string;
3772
3902
 
3773
- export { type AddressInfo, CHARSET, CurrencyUtils, DEFAULT_DERIVATION_PATH, DEFAULT_TOKEN_DECIMALS, type DerivedKey, type EncryptedData, type EncryptionOptions, type KeyPair, type L1Config, type MasterKey, type ScanAddressProgress, type ScanAddressesOptions, type ScanAddressesResult, type ScannedAddressResult, Sphere, type SphereCreateOptions, type SphereImportOptions, type SphereInitOptions, type SphereInitResult, type SphereLoadOptions, base58Decode, base58Encode, bytesToHex, computeHash160, convertBits, createAddress, createBech32, createKeyPair, createSphere, decodeBech32, decrypt, decryptJson, decryptMnemonic, decryptSimple, decryptWithSalt, deriveAddressInfo, deriveChildKey, deriveKeyAtPath, deserializeEncrypted, doubleSha256, ec, encodeBech32, encrypt, encryptMnemonic, encryptSimple, entropyToMnemonic, extractFromText, findPattern, formatAmount, generateAddressInfo, generateMasterKey, generateMnemonic, generateRandomKey, getAddressHrp, getPublicKey, getSphere, hash160, hash160ToBytes, hexToBytes, identityFromMnemonic, identityFromMnemonicSync, importSphere, initSphere, isEncryptedData, isValidBech32, isValidNametag, isValidPrivateKey, loadSphere, mnemonicToEntropy, mnemonicToSeed, mnemonicToSeedSync, privateKeyToAddressInfo, publicKeyToAddress, randomBytes, randomHex, randomUUID, ripemd160, scanAddressesImpl, serializeEncrypted, sha256, sleep, sphereExists, toHumanReadable, toSmallestUnit, validateMnemonic };
3903
+ /**
3904
+ * Network Health Check
3905
+ *
3906
+ * Standalone utility for checking network service availability before Sphere.init().
3907
+ * Uses NETWORKS config for URLs — no providers or Sphere instance needed.
3908
+ */
3909
+
3910
+ type ServiceName = 'relay' | 'oracle' | 'l1';
3911
+ interface CheckNetworkHealthOptions {
3912
+ /** Timeout per service check in ms (default: 5000) */
3913
+ timeoutMs?: number;
3914
+ /** Which services to check (default: all) */
3915
+ services?: ServiceName[];
3916
+ /** Custom URLs — override defaults from NETWORKS[network] */
3917
+ urls?: {
3918
+ /** Custom Nostr relay WebSocket URL (e.g. 'wss://my-relay.example.com') */
3919
+ relay?: string;
3920
+ /** Custom aggregator HTTP URL (e.g. 'https://my-aggregator.example.com') */
3921
+ oracle?: string;
3922
+ /** Custom Electrum WebSocket URL (e.g. 'wss://my-fulcrum.example.com:50004') */
3923
+ l1?: string;
3924
+ };
3925
+ /**
3926
+ * Custom health checks — run in parallel alongside built-in checks.
3927
+ * Key = service name (e.g. 'mongodb', 'ipfs', 'redis'), value = check function.
3928
+ *
3929
+ * @example
3930
+ * ```typescript
3931
+ * const health = await checkNetworkHealth('testnet', {
3932
+ * checks: {
3933
+ * mongodb: async (timeoutMs) => {
3934
+ * const start = Date.now();
3935
+ * try {
3936
+ * await mongoClient.db().command({ ping: 1 });
3937
+ * return { healthy: true, url: 'mongodb://localhost:27017', responseTimeMs: Date.now() - start };
3938
+ * } catch (err) {
3939
+ * return { healthy: false, url: 'mongodb://localhost:27017', responseTimeMs: null, error: err.message };
3940
+ * }
3941
+ * },
3942
+ * },
3943
+ * });
3944
+ * // health.services.mongodb?.healthy
3945
+ * ```
3946
+ */
3947
+ checks?: Record<string, HealthCheckFn>;
3948
+ }
3949
+ /**
3950
+ * Check network service availability before Sphere.init().
3951
+ *
3952
+ * Runs all checks in parallel. Each service is tested independently with its own timeout.
3953
+ *
3954
+ * @example
3955
+ * ```typescript
3956
+ * import { checkNetworkHealth } from '@unicitylabs/sphere-sdk';
3957
+ *
3958
+ * const health = await checkNetworkHealth('testnet');
3959
+ * if (health.healthy) {
3960
+ * // Safe to init
3961
+ * const { sphere } = await Sphere.init({ ... });
3962
+ * } else {
3963
+ * // Show which services are down
3964
+ * for (const [name, result] of Object.entries(health.services)) {
3965
+ * if (!result.healthy) console.warn(`${name}: ${result.error}`);
3966
+ * }
3967
+ * }
3968
+ *
3969
+ * // Check only specific services
3970
+ * const relayHealth = await checkNetworkHealth('testnet', { services: ['relay'] });
3971
+ *
3972
+ * // Use custom URLs instead of defaults
3973
+ * const custom = await checkNetworkHealth('testnet', {
3974
+ * urls: {
3975
+ * relay: 'wss://my-relay.example.com',
3976
+ * oracle: 'https://my-aggregator.example.com',
3977
+ * l1: 'wss://my-fulcrum.example.com:50004',
3978
+ * },
3979
+ * });
3980
+ *
3981
+ * // Add custom health checks for your own providers
3982
+ * const health = await checkNetworkHealth('testnet', {
3983
+ * checks: {
3984
+ * mongodb: async (timeoutMs) => {
3985
+ * const start = Date.now();
3986
+ * try {
3987
+ * await mongoClient.db().command({ ping: 1 });
3988
+ * return { healthy: true, url: 'mongodb://localhost:27017', responseTimeMs: Date.now() - start };
3989
+ * } catch (err) {
3990
+ * return { healthy: false, url: 'mongodb://localhost:27017', responseTimeMs: null, error: String(err) };
3991
+ * }
3992
+ * },
3993
+ * },
3994
+ * });
3995
+ * // health.services.mongodb?.healthy === true
3996
+ * ```
3997
+ */
3998
+ declare function checkNetworkHealth(network?: NetworkType, options?: CheckNetworkHealthOptions): Promise<NetworkHealthResult>;
3999
+
4000
+ export { type AddressInfo, CHARSET, type CheckNetworkHealthOptions, CurrencyUtils, DEFAULT_DERIVATION_PATH, DEFAULT_TOKEN_DECIMALS, type DerivedKey, type EncryptedData, type EncryptionOptions, type KeyPair, type L1Config, type MasterKey, type ScanAddressProgress, type ScanAddressesOptions, type ScanAddressesResult, type ScannedAddressResult, Sphere, type SphereCreateOptions, type SphereImportOptions, type SphereInitOptions, type SphereInitResult, type SphereLoadOptions, base58Decode, base58Encode, bytesToHex, checkNetworkHealth, computeHash160, convertBits, createAddress, createBech32, createKeyPair, createSphere, decodeBech32, decrypt, decryptJson, decryptMnemonic, decryptSimple, decryptWithSalt, deriveAddressInfo, deriveChildKey, deriveKeyAtPath, deserializeEncrypted, doubleSha256, ec, encodeBech32, encrypt, encryptMnemonic, encryptSimple, entropyToMnemonic, extractFromText, findPattern, formatAmount, generateAddressInfo, generateMasterKey, generateMnemonic, generateRandomKey, getAddressHrp, getPublicKey, getSphere, hash160, hash160ToBytes, hexToBytes, identityFromMnemonic, identityFromMnemonicSync, importSphere, initSphere, isEncryptedData, isValidBech32, isValidNametag, isValidPrivateKey, loadSphere, mnemonicToEntropy, mnemonicToSeed, mnemonicToSeedSync, privateKeyToAddressInfo, publicKeyToAddress, randomBytes, randomHex, randomUUID, ripemd160, scanAddressesImpl, serializeEncrypted, sha256, sleep, sphereExists, toHumanReadable, toSmallestUnit, validateMnemonic };