@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.
Files changed (276) hide show
  1. package/README.md +48 -0
  2. package/USAGE_EXAMPLES.md +476 -0
  3. package/assets/wallets/extension.svg +7 -0
  4. package/assets/wallets/hashpack.svg +6 -0
  5. package/assets/wallets/hsuite.svg +11 -0
  6. package/assets/wallets/kabila.svg +11 -0
  7. package/assets/wallets/walletconnect.svg +13 -0
  8. package/coverage/base.css +224 -0
  9. package/coverage/block-navigation.js +87 -0
  10. package/coverage/coverage-summary.json +50 -0
  11. package/coverage/favicon.png +0 -0
  12. package/coverage/index.html +476 -0
  13. package/coverage/lcov-report/base.css +224 -0
  14. package/coverage/lcov-report/block-navigation.js +87 -0
  15. package/coverage/lcov-report/favicon.png +0 -0
  16. package/coverage/lcov-report/index.html +476 -0
  17. package/coverage/lcov-report/lib/components/account-selector/account-actions/account-actions.component.ts.html +868 -0
  18. package/coverage/lcov-report/lib/components/account-selector/account-actions/index.html +116 -0
  19. package/coverage/lcov-report/lib/components/account-selector/account-filter/account-filter.component.ts.html +1288 -0
  20. package/coverage/lcov-report/lib/components/account-selector/account-filter/index.html +116 -0
  21. package/coverage/lcov-report/lib/components/account-selector/account-formatting.service.ts.html +685 -0
  22. package/coverage/lcov-report/lib/components/account-selector/account-grouping.service.ts.html +766 -0
  23. package/coverage/lcov-report/lib/components/account-selector/account-list/account-list.component.ts.html +1495 -0
  24. package/coverage/lcov-report/lib/components/account-selector/account-list/index.html +116 -0
  25. package/coverage/lcov-report/lib/components/account-selector/account-selector.component.ts.html +1495 -0
  26. package/coverage/lcov-report/lib/components/account-selector/account-selector.service.ts.html +1588 -0
  27. package/coverage/lcov-report/lib/components/account-selector/index.html +161 -0
  28. package/coverage/lcov-report/lib/components/wallet-account-display/index.html +116 -0
  29. package/coverage/lcov-report/lib/components/wallet-account-display/wallet-account-display.component.ts.html +505 -0
  30. package/coverage/lcov-report/lib/components/wallet-connect-button/index.html +116 -0
  31. package/coverage/lcov-report/lib/components/wallet-connect-button/wallet-connect-button.component.ts.html +805 -0
  32. package/coverage/lcov-report/lib/components/wallet-connect-prompt/index.html +116 -0
  33. package/coverage/lcov-report/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.ts.html +409 -0
  34. package/coverage/lcov-report/lib/components/wallet-connected-guard/index.html +116 -0
  35. package/coverage/lcov-report/lib/components/wallet-connected-guard/wallet-connected-guard.component.ts.html +304 -0
  36. package/coverage/lcov-report/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.ts.html +436 -0
  37. package/coverage/lcov-report/lib/components/wallet-connection-modal/connection-method-step/index.html +116 -0
  38. package/coverage/lcov-report/lib/components/wallet-connection-modal/index.html +116 -0
  39. package/coverage/lcov-report/lib/components/wallet-connection-modal/qr-pairing-step/index.html +116 -0
  40. package/coverage/lcov-report/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.ts.html +2287 -0
  41. package/coverage/lcov-report/lib/components/wallet-connection-modal/wallet-connection-modal.component.ts.html +2275 -0
  42. package/coverage/lcov-report/lib/components/wallet-session-display/index.html +116 -0
  43. package/coverage/lcov-report/lib/components/wallet-session-display/wallet-session-display.component.ts.html +676 -0
  44. package/coverage/lcov-report/lib/components/wallet-transaction-status/index.html +116 -0
  45. package/coverage/lcov-report/lib/components/wallet-transaction-status/wallet-transaction-status.component.ts.html +703 -0
  46. package/coverage/lcov-report/lib/directives/index.html +146 -0
  47. package/coverage/lcov-report/lib/directives/wallet-connected.directive.ts.html +670 -0
  48. package/coverage/lcov-report/lib/directives/wallet-context.directive.ts.html +547 -0
  49. package/coverage/lcov-report/lib/directives/wallet-events.directive.ts.html +781 -0
  50. package/coverage/lcov-report/lib/hsuite-wallet.module.ts.html +715 -0
  51. package/coverage/lcov-report/lib/index.html +116 -0
  52. package/coverage/lcov-report/lib/models/connection-config.model.ts.html +280 -0
  53. package/coverage/lcov-report/lib/models/index.html +131 -0
  54. package/coverage/lcov-report/lib/models/provider-types.ts.html +577 -0
  55. package/coverage/lcov-report/lib/providers/base-wallet-provider.ts.html +1138 -0
  56. package/coverage/lcov-report/lib/providers/hsuite-native/channel-client.service.ts.html +2671 -0
  57. package/coverage/lcov-report/lib/providers/hsuite-native/index.html +116 -0
  58. package/coverage/lcov-report/lib/providers/hsuite-native-provider.ts.html +2347 -0
  59. package/coverage/lcov-report/lib/providers/index.html +146 -0
  60. package/coverage/lcov-report/lib/providers/p2p-native/index.html +131 -0
  61. package/coverage/lcov-report/lib/providers/p2p-native/p2p-native.provider.ts.html +2254 -0
  62. package/coverage/lcov-report/lib/providers/p2p-native/p2p-session-manager.ts.html +2170 -0
  63. package/coverage/lcov-report/lib/providers/wallet-error-handler.ts.html +1132 -0
  64. package/coverage/lcov-report/lib/providers/walletconnect/core/index.html +176 -0
  65. package/coverage/lcov-report/lib/providers/walletconnect/core/session-health.ts.html +673 -0
  66. package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-client-manager.ts.html +1177 -0
  67. package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-provider.ts.html +2563 -0
  68. package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-session-store.ts.html +904 -0
  69. package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-signing-orchestrator.ts.html +982 -0
  70. package/coverage/lcov-report/lib/providers/walletconnect/signers/hedera-signer.ts.html +1915 -0
  71. package/coverage/lcov-report/lib/providers/walletconnect/signers/index.html +146 -0
  72. package/coverage/lcov-report/lib/providers/walletconnect/signers/signer-factory.ts.html +445 -0
  73. package/coverage/lcov-report/lib/providers/walletconnect/signers/xrpl-signer.ts.html +1519 -0
  74. package/coverage/lcov-report/lib/services/index.html +191 -0
  75. package/coverage/lcov-report/lib/services/logger.service.ts.html +463 -0
  76. package/coverage/lcov-report/lib/services/transaction-builders/base-transaction-builder.service.ts.html +1840 -0
  77. package/coverage/lcov-report/lib/services/transaction-builders/hedera-amount-utils.ts.html +337 -0
  78. package/coverage/lcov-report/lib/services/transaction-builders/hedera-transaction-builder.service.ts.html +3940 -0
  79. package/coverage/lcov-report/lib/services/transaction-builders/index.html +161 -0
  80. package/coverage/lcov-report/lib/services/transaction-builders/xrpl-transaction-builder.service.ts.html +2581 -0
  81. package/coverage/lcov-report/lib/services/transaction.service.ts.html +1123 -0
  82. package/coverage/lcov-report/lib/services/unified-wallet.service.ts.html +2641 -0
  83. package/coverage/lcov-report/lib/services/wallet-context.service.ts.html +637 -0
  84. package/coverage/lcov-report/lib/services/wallet-event-bus.service.ts.html +643 -0
  85. package/coverage/lcov-report/lib/services/wallet-providers.service.ts.html +496 -0
  86. package/coverage/lcov-report/lib/transports/chrome-extension-transport.ts.html +823 -0
  87. package/coverage/lcov-report/lib/transports/index.html +116 -0
  88. package/coverage/lcov-report/lib/utils/index.html +116 -0
  89. package/coverage/lcov-report/lib/utils/ledger-icons.util.ts.html +319 -0
  90. package/coverage/lcov-report/prettify.css +1 -0
  91. package/coverage/lcov-report/prettify.js +2 -0
  92. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  93. package/coverage/lcov-report/sorter.js +210 -0
  94. package/coverage/lcov.info +19252 -0
  95. package/coverage/lib/components/account-selector/account-actions/account-actions.component.ts.html +868 -0
  96. package/coverage/lib/components/account-selector/account-actions/index.html +116 -0
  97. package/coverage/lib/components/account-selector/account-filter/account-filter.component.ts.html +1288 -0
  98. package/coverage/lib/components/account-selector/account-filter/index.html +116 -0
  99. package/coverage/lib/components/account-selector/account-formatting.service.ts.html +685 -0
  100. package/coverage/lib/components/account-selector/account-grouping.service.ts.html +766 -0
  101. package/coverage/lib/components/account-selector/account-list/account-list.component.ts.html +1495 -0
  102. package/coverage/lib/components/account-selector/account-list/index.html +116 -0
  103. package/coverage/lib/components/account-selector/account-selector.component.ts.html +1495 -0
  104. package/coverage/lib/components/account-selector/account-selector.service.ts.html +1588 -0
  105. package/coverage/lib/components/account-selector/index.html +161 -0
  106. package/coverage/lib/components/wallet-account-display/index.html +116 -0
  107. package/coverage/lib/components/wallet-account-display/wallet-account-display.component.ts.html +505 -0
  108. package/coverage/lib/components/wallet-connect-button/index.html +116 -0
  109. package/coverage/lib/components/wallet-connect-button/wallet-connect-button.component.ts.html +805 -0
  110. package/coverage/lib/components/wallet-connect-prompt/index.html +116 -0
  111. package/coverage/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.ts.html +409 -0
  112. package/coverage/lib/components/wallet-connected-guard/index.html +116 -0
  113. package/coverage/lib/components/wallet-connected-guard/wallet-connected-guard.component.ts.html +304 -0
  114. package/coverage/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.ts.html +436 -0
  115. package/coverage/lib/components/wallet-connection-modal/connection-method-step/index.html +116 -0
  116. package/coverage/lib/components/wallet-connection-modal/index.html +116 -0
  117. package/coverage/lib/components/wallet-connection-modal/qr-pairing-step/index.html +116 -0
  118. package/coverage/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.ts.html +2287 -0
  119. package/coverage/lib/components/wallet-connection-modal/wallet-connection-modal.component.ts.html +2275 -0
  120. package/coverage/lib/components/wallet-session-display/index.html +116 -0
  121. package/coverage/lib/components/wallet-session-display/wallet-session-display.component.ts.html +676 -0
  122. package/coverage/lib/components/wallet-transaction-status/index.html +116 -0
  123. package/coverage/lib/components/wallet-transaction-status/wallet-transaction-status.component.ts.html +703 -0
  124. package/coverage/lib/directives/index.html +146 -0
  125. package/coverage/lib/directives/wallet-connected.directive.ts.html +670 -0
  126. package/coverage/lib/directives/wallet-context.directive.ts.html +547 -0
  127. package/coverage/lib/directives/wallet-events.directive.ts.html +781 -0
  128. package/coverage/lib/hsuite-wallet.module.ts.html +715 -0
  129. package/coverage/lib/index.html +116 -0
  130. package/coverage/lib/models/connection-config.model.ts.html +280 -0
  131. package/coverage/lib/models/index.html +131 -0
  132. package/coverage/lib/models/provider-types.ts.html +577 -0
  133. package/coverage/lib/providers/base-wallet-provider.ts.html +1138 -0
  134. package/coverage/lib/providers/hsuite-native/channel-client.service.ts.html +2671 -0
  135. package/coverage/lib/providers/hsuite-native/index.html +116 -0
  136. package/coverage/lib/providers/hsuite-native-provider.ts.html +2347 -0
  137. package/coverage/lib/providers/index.html +146 -0
  138. package/coverage/lib/providers/p2p-native/index.html +131 -0
  139. package/coverage/lib/providers/p2p-native/p2p-native.provider.ts.html +2254 -0
  140. package/coverage/lib/providers/p2p-native/p2p-session-manager.ts.html +2170 -0
  141. package/coverage/lib/providers/wallet-error-handler.ts.html +1132 -0
  142. package/coverage/lib/providers/walletconnect/core/index.html +176 -0
  143. package/coverage/lib/providers/walletconnect/core/session-health.ts.html +673 -0
  144. package/coverage/lib/providers/walletconnect/core/walletconnect-client-manager.ts.html +1177 -0
  145. package/coverage/lib/providers/walletconnect/core/walletconnect-provider.ts.html +2563 -0
  146. package/coverage/lib/providers/walletconnect/core/walletconnect-session-store.ts.html +904 -0
  147. package/coverage/lib/providers/walletconnect/core/walletconnect-signing-orchestrator.ts.html +982 -0
  148. package/coverage/lib/providers/walletconnect/signers/hedera-signer.ts.html +1915 -0
  149. package/coverage/lib/providers/walletconnect/signers/index.html +146 -0
  150. package/coverage/lib/providers/walletconnect/signers/signer-factory.ts.html +445 -0
  151. package/coverage/lib/providers/walletconnect/signers/xrpl-signer.ts.html +1519 -0
  152. package/coverage/lib/services/index.html +191 -0
  153. package/coverage/lib/services/logger.service.ts.html +463 -0
  154. package/coverage/lib/services/transaction-builders/base-transaction-builder.service.ts.html +1840 -0
  155. package/coverage/lib/services/transaction-builders/hedera-amount-utils.ts.html +337 -0
  156. package/coverage/lib/services/transaction-builders/hedera-transaction-builder.service.ts.html +3940 -0
  157. package/coverage/lib/services/transaction-builders/index.html +161 -0
  158. package/coverage/lib/services/transaction-builders/xrpl-transaction-builder.service.ts.html +2581 -0
  159. package/coverage/lib/services/transaction.service.ts.html +1123 -0
  160. package/coverage/lib/services/unified-wallet.service.ts.html +2641 -0
  161. package/coverage/lib/services/wallet-context.service.ts.html +637 -0
  162. package/coverage/lib/services/wallet-event-bus.service.ts.html +643 -0
  163. package/coverage/lib/services/wallet-providers.service.ts.html +496 -0
  164. package/coverage/lib/transports/chrome-extension-transport.ts.html +823 -0
  165. package/coverage/lib/transports/index.html +116 -0
  166. package/coverage/lib/utils/index.html +116 -0
  167. package/coverage/lib/utils/ledger-icons.util.ts.html +319 -0
  168. package/coverage/prettify.css +1 -0
  169. package/coverage/prettify.js +2 -0
  170. package/coverage/sort-arrow-sprite.png +0 -0
  171. package/coverage/sorter.js +210 -0
  172. package/dist/README.md +48 -0
  173. package/dist/fesm2022/hsuite-native-connect-angular.mjs +14592 -0
  174. package/dist/fesm2022/hsuite-native-connect-angular.mjs.map +1 -0
  175. package/dist/index.d.ts +6949 -0
  176. package/examples/minimal-connect.ts +178 -0
  177. package/examples/multi-protocol.ts +495 -0
  178. package/examples/transaction-signing.ts +361 -0
  179. package/jest.config.json +45 -0
  180. package/karma.conf.js +42 -0
  181. package/ng-package.json +20 -0
  182. package/package.json +60 -0
  183. package/src/index.ts +203 -0
  184. package/src/lib/components/account-selector/account-actions/account-actions.component.ts +261 -0
  185. package/src/lib/components/account-selector/account-filter/account-filter.component.ts +401 -0
  186. package/src/lib/components/account-selector/account-formatting.service.ts +200 -0
  187. package/src/lib/components/account-selector/account-grouping.service.ts +227 -0
  188. package/src/lib/components/account-selector/account-list/account-list.component.ts +470 -0
  189. package/src/lib/components/account-selector/account-selector.component.html +135 -0
  190. package/src/lib/components/account-selector/account-selector.component.scss +2039 -0
  191. package/src/lib/components/account-selector/account-selector.component.ts +470 -0
  192. package/src/lib/components/account-selector/account-selector.service.ts +501 -0
  193. package/src/lib/components/wallet-account-display/wallet-account-display.component.html +34 -0
  194. package/src/lib/components/wallet-account-display/wallet-account-display.component.scss +99 -0
  195. package/src/lib/components/wallet-account-display/wallet-account-display.component.ts +140 -0
  196. package/src/lib/components/wallet-connect-button/wallet-connect-button.component.html +14 -0
  197. package/src/lib/components/wallet-connect-button/wallet-connect-button.component.scss +272 -0
  198. package/src/lib/components/wallet-connect-button/wallet-connect-button.component.ts +240 -0
  199. package/src/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.html +24 -0
  200. package/src/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.scss +50 -0
  201. package/src/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.ts +108 -0
  202. package/src/lib/components/wallet-connected-guard/wallet-connected-guard.component.html +24 -0
  203. package/src/lib/components/wallet-connected-guard/wallet-connected-guard.component.ts +73 -0
  204. package/src/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.html +56 -0
  205. package/src/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.scss +218 -0
  206. package/src/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.ts +117 -0
  207. package/src/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.html +94 -0
  208. package/src/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.scss +272 -0
  209. package/src/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.ts +734 -0
  210. package/src/lib/components/wallet-connection-modal/wallet-connection-modal.component.html +197 -0
  211. package/src/lib/components/wallet-connection-modal/wallet-connection-modal.component.scss +678 -0
  212. package/src/lib/components/wallet-connection-modal/wallet-connection-modal.component.ts +730 -0
  213. package/src/lib/components/wallet-session-display/wallet-session-display.component.html +110 -0
  214. package/src/lib/components/wallet-session-display/wallet-session-display.component.scss +179 -0
  215. package/src/lib/components/wallet-session-display/wallet-session-display.component.ts +197 -0
  216. package/src/lib/components/wallet-transaction-status/wallet-transaction-status.component.html +65 -0
  217. package/src/lib/components/wallet-transaction-status/wallet-transaction-status.component.scss +254 -0
  218. package/src/lib/components/wallet-transaction-status/wallet-transaction-status.component.ts +206 -0
  219. package/src/lib/directives/wallet-connected.directive.ts +195 -0
  220. package/src/lib/directives/wallet-context.directive.ts +154 -0
  221. package/src/lib/directives/wallet-events.directive.ts +232 -0
  222. package/src/lib/hsuite-wallet.module.ts +210 -0
  223. package/src/lib/models/connection-config.model.ts +65 -0
  224. package/src/lib/models/provider-types.ts +164 -0
  225. package/src/lib/models/unified-account.model.ts +76 -0
  226. package/src/lib/models/wallet-context.model.ts +121 -0
  227. package/src/lib/models/wallet-events.model.ts +158 -0
  228. package/src/lib/providers/base-wallet-provider.ts +351 -0
  229. package/src/lib/providers/hsuite-native/channel-client.service.spec.ts +73 -0
  230. package/src/lib/providers/hsuite-native/channel-client.service.ts +862 -0
  231. package/src/lib/providers/hsuite-native/index.ts +8 -0
  232. package/src/lib/providers/hsuite-native-provider.ts +754 -0
  233. package/src/lib/providers/mobile-native/mobile-native.provider.spec.ts +19 -0
  234. package/src/lib/providers/p2p-native/index.ts +30 -0
  235. package/src/lib/providers/p2p-native/p2p-native.provider.spec.ts +523 -0
  236. package/src/lib/providers/p2p-native/p2p-native.provider.ts +723 -0
  237. package/src/lib/providers/p2p-native/p2p-session-manager.ts +695 -0
  238. package/src/lib/providers/wallet-error-handler.ts +349 -0
  239. package/src/lib/providers/walletconnect/core/base-signer.interface.ts +122 -0
  240. package/src/lib/providers/walletconnect/core/session-health.ts +196 -0
  241. package/src/lib/providers/walletconnect/core/walletconnect-client-manager.ts +364 -0
  242. package/src/lib/providers/walletconnect/core/walletconnect-provider.integration.spec.ts +348 -0
  243. package/src/lib/providers/walletconnect/core/walletconnect-provider.ts +826 -0
  244. package/src/lib/providers/walletconnect/core/walletconnect-session-store.ts +273 -0
  245. package/src/lib/providers/walletconnect/core/walletconnect-signing-orchestrator.ts +299 -0
  246. package/src/lib/providers/walletconnect/core/walletconnect-types.ts +48 -0
  247. package/src/lib/providers/walletconnect/index.ts +33 -0
  248. package/src/lib/providers/walletconnect/signers/hedera-signer.spec.ts +367 -0
  249. package/src/lib/providers/walletconnect/signers/hedera-signer.ts +610 -0
  250. package/src/lib/providers/walletconnect/signers/signer-factory.spec.ts +62 -0
  251. package/src/lib/providers/walletconnect/signers/signer-factory.ts +120 -0
  252. package/src/lib/providers/walletconnect/signers/xrpl-signer.spec.ts +296 -0
  253. package/src/lib/providers/walletconnect/signers/xrpl-signer.ts +478 -0
  254. package/src/lib/services/logger.service.ts +126 -0
  255. package/src/lib/services/transaction-builders/base-transaction-builder.service.ts +585 -0
  256. package/src/lib/services/transaction-builders/hedera-amount-utils.ts +84 -0
  257. package/src/lib/services/transaction-builders/hedera-transaction-builder.service.spec.ts +741 -0
  258. package/src/lib/services/transaction-builders/hedera-transaction-builder.service.ts +1285 -0
  259. package/src/lib/services/transaction-builders/index.ts +54 -0
  260. package/src/lib/services/transaction-builders/xrpl-transaction-builder.service.spec.ts +937 -0
  261. package/src/lib/services/transaction-builders/xrpl-transaction-builder.service.ts +832 -0
  262. package/src/lib/services/transaction.service.ts +346 -0
  263. package/src/lib/services/unified-wallet.service.spec.ts +1382 -0
  264. package/src/lib/services/unified-wallet.service.ts +852 -0
  265. package/src/lib/services/wallet-context.service.ts +184 -0
  266. package/src/lib/services/wallet-event-bus.service.ts +186 -0
  267. package/src/lib/services/wallet-providers.service.ts +137 -0
  268. package/src/lib/transports/chrome-extension-transport.ts +246 -0
  269. package/src/lib/utils/index.ts +14 -0
  270. package/src/lib/utils/ledger-icons.util.ts +78 -0
  271. package/test/test-setup.ts +21 -0
  272. package/test-setup.ts +63 -0
  273. package/tsconfig.build.json +11 -0
  274. package/tsconfig.json +29 -0
  275. package/tsconfig.spec.json +15 -0
  276. package/vitest.config.ts +48 -0
@@ -0,0 +1,754 @@
1
+ /**
2
+ * @file Provider implementation for HSuite Native Connect protocol.
3
+ * @module providers/hsuite-native-provider
4
+ *
5
+ * @description
6
+ * HsuiteNativeProvider implements the {@link BaseWalletProvider} interface for the
7
+ * HSuite Native Connect protocol. This provider enables secure communication between
8
+ * dApps and HSuite Wallet using the `hsc:` protocol over Nostr relays with automatic
9
+ * WebRTC P2P upgrade.
10
+ *
11
+ * Key Features:
12
+ * - **Local-First Discovery**: Uses BroadcastChannel for instant same-browser wallet detection
13
+ * - **Nostr Communication**: Uses Nostr relays for encrypted channel messaging
14
+ * - **Automatic P2P Upgrade**: Upgrades to direct WebRTC when possible for lower latency
15
+ * - **Session Persistence**: Supports automatic reconnection after page reload
16
+ * - **Cross-Platform**: Works with desktop browsers, mobile browsers, and native apps
17
+ *
18
+ * Connection Flow:
19
+ * ```
20
+ * 1. dApp calls connect() with configuration
21
+ * 2. Provider checks local discovery for same-browser wallets (instant!)
22
+ * 3. If wallet found -> sends invite via BroadcastChannel (<1ms)
23
+ * 4. If not found -> opens wallet tab/window with invite URL
24
+ * 5. Wallet receives invite and establishes channel via Nostr relay
25
+ * 6. User approves connection in wallet
26
+ * 7. Channel becomes active, accounts are available
27
+ * 8. P2P upgrade happens automatically in background
28
+ * ```
29
+ */
30
+
31
+ import { Injectable, signal, computed, inject, effect, NgZone } from '@angular/core';
32
+ import { getLogger, LocalDiscoveryService } from '@hsuite/native-connect-sdk';
33
+
34
+ import type {
35
+ ConnectionStatus,
36
+ ProviderMetadata,
37
+ ConnectionConfig,
38
+ HsuiteNativeConfig,
39
+ } from '../models/provider-types';
40
+ import { DEFAULT_WALLET_URL } from '../models/provider-types';
41
+ import type { UnifiedAccount } from '../models/unified-account.model';
42
+ import { WalletEventBus } from '../services/wallet-event-bus.service';
43
+
44
+ import {
45
+ BaseWalletProvider,
46
+ SignTransactionOptions,
47
+ SubmitTransactionOptions,
48
+ SignResult,
49
+ SubmitResult,
50
+ SignMessageOptions,
51
+ SignMessageResult,
52
+ } from './base-wallet-provider';
53
+ import { ChannelClientService } from './hsuite-native/channel-client.service';
54
+
55
+ const logger = getLogger().scoped?.('HsuiteNativeProvider') ?? getLogger();
56
+
57
+ /**
58
+ * HSuite Native Connect Provider.
59
+ *
60
+ * @description
61
+ * Angular injectable service that manages wallet connections via the HSuite Native
62
+ * Connect protocol. This provider uses the unified channel system for secure,
63
+ * encrypted communication between dApps and the HSuite Wallet.
64
+ *
65
+ * Architecture:
66
+ * - Uses {@link ChannelClientService} for unified channel-based communication
67
+ * - Implements {@link BaseWalletProvider} interface for integration with {@link UnifiedWalletService}
68
+ * - Supports both session (1:1 dApp-wallet) and party (N:N multisig) channels
69
+ * - Auto-registers with UnifiedWalletService on injection
70
+ *
71
+ * Transport States (exposed via `transportState` signal):
72
+ * - `'idle'` - No active connection
73
+ * - `'nostr-only'` - Connected via Nostr relay only
74
+ * - `'upgrading'` - P2P upgrade in progress
75
+ * - `'p2p-connected'` - Direct P2P connection established
76
+ * - `'p2p-failed'` - P2P upgrade failed, using Nostr fallback
77
+ *
78
+ * @Component({
79
+ * template: `
80
+ * <ion-badge [color]="transportColor()">
81
+ * {{ transportState() }}
82
+ * </ion-badge>
83
+ * `
84
+ * })
85
+ * export class ConnectionStatus {
86
+ * private provider = inject(HsuiteNativeProvider);
87
+ *
88
+ * transportState = this.provider.transportState;
89
+ *
90
+ * transportColor = computed(() => {
91
+ * const state = this.transportState();
92
+ * return state === 'p2p-connected' ? 'success' : 'warning';
93
+ * });
94
+ * }
95
+ * ```
96
+ *
97
+ * @publicApi
98
+ */
99
+ @Injectable({ providedIn: 'root' })
100
+ export class HsuiteNativeProvider extends BaseWalletProvider {
101
+ private readonly eventBus = inject(WalletEventBus);
102
+ private readonly zone = inject(NgZone);
103
+ private readonly channelService = inject(ChannelClientService);
104
+
105
+ readonly id = 'hsuite-native';
106
+
107
+ readonly metadata: ProviderMetadata = {
108
+ id: this.id,
109
+ name: 'HSuite Native',
110
+ type: 'hsuite-native',
111
+ description: 'Connect via HSuite Native Connect protocol',
112
+ supportsMultipleAccounts: true,
113
+ };
114
+
115
+ /**
116
+ * Error signal (reactive)
117
+ */
118
+ readonly error = signal<string | null>(null);
119
+
120
+ // Track previous connection state for disconnect detection
121
+ private previouslyConnected = false;
122
+
123
+ /**
124
+ * Local discovery service instance.
125
+ * Uses BroadcastChannel for instant, private, same-browser wallet discovery.
126
+ */
127
+ private localDiscoveryService: LocalDiscoveryService | null = null;
128
+
129
+ /**
130
+ *
131
+ */
132
+ constructor() {
133
+ super();
134
+
135
+ // Initialize local discovery service for same-browser wallet detection
136
+ this.initializeLocalDiscovery();
137
+
138
+ // Synchronize error state from channel service
139
+ effect(() => {
140
+ const channelError = this.channelService.error();
141
+ if (channelError) {
142
+ this.error.set(channelError);
143
+ }
144
+ });
145
+
146
+ // Listen to channel state changes to detect wallet-initiated disconnects
147
+ effect(() => {
148
+ const status = this.status();
149
+ const isConnected = this.channelService.isConnected();
150
+
151
+ // If we were connected but now disconnected, emit disconnect event
152
+ if (this.previouslyConnected && !isConnected && status === 'disconnected') {
153
+ logger.info('[HsuiteNativeProvider] Channel terminated');
154
+ this.eventBus.disconnected.emit({
155
+ providerId: this.id,
156
+ providerType: 'hsuite-native',
157
+ reason: 'session_terminated',
158
+ timestamp: Date.now(),
159
+ });
160
+ }
161
+
162
+ // Update tracking state
163
+ this.previouslyConnected = isConnected;
164
+ });
165
+
166
+ // Attempt automatic reconnect when session exists after reload
167
+ void this.attemptReconnect().catch((error) => {
168
+ logger.debug('[HsuiteNativeProvider] Auto-reconnect skipped', { error });
169
+ });
170
+ }
171
+
172
+ /**
173
+ * Initialize local discovery for same-browser wallet detection.
174
+ * Uses BroadcastChannel for instant, private discovery.
175
+ * Cross-device connections use QR/URL flow (no discovery needed).
176
+ */
177
+ private initializeLocalDiscovery(): void {
178
+ this.localDiscoveryService = LocalDiscoveryService.getDAppInstance();
179
+ this.localDiscoveryService.start();
180
+ }
181
+
182
+ /**
183
+ * Maps the internal channel state to the provider connection status.
184
+ *
185
+ * @description
186
+ * Computed signal that translates ChannelClientService states to
187
+ * standard ConnectionStatus values for UI binding.
188
+ *
189
+ * @returns Current connection status
190
+ */
191
+ readonly status = computed<ConnectionStatus>(() => {
192
+ const state = this.channelService.state();
193
+
194
+ switch (state) {
195
+ case 'idle':
196
+ return 'idle';
197
+ case 'connecting':
198
+ case 'pending':
199
+ return 'connecting';
200
+ case 'active':
201
+ case 'approved':
202
+ return 'connected';
203
+ case 'disconnected':
204
+ return 'disconnected';
205
+ case 'error':
206
+ return 'error';
207
+ default:
208
+ return 'idle';
209
+ }
210
+ });
211
+
212
+ /**
213
+ * Current transport state (nostr-only, upgrading, p2p-connected, p2p-failed).
214
+ * Use this to show users whether they're connected via Nostr relay or P2P.
215
+ */
216
+ readonly transportState = computed(() => this.channelService.transportState());
217
+
218
+ /**
219
+ * Connected accounts from the wallet in UnifiedAccount format.
220
+ *
221
+ * @description
222
+ * Computed signal that exposes wallet accounts from the channel service
223
+ * in the standard UnifiedAccount format for UI binding.
224
+ *
225
+ * @returns Array of connected accounts (empty when disconnected)
226
+ */
227
+ readonly accounts = computed<UnifiedAccount[]>(() => {
228
+ return this.channelService.unifiedAccounts();
229
+ });
230
+
231
+ /**
232
+ * Check if provider is connected
233
+ */
234
+ override isConnected(): boolean {
235
+ return this.channelService.isConnected();
236
+ }
237
+
238
+ /**
239
+ * Connects to HSuite Wallet via the Native Connect protocol.
240
+ *
241
+ * @description
242
+ * Initiates a connection to HSuite Wallet using the optimal method for the
243
+ * current platform:
244
+ *
245
+ * **Desktop Browsers**:
246
+ * 1. Checks if wallet is already online via Nostr discovery (instant!)
247
+ * 2. If found, sends invite directly via relay
248
+ * 3. If not found, opens wallet in new tab/window
249
+ *
250
+ * **Mobile Browsers**:
251
+ * 1. Tries hsuite: deep link to open native wallet app
252
+ * 2. Falls back to opening wallet in same tab (PWA) or new tab
253
+ *
254
+ * The connection completes when the wallet user approves the session.
255
+ *
256
+ * @param config - HSuite Native connection configuration
257
+ *
258
+ * @throws {Error} If configuration is invalid
259
+ * @throws {Error} If connection times out (default 120 seconds)
260
+ * @throws {Error} If popup is blocked and wallet cannot be opened
261
+ */
262
+ override async connect(config: ConnectionConfig): Promise<void> {
263
+ if (!this.isHsuiteNativeConfig(config)) {
264
+ throw new Error('Invalid HSuite Native configuration');
265
+ }
266
+
267
+ // Guard: Don't start a new connection if already connecting
268
+ const currentStatus = this.status();
269
+ if (currentStatus === 'connecting') {
270
+ logger.warn('Connection already in progress, ignoring duplicate request');
271
+ return;
272
+ }
273
+
274
+ logger.info('Connecting to HSuite Wallet via unified channel protocol', { config });
275
+
276
+ try {
277
+ const invite = await this.channelService.connect({
278
+ type: 'session',
279
+ appId: config.appId || 'hsuite-dapp',
280
+ appName: config.appName || 'HSuite dApp',
281
+ ledgerId: config.ledgerId,
282
+ networkId: config.networkId,
283
+ walletUrl: config.walletUrl || DEFAULT_WALLET_URL,
284
+ });
285
+
286
+ // Open wallet with invite URL
287
+ const walletUrl = config.walletUrl || DEFAULT_WALLET_URL;
288
+ const inviteUrl = this.channelService.getWalletInviteUrl(invite, walletUrl);
289
+
290
+ // Open wallet using Nostr-based discovery (works cross-origin, cross-port)
291
+ await this.openWalletWindow(inviteUrl, walletUrl, config);
292
+
293
+ // Wait for connection to be established
294
+ await this.waitForConnection();
295
+
296
+ // Run in NgZone to trigger Angular change detection
297
+ this.zone.run(() => {
298
+ const accounts = this.accounts();
299
+ this.eventBus.connected.emit({
300
+ providerId: this.id,
301
+ providerType: 'hsuite-native',
302
+ accounts,
303
+ timestamp: Date.now(),
304
+ });
305
+
306
+ logger.info('Connected successfully via unified channel', {
307
+ channelId: invite.id.slice(0, 8),
308
+ accountCount: accounts.length,
309
+ });
310
+ });
311
+ } catch (error) {
312
+ logger.error('Connection failed', { error });
313
+ throw error;
314
+ }
315
+ }
316
+
317
+ /**
318
+ * Open wallet window with LOCAL-FIRST discovery.
319
+ *
320
+ * LOCAL DISCOVERY MODEL:
321
+ * 1. Check if wallet is online in same browser via BroadcastChannel (instant!)
322
+ * 2. If not immediately found, wait briefly (500ms) for wallet heartbeat
323
+ * 3. If wallet found → send invite via BroadcastChannel (<1ms), focus existing tab
324
+ * 4. If not found → open wallet tab or use QR/deep link
325
+ *
326
+ * Cross-device connections use QR/URL flow - the invite is self-contained,
327
+ * no discovery needed.
328
+ *
329
+ * @param inviteUrl - Full URL with invite parameter
330
+ * @param walletBaseUrl - Base URL of the wallet
331
+ * @param config - Connection configuration with app metadata
332
+ */
333
+ private async openWalletWindow(
334
+ inviteUrl: string,
335
+ walletBaseUrl: string,
336
+ config?: HsuiteNativeConfig,
337
+ ): Promise<void> {
338
+ const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
339
+
340
+ // LOCAL-FIRST DISCOVERY
341
+ // Wait briefly for wallet heartbeat before opening new tab
342
+ if (this.localDiscoveryService?.active) {
343
+ // Wait up to 500ms for a wallet to announce itself
344
+ const wallet = await this.localDiscoveryService.waitForWallet({
345
+ timeoutMs: 500,
346
+ ledgerId: config?.ledgerId,
347
+ });
348
+
349
+ if (wallet) {
350
+ // Send invite directly via BroadcastChannel - instant, no network!
351
+ this.localDiscoveryService.sendInvite(
352
+ wallet.fingerprint,
353
+ inviteUrl,
354
+ config?.appId,
355
+ config?.appName,
356
+ );
357
+ logger.info('[HsuiteNativeProvider] Sent invite via local discovery', {
358
+ wallet: wallet.fingerprint.slice(0, 8),
359
+ });
360
+ return;
361
+ }
362
+ }
363
+
364
+ // MOBILE: Prefer same-tab navigation for PWA wallet
365
+ if (isMobile) {
366
+ const isSameOrigin = this.isSameOrigin(walletBaseUrl);
367
+
368
+ if (isSameOrigin) {
369
+ window.location.href = inviteUrl;
370
+ return;
371
+ } else {
372
+ // Try deep link first
373
+ const deepLinkUrl = inviteUrl.replace(/^https?:/, 'hsuite:');
374
+ try {
375
+ window.location.href = deepLinkUrl;
376
+ await new Promise((resolve) => setTimeout(resolve, 500));
377
+ } catch {
378
+ // Deep link failed, continue to open tab
379
+ }
380
+ }
381
+ }
382
+
383
+ // FALLBACK: Open wallet in a new tab (for same-browser) or show QR (cross-device)
384
+ // §29.8 SOC2 CC6.1: noopener,noreferrer prevents a compromised dApp-supplied
385
+ // inviteUrl from hijacking the dApp tab via window.opener. A side effect is
386
+ // that window.open() returns null, so we can no longer use the return value
387
+ // to detect popup-blocked; modern browsers surface that via their own UI
388
+ // and the caller's waitForConnection() timeout will error out if the user
389
+ // dismissed the popup dialog without allowing.
390
+ const walletWindow = window.open(inviteUrl, 'hsuite-wallet', 'noopener,noreferrer');
391
+ // .focus() is a no-op with noopener (walletWindow === null); fresh tabs
392
+ // are already focused in every mainstream browser.
393
+ void walletWindow;
394
+ }
395
+
396
+ /**
397
+ * Check if a URL is same origin as current page.
398
+ * @param url
399
+ */
400
+ private isSameOrigin(url: string): boolean {
401
+ try {
402
+ const walletOrigin = new URL(url).origin;
403
+ return walletOrigin === window.location.origin;
404
+ } catch {
405
+ return false;
406
+ }
407
+ }
408
+
409
+ /**
410
+ * Wait for channel connection to be established
411
+ * @param timeoutMs
412
+ */
413
+ private async waitForConnection(timeoutMs = 120000): Promise<void> {
414
+ const startTime = Date.now();
415
+
416
+ return new Promise((resolve, reject) => {
417
+ const checkConnection = () => {
418
+ if (this.channelService.isConnected()) {
419
+ resolve();
420
+ return;
421
+ }
422
+
423
+ const state = this.channelService.state();
424
+ if (state === 'error') {
425
+ reject(new Error(this.channelService.error() || 'Connection failed'));
426
+ return;
427
+ }
428
+
429
+ // Also handle disconnected state (wallet rejected or terminated)
430
+ if (state === 'disconnected') {
431
+ reject(new Error(this.channelService.error() || 'Connection rejected by wallet'));
432
+ return;
433
+ }
434
+
435
+ if (Date.now() - startTime > timeoutMs) {
436
+ reject(new Error('Connection timeout'));
437
+ return;
438
+ }
439
+
440
+ setTimeout(checkConnection, 100);
441
+ };
442
+
443
+ checkConnection();
444
+ });
445
+ }
446
+
447
+ /**
448
+ * Disconnects from the HSuite Wallet.
449
+ *
450
+ * @description
451
+ * Terminates the channel connection and clears session state. The wallet
452
+ * is notified of the disconnection. Emits a 'disconnected' event via
453
+ * WalletEventBus regardless of success or failure.
454
+ *
455
+ * @throws {Error} If disconnection fails (event still emitted)
456
+ */
457
+ override async disconnect(): Promise<void> {
458
+ logger.info('Disconnecting from HSuite Wallet');
459
+
460
+ try {
461
+ await this.channelService.disconnect();
462
+
463
+ // Emit disconnection event
464
+ this.eventBus.disconnected.emit({
465
+ providerId: this.id,
466
+ providerType: 'hsuite-native',
467
+ reason: 'user_initiated',
468
+ timestamp: Date.now(),
469
+ });
470
+
471
+ logger.info('Disconnected successfully');
472
+ } catch (error) {
473
+ logger.error('Disconnection failed', { error });
474
+ // Still emit event even if disconnect fails
475
+ this.eventBus.disconnected.emit({
476
+ providerId: this.id,
477
+ providerType: 'hsuite-native',
478
+ reason: 'error',
479
+ timestamp: Date.now(),
480
+ });
481
+ throw error;
482
+ }
483
+ }
484
+
485
+ /**
486
+ * Signs a transaction without submitting it to the network.
487
+ *
488
+ * @description
489
+ * Sends the transaction payload to the wallet for signing. The wallet
490
+ * displays the transaction details and prompts the user for approval.
491
+ * If approved, the signed transaction is returned.
492
+ *
493
+ * @param options - Transaction signing options
494
+ *
495
+ * @returns Promise resolving to the signing result with signed payload
496
+ *
497
+ * @throws {Error} If user rejects the signing request
498
+ * @throws {Error} If wallet is not connected
499
+ * @throws {Error} If channel communication fails
500
+ */
501
+ override async signTransaction(options: SignTransactionOptions): Promise<SignResult> {
502
+ logger.info('Signing transaction', { options });
503
+
504
+ try {
505
+ const response = await this.channelService.signTransaction({
506
+ accountAddress: options.accountAddress,
507
+ payload: options.payload,
508
+ ledgerId: options.ledgerId,
509
+ networkId: options.networkId,
510
+ });
511
+
512
+ logger.info('Transaction signed');
513
+
514
+ return {
515
+ signedPayload: response.signedPayload || '',
516
+ signature: response.signature,
517
+ metadata: response.metadata,
518
+ };
519
+ } catch (error) {
520
+ logger.error('Transaction signing failed', { error });
521
+ throw error;
522
+ }
523
+ }
524
+
525
+ /**
526
+ * Signs and executes a transaction atomically in a single prompt.
527
+ *
528
+ * @description
529
+ * Performs sign and submit as a single atomic operation with one user
530
+ * approval prompt. This is the recommended method for transaction submission
531
+ * as it provides better UX and matches WalletConnect's behavior.
532
+ *
533
+ * Called by {@link UnifiedWalletService.signAndExecuteTransaction} to ensure
534
+ * consistent single-prompt behavior across all provider types.
535
+ *
536
+ * @param options - Transaction submission options
537
+ *
538
+ * @returns Promise resolving to submission result with transaction ID
539
+ *
540
+ * @throws {Error} If user rejects the transaction
541
+ * @throws {Error} If wallet is not connected
542
+ * @throws {Error} If transaction submission fails
543
+ */
544
+ async signAndExecuteTransaction(options: SubmitTransactionOptions): Promise<SubmitResult> {
545
+ logger.info('signAndExecuteTransaction called (single prompt)', {
546
+ accountAddress: options.accountAddress,
547
+ ledgerId: options.ledgerId,
548
+ networkId: options.networkId,
549
+ });
550
+
551
+ return this.submitTransactionInternal(options);
552
+ }
553
+
554
+ /**
555
+ * Signs and submits a transaction to the blockchain.
556
+ *
557
+ * @description
558
+ * The **preferred method** for submitting transactions. Performs sign and
559
+ * submit as a single atomic operation requiring only ONE user approval.
560
+ *
561
+ * Advantages over separate sign/submit:
562
+ * - Single wallet prompt (better UX)
563
+ * - Matches WalletConnect's `hedera_signAndExecuteTransaction` behavior
564
+ * - Atomic operation (no partial state)
565
+ *
566
+ * @param options - Transaction submission options
567
+ *
568
+ * @returns Promise resolving to submission result with transaction ID
569
+ *
570
+ * @throws {Error} If user rejects the transaction
571
+ * @throws {Error} If wallet is not connected
572
+ * @throws {Error} If transaction submission fails
573
+ */
574
+ override async submitTransaction(options: SubmitTransactionOptions): Promise<SubmitResult> {
575
+ return this.submitTransactionInternal(options);
576
+ }
577
+
578
+ /**
579
+ * Internal implementation of sign and submit.
580
+ * Both submitTransaction() and signAndExecuteTransaction() delegate here.
581
+ *
582
+ * @param options
583
+ */
584
+ private async submitTransactionInternal(
585
+ options: SubmitTransactionOptions,
586
+ ): Promise<SubmitResult> {
587
+ logger.info('Signing and submitting transaction (single prompt)', {
588
+ accountAddress: options.accountAddress,
589
+ ledgerId: options.ledgerId,
590
+ networkId: options.networkId,
591
+ });
592
+
593
+ try {
594
+ const response = await this.channelService.signAndSubmitTransaction({
595
+ accountAddress: options.accountAddress,
596
+ payload: options.payload,
597
+ ledgerId: options.ledgerId,
598
+ networkId: options.networkId,
599
+ // Pass batch transaction fields if present
600
+ ...(options.isBatch && {
601
+ isBatch: options.isBatch,
602
+ batchKey: options.batchKey,
603
+ innerTransactions: options.innerTransactions,
604
+ }),
605
+ });
606
+
607
+ logger.info('Transaction signed and submitted successfully', {
608
+ transactionId: response.transactionId,
609
+ transactionHash: response.transactionHash?.substring(0, 16),
610
+ });
611
+
612
+ return {
613
+ transactionId: response.transactionId,
614
+ transactionHash: response.transactionHash,
615
+ metadata: response.metadata,
616
+ };
617
+ } catch (error) {
618
+ logger.error('Transaction sign+submit failed', { error });
619
+ throw error;
620
+ }
621
+ }
622
+
623
+ /**
624
+ * Signs an arbitrary message for authentication or verification.
625
+ *
626
+ * @description
627
+ * Requests the wallet to sign a non-transaction message. Common use cases:
628
+ * - Authentication challenges (prove account ownership)
629
+ * - DAO voting
630
+ * - Off-chain signatures
631
+ * - Message verification
632
+ *
633
+ * @param options - Message signing options
634
+ *
635
+ * @returns Promise resolving to signature result
636
+ *
637
+ * @throws {Error} If user rejects the signing request
638
+ * @throws {Error} If wallet is not connected
639
+ */
640
+ override async signMessage(options: SignMessageOptions): Promise<SignMessageResult> {
641
+ logger.info('Signing message', {
642
+ accountAddress: options.accountAddress,
643
+ encoding: options.encoding,
644
+ messageLength: options.message?.length,
645
+ });
646
+
647
+ try {
648
+ const response = await this.channelService.request<{
649
+ signature?: string;
650
+ publicKey?: string;
651
+ // §21.3 extended shape — new wallets include these fields.
652
+ // Older wallets (pre-§21.3) omit them; the optional chain below
653
+ // keeps us backwards-compatible with both.
654
+ algorithm?: 'ed25519' | 'ecdsa_secp256k1' | 'secp256k1';
655
+ encoding?: 'utf-8' | 'base64';
656
+ caipChainId?: string;
657
+ messageLength?: number;
658
+ metadata?: Record<string, unknown>;
659
+ }>('ledger/signMessage', {
660
+ accountAddress: options.accountAddress,
661
+ message: options.message,
662
+ encoding: options.encoding || 'utf-8',
663
+ ledgerId: options.ledgerId,
664
+ networkId: options.networkId,
665
+ });
666
+
667
+ logger.info('Message signed successfully', {
668
+ algorithm: response.algorithm,
669
+ caipChainId: response.caipChainId,
670
+ });
671
+
672
+ // Pass ALL fields through so the dApp's TransactionService sees the
673
+ // full MessageSignResult shape (§21.3 strict end-to-end contract).
674
+ return {
675
+ signature: response.signature || '',
676
+ publicKey: response.publicKey,
677
+ algorithm: response.algorithm,
678
+ encoding: response.encoding,
679
+ caipChainId: response.caipChainId,
680
+ messageLength: response.messageLength,
681
+ metadata: response.metadata,
682
+ };
683
+ } catch (error) {
684
+ logger.error('Message signing failed', { error });
685
+ throw error;
686
+ }
687
+ }
688
+
689
+ /**
690
+ * Checks if HSuite Native provider is available.
691
+ *
692
+ * @description
693
+ * HSuite Native is always available because it can use either:
694
+ * - Direct Nostr relay connection (if wallet is online)
695
+ * - Opening wallet in a new browser tab/window
696
+ * - Deep linking to native app on mobile
697
+ *
698
+ * @returns Promise always resolving to true
699
+ */
700
+ override async isAvailable(): Promise<boolean> {
701
+ // HSuite Native is always available (can open wallet window or use extension)
702
+ return true;
703
+ }
704
+
705
+ /**
706
+ * Attempts to restore a previous session and reconnect automatically.
707
+ *
708
+ * @description
709
+ * Checks for stored session data and attempts to re-establish the wallet
710
+ * connection without requiring user interaction. This is called automatically
711
+ * on provider initialization.
712
+ *
713
+ * If successful, emits a 'sessionRestored' event via WalletEventBus.
714
+ *
715
+ * @returns Promise resolving to true if reconnection succeeded, false otherwise
716
+ */
717
+ async attemptReconnect(): Promise<boolean> {
718
+ logger.info('Attempting reconnect via unified channel');
719
+
720
+ try {
721
+ const success = await this.channelService.attemptRestore();
722
+
723
+ if (success) {
724
+ const accounts = this.accounts();
725
+ const invite = this.channelService.currentInvite();
726
+
727
+ this.eventBus.sessionRestored.emit({
728
+ providerId: this.id,
729
+ sessionKey: invite?.id || '',
730
+ accounts,
731
+ metadata: { autoReconnected: true },
732
+ timestamp: Date.now(),
733
+ });
734
+
735
+ logger.info('Reconnect successful');
736
+ } else {
737
+ logger.warn('Reconnect failed - no session or unable to connect');
738
+ }
739
+
740
+ return success;
741
+ } catch (error) {
742
+ logger.error('Reconnect failed', { error });
743
+ return false;
744
+ }
745
+ }
746
+
747
+ /**
748
+ * Type guard for HSuite Native config
749
+ * @param config
750
+ */
751
+ private isHsuiteNativeConfig(config: ConnectionConfig): config is HsuiteNativeConfig {
752
+ return config.type === 'hsuite-native';
753
+ }
754
+ }