@hsuite/native-connect-angular 1.0.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.
- package/README.md +48 -0
- package/USAGE_EXAMPLES.md +476 -0
- package/assets/wallets/extension.svg +7 -0
- package/assets/wallets/hashpack.svg +6 -0
- package/assets/wallets/hsuite.svg +11 -0
- package/assets/wallets/kabila.svg +11 -0
- package/assets/wallets/walletconnect.svg +13 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/coverage-summary.json +50 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +476 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +476 -0
- package/coverage/lcov-report/lib/components/account-selector/account-actions/account-actions.component.ts.html +868 -0
- package/coverage/lcov-report/lib/components/account-selector/account-actions/index.html +116 -0
- package/coverage/lcov-report/lib/components/account-selector/account-filter/account-filter.component.ts.html +1288 -0
- package/coverage/lcov-report/lib/components/account-selector/account-filter/index.html +116 -0
- package/coverage/lcov-report/lib/components/account-selector/account-formatting.service.ts.html +685 -0
- package/coverage/lcov-report/lib/components/account-selector/account-grouping.service.ts.html +766 -0
- package/coverage/lcov-report/lib/components/account-selector/account-list/account-list.component.ts.html +1495 -0
- package/coverage/lcov-report/lib/components/account-selector/account-list/index.html +116 -0
- package/coverage/lcov-report/lib/components/account-selector/account-selector.component.ts.html +1495 -0
- package/coverage/lcov-report/lib/components/account-selector/account-selector.service.ts.html +1588 -0
- package/coverage/lcov-report/lib/components/account-selector/index.html +161 -0
- package/coverage/lcov-report/lib/components/wallet-account-display/index.html +116 -0
- package/coverage/lcov-report/lib/components/wallet-account-display/wallet-account-display.component.ts.html +505 -0
- package/coverage/lcov-report/lib/components/wallet-connect-button/index.html +116 -0
- package/coverage/lcov-report/lib/components/wallet-connect-button/wallet-connect-button.component.ts.html +805 -0
- package/coverage/lcov-report/lib/components/wallet-connect-prompt/index.html +116 -0
- package/coverage/lcov-report/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.ts.html +409 -0
- package/coverage/lcov-report/lib/components/wallet-connected-guard/index.html +116 -0
- package/coverage/lcov-report/lib/components/wallet-connected-guard/wallet-connected-guard.component.ts.html +304 -0
- package/coverage/lcov-report/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.ts.html +436 -0
- package/coverage/lcov-report/lib/components/wallet-connection-modal/connection-method-step/index.html +116 -0
- package/coverage/lcov-report/lib/components/wallet-connection-modal/index.html +116 -0
- package/coverage/lcov-report/lib/components/wallet-connection-modal/qr-pairing-step/index.html +116 -0
- package/coverage/lcov-report/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.ts.html +2287 -0
- package/coverage/lcov-report/lib/components/wallet-connection-modal/wallet-connection-modal.component.ts.html +2275 -0
- package/coverage/lcov-report/lib/components/wallet-session-display/index.html +116 -0
- package/coverage/lcov-report/lib/components/wallet-session-display/wallet-session-display.component.ts.html +676 -0
- package/coverage/lcov-report/lib/components/wallet-transaction-status/index.html +116 -0
- package/coverage/lcov-report/lib/components/wallet-transaction-status/wallet-transaction-status.component.ts.html +703 -0
- package/coverage/lcov-report/lib/directives/index.html +146 -0
- package/coverage/lcov-report/lib/directives/wallet-connected.directive.ts.html +670 -0
- package/coverage/lcov-report/lib/directives/wallet-context.directive.ts.html +547 -0
- package/coverage/lcov-report/lib/directives/wallet-events.directive.ts.html +781 -0
- package/coverage/lcov-report/lib/hsuite-wallet.module.ts.html +715 -0
- package/coverage/lcov-report/lib/index.html +116 -0
- package/coverage/lcov-report/lib/models/connection-config.model.ts.html +280 -0
- package/coverage/lcov-report/lib/models/index.html +131 -0
- package/coverage/lcov-report/lib/models/provider-types.ts.html +577 -0
- package/coverage/lcov-report/lib/providers/base-wallet-provider.ts.html +1138 -0
- package/coverage/lcov-report/lib/providers/hsuite-native/channel-client.service.ts.html +2671 -0
- package/coverage/lcov-report/lib/providers/hsuite-native/index.html +116 -0
- package/coverage/lcov-report/lib/providers/hsuite-native-provider.ts.html +2347 -0
- package/coverage/lcov-report/lib/providers/index.html +146 -0
- package/coverage/lcov-report/lib/providers/p2p-native/index.html +131 -0
- package/coverage/lcov-report/lib/providers/p2p-native/p2p-native.provider.ts.html +2254 -0
- package/coverage/lcov-report/lib/providers/p2p-native/p2p-session-manager.ts.html +2170 -0
- package/coverage/lcov-report/lib/providers/wallet-error-handler.ts.html +1132 -0
- package/coverage/lcov-report/lib/providers/walletconnect/core/index.html +176 -0
- package/coverage/lcov-report/lib/providers/walletconnect/core/session-health.ts.html +673 -0
- package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-client-manager.ts.html +1177 -0
- package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-provider.ts.html +2563 -0
- package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-session-store.ts.html +904 -0
- package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-signing-orchestrator.ts.html +982 -0
- package/coverage/lcov-report/lib/providers/walletconnect/signers/hedera-signer.ts.html +1915 -0
- package/coverage/lcov-report/lib/providers/walletconnect/signers/index.html +146 -0
- package/coverage/lcov-report/lib/providers/walletconnect/signers/signer-factory.ts.html +445 -0
- package/coverage/lcov-report/lib/providers/walletconnect/signers/xrpl-signer.ts.html +1519 -0
- package/coverage/lcov-report/lib/services/index.html +191 -0
- package/coverage/lcov-report/lib/services/logger.service.ts.html +463 -0
- package/coverage/lcov-report/lib/services/transaction-builders/base-transaction-builder.service.ts.html +1840 -0
- package/coverage/lcov-report/lib/services/transaction-builders/hedera-amount-utils.ts.html +337 -0
- package/coverage/lcov-report/lib/services/transaction-builders/hedera-transaction-builder.service.ts.html +3940 -0
- package/coverage/lcov-report/lib/services/transaction-builders/index.html +161 -0
- package/coverage/lcov-report/lib/services/transaction-builders/xrpl-transaction-builder.service.ts.html +2581 -0
- package/coverage/lcov-report/lib/services/transaction.service.ts.html +1123 -0
- package/coverage/lcov-report/lib/services/unified-wallet.service.ts.html +2641 -0
- package/coverage/lcov-report/lib/services/wallet-context.service.ts.html +637 -0
- package/coverage/lcov-report/lib/services/wallet-event-bus.service.ts.html +643 -0
- package/coverage/lcov-report/lib/services/wallet-providers.service.ts.html +496 -0
- package/coverage/lcov-report/lib/transports/chrome-extension-transport.ts.html +823 -0
- package/coverage/lcov-report/lib/transports/index.html +116 -0
- package/coverage/lcov-report/lib/utils/index.html +116 -0
- package/coverage/lcov-report/lib/utils/ledger-icons.util.ts.html +319 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov.info +19252 -0
- package/coverage/lib/components/account-selector/account-actions/account-actions.component.ts.html +868 -0
- package/coverage/lib/components/account-selector/account-actions/index.html +116 -0
- package/coverage/lib/components/account-selector/account-filter/account-filter.component.ts.html +1288 -0
- package/coverage/lib/components/account-selector/account-filter/index.html +116 -0
- package/coverage/lib/components/account-selector/account-formatting.service.ts.html +685 -0
- package/coverage/lib/components/account-selector/account-grouping.service.ts.html +766 -0
- package/coverage/lib/components/account-selector/account-list/account-list.component.ts.html +1495 -0
- package/coverage/lib/components/account-selector/account-list/index.html +116 -0
- package/coverage/lib/components/account-selector/account-selector.component.ts.html +1495 -0
- package/coverage/lib/components/account-selector/account-selector.service.ts.html +1588 -0
- package/coverage/lib/components/account-selector/index.html +161 -0
- package/coverage/lib/components/wallet-account-display/index.html +116 -0
- package/coverage/lib/components/wallet-account-display/wallet-account-display.component.ts.html +505 -0
- package/coverage/lib/components/wallet-connect-button/index.html +116 -0
- package/coverage/lib/components/wallet-connect-button/wallet-connect-button.component.ts.html +805 -0
- package/coverage/lib/components/wallet-connect-prompt/index.html +116 -0
- package/coverage/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.ts.html +409 -0
- package/coverage/lib/components/wallet-connected-guard/index.html +116 -0
- package/coverage/lib/components/wallet-connected-guard/wallet-connected-guard.component.ts.html +304 -0
- package/coverage/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.ts.html +436 -0
- package/coverage/lib/components/wallet-connection-modal/connection-method-step/index.html +116 -0
- package/coverage/lib/components/wallet-connection-modal/index.html +116 -0
- package/coverage/lib/components/wallet-connection-modal/qr-pairing-step/index.html +116 -0
- package/coverage/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.ts.html +2287 -0
- package/coverage/lib/components/wallet-connection-modal/wallet-connection-modal.component.ts.html +2275 -0
- package/coverage/lib/components/wallet-session-display/index.html +116 -0
- package/coverage/lib/components/wallet-session-display/wallet-session-display.component.ts.html +676 -0
- package/coverage/lib/components/wallet-transaction-status/index.html +116 -0
- package/coverage/lib/components/wallet-transaction-status/wallet-transaction-status.component.ts.html +703 -0
- package/coverage/lib/directives/index.html +146 -0
- package/coverage/lib/directives/wallet-connected.directive.ts.html +670 -0
- package/coverage/lib/directives/wallet-context.directive.ts.html +547 -0
- package/coverage/lib/directives/wallet-events.directive.ts.html +781 -0
- package/coverage/lib/hsuite-wallet.module.ts.html +715 -0
- package/coverage/lib/index.html +116 -0
- package/coverage/lib/models/connection-config.model.ts.html +280 -0
- package/coverage/lib/models/index.html +131 -0
- package/coverage/lib/models/provider-types.ts.html +577 -0
- package/coverage/lib/providers/base-wallet-provider.ts.html +1138 -0
- package/coverage/lib/providers/hsuite-native/channel-client.service.ts.html +2671 -0
- package/coverage/lib/providers/hsuite-native/index.html +116 -0
- package/coverage/lib/providers/hsuite-native-provider.ts.html +2347 -0
- package/coverage/lib/providers/index.html +146 -0
- package/coverage/lib/providers/p2p-native/index.html +131 -0
- package/coverage/lib/providers/p2p-native/p2p-native.provider.ts.html +2254 -0
- package/coverage/lib/providers/p2p-native/p2p-session-manager.ts.html +2170 -0
- package/coverage/lib/providers/wallet-error-handler.ts.html +1132 -0
- package/coverage/lib/providers/walletconnect/core/index.html +176 -0
- package/coverage/lib/providers/walletconnect/core/session-health.ts.html +673 -0
- package/coverage/lib/providers/walletconnect/core/walletconnect-client-manager.ts.html +1177 -0
- package/coverage/lib/providers/walletconnect/core/walletconnect-provider.ts.html +2563 -0
- package/coverage/lib/providers/walletconnect/core/walletconnect-session-store.ts.html +904 -0
- package/coverage/lib/providers/walletconnect/core/walletconnect-signing-orchestrator.ts.html +982 -0
- package/coverage/lib/providers/walletconnect/signers/hedera-signer.ts.html +1915 -0
- package/coverage/lib/providers/walletconnect/signers/index.html +146 -0
- package/coverage/lib/providers/walletconnect/signers/signer-factory.ts.html +445 -0
- package/coverage/lib/providers/walletconnect/signers/xrpl-signer.ts.html +1519 -0
- package/coverage/lib/services/index.html +191 -0
- package/coverage/lib/services/logger.service.ts.html +463 -0
- package/coverage/lib/services/transaction-builders/base-transaction-builder.service.ts.html +1840 -0
- package/coverage/lib/services/transaction-builders/hedera-amount-utils.ts.html +337 -0
- package/coverage/lib/services/transaction-builders/hedera-transaction-builder.service.ts.html +3940 -0
- package/coverage/lib/services/transaction-builders/index.html +161 -0
- package/coverage/lib/services/transaction-builders/xrpl-transaction-builder.service.ts.html +2581 -0
- package/coverage/lib/services/transaction.service.ts.html +1123 -0
- package/coverage/lib/services/unified-wallet.service.ts.html +2641 -0
- package/coverage/lib/services/wallet-context.service.ts.html +637 -0
- package/coverage/lib/services/wallet-event-bus.service.ts.html +643 -0
- package/coverage/lib/services/wallet-providers.service.ts.html +496 -0
- package/coverage/lib/transports/chrome-extension-transport.ts.html +823 -0
- package/coverage/lib/transports/index.html +116 -0
- package/coverage/lib/utils/index.html +116 -0
- package/coverage/lib/utils/ledger-icons.util.ts.html +319 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/dist/README.md +48 -0
- package/dist/fesm2022/hsuite-native-connect-angular.mjs +14592 -0
- package/dist/fesm2022/hsuite-native-connect-angular.mjs.map +1 -0
- package/dist/index.d.ts +6949 -0
- package/examples/minimal-connect.ts +178 -0
- package/examples/multi-protocol.ts +495 -0
- package/examples/transaction-signing.ts +361 -0
- package/jest.config.json +45 -0
- package/karma.conf.js +42 -0
- package/ng-package.json +20 -0
- package/package.json +60 -0
- package/src/index.ts +203 -0
- package/src/lib/components/account-selector/account-actions/account-actions.component.ts +261 -0
- package/src/lib/components/account-selector/account-filter/account-filter.component.ts +401 -0
- package/src/lib/components/account-selector/account-formatting.service.ts +200 -0
- package/src/lib/components/account-selector/account-grouping.service.ts +227 -0
- package/src/lib/components/account-selector/account-list/account-list.component.ts +470 -0
- package/src/lib/components/account-selector/account-selector.component.html +135 -0
- package/src/lib/components/account-selector/account-selector.component.scss +2039 -0
- package/src/lib/components/account-selector/account-selector.component.ts +470 -0
- package/src/lib/components/account-selector/account-selector.service.ts +501 -0
- package/src/lib/components/wallet-account-display/wallet-account-display.component.html +34 -0
- package/src/lib/components/wallet-account-display/wallet-account-display.component.scss +99 -0
- package/src/lib/components/wallet-account-display/wallet-account-display.component.ts +140 -0
- package/src/lib/components/wallet-connect-button/wallet-connect-button.component.html +14 -0
- package/src/lib/components/wallet-connect-button/wallet-connect-button.component.scss +272 -0
- package/src/lib/components/wallet-connect-button/wallet-connect-button.component.ts +240 -0
- package/src/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.html +24 -0
- package/src/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.scss +50 -0
- package/src/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.ts +108 -0
- package/src/lib/components/wallet-connected-guard/wallet-connected-guard.component.html +24 -0
- package/src/lib/components/wallet-connected-guard/wallet-connected-guard.component.ts +73 -0
- package/src/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.html +56 -0
- package/src/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.scss +218 -0
- package/src/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.ts +117 -0
- package/src/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.html +94 -0
- package/src/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.scss +272 -0
- package/src/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.ts +734 -0
- package/src/lib/components/wallet-connection-modal/wallet-connection-modal.component.html +197 -0
- package/src/lib/components/wallet-connection-modal/wallet-connection-modal.component.scss +678 -0
- package/src/lib/components/wallet-connection-modal/wallet-connection-modal.component.ts +730 -0
- package/src/lib/components/wallet-session-display/wallet-session-display.component.html +110 -0
- package/src/lib/components/wallet-session-display/wallet-session-display.component.scss +179 -0
- package/src/lib/components/wallet-session-display/wallet-session-display.component.ts +197 -0
- package/src/lib/components/wallet-transaction-status/wallet-transaction-status.component.html +65 -0
- package/src/lib/components/wallet-transaction-status/wallet-transaction-status.component.scss +254 -0
- package/src/lib/components/wallet-transaction-status/wallet-transaction-status.component.ts +206 -0
- package/src/lib/directives/wallet-connected.directive.ts +195 -0
- package/src/lib/directives/wallet-context.directive.ts +154 -0
- package/src/lib/directives/wallet-events.directive.ts +232 -0
- package/src/lib/hsuite-wallet.module.ts +210 -0
- package/src/lib/models/connection-config.model.ts +65 -0
- package/src/lib/models/provider-types.ts +164 -0
- package/src/lib/models/unified-account.model.ts +76 -0
- package/src/lib/models/wallet-context.model.ts +121 -0
- package/src/lib/models/wallet-events.model.ts +158 -0
- package/src/lib/providers/base-wallet-provider.ts +351 -0
- package/src/lib/providers/hsuite-native/channel-client.service.spec.ts +73 -0
- package/src/lib/providers/hsuite-native/channel-client.service.ts +862 -0
- package/src/lib/providers/hsuite-native/index.ts +8 -0
- package/src/lib/providers/hsuite-native-provider.ts +754 -0
- package/src/lib/providers/mobile-native/mobile-native.provider.spec.ts +19 -0
- package/src/lib/providers/p2p-native/index.ts +30 -0
- package/src/lib/providers/p2p-native/p2p-native.provider.spec.ts +523 -0
- package/src/lib/providers/p2p-native/p2p-native.provider.ts +723 -0
- package/src/lib/providers/p2p-native/p2p-session-manager.ts +695 -0
- package/src/lib/providers/wallet-error-handler.ts +349 -0
- package/src/lib/providers/walletconnect/core/base-signer.interface.ts +122 -0
- package/src/lib/providers/walletconnect/core/session-health.ts +196 -0
- package/src/lib/providers/walletconnect/core/walletconnect-client-manager.ts +364 -0
- package/src/lib/providers/walletconnect/core/walletconnect-provider.integration.spec.ts +348 -0
- package/src/lib/providers/walletconnect/core/walletconnect-provider.ts +826 -0
- package/src/lib/providers/walletconnect/core/walletconnect-session-store.ts +273 -0
- package/src/lib/providers/walletconnect/core/walletconnect-signing-orchestrator.ts +299 -0
- package/src/lib/providers/walletconnect/core/walletconnect-types.ts +48 -0
- package/src/lib/providers/walletconnect/index.ts +33 -0
- package/src/lib/providers/walletconnect/signers/hedera-signer.spec.ts +367 -0
- package/src/lib/providers/walletconnect/signers/hedera-signer.ts +610 -0
- package/src/lib/providers/walletconnect/signers/signer-factory.spec.ts +62 -0
- package/src/lib/providers/walletconnect/signers/signer-factory.ts +120 -0
- package/src/lib/providers/walletconnect/signers/xrpl-signer.spec.ts +296 -0
- package/src/lib/providers/walletconnect/signers/xrpl-signer.ts +478 -0
- package/src/lib/services/logger.service.ts +126 -0
- package/src/lib/services/transaction-builders/base-transaction-builder.service.ts +585 -0
- package/src/lib/services/transaction-builders/hedera-amount-utils.ts +84 -0
- package/src/lib/services/transaction-builders/hedera-transaction-builder.service.spec.ts +741 -0
- package/src/lib/services/transaction-builders/hedera-transaction-builder.service.ts +1285 -0
- package/src/lib/services/transaction-builders/index.ts +54 -0
- package/src/lib/services/transaction-builders/xrpl-transaction-builder.service.spec.ts +937 -0
- package/src/lib/services/transaction-builders/xrpl-transaction-builder.service.ts +832 -0
- package/src/lib/services/transaction.service.ts +346 -0
- package/src/lib/services/unified-wallet.service.spec.ts +1382 -0
- package/src/lib/services/unified-wallet.service.ts +852 -0
- package/src/lib/services/wallet-context.service.ts +184 -0
- package/src/lib/services/wallet-event-bus.service.ts +186 -0
- package/src/lib/services/wallet-providers.service.ts +137 -0
- package/src/lib/transports/chrome-extension-transport.ts +246 -0
- package/src/lib/utils/index.ts +14 -0
- package/src/lib/utils/ledger-icons.util.ts +78 -0
- package/test/test-setup.ts +21 -0
- package/test-setup.ts +63 -0
- package/tsconfig.build.json +11 -0
- package/tsconfig.json +29 -0
- package/tsconfig.spec.json +15 -0
- package/vitest.config.ts +48 -0
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HSuite Native Connect
|
|
3
|
+
* Copyright 2024-2025 HSuite (https://hsuite.finance)
|
|
4
|
+
*
|
|
5
|
+
* SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
|
|
6
|
+
*
|
|
7
|
+
* This file is part of HSuite Native Connect. For commercial licensing,
|
|
8
|
+
* visit https://hsuite.finance/licensing
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @file wallet-error-handler.ts
|
|
13
|
+
* @description Configurable error handler with automatic toast notifications
|
|
14
|
+
*
|
|
15
|
+
* Provides automatic error handling for wallet operations with beautiful
|
|
16
|
+
* Ionic toast notifications. Fully customizable per error type.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { Injectable, Provider, inject, InjectionToken } from '@angular/core';
|
|
20
|
+
import { getLogger } from '@hsuite/native-connect-sdk';
|
|
21
|
+
import { ToastController } from '@ionic/angular/standalone';
|
|
22
|
+
|
|
23
|
+
import { WalletEventBus } from '../services/wallet-event-bus.service';
|
|
24
|
+
|
|
25
|
+
const logger = getLogger().scoped?.('WalletErrorHandler') ?? getLogger();
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Error category for categorizing wallet errors
|
|
29
|
+
*/
|
|
30
|
+
export type WalletErrorCategory =
|
|
31
|
+
| 'network' // Network connectivity issues
|
|
32
|
+
| 'auth' // Authentication failures (PIN, biometric)
|
|
33
|
+
| 'user_cancelled' // User cancelled the operation
|
|
34
|
+
| 'provider' // Provider-specific errors
|
|
35
|
+
| 'transaction' // Transaction failures
|
|
36
|
+
| 'validation' // Input validation errors
|
|
37
|
+
| 'unknown'; // Uncategorized errors
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Categorized wallet error with user-friendly message
|
|
41
|
+
*/
|
|
42
|
+
export interface CategorizedError {
|
|
43
|
+
/** Original error */
|
|
44
|
+
original: Error;
|
|
45
|
+
/** Error category */
|
|
46
|
+
category: WalletErrorCategory;
|
|
47
|
+
/** User-friendly message */
|
|
48
|
+
userMessage: string;
|
|
49
|
+
/** Whether this error is recoverable */
|
|
50
|
+
recoverable: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Configuration for the wallet error handler
|
|
55
|
+
*/
|
|
56
|
+
export interface WalletErrorHandlerConfig {
|
|
57
|
+
/**
|
|
58
|
+
* Whether to show toast notifications for errors (default: true)
|
|
59
|
+
*/
|
|
60
|
+
showToasts?: boolean;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Custom handler for connection errors
|
|
64
|
+
*/
|
|
65
|
+
onConnectionError?: (error: Error) => void;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Custom handler for transaction errors
|
|
69
|
+
*/
|
|
70
|
+
onTransactionError?: (error: Error) => void;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Custom handler for provider errors
|
|
74
|
+
*/
|
|
75
|
+
onProviderError?: (error: Error) => void;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Toast duration in milliseconds (default: 4000)
|
|
79
|
+
*/
|
|
80
|
+
toastDuration?: number;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Toast position (default: 'top')
|
|
84
|
+
*/
|
|
85
|
+
toastPosition?: 'top' | 'bottom' | 'middle';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Injection token for error handler config
|
|
90
|
+
*/
|
|
91
|
+
export const WALLET_ERROR_HANDLER_CONFIG = new InjectionToken<WalletErrorHandlerConfig>(
|
|
92
|
+
'WALLET_ERROR_HANDLER_CONFIG',
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Wallet error handler service
|
|
97
|
+
*
|
|
98
|
+
* Automatically subscribes to wallet events and shows error toasts.
|
|
99
|
+
* Can be customized via configuration.
|
|
100
|
+
*/
|
|
101
|
+
@Injectable()
|
|
102
|
+
export class WalletErrorHandler {
|
|
103
|
+
private readonly config = inject(WALLET_ERROR_HANDLER_CONFIG, { optional: true });
|
|
104
|
+
private readonly eventBus = inject(WalletEventBus);
|
|
105
|
+
private readonly toastController = inject(ToastController);
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
*
|
|
109
|
+
*/
|
|
110
|
+
constructor() {
|
|
111
|
+
// Setup error listeners
|
|
112
|
+
this.setupErrorListeners();
|
|
113
|
+
logger.debug('Initialized with config', { config: this.config });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Setup listeners for wallet errors
|
|
118
|
+
*/
|
|
119
|
+
private setupErrorListeners(): void {
|
|
120
|
+
// Listen to provider errors
|
|
121
|
+
this.eventBus.providerError.subscribe((event) => {
|
|
122
|
+
logger.error('Provider error', { event });
|
|
123
|
+
|
|
124
|
+
// Custom handler
|
|
125
|
+
if (this.config?.onProviderError) {
|
|
126
|
+
this.config.onProviderError(
|
|
127
|
+
event.error instanceof Error ? event.error : new Error(String(event.error)),
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Show toast if enabled (default: true)
|
|
132
|
+
if (this.config?.showToasts !== false) {
|
|
133
|
+
void this.showErrorToast(
|
|
134
|
+
'Wallet Error',
|
|
135
|
+
event.error instanceof Error ? event.error.message : String(event.error),
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Listen to disconnections for unexpected disconnects
|
|
141
|
+
this.eventBus.disconnected.subscribe((event) => {
|
|
142
|
+
if (event.reason === 'wallet_initiated_disconnect' || event.reason === 'session_terminated') {
|
|
143
|
+
logger.warn('Unexpected disconnect', { event });
|
|
144
|
+
|
|
145
|
+
// Show toast if enabled
|
|
146
|
+
if (this.config?.showToasts !== false) {
|
|
147
|
+
void this.showWarningToast(
|
|
148
|
+
'Wallet Disconnected',
|
|
149
|
+
`${event.providerType === 'hsuite-native' ? 'HSuite Wallet' : 'WalletConnect'} session ended`,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Show error toast
|
|
158
|
+
* Uses cssClass-only styling (no Ionic color property) for theme compatibility.
|
|
159
|
+
* @param header
|
|
160
|
+
* @param message
|
|
161
|
+
*/
|
|
162
|
+
private async showErrorToast(header: string, message: string): Promise<void> {
|
|
163
|
+
const toast = await this.toastController.create({
|
|
164
|
+
header,
|
|
165
|
+
message,
|
|
166
|
+
duration: this.config?.toastDuration || 4000,
|
|
167
|
+
position: this.config?.toastPosition || 'top',
|
|
168
|
+
cssClass: 'toast-danger toast-compact',
|
|
169
|
+
buttons: [{ icon: 'close', role: 'cancel' }],
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
await toast.present();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Show warning toast
|
|
177
|
+
* Uses cssClass-only styling (no Ionic color property) for theme compatibility.
|
|
178
|
+
* @param header
|
|
179
|
+
* @param message
|
|
180
|
+
*/
|
|
181
|
+
private async showWarningToast(header: string, message: string): Promise<void> {
|
|
182
|
+
const toast = await this.toastController.create({
|
|
183
|
+
header,
|
|
184
|
+
message,
|
|
185
|
+
duration: this.config?.toastDuration || 4000,
|
|
186
|
+
position: this.config?.toastPosition || 'top',
|
|
187
|
+
cssClass: 'toast-warning toast-compact',
|
|
188
|
+
buttons: [{ icon: 'close', role: 'cancel' }],
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
await toast.present();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Manually handle an error (for use in components)
|
|
196
|
+
* @param title
|
|
197
|
+
* @param error
|
|
198
|
+
*/
|
|
199
|
+
async handleError(title: string, error: Error | string): Promise<void> {
|
|
200
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
201
|
+
|
|
202
|
+
if (this.config?.showToasts !== false) {
|
|
203
|
+
await this.showErrorToast(title, message);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Manually show success toast (convenience method)
|
|
209
|
+
* Uses cssClass-only styling (no Ionic color property) for theme compatibility.
|
|
210
|
+
* @param header
|
|
211
|
+
* @param message
|
|
212
|
+
*/
|
|
213
|
+
async showSuccess(header: string, message: string): Promise<void> {
|
|
214
|
+
const toast = await this.toastController.create({
|
|
215
|
+
header,
|
|
216
|
+
message,
|
|
217
|
+
duration: this.config?.toastDuration || 3000,
|
|
218
|
+
position: this.config?.toastPosition || 'top',
|
|
219
|
+
cssClass: 'toast-success toast-compact',
|
|
220
|
+
buttons: [{ icon: 'close', role: 'cancel' }],
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
await toast.present();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Categorize an error for better handling
|
|
228
|
+
* @param error - The error to categorize
|
|
229
|
+
* @returns Categorized error with user-friendly message
|
|
230
|
+
*/
|
|
231
|
+
categorizeError(error: Error | string): CategorizedError {
|
|
232
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
233
|
+
const lowerMessage = errorMessage.toLowerCase();
|
|
234
|
+
|
|
235
|
+
// Network errors
|
|
236
|
+
if (
|
|
237
|
+
lowerMessage.includes('network') ||
|
|
238
|
+
lowerMessage.includes('timeout') ||
|
|
239
|
+
lowerMessage.includes('fetch') ||
|
|
240
|
+
lowerMessage.includes('connection')
|
|
241
|
+
) {
|
|
242
|
+
return {
|
|
243
|
+
original: error instanceof Error ? error : new Error(errorMessage),
|
|
244
|
+
category: 'network',
|
|
245
|
+
userMessage: 'Network connection issue. Please check your internet connection.',
|
|
246
|
+
recoverable: true,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// User cancelled
|
|
251
|
+
if (
|
|
252
|
+
lowerMessage.includes('cancel') ||
|
|
253
|
+
lowerMessage.includes('rejected') ||
|
|
254
|
+
lowerMessage.includes('denied') ||
|
|
255
|
+
lowerMessage.includes('user rejected')
|
|
256
|
+
) {
|
|
257
|
+
return {
|
|
258
|
+
original: error instanceof Error ? error : new Error(errorMessage),
|
|
259
|
+
category: 'user_cancelled',
|
|
260
|
+
userMessage: 'Operation cancelled.',
|
|
261
|
+
recoverable: true,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Authentication errors
|
|
266
|
+
if (
|
|
267
|
+
lowerMessage.includes('pin') ||
|
|
268
|
+
lowerMessage.includes('biometric') ||
|
|
269
|
+
lowerMessage.includes('auth') ||
|
|
270
|
+
lowerMessage.includes('unlock')
|
|
271
|
+
) {
|
|
272
|
+
return {
|
|
273
|
+
original: error instanceof Error ? error : new Error(errorMessage),
|
|
274
|
+
category: 'auth',
|
|
275
|
+
userMessage: 'Authentication failed. Please try again.',
|
|
276
|
+
recoverable: true,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Transaction errors
|
|
281
|
+
if (
|
|
282
|
+
lowerMessage.includes('transaction') ||
|
|
283
|
+
lowerMessage.includes('insufficient') ||
|
|
284
|
+
lowerMessage.includes('balance') ||
|
|
285
|
+
lowerMessage.includes('sign')
|
|
286
|
+
) {
|
|
287
|
+
return {
|
|
288
|
+
original: error instanceof Error ? error : new Error(errorMessage),
|
|
289
|
+
category: 'transaction',
|
|
290
|
+
userMessage: 'Transaction failed. Please check the details and try again.',
|
|
291
|
+
recoverable: true,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Validation errors
|
|
296
|
+
if (
|
|
297
|
+
lowerMessage.includes('invalid') ||
|
|
298
|
+
lowerMessage.includes('required') ||
|
|
299
|
+
lowerMessage.includes('format')
|
|
300
|
+
) {
|
|
301
|
+
return {
|
|
302
|
+
original: error instanceof Error ? error : new Error(errorMessage),
|
|
303
|
+
category: 'validation',
|
|
304
|
+
userMessage: errorMessage,
|
|
305
|
+
recoverable: true,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Provider errors
|
|
310
|
+
if (
|
|
311
|
+
lowerMessage.includes('provider') ||
|
|
312
|
+
lowerMessage.includes('wallet') ||
|
|
313
|
+
lowerMessage.includes('session')
|
|
314
|
+
) {
|
|
315
|
+
return {
|
|
316
|
+
original: error instanceof Error ? error : new Error(errorMessage),
|
|
317
|
+
category: 'provider',
|
|
318
|
+
userMessage: 'Wallet connection issue. Please reconnect.',
|
|
319
|
+
recoverable: true,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Unknown
|
|
324
|
+
return {
|
|
325
|
+
original: error instanceof Error ? error : new Error(errorMessage),
|
|
326
|
+
category: 'unknown',
|
|
327
|
+
userMessage: 'An unexpected error occurred.',
|
|
328
|
+
recoverable: false,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Provider function for WalletErrorHandler
|
|
335
|
+
*
|
|
336
|
+
* Call this in your app configuration to enable automatic error handling.
|
|
337
|
+
*
|
|
338
|
+
* @param config - Optional configuration
|
|
339
|
+
* @returns Angular providers
|
|
340
|
+
*/
|
|
341
|
+
export function provideWalletErrorHandler(config?: WalletErrorHandlerConfig): Provider[] {
|
|
342
|
+
return [
|
|
343
|
+
{
|
|
344
|
+
provide: WALLET_ERROR_HANDLER_CONFIG,
|
|
345
|
+
useValue: config || { showToasts: true },
|
|
346
|
+
},
|
|
347
|
+
WalletErrorHandler,
|
|
348
|
+
];
|
|
349
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HSuite Native Connect
|
|
3
|
+
* Copyright 2024-2025 HSuite (https://hsuite.finance)
|
|
4
|
+
*
|
|
5
|
+
* SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
|
|
6
|
+
*
|
|
7
|
+
* This file is part of HSuite Native Connect. For commercial licensing,
|
|
8
|
+
* visit https://hsuite.finance/licensing
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @file base-signer.interface.ts
|
|
13
|
+
* @description Abstract signer interface for WalletConnect multi-chain support
|
|
14
|
+
*
|
|
15
|
+
* Defines the contract that all ledger-specific signers must implement.
|
|
16
|
+
* This enables the Strategy Pattern for clean separation of ledger logic.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { SignResult, SubmitResult, SignMessageResult } from '../../base-wallet-provider';
|
|
20
|
+
import type SignClient from '@walletconnect/sign-client';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Configuration for initializing a WalletConnect signer
|
|
24
|
+
*/
|
|
25
|
+
export interface WalletConnectSignerConfig {
|
|
26
|
+
ledgerId: string;
|
|
27
|
+
networkId: string;
|
|
28
|
+
chainId: string; // e.g., 'hedera:testnet', 'xrpl:testnet'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Parameters for signing operations
|
|
33
|
+
*/
|
|
34
|
+
export interface SignerOperationParams {
|
|
35
|
+
client: SignClient;
|
|
36
|
+
topic: string;
|
|
37
|
+
accountAddress: string;
|
|
38
|
+
payload: string;
|
|
39
|
+
networkId: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Interface that all WalletConnect signers must implement.
|
|
44
|
+
* Each ledger (Hedera, XRPL, etc.) provides its own implementation.
|
|
45
|
+
*
|
|
46
|
+
* This follows the Strategy Pattern, allowing the WalletConnect provider
|
|
47
|
+
* to delegate ledger-specific logic to the appropriate signer.
|
|
48
|
+
*/
|
|
49
|
+
export interface IWalletConnectSigner {
|
|
50
|
+
/**
|
|
51
|
+
* Unique identifier for this ledger (e.g., 'hedera', 'xrpl')
|
|
52
|
+
*/
|
|
53
|
+
readonly ledgerId: string;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Build WalletConnect namespace configuration for this ledger.
|
|
57
|
+
* Defines the JSON-RPC methods, chains, and events supported.
|
|
58
|
+
*
|
|
59
|
+
* @param networkId - The network identifier (e.g., 'hedera:testnet')
|
|
60
|
+
* @returns Namespace configuration object
|
|
61
|
+
*/
|
|
62
|
+
buildNamespace(networkId: string): {
|
|
63
|
+
methods: string[];
|
|
64
|
+
chains: string[];
|
|
65
|
+
events: string[];
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Sign a transaction without submitting to the network.
|
|
70
|
+
* Used for multi-sig workflows or when the dApp handles submission.
|
|
71
|
+
*
|
|
72
|
+
* @param params - Signing parameters including client, topic, account, and payload
|
|
73
|
+
* @returns Promise resolving to signed transaction data
|
|
74
|
+
*/
|
|
75
|
+
signTransaction(params: SignerOperationParams): Promise<SignResult>;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Sign and submit a transaction to the network.
|
|
79
|
+
* The wallet handles both signing and network submission.
|
|
80
|
+
*
|
|
81
|
+
* @param params - Submission parameters including client, topic, account, and payload
|
|
82
|
+
* @returns Promise resolving to transaction ID and metadata
|
|
83
|
+
*/
|
|
84
|
+
submitTransaction(params: SignerOperationParams): Promise<SubmitResult>;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Sign and execute a transaction in one call (preferred method to avoid double prompts).
|
|
88
|
+
* This uses the wallet's native sign+execute method when available (e.g., hedera_signAndExecuteTransaction).
|
|
89
|
+
* Falls back to sign then submit for wallets that don't support it.
|
|
90
|
+
*
|
|
91
|
+
* @param params - Transaction parameters including client, topic, account, and payload
|
|
92
|
+
* @returns Promise resolving to transaction ID and metadata
|
|
93
|
+
*/
|
|
94
|
+
signAndExecuteTransaction?(params: SignerOperationParams): Promise<SubmitResult>;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Sign an arbitrary message (e.g., for DAO votes, authentication, proofs).
|
|
98
|
+
* The message can be plain text or base64 encoded.
|
|
99
|
+
*
|
|
100
|
+
* @param params - Signing parameters with message string
|
|
101
|
+
* @returns Promise resolving to signature and optional public key
|
|
102
|
+
*/
|
|
103
|
+
signMessage(
|
|
104
|
+
params: SignerOperationParams & { message: string; encoding?: 'utf-8' | 'base64' },
|
|
105
|
+
): Promise<SignMessageResult>;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Parse accounts from WalletConnect session namespace.
|
|
109
|
+
* Extracts account addresses and chain IDs from the session data.
|
|
110
|
+
*
|
|
111
|
+
* Optionally filters accounts to only include those matching a target network.
|
|
112
|
+
* This is important for respecting the user's network selection in the dApp.
|
|
113
|
+
*
|
|
114
|
+
* @param namespace - The WalletConnect namespace object for this ledger
|
|
115
|
+
* @param targetNetworkId - Optional network ID to filter accounts (e.g., 'hedera:mainnet')
|
|
116
|
+
* @returns Array of parsed account objects, filtered by target network if specified
|
|
117
|
+
*/
|
|
118
|
+
parseAccounts(
|
|
119
|
+
namespace: any,
|
|
120
|
+
targetNetworkId?: string,
|
|
121
|
+
): Array<{ address: string; chainId: string }>;
|
|
122
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HSuite Native Connect
|
|
3
|
+
* Copyright 2024-2025 HSuite (https://hsuite.finance)
|
|
4
|
+
*
|
|
5
|
+
* SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
|
|
6
|
+
*
|
|
7
|
+
* This file is part of HSuite Native Connect. For commercial licensing,
|
|
8
|
+
* visit https://hsuite.finance/licensing
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @file session-health.ts
|
|
13
|
+
* @description Manages WalletConnect session health - ensures relay subscriptions
|
|
14
|
+
* are active before making requests. Transparent to dApp developers.
|
|
15
|
+
*
|
|
16
|
+
* This class handles the common WalletConnect issue where relay subscriptions
|
|
17
|
+
* become stale, causing requests to fail with empty error objects.
|
|
18
|
+
*
|
|
19
|
+
* Features:
|
|
20
|
+
* - Pre-request session ping to ensure relay subscription is active
|
|
21
|
+
* - Relay connection monitoring (connect/disconnect/error events)
|
|
22
|
+
* - Automatic ping cache management
|
|
23
|
+
* - Subscription refresh capability
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { getLogger } from '@hsuite/native-connect-sdk';
|
|
27
|
+
import type SignClient from '@walletconnect/sign-client';
|
|
28
|
+
|
|
29
|
+
const logger = getLogger().scoped?.('WCSessionHealth') ?? getLogger();
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Manages WalletConnect session health to prevent stale relay subscription issues.
|
|
33
|
+
*
|
|
34
|
+
* The WalletConnect relay uses WebSocket connections that can become stale,
|
|
35
|
+
* causing push events to stop arriving. This manager:
|
|
36
|
+
* - Pings sessions before requests to ensure subscriptions are active
|
|
37
|
+
* - Monitors relay connection state
|
|
38
|
+
* - Clears ping cache on disconnect to force re-ping
|
|
39
|
+
*/
|
|
40
|
+
export class SessionHealthManager {
|
|
41
|
+
private client: SignClient;
|
|
42
|
+
private lastPingTime = new Map<string, number>();
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Minimum interval between pings for the same topic (30 seconds).
|
|
46
|
+
* Pinging too frequently is unnecessary and adds latency.
|
|
47
|
+
*/
|
|
48
|
+
private readonly PING_INTERVAL_MS = 30000;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Maximum time to wait for a ping response (5 seconds).
|
|
52
|
+
* If ping times out, we proceed anyway but log a warning.
|
|
53
|
+
*/
|
|
54
|
+
private readonly PING_TIMEOUT_MS = 5000;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Create a new SessionHealthManager.
|
|
58
|
+
*
|
|
59
|
+
* @param client - Initialized WalletConnect SignClient instance
|
|
60
|
+
*/
|
|
61
|
+
constructor(client: SignClient) {
|
|
62
|
+
this.client = client;
|
|
63
|
+
this.setupRelayMonitoring();
|
|
64
|
+
logger.info('SessionHealthManager initialized');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Ensure session is healthy before making a request.
|
|
69
|
+
*
|
|
70
|
+
* Pings the session if the last ping was more than 30 seconds ago.
|
|
71
|
+
* This refreshes the relay subscription and helps prevent the
|
|
72
|
+
* empty error object issue.
|
|
73
|
+
*
|
|
74
|
+
* Called automatically by WalletConnectClientManager before requests.
|
|
75
|
+
*
|
|
76
|
+
* @param topic - Session topic to verify
|
|
77
|
+
*/
|
|
78
|
+
async ensureSessionHealth(topic: string): Promise<void> {
|
|
79
|
+
const lastPing = this.lastPingTime.get(topic) || 0;
|
|
80
|
+
const now = Date.now();
|
|
81
|
+
|
|
82
|
+
// Skip if we pinged recently
|
|
83
|
+
if (now - lastPing <= this.PING_INTERVAL_MS) {
|
|
84
|
+
logger.debug('Skipping ping - recent ping exists', {
|
|
85
|
+
topic: topic.substring(0, 16) + '...',
|
|
86
|
+
lastPingAge: now - lastPing,
|
|
87
|
+
});
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
logger.debug('Pinging session to ensure relay subscription', {
|
|
93
|
+
topic: topic.substring(0, 16) + '...',
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Race ping against timeout
|
|
97
|
+
await Promise.race([
|
|
98
|
+
this.client.ping({ topic }),
|
|
99
|
+
new Promise<never>((_, reject) =>
|
|
100
|
+
setTimeout(() => reject(new Error('Ping timeout')), this.PING_TIMEOUT_MS),
|
|
101
|
+
),
|
|
102
|
+
]);
|
|
103
|
+
|
|
104
|
+
this.lastPingTime.set(topic, now);
|
|
105
|
+
logger.debug('Session ping successful', {
|
|
106
|
+
topic: topic.substring(0, 16) + '...',
|
|
107
|
+
});
|
|
108
|
+
} catch (err) {
|
|
109
|
+
// Log warning but don't throw - let the request attempt proceed
|
|
110
|
+
// The request might still succeed if the subscription is actually active
|
|
111
|
+
logger.warn('Session ping failed - relay subscription may be stale', {
|
|
112
|
+
topic: topic.substring(0, 16) + '...',
|
|
113
|
+
error: err instanceof Error ? err.message : String(err),
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Force refresh relay subscription for a topic.
|
|
120
|
+
*
|
|
121
|
+
* Use this when you suspect the subscription is stale and want
|
|
122
|
+
* to explicitly re-subscribe rather than relying on ping.
|
|
123
|
+
*
|
|
124
|
+
* @param topic - Session topic to refresh subscription for
|
|
125
|
+
*/
|
|
126
|
+
async refreshSubscription(topic: string): Promise<void> {
|
|
127
|
+
try {
|
|
128
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- WalletConnect internal API not typed
|
|
129
|
+
const relayer = (this.client as any).core?.relayer;
|
|
130
|
+
if (relayer?.subscribe) {
|
|
131
|
+
await relayer.subscribe(topic);
|
|
132
|
+
// Clear ping cache so next ensureSessionHealth will ping
|
|
133
|
+
this.lastPingTime.delete(topic);
|
|
134
|
+
logger.info('Refreshed relay subscription', {
|
|
135
|
+
topic: topic.substring(0, 16) + '...',
|
|
136
|
+
});
|
|
137
|
+
} else {
|
|
138
|
+
logger.warn('Relayer.subscribe not available');
|
|
139
|
+
}
|
|
140
|
+
} catch (err) {
|
|
141
|
+
logger.warn('Failed to refresh subscription', {
|
|
142
|
+
topic: topic.substring(0, 16) + '...',
|
|
143
|
+
error: err instanceof Error ? err.message : String(err),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Clear ping cache for a specific topic or all topics.
|
|
150
|
+
*
|
|
151
|
+
* @param topic - Optional topic to clear. If not provided, clears all.
|
|
152
|
+
*/
|
|
153
|
+
clearPingCache(topic?: string): void {
|
|
154
|
+
if (topic) {
|
|
155
|
+
this.lastPingTime.delete(topic);
|
|
156
|
+
} else {
|
|
157
|
+
this.lastPingTime.clear();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Setup relay connection monitoring.
|
|
163
|
+
*
|
|
164
|
+
* Listens for:
|
|
165
|
+
* - connect: Logs when WebSocket connects
|
|
166
|
+
* - disconnect: Clears ping cache to force re-ping on next request
|
|
167
|
+
* - error: Logs relay errors
|
|
168
|
+
*
|
|
169
|
+
* @private
|
|
170
|
+
*/
|
|
171
|
+
private setupRelayMonitoring(): void {
|
|
172
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- WalletConnect internal API not typed
|
|
173
|
+
const relayer = (this.client as any).core?.relayer;
|
|
174
|
+
if (!relayer) {
|
|
175
|
+
logger.warn('Could not access relayer for monitoring');
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
relayer.on('connect', () => {
|
|
180
|
+
logger.info('Relay WebSocket connected');
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
relayer.on('disconnect', () => {
|
|
184
|
+
logger.warn('Relay WebSocket disconnected - clearing ping cache');
|
|
185
|
+
this.lastPingTime.clear();
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
relayer.on('error', (err: Error) => {
|
|
189
|
+
logger.error('Relay error', {
|
|
190
|
+
error: err?.message || String(err),
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
logger.debug('Relay monitoring setup complete');
|
|
195
|
+
}
|
|
196
|
+
}
|