@bsv/sdk 2.1.0 → 2.1.2

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 (392) hide show
  1. package/README.md +7 -7
  2. package/dist/cjs/package.json +1 -1
  3. package/dist/cjs/src/auth/Peer.js +8 -13
  4. package/dist/cjs/src/auth/Peer.js.map +1 -1
  5. package/dist/cjs/src/auth/SessionManager.js +4 -7
  6. package/dist/cjs/src/auth/SessionManager.js.map +1 -1
  7. package/dist/cjs/src/auth/certificates/MasterCertificate.js +1 -1
  8. package/dist/cjs/src/auth/certificates/MasterCertificate.js.map +1 -1
  9. package/dist/cjs/src/auth/certificates/__tests/CompletedProtoWallet.js +1 -1
  10. package/dist/cjs/src/auth/certificates/__tests/CompletedProtoWallet.js.map +1 -1
  11. package/dist/cjs/src/auth/clients/AuthFetch.js +32 -32
  12. package/dist/cjs/src/auth/clients/AuthFetch.js.map +1 -1
  13. package/dist/cjs/src/auth/transports/SimplifiedFetchTransport.js +4 -4
  14. package/dist/cjs/src/auth/transports/SimplifiedFetchTransport.js.map +1 -1
  15. package/dist/cjs/src/compat/ECIES.js +29 -34
  16. package/dist/cjs/src/compat/ECIES.js.map +1 -1
  17. package/dist/cjs/src/compat/HD.js +9 -4
  18. package/dist/cjs/src/compat/HD.js.map +1 -1
  19. package/dist/cjs/src/compat/Mnemonic.js +12 -12
  20. package/dist/cjs/src/compat/Mnemonic.js.map +1 -1
  21. package/dist/cjs/src/identity/ContactsManager.js +212 -234
  22. package/dist/cjs/src/identity/ContactsManager.js.map +1 -1
  23. package/dist/cjs/src/identity/IdentityClient.js +199 -63
  24. package/dist/cjs/src/identity/IdentityClient.js.map +1 -1
  25. package/dist/cjs/src/kvstore/GlobalKVStore.js +30 -31
  26. package/dist/cjs/src/kvstore/GlobalKVStore.js.map +1 -1
  27. package/dist/cjs/src/kvstore/LocalKVStore.js +9 -9
  28. package/dist/cjs/src/kvstore/LocalKVStore.js.map +1 -1
  29. package/dist/cjs/src/kvstore/kvStoreInterpreter.js +2 -2
  30. package/dist/cjs/src/kvstore/kvStoreInterpreter.js.map +1 -1
  31. package/dist/cjs/src/messages/SignedMessage.js +1 -1
  32. package/dist/cjs/src/messages/SignedMessage.js.map +1 -1
  33. package/dist/cjs/src/overlay-tools/Historian.js +1 -1
  34. package/dist/cjs/src/overlay-tools/Historian.js.map +1 -1
  35. package/dist/cjs/src/overlay-tools/LookupResolver.js +213 -93
  36. package/dist/cjs/src/overlay-tools/LookupResolver.js.map +1 -1
  37. package/dist/cjs/src/overlay-tools/SHIPBroadcaster.js +75 -146
  38. package/dist/cjs/src/overlay-tools/SHIPBroadcaster.js.map +1 -1
  39. package/dist/cjs/src/primitives/AESGCM.js +2 -2
  40. package/dist/cjs/src/primitives/AESGCM.js.map +1 -1
  41. package/dist/cjs/src/primitives/BigNumber.js +164 -148
  42. package/dist/cjs/src/primitives/BigNumber.js.map +1 -1
  43. package/dist/cjs/src/primitives/Curve.js +17 -15
  44. package/dist/cjs/src/primitives/Curve.js.map +1 -1
  45. package/dist/cjs/src/primitives/ECDSA.js +12 -7
  46. package/dist/cjs/src/primitives/ECDSA.js.map +1 -1
  47. package/dist/cjs/src/primitives/Hash.js +312 -105
  48. package/dist/cjs/src/primitives/Hash.js.map +1 -1
  49. package/dist/cjs/src/primitives/JacobianPoint.js +8 -8
  50. package/dist/cjs/src/primitives/JacobianPoint.js.map +1 -1
  51. package/dist/cjs/src/primitives/K256.js +3 -3
  52. package/dist/cjs/src/primitives/K256.js.map +1 -1
  53. package/dist/cjs/src/primitives/Point.js +36 -40
  54. package/dist/cjs/src/primitives/Point.js.map +1 -1
  55. package/dist/cjs/src/primitives/PrivateKey.js +4 -4
  56. package/dist/cjs/src/primitives/PrivateKey.js.map +1 -1
  57. package/dist/cjs/src/primitives/PublicKey.js +4 -4
  58. package/dist/cjs/src/primitives/PublicKey.js.map +1 -1
  59. package/dist/cjs/src/primitives/Random.js +10 -14
  60. package/dist/cjs/src/primitives/Random.js.map +1 -1
  61. package/dist/cjs/src/primitives/ReaderUint8Array.js +6 -6
  62. package/dist/cjs/src/primitives/ReaderUint8Array.js.map +1 -1
  63. package/dist/cjs/src/primitives/Schnorr.js +2 -2
  64. package/dist/cjs/src/primitives/Schnorr.js.map +1 -1
  65. package/dist/cjs/src/primitives/Secp256r1.js +2 -1
  66. package/dist/cjs/src/primitives/Secp256r1.js.map +1 -1
  67. package/dist/cjs/src/primitives/Signature.js +8 -8
  68. package/dist/cjs/src/primitives/Signature.js.map +1 -1
  69. package/dist/cjs/src/primitives/SymmetricKey.js +123 -1
  70. package/dist/cjs/src/primitives/SymmetricKey.js.map +1 -1
  71. package/dist/cjs/src/primitives/TransactionSignature.js +20 -21
  72. package/dist/cjs/src/primitives/TransactionSignature.js.map +1 -1
  73. package/dist/cjs/src/primitives/utils.js +39 -46
  74. package/dist/cjs/src/primitives/utils.js.map +1 -1
  75. package/dist/cjs/src/registry/RegistryClient.js +31 -23
  76. package/dist/cjs/src/registry/RegistryClient.js.map +1 -1
  77. package/dist/cjs/src/remittance/RemittanceManager.js +19 -18
  78. package/dist/cjs/src/remittance/RemittanceManager.js.map +1 -1
  79. package/dist/cjs/src/remittance/modules/BasicBRC29.js.map +1 -1
  80. package/dist/cjs/src/script/Script.js +93 -170
  81. package/dist/cjs/src/script/Script.js.map +1 -1
  82. package/dist/cjs/src/script/ScriptEvaluationError.js +2 -2
  83. package/dist/cjs/src/script/ScriptEvaluationError.js.map +1 -1
  84. package/dist/cjs/src/script/Spend.js +14 -12
  85. package/dist/cjs/src/script/Spend.js.map +1 -1
  86. package/dist/cjs/src/script/templates/PushDrop.js +22 -18
  87. package/dist/cjs/src/script/templates/PushDrop.js.map +1 -1
  88. package/dist/cjs/src/script/templates/RPuzzle.js +2 -4
  89. package/dist/cjs/src/script/templates/RPuzzle.js.map +1 -1
  90. package/dist/cjs/src/storage/StorageDownloader.js +42 -9
  91. package/dist/cjs/src/storage/StorageDownloader.js.map +1 -1
  92. package/dist/cjs/src/totp/totp.js +1 -1
  93. package/dist/cjs/src/totp/totp.js.map +1 -1
  94. package/dist/cjs/src/transaction/Beef.js +239 -192
  95. package/dist/cjs/src/transaction/Beef.js.map +1 -1
  96. package/dist/cjs/src/transaction/BeefConstants.js +19 -0
  97. package/dist/cjs/src/transaction/BeefConstants.js.map +1 -0
  98. package/dist/cjs/src/transaction/BeefTx.js +12 -12
  99. package/dist/cjs/src/transaction/BeefTx.js.map +1 -1
  100. package/dist/cjs/src/transaction/MerklePath.js +4 -4
  101. package/dist/cjs/src/transaction/MerklePath.js.map +1 -1
  102. package/dist/cjs/src/transaction/Transaction.js +49 -52
  103. package/dist/cjs/src/transaction/Transaction.js.map +1 -1
  104. package/dist/cjs/src/transaction/fee-models/SatoshisPerKilobyte.js +1 -1
  105. package/dist/cjs/src/transaction/fee-models/SatoshisPerKilobyte.js.map +1 -1
  106. package/dist/cjs/src/transaction/http/BinaryFetchClient.js +9 -9
  107. package/dist/cjs/src/transaction/http/BinaryFetchClient.js.map +1 -1
  108. package/dist/cjs/src/transaction/http/DefaultHttpClient.js +9 -9
  109. package/dist/cjs/src/transaction/http/DefaultHttpClient.js.map +1 -1
  110. package/dist/cjs/src/wallet/CachedKeyDeriver.js +1 -1
  111. package/dist/cjs/src/wallet/CachedKeyDeriver.js.map +1 -1
  112. package/dist/cjs/src/wallet/WalletClient.js.map +1 -1
  113. package/dist/cjs/src/wallet/WalletError.js.map +1 -1
  114. package/dist/cjs/src/wallet/substrates/HTTPWalletJSON.js +5 -4
  115. package/dist/cjs/src/wallet/substrates/HTTPWalletJSON.js.map +1 -1
  116. package/dist/cjs/src/wallet/substrates/ReactNativeWebView.js +9 -9
  117. package/dist/cjs/src/wallet/substrates/ReactNativeWebView.js.map +1 -1
  118. package/dist/cjs/src/wallet/substrates/WalletWireProcessor.js +92 -92
  119. package/dist/cjs/src/wallet/substrates/WalletWireProcessor.js.map +1 -1
  120. package/dist/cjs/src/wallet/substrates/WalletWireTransceiver.js +387 -711
  121. package/dist/cjs/src/wallet/substrates/WalletWireTransceiver.js.map +1 -1
  122. package/dist/cjs/src/wallet/substrates/XDM.js +4 -4
  123. package/dist/cjs/src/wallet/substrates/XDM.js.map +1 -1
  124. package/dist/cjs/src/wallet/substrates/window.CWI.js +2 -2
  125. package/dist/cjs/src/wallet/substrates/window.CWI.js.map +1 -1
  126. package/dist/cjs/src/wallet/validationHelpers.js +9 -9
  127. package/dist/cjs/src/wallet/validationHelpers.js.map +1 -1
  128. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  129. package/dist/esm/src/auth/Peer.js +25 -13
  130. package/dist/esm/src/auth/Peer.js.map +1 -1
  131. package/dist/esm/src/auth/SessionManager.js +4 -7
  132. package/dist/esm/src/auth/SessionManager.js.map +1 -1
  133. package/dist/esm/src/auth/certificates/MasterCertificate.js +1 -1
  134. package/dist/esm/src/auth/certificates/MasterCertificate.js.map +1 -1
  135. package/dist/esm/src/auth/certificates/__tests/CompletedProtoWallet.js +1 -1
  136. package/dist/esm/src/auth/certificates/__tests/CompletedProtoWallet.js.map +1 -1
  137. package/dist/esm/src/auth/clients/AuthFetch.js +32 -32
  138. package/dist/esm/src/auth/clients/AuthFetch.js.map +1 -1
  139. package/dist/esm/src/auth/transports/SimplifiedFetchTransport.js +4 -4
  140. package/dist/esm/src/auth/transports/SimplifiedFetchTransport.js.map +1 -1
  141. package/dist/esm/src/compat/ECIES.js +29 -34
  142. package/dist/esm/src/compat/ECIES.js.map +1 -1
  143. package/dist/esm/src/compat/HD.js +9 -4
  144. package/dist/esm/src/compat/HD.js.map +1 -1
  145. package/dist/esm/src/compat/Mnemonic.js +12 -12
  146. package/dist/esm/src/compat/Mnemonic.js.map +1 -1
  147. package/dist/esm/src/identity/ContactsManager.js +212 -234
  148. package/dist/esm/src/identity/ContactsManager.js.map +1 -1
  149. package/dist/esm/src/identity/IdentityClient.js +199 -63
  150. package/dist/esm/src/identity/IdentityClient.js.map +1 -1
  151. package/dist/esm/src/kvstore/GlobalKVStore.js +30 -31
  152. package/dist/esm/src/kvstore/GlobalKVStore.js.map +1 -1
  153. package/dist/esm/src/kvstore/LocalKVStore.js +9 -9
  154. package/dist/esm/src/kvstore/LocalKVStore.js.map +1 -1
  155. package/dist/esm/src/kvstore/kvStoreInterpreter.js +2 -2
  156. package/dist/esm/src/kvstore/kvStoreInterpreter.js.map +1 -1
  157. package/dist/esm/src/messages/SignedMessage.js +1 -1
  158. package/dist/esm/src/messages/SignedMessage.js.map +1 -1
  159. package/dist/esm/src/overlay-tools/Historian.js +1 -1
  160. package/dist/esm/src/overlay-tools/Historian.js.map +1 -1
  161. package/dist/esm/src/overlay-tools/LookupResolver.js +213 -93
  162. package/dist/esm/src/overlay-tools/LookupResolver.js.map +1 -1
  163. package/dist/esm/src/overlay-tools/SHIPBroadcaster.js +74 -146
  164. package/dist/esm/src/overlay-tools/SHIPBroadcaster.js.map +1 -1
  165. package/dist/esm/src/primitives/AESGCM.js +2 -2
  166. package/dist/esm/src/primitives/AESGCM.js.map +1 -1
  167. package/dist/esm/src/primitives/BigNumber.js +167 -154
  168. package/dist/esm/src/primitives/BigNumber.js.map +1 -1
  169. package/dist/esm/src/primitives/Curve.js +17 -15
  170. package/dist/esm/src/primitives/Curve.js.map +1 -1
  171. package/dist/esm/src/primitives/ECDSA.js +12 -7
  172. package/dist/esm/src/primitives/ECDSA.js.map +1 -1
  173. package/dist/esm/src/primitives/Hash.js +316 -105
  174. package/dist/esm/src/primitives/Hash.js.map +1 -1
  175. package/dist/esm/src/primitives/JacobianPoint.js +8 -8
  176. package/dist/esm/src/primitives/JacobianPoint.js.map +1 -1
  177. package/dist/esm/src/primitives/K256.js +3 -3
  178. package/dist/esm/src/primitives/K256.js.map +1 -1
  179. package/dist/esm/src/primitives/Point.js +36 -40
  180. package/dist/esm/src/primitives/Point.js.map +1 -1
  181. package/dist/esm/src/primitives/PrivateKey.js +4 -4
  182. package/dist/esm/src/primitives/PrivateKey.js.map +1 -1
  183. package/dist/esm/src/primitives/PublicKey.js +4 -4
  184. package/dist/esm/src/primitives/PublicKey.js.map +1 -1
  185. package/dist/esm/src/primitives/Random.js +10 -14
  186. package/dist/esm/src/primitives/Random.js.map +1 -1
  187. package/dist/esm/src/primitives/ReaderUint8Array.js +6 -6
  188. package/dist/esm/src/primitives/ReaderUint8Array.js.map +1 -1
  189. package/dist/esm/src/primitives/Schnorr.js +1 -1
  190. package/dist/esm/src/primitives/Schnorr.js.map +1 -1
  191. package/dist/esm/src/primitives/Secp256r1.js +2 -1
  192. package/dist/esm/src/primitives/Secp256r1.js.map +1 -1
  193. package/dist/esm/src/primitives/Signature.js +8 -8
  194. package/dist/esm/src/primitives/Signature.js.map +1 -1
  195. package/dist/esm/src/primitives/SymmetricKey.js +123 -1
  196. package/dist/esm/src/primitives/SymmetricKey.js.map +1 -1
  197. package/dist/esm/src/primitives/TransactionSignature.js +20 -21
  198. package/dist/esm/src/primitives/TransactionSignature.js.map +1 -1
  199. package/dist/esm/src/primitives/utils.js +39 -48
  200. package/dist/esm/src/primitives/utils.js.map +1 -1
  201. package/dist/esm/src/registry/RegistryClient.js +31 -23
  202. package/dist/esm/src/registry/RegistryClient.js.map +1 -1
  203. package/dist/esm/src/remittance/RemittanceManager.js +19 -18
  204. package/dist/esm/src/remittance/RemittanceManager.js.map +1 -1
  205. package/dist/esm/src/remittance/modules/BasicBRC29.js.map +1 -1
  206. package/dist/esm/src/script/Script.js +93 -170
  207. package/dist/esm/src/script/Script.js.map +1 -1
  208. package/dist/esm/src/script/ScriptEvaluationError.js +2 -2
  209. package/dist/esm/src/script/ScriptEvaluationError.js.map +1 -1
  210. package/dist/esm/src/script/Spend.js +14 -12
  211. package/dist/esm/src/script/Spend.js.map +1 -1
  212. package/dist/esm/src/script/templates/PushDrop.js +4 -3
  213. package/dist/esm/src/script/templates/PushDrop.js.map +1 -1
  214. package/dist/esm/src/script/templates/RPuzzle.js +2 -4
  215. package/dist/esm/src/script/templates/RPuzzle.js.map +1 -1
  216. package/dist/esm/src/storage/StorageDownloader.js +1 -1
  217. package/dist/esm/src/storage/StorageDownloader.js.map +1 -1
  218. package/dist/esm/src/totp/totp.js +1 -1
  219. package/dist/esm/src/totp/totp.js.map +1 -1
  220. package/dist/esm/src/transaction/Beef.js +229 -186
  221. package/dist/esm/src/transaction/Beef.js.map +1 -1
  222. package/dist/esm/src/transaction/BeefConstants.js +16 -0
  223. package/dist/esm/src/transaction/BeefConstants.js.map +1 -0
  224. package/dist/esm/src/transaction/BeefTx.js +3 -3
  225. package/dist/esm/src/transaction/BeefTx.js.map +1 -1
  226. package/dist/esm/src/transaction/MerklePath.js +4 -4
  227. package/dist/esm/src/transaction/MerklePath.js.map +1 -1
  228. package/dist/esm/src/transaction/Transaction.js +49 -52
  229. package/dist/esm/src/transaction/Transaction.js.map +1 -1
  230. package/dist/esm/src/transaction/fee-models/SatoshisPerKilobyte.js +1 -1
  231. package/dist/esm/src/transaction/fee-models/SatoshisPerKilobyte.js.map +1 -1
  232. package/dist/esm/src/transaction/http/BinaryFetchClient.js +9 -9
  233. package/dist/esm/src/transaction/http/BinaryFetchClient.js.map +1 -1
  234. package/dist/esm/src/transaction/http/DefaultHttpClient.js +9 -9
  235. package/dist/esm/src/transaction/http/DefaultHttpClient.js.map +1 -1
  236. package/dist/esm/src/wallet/CachedKeyDeriver.js +1 -1
  237. package/dist/esm/src/wallet/CachedKeyDeriver.js.map +1 -1
  238. package/dist/esm/src/wallet/WalletClient.js.map +1 -1
  239. package/dist/esm/src/wallet/WalletError.js.map +1 -1
  240. package/dist/esm/src/wallet/substrates/HTTPWalletJSON.js +5 -4
  241. package/dist/esm/src/wallet/substrates/HTTPWalletJSON.js.map +1 -1
  242. package/dist/esm/src/wallet/substrates/ReactNativeWebView.js +9 -9
  243. package/dist/esm/src/wallet/substrates/ReactNativeWebView.js.map +1 -1
  244. package/dist/esm/src/wallet/substrates/WalletWireProcessor.js +92 -92
  245. package/dist/esm/src/wallet/substrates/WalletWireProcessor.js.map +1 -1
  246. package/dist/esm/src/wallet/substrates/WalletWireTransceiver.js +387 -711
  247. package/dist/esm/src/wallet/substrates/WalletWireTransceiver.js.map +1 -1
  248. package/dist/esm/src/wallet/substrates/XDM.js +4 -4
  249. package/dist/esm/src/wallet/substrates/XDM.js.map +1 -1
  250. package/dist/esm/src/wallet/substrates/window.CWI.js +2 -2
  251. package/dist/esm/src/wallet/substrates/window.CWI.js.map +1 -1
  252. package/dist/esm/src/wallet/validationHelpers.js +9 -9
  253. package/dist/esm/src/wallet/validationHelpers.js.map +1 -1
  254. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  255. package/dist/types/src/auth/Peer.d.ts +13 -0
  256. package/dist/types/src/auth/Peer.d.ts.map +1 -1
  257. package/dist/types/src/auth/SessionManager.d.ts.map +1 -1
  258. package/dist/types/src/auth/clients/AuthFetch.d.ts.map +1 -1
  259. package/dist/types/src/compat/ECIES.d.ts.map +1 -1
  260. package/dist/types/src/compat/HD.d.ts.map +1 -1
  261. package/dist/types/src/identity/ContactsManager.d.ts +31 -2
  262. package/dist/types/src/identity/ContactsManager.d.ts.map +1 -1
  263. package/dist/types/src/identity/IdentityClient.d.ts +75 -10
  264. package/dist/types/src/identity/IdentityClient.d.ts.map +1 -1
  265. package/dist/types/src/kvstore/GlobalKVStore.d.ts.map +1 -1
  266. package/dist/types/src/overlay-tools/LookupResolver.d.ts +73 -2
  267. package/dist/types/src/overlay-tools/LookupResolver.d.ts.map +1 -1
  268. package/dist/types/src/overlay-tools/SHIPBroadcaster.d.ts +18 -3
  269. package/dist/types/src/overlay-tools/SHIPBroadcaster.d.ts.map +1 -1
  270. package/dist/types/src/primitives/BigNumber.d.ts +13 -3
  271. package/dist/types/src/primitives/BigNumber.d.ts.map +1 -1
  272. package/dist/types/src/primitives/Curve.d.ts.map +1 -1
  273. package/dist/types/src/primitives/ECDSA.d.ts.map +1 -1
  274. package/dist/types/src/primitives/Hash.d.ts +22 -17
  275. package/dist/types/src/primitives/Hash.d.ts.map +1 -1
  276. package/dist/types/src/primitives/JacobianPoint.d.ts +3 -1
  277. package/dist/types/src/primitives/JacobianPoint.d.ts.map +1 -1
  278. package/dist/types/src/primitives/Point.d.ts.map +1 -1
  279. package/dist/types/src/primitives/Random.d.ts +2 -2
  280. package/dist/types/src/primitives/Random.d.ts.map +1 -1
  281. package/dist/types/src/primitives/ReaderUint8Array.d.ts.map +1 -1
  282. package/dist/types/src/primitives/Schnorr.d.ts +2 -1
  283. package/dist/types/src/primitives/Schnorr.d.ts.map +1 -1
  284. package/dist/types/src/primitives/Secp256r1.d.ts.map +1 -1
  285. package/dist/types/src/primitives/SymmetricKey.d.ts.map +1 -1
  286. package/dist/types/src/primitives/utils.d.ts +2 -4
  287. package/dist/types/src/primitives/utils.d.ts.map +1 -1
  288. package/dist/types/src/registry/RegistryClient.d.ts.map +1 -1
  289. package/dist/types/src/remittance/RemittanceManager.d.ts.map +1 -1
  290. package/dist/types/src/remittance/modules/BasicBRC29.d.ts.map +1 -1
  291. package/dist/types/src/script/Script.d.ts +15 -8
  292. package/dist/types/src/script/Script.d.ts.map +1 -1
  293. package/dist/types/src/script/Spend.d.ts.map +1 -1
  294. package/dist/types/src/script/templates/PushDrop.d.ts +3 -1
  295. package/dist/types/src/script/templates/PushDrop.d.ts.map +1 -1
  296. package/dist/types/src/script/templates/RPuzzle.d.ts.map +1 -1
  297. package/dist/types/src/transaction/Beef.d.ts +46 -8
  298. package/dist/types/src/transaction/Beef.d.ts.map +1 -1
  299. package/dist/types/src/transaction/BeefConstants.d.ts +15 -0
  300. package/dist/types/src/transaction/BeefConstants.d.ts.map +1 -0
  301. package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
  302. package/dist/types/src/wallet/CachedKeyDeriver.d.ts.map +1 -1
  303. package/dist/types/src/wallet/KeyDeriver.d.ts +1 -1
  304. package/dist/types/src/wallet/KeyDeriver.d.ts.map +1 -1
  305. package/dist/types/src/wallet/Wallet.interfaces.d.ts +18 -3
  306. package/dist/types/src/wallet/Wallet.interfaces.d.ts.map +1 -1
  307. package/dist/types/src/wallet/WalletClient.d.ts +8 -8
  308. package/dist/types/src/wallet/WalletClient.d.ts.map +1 -1
  309. package/dist/types/src/wallet/substrates/HTTPWalletJSON.d.ts +7 -7
  310. package/dist/types/src/wallet/substrates/HTTPWalletJSON.d.ts.map +1 -1
  311. package/dist/types/src/wallet/substrates/WalletWireTransceiver.d.ts +36 -7
  312. package/dist/types/src/wallet/substrates/WalletWireTransceiver.d.ts.map +1 -1
  313. package/dist/types/src/wallet/substrates/window.CWI.d.ts +9 -9
  314. package/dist/types/src/wallet/substrates/window.CWI.d.ts.map +1 -1
  315. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  316. package/dist/umd/bundle.js +3 -3
  317. package/package.json +1 -1
  318. package/src/auth/Peer.ts +26 -13
  319. package/src/auth/SessionManager.ts +4 -7
  320. package/src/auth/certificates/MasterCertificate.ts +1 -1
  321. package/src/auth/certificates/__tests/CompletedProtoWallet.ts +1 -1
  322. package/src/auth/clients/AuthFetch.ts +41 -41
  323. package/src/auth/transports/SimplifiedFetchTransport.ts +4 -4
  324. package/src/compat/ECIES.ts +29 -34
  325. package/src/compat/HD.ts +10 -5
  326. package/src/compat/Mnemonic.ts +11 -11
  327. package/src/compat/__tests/HD.test.ts +19 -0
  328. package/src/identity/ContactsManager.ts +236 -258
  329. package/src/identity/IdentityClient.ts +244 -71
  330. package/src/identity/__tests/IdentityClient.additional.test.ts +150 -1
  331. package/src/identity/__tests/IdentityClient.test.ts +27 -3
  332. package/src/kvstore/GlobalKVStore.ts +31 -32
  333. package/src/kvstore/LocalKVStore.ts +8 -8
  334. package/src/kvstore/kvStoreInterpreter.ts +2 -2
  335. package/src/messages/SignedMessage.ts +1 -1
  336. package/src/overlay-tools/Historian.ts +1 -1
  337. package/src/overlay-tools/LookupResolver.ts +264 -90
  338. package/src/overlay-tools/SHIPBroadcaster.ts +92 -168
  339. package/src/primitives/AESGCM.ts +2 -2
  340. package/src/primitives/BigNumber.ts +122 -113
  341. package/src/primitives/Curve.ts +16 -15
  342. package/src/primitives/ECDSA.ts +10 -8
  343. package/src/primitives/Hash.ts +381 -146
  344. package/src/primitives/JacobianPoint.ts +13 -11
  345. package/src/primitives/K256.ts +3 -3
  346. package/src/primitives/Point.ts +35 -38
  347. package/src/primitives/PrivateKey.ts +3 -3
  348. package/src/primitives/PublicKey.ts +3 -3
  349. package/src/primitives/Random.ts +11 -14
  350. package/src/primitives/ReaderUint8Array.ts +7 -7
  351. package/src/primitives/Schnorr.ts +2 -1
  352. package/src/primitives/Secp256r1.ts +2 -1
  353. package/src/primitives/Signature.ts +8 -8
  354. package/src/primitives/SymmetricKey.ts +145 -1
  355. package/src/primitives/TransactionSignature.ts +16 -16
  356. package/src/primitives/__tests/Hash.additional.test.ts +65 -0
  357. package/src/primitives/__tests/Hash.test.ts +6 -1
  358. package/src/primitives/utils.ts +37 -47
  359. package/src/registry/RegistryClient.ts +25 -25
  360. package/src/remittance/RemittanceManager.ts +17 -18
  361. package/src/remittance/modules/BasicBRC29.ts +2 -5
  362. package/src/script/Script.ts +114 -170
  363. package/src/script/ScriptEvaluationError.ts +2 -2
  364. package/src/script/Spend.ts +14 -15
  365. package/src/script/templates/PushDrop.ts +5 -3
  366. package/src/script/templates/RPuzzle.ts +2 -4
  367. package/src/storage/StorageDownloader.ts +1 -1
  368. package/src/totp/totp.ts +1 -1
  369. package/src/transaction/Beef.ts +241 -203
  370. package/src/transaction/BeefConstants.ts +16 -0
  371. package/src/transaction/BeefTx.ts +3 -3
  372. package/src/transaction/MerklePath.ts +4 -4
  373. package/src/transaction/Transaction.ts +48 -51
  374. package/src/transaction/fee-models/SatoshisPerKilobyte.ts +1 -1
  375. package/src/transaction/http/BinaryFetchClient.ts +8 -8
  376. package/src/transaction/http/DefaultHttpClient.ts +8 -8
  377. package/src/wallet/CachedKeyDeriver.ts +8 -6
  378. package/src/wallet/KeyDeriver.ts +1 -1
  379. package/src/wallet/Wallet.interfaces.ts +18 -5
  380. package/src/wallet/WalletClient.ts +9 -9
  381. package/src/wallet/WalletError.ts +1 -1
  382. package/src/wallet/__tests/WalletClient.substrate.test.ts +10 -6
  383. package/src/wallet/substrates/HTTPWalletJSON.ts +22 -21
  384. package/src/wallet/substrates/ReactNativeWebView.ts +9 -9
  385. package/src/wallet/substrates/WalletWireProcessor.ts +83 -83
  386. package/src/wallet/substrates/WalletWireTransceiver.ts +528 -938
  387. package/src/wallet/substrates/XDM.ts +4 -4
  388. package/src/wallet/substrates/__tests/HTTPWalletJSON.test.ts +38 -25
  389. package/src/wallet/substrates/__tests/ReactNativeWebView.test.ts +174 -0
  390. package/src/wallet/substrates/__tests/window.CWI.test.ts +256 -0
  391. package/src/wallet/substrates/window.CWI.ts +11 -11
  392. package/src/wallet/validationHelpers.ts +9 -9
@@ -18,6 +18,74 @@ import { PrivateKey, Utils } from '../primitives/index.js'
18
18
  import { LookupResolver, SHIPBroadcaster, TopicBroadcaster, withDoubleSpendRetry } from '../overlay-tools/index.js'
19
19
  import { ContactsManager, Contact } from './ContactsManager.js'
20
20
 
21
+ /**
22
+ * Maximum number of identity certificates to parse synchronously before yielding to the
23
+ * event loop. Keeps the main thread responsive when an overlay query returns many results
24
+ * (e.g. a bulk enrichment of N identityKeys).
25
+ */
26
+ const PARSE_BATCH_SIZE = 32
27
+
28
+ /**
29
+ * Yield control to the event loop so queued microtasks / timers can run. Uses
30
+ * `scheduler.yield()` when available (Chromium) or a 0ms macrotask fallback.
31
+ */
32
+ async function yieldToEventLoop (): Promise<void> {
33
+ const sched = (globalThis as any).scheduler
34
+ if (sched != null && typeof sched.yield === 'function') {
35
+ return await sched.yield()
36
+ }
37
+ return await new Promise<void>((resolve) => setTimeout(resolve, 0))
38
+ }
39
+
40
+ /** Options for {@link IdentityClient.resolveByIdentityKey}. */
41
+ export interface ResolveByIdentityKeyOptions {
42
+ /**
43
+ * Opt-in to consulting personal contacts before/alongside the overlay. Default `false`.
44
+ *
45
+ * Most callers (including any client without a populated contacts basket) pay no benefit
46
+ * from the contacts path and incur its setup cost. Set `true` only in UI contexts where
47
+ * the user has likely saved contacts and a local cache hit is preferable to a fresh overlay
48
+ * answer.
49
+ */
50
+ useContacts?: boolean
51
+ /**
52
+ * Legacy alias for {@link useContacts}. When provided, takes precedence over the new flag.
53
+ * Kept for binary compatibility — new code should use `useContacts`.
54
+ */
55
+ overrideWithContacts?: boolean
56
+ /**
57
+ * When `true` (and {@link useContacts} is also true), fire contacts and overlay in parallel
58
+ * rather than short-circuiting on a contacts hit. Use only when callers specifically need a
59
+ * fresh overlay answer alongside any cached contact record.
60
+ */
61
+ parallel?: boolean
62
+ }
63
+
64
+ /** Options for {@link IdentityClient.resolveByAttributes}. */
65
+ export interface ResolveByAttributesOptions {
66
+ /**
67
+ * Opt-in to consulting personal contacts before/alongside the overlay. Default `false`.
68
+ * See {@link ResolveByIdentityKeyOptions.useContacts}.
69
+ */
70
+ useContacts?: boolean
71
+ /** Legacy alias for {@link useContacts}. Takes precedence when provided. */
72
+ overrideWithContacts?: boolean
73
+ /**
74
+ * When `true` (and {@link useContacts} is also true), fire contacts and overlay in parallel.
75
+ */
76
+ parallel?: boolean
77
+ }
78
+
79
+ /** Normalize either legacy boolean / new options object into a canonical { useContacts, parallel }. */
80
+ function normalizeOpts (
81
+ raw: boolean | ResolveByIdentityKeyOptions | ResolveByAttributesOptions | undefined
82
+ ): { useContacts: boolean, parallel: boolean } {
83
+ if (raw === undefined) return { useContacts: false, parallel: false }
84
+ if (typeof raw === 'boolean') return { useContacts: raw, parallel: false }
85
+ const useContacts = raw.overrideWithContacts ?? raw.useContacts ?? false
86
+ return { useContacts, parallel: raw.parallel === true }
87
+ }
88
+
21
89
  /**
22
90
  * IdentityClient lets you discover who others are, and let the world know who you are.
23
91
  */
@@ -69,7 +137,8 @@ export class IdentityClient {
69
137
  certificate.signature
70
138
  )
71
139
  await masterCert.verify()
72
- } catch (error) {
140
+ } catch (_certVerificationError) {
141
+ // Low-level cert error details are suppressed — surface a user-facing message only
73
142
  throw new Error('Public reveal failed: Certificate verification failed!')
74
143
  }
75
144
 
@@ -97,7 +166,7 @@ export class IdentityClient {
97
166
  true,
98
167
  true
99
168
  )
100
- // TODO: Consider verification and if this is necessary
169
+ // Consider verification and if this is necessary
101
170
  // counterpartyCanVerifyMyOwnership: true
102
171
 
103
172
  const { tx } = await this.wallet.createAction(
@@ -128,67 +197,125 @@ export class IdentityClient {
128
197
  }
129
198
 
130
199
  /**
131
- * Resolves displayable identity certificates, issued to a given identity key by a trusted certifier.
200
+ * Resolves displayable identity certificates issued to a given identity key.
201
+ *
202
+ * **Default behavior (changed): contacts are NOT consulted.** Most clients have no
203
+ * contacts saved locally, so the previous "contacts-first" default paid setup cost for no
204
+ * gain. Pass `{ useContacts: true }` to opt in — appropriate when you know the user has
205
+ * saved contacts and prefers a local hit over a fresh overlay answer.
206
+ *
207
+ * When `useContacts: true`:
208
+ * - Default short-circuits: if a contact matches, the overlay is skipped entirely.
209
+ * - `{ parallel: true }` fires contacts and overlay in parallel; contact wins on hit.
132
210
  *
133
- * @param {DiscoverByIdentityKeyArgs} args - Arguments for requesting the discovery based on the identity key.
134
- * @param {boolean} [overrideWithContacts=true] - Whether to override the results with personal contacts if available.
135
- * @returns {Promise<DisplayableIdentity[]>} The promise resolves to displayable identities.
211
+ * @param args - Arguments for requesting the discovery based on the identity key.
212
+ * @param opts - Boolean (legacy) or options object. Boolean `true` `{ useContacts: true }`.
136
213
  */
137
214
  async resolveByIdentityKey (
138
215
  args: DiscoverByIdentityKeyArgs,
139
- overrideWithContacts = true
216
+ opts: boolean | ResolveByIdentityKeyOptions = false
140
217
  ): Promise<DisplayableIdentity[]> {
141
- // Run both queries in parallel for better performance
218
+ const { useContacts, parallel } = normalizeOpts(opts)
219
+
220
+ // Fast path: skip contacts entirely. Default — straight overlay query,
221
+ // no listOutputs / decrypt / cache churn.
222
+ if (!useContacts) {
223
+ const certificatesResult = await this.wallet.discoverByIdentityKey(args, this.originator)
224
+ const certs = certificatesResult?.certificates ?? []
225
+ return await IdentityClient.parseIdentities(certs)
226
+ }
227
+
228
+ if (!parallel) {
229
+ const contacts = await this.contactsManager.getContacts(args.identityKey)
230
+ if (contacts.length > 0) return contacts
231
+
232
+ const certificatesResult = await this.wallet.discoverByIdentityKey(args, this.originator)
233
+ const certs = certificatesResult?.certificates ?? []
234
+ return await IdentityClient.parseIdentities(certs)
235
+ }
236
+
142
237
  const [contacts, certificatesResult] = await Promise.all([
143
- overrideWithContacts
144
- ? this.contactsManager.getContacts(args.identityKey)
145
- : Promise.resolve([]),
238
+ this.contactsManager.getContacts(args.identityKey),
146
239
  this.wallet.discoverByIdentityKey(args, this.originator)
147
240
  ])
148
241
 
149
- // Override results with personal contacts if available
150
- if (contacts.length > 0) {
151
- return contacts
152
- }
153
-
242
+ if (contacts.length > 0) return contacts
154
243
  const certs = certificatesResult?.certificates ?? []
155
- return certs.map((cert) => {
156
- return IdentityClient.parseIdentity(cert)
157
- })
244
+ return await IdentityClient.parseIdentities(certs)
158
245
  }
159
246
 
160
247
  /**
161
- * Resolves displayable identity certificates by specific identity attributes, issued by a trusted entity.
248
+ * Resolves displayable identity certificates by specific identity attributes.
162
249
  *
163
- * @param {DiscoverByAttributesArgs} args - Attributes and optional parameters used to discover certificates.
164
- * @param {boolean} [overrideWithContacts=true] - Whether to override the results with personal contacts if available.
165
- * @returns {Promise<DisplayableIdentity[]>} The promise resolves to displayable identities.
250
+ * **Default behavior (changed): contacts are NOT consulted.** See
251
+ * {@link resolveByIdentityKey} for the reasoning. Pass `{ useContacts: true }` to opt in.
252
+ *
253
+ * @param args - Attributes and optional parameters used to discover certificates.
254
+ * @param opts - Boolean (legacy) or options object. Boolean `true` ≡ `{ useContacts: true }`.
166
255
  */
167
256
  async resolveByAttributes (
168
257
  args: DiscoverByAttributesArgs,
169
- overrideWithContacts = true
258
+ opts: boolean | ResolveByAttributesOptions = false
170
259
  ): Promise<DisplayableIdentity[]> {
171
- // Run both queries in parallel for better performance
260
+ const { useContacts, parallel } = normalizeOpts(opts)
261
+
262
+ // Fast path: skip contacts entirely.
263
+ if (!useContacts) {
264
+ const certificatesResult = await this.wallet.discoverByAttributes(args, this.originator)
265
+ const certs = certificatesResult?.certificates ?? []
266
+ return await IdentityClient.parseIdentities(certs)
267
+ }
268
+
269
+ if (!parallel) {
270
+ const contacts = await this.contactsManager.getContacts()
271
+ const matches = this.matchContactsByAttributes(contacts, args)
272
+ if (matches.length > 0) return matches
273
+
274
+ const certificatesResult = await this.wallet.discoverByAttributes(args, this.originator)
275
+ const certs = certificatesResult?.certificates ?? []
276
+ if (contacts.length === 0) return await IdentityClient.parseIdentities(certs)
277
+ const contactByKey = new Map<PubKeyHex, Contact>(
278
+ contacts.map((contact) => [contact.identityKey, contact] as const)
279
+ )
280
+ return await IdentityClient.parseIdentitiesWithOverrides(certs, contactByKey)
281
+ }
282
+
172
283
  const [contacts, certificatesResult] = await Promise.all([
173
- overrideWithContacts
174
- ? this.contactsManager.getContacts()
175
- : Promise.resolve([]),
284
+ this.contactsManager.getContacts(),
176
285
  this.wallet.discoverByAttributes(args, this.originator)
177
286
  ])
178
287
 
179
- // Fast lookup by identityKey
288
+ const certs = certificatesResult?.certificates ?? []
289
+ if (contacts.length === 0) return await IdentityClient.parseIdentities(certs)
180
290
  const contactByKey = new Map<PubKeyHex, Contact>(
181
291
  contacts.map((contact) => [contact.identityKey, contact] as const)
182
292
  )
293
+ return await IdentityClient.parseIdentitiesWithOverrides(certs, contactByKey)
294
+ }
183
295
 
184
- // Guard if certificates might be absent
185
- const certs = certificatesResult?.certificates ?? []
186
-
187
- // Parse certificates and substitute with contacts where available
188
- return certs.map(
189
- (cert) =>
190
- contactByKey.get(cert.subject) ?? IdentityClient.parseIdentity(cert)
191
- )
296
+ /**
297
+ * Best-effort match of contacts against a `DiscoverByAttributesArgs.attributes` shape.
298
+ * Used by the contacts-first path of {@link resolveByAttributes} to decide whether the overlay
299
+ * can be skipped. Compares string-valued attributes against same-named fields on the contact's
300
+ * decrypted record. Returns the subset of contacts that match every supplied attribute.
301
+ */
302
+ private matchContactsByAttributes (
303
+ contacts: Contact[],
304
+ args: DiscoverByAttributesArgs
305
+ ): Contact[] {
306
+ const attrs = (args).attributes
307
+ if (attrs == null || typeof attrs !== 'object' || Array.isArray(attrs)) return []
308
+ const entries = Object.entries(attrs as Record<string, unknown>).filter(
309
+ ([, v]) => typeof v === 'string' && v.length > 0
310
+ ) as Array<[string, string]>
311
+ if (entries.length === 0) return []
312
+ return contacts.filter((contact) => {
313
+ const bag: Record<string, unknown> = {
314
+ name: contact.name,
315
+ identityKey: contact.identityKey
316
+ }
317
+ return entries.every(([k, v]) => typeof bag[k] === 'string' && (bag[k] as string).toLowerCase() === v.toLowerCase())
318
+ })
192
319
  }
193
320
 
194
321
  /**
@@ -328,6 +455,45 @@ export class IdentityClient {
328
455
  return await this.contactsManager.removeContact(identityKey)
329
456
  }
330
457
 
458
+ /**
459
+ * Parse an array of certificates into DisplayableIdentity records, yielding to the
460
+ * event loop every {@link PARSE_BATCH_SIZE} entries so large result sets don't hog
461
+ * the main thread. Equivalent to `certs.map(parseIdentity)` for small inputs.
462
+ */
463
+ static async parseIdentities (certs: IdentityCertificate[]): Promise<DisplayableIdentity[]> {
464
+ const n = certs.length
465
+ if (n <= PARSE_BATCH_SIZE) {
466
+ return certs.map((c) => IdentityClient.parseIdentity(c))
467
+ }
468
+ const out: DisplayableIdentity[] = new Array(n)
469
+ for (let i = 0; i < n; i++) {
470
+ out[i] = IdentityClient.parseIdentity(certs[i])
471
+ if ((i + 1) % PARSE_BATCH_SIZE === 0) await yieldToEventLoop()
472
+ }
473
+ return out
474
+ }
475
+
476
+ /**
477
+ * Same as {@link parseIdentities} but consults a contact override map keyed by subject
478
+ * identity key. Used by `resolveByAttributes` when contacts are loaded.
479
+ */
480
+ static async parseIdentitiesWithOverrides (
481
+ certs: IdentityCertificate[],
482
+ contactByKey: Map<PubKeyHex, Contact>
483
+ ): Promise<DisplayableIdentity[]> {
484
+ const n = certs.length
485
+ if (n <= PARSE_BATCH_SIZE) {
486
+ return certs.map((cert) => contactByKey.get(cert.subject) ?? IdentityClient.parseIdentity(cert))
487
+ }
488
+ const out: DisplayableIdentity[] = new Array(n)
489
+ for (let i = 0; i < n; i++) {
490
+ const cert = certs[i]
491
+ out[i] = contactByKey.get(cert.subject) ?? IdentityClient.parseIdentity(cert)
492
+ if ((i + 1) % PARSE_BATCH_SIZE === 0) await yieldToEventLoop()
493
+ }
494
+ return out
495
+ }
496
+
331
497
  /**
332
498
  * Parse out identity and certifier attributes to display from an IdentityCertificate
333
499
  * @param identityToParse - The Identity Certificate to parse
@@ -346,42 +512,42 @@ export class IdentityClient {
346
512
  avatarURL = decryptedFields.profilePhoto
347
513
  badgeLabel = `X account certified by ${certifierInfo.name}`
348
514
  badgeIconURL = certifierInfo.iconUrl
349
- badgeClickURL = 'https://socialcert.net' // TODO Make a specific page for this.
515
+ badgeClickURL = 'https://socialcert.net' // (no dedicated page yet)
350
516
  break
351
517
  case KNOWN_IDENTITY_TYPES.discordCert:
352
518
  name = decryptedFields.userName
353
519
  avatarURL = decryptedFields.profilePhoto
354
520
  badgeLabel = `Discord account certified by ${certifierInfo.name}`
355
521
  badgeIconURL = certifierInfo.iconUrl
356
- badgeClickURL = 'https://socialcert.net' // TODO Make a specific page for this.
522
+ badgeClickURL = 'https://socialcert.net' // (no dedicated page yet)
357
523
  break
358
524
  case KNOWN_IDENTITY_TYPES.emailCert:
359
525
  name = decryptedFields.email
360
526
  avatarURL = 'XUTZxep7BBghAJbSBwTjNfmcsDdRFs5EaGEgkESGSgjJVYgMEizu'
361
527
  badgeLabel = `Email certified by ${certifierInfo.name}`
362
528
  badgeIconURL = certifierInfo.iconUrl
363
- badgeClickURL = 'https://socialcert.net' // TODO Make a specific page for this.
529
+ badgeClickURL = 'https://socialcert.net' // (no dedicated page yet)
364
530
  break
365
531
  case KNOWN_IDENTITY_TYPES.phoneCert:
366
532
  name = decryptedFields.phoneNumber
367
533
  avatarURL = 'XUTLxtX3ELNUwRhLwL7kWNGbdnFM8WG2eSLv84J7654oH8HaJWrU'
368
534
  badgeLabel = `Phone certified by ${certifierInfo.name}`
369
535
  badgeIconURL = certifierInfo.iconUrl
370
- badgeClickURL = 'https://socialcert.net' // TODO Make a specific page for this.
536
+ badgeClickURL = 'https://socialcert.net' // (no dedicated page yet)
371
537
  break
372
538
  case KNOWN_IDENTITY_TYPES.identiCert:
373
539
  name = `${decryptedFields.firstName} ${decryptedFields.lastName}`
374
540
  avatarURL = decryptedFields.profilePhoto
375
541
  badgeLabel = `Government ID certified by ${certifierInfo.name}`
376
542
  badgeIconURL = certifierInfo.iconUrl
377
- badgeClickURL = 'https://identicert.me' // TODO Make a specific page for this.
543
+ badgeClickURL = 'https://identicert.me' // (no dedicated page yet)
378
544
  break
379
545
  case KNOWN_IDENTITY_TYPES.registrant:
380
546
  name = decryptedFields.name
381
547
  avatarURL = decryptedFields.icon
382
548
  badgeLabel = `Entity certified by ${certifierInfo.name}`
383
549
  badgeIconURL = certifierInfo.iconUrl
384
- badgeClickURL = 'https://bsv-blockchain.github.io/ts-sdk/reference/identity/' // TODO: Make this doc page exist
550
+ badgeClickURL = 'https://bsv-blockchain.github.io/ts-sdk/reference/identity/' // (no dedicated page yet)
385
551
  break
386
552
  case KNOWN_IDENTITY_TYPES.coolCert:
387
553
  name = decryptedFields.cool === 'true' ? 'Cool Person!' : 'Not cool!'
@@ -392,14 +558,14 @@ export class IdentityClient {
392
558
  badgeLabel =
393
559
  'Represents the ability for anyone to access this information.'
394
560
  badgeIconURL = 'XUUV39HVPkpmMzYNTx7rpKzJvXfeiVyQWg2vfSpjBAuhunTCA9uG'
395
- badgeClickURL = 'https://bsv-blockchain.github.io/ts-sdk/reference/identity/' // TODO: Make this doc page exist
561
+ badgeClickURL = 'https://bsv-blockchain.github.io/ts-sdk/reference/identity/' // (no dedicated page yet)
396
562
  break
397
563
  case KNOWN_IDENTITY_TYPES.self:
398
564
  name = 'You'
399
565
  avatarURL = 'XUT9jHGk2qace148jeCX5rDsMftkSGYKmigLwU2PLLBc7Hm63VYR'
400
566
  badgeLabel = 'Represents your ability to access this information.'
401
567
  badgeIconURL = 'XUUV39HVPkpmMzYNTx7rpKzJvXfeiVyQWg2vfSpjBAuhunTCA9uG'
402
- badgeClickURL = 'https://bsv-blockchain.github.io/ts-sdk/reference/identity/' // TODO: Make this doc page exist
568
+ badgeClickURL = 'https://bsv-blockchain.github.io/ts-sdk/reference/identity/' // (no dedicated page yet)
403
569
  break
404
570
  default: {
405
571
  const parsed = IdentityClient.tryToParseGenericIdentity(
@@ -455,34 +621,41 @@ export class IdentityClient {
455
621
  // Try to construct a name from common field patterns
456
622
  const firstName = decryptedFields.firstName
457
623
  const lastName = decryptedFields.lastName
458
- const fullName =
459
- IdentityClient.hasValue(firstName) && IdentityClient.hasValue(lastName)
460
- ? `${firstName} ${lastName}`
461
- : IdentityClient.hasValue(firstName)
462
- ? firstName
463
- : IdentityClient.hasValue(lastName)
464
- ? lastName
465
- : undefined
466
-
467
- const name = IdentityClient.hasValue(decryptedFields.name)
468
- ? decryptedFields.name
469
- : IdentityClient.hasValue(decryptedFields.userName)
470
- ? decryptedFields.userName
471
- : (fullName ??
472
- (IdentityClient.hasValue(decryptedFields.email)
473
- ? decryptedFields.email
474
- : defaultIdentity.name))
624
+ let fullName: string | undefined
625
+ if (IdentityClient.hasValue(firstName) && IdentityClient.hasValue(lastName)) {
626
+ fullName = `${firstName} ${lastName}`
627
+ } else if (IdentityClient.hasValue(firstName)) {
628
+ fullName = firstName
629
+ } else if (IdentityClient.hasValue(lastName)) {
630
+ fullName = lastName
631
+ }
632
+
633
+ let name: string | undefined
634
+ if (IdentityClient.hasValue(decryptedFields.name)) {
635
+ name = decryptedFields.name
636
+ } else if (IdentityClient.hasValue(decryptedFields.userName)) {
637
+ name = decryptedFields.userName
638
+ } else if (fullName !== undefined) {
639
+ name = fullName
640
+ } else if (IdentityClient.hasValue(decryptedFields.email)) {
641
+ name = decryptedFields.email
642
+ } else {
643
+ name = defaultIdentity.name
644
+ }
475
645
 
476
646
  // Try to find an avatar/photo from common field names
477
- const avatarURL = IdentityClient.hasValue(decryptedFields.profilePhoto)
478
- ? decryptedFields.profilePhoto
479
- : IdentityClient.hasValue(decryptedFields.avatar)
480
- ? decryptedFields.avatar
481
- : IdentityClient.hasValue(decryptedFields.icon)
482
- ? decryptedFields.icon
483
- : IdentityClient.hasValue(decryptedFields.photo)
484
- ? decryptedFields.photo
485
- : defaultIdentity.avatarURL
647
+ let avatarURL: string | undefined
648
+ if (IdentityClient.hasValue(decryptedFields.profilePhoto)) {
649
+ avatarURL = decryptedFields.profilePhoto
650
+ } else if (IdentityClient.hasValue(decryptedFields.avatar)) {
651
+ avatarURL = decryptedFields.avatar
652
+ } else if (IdentityClient.hasValue(decryptedFields.icon)) {
653
+ avatarURL = decryptedFields.icon
654
+ } else if (IdentityClient.hasValue(decryptedFields.photo)) {
655
+ avatarURL = decryptedFields.photo
656
+ } else {
657
+ avatarURL = defaultIdentity.avatarURL
658
+ }
486
659
 
487
660
  // Generate badge information
488
661
  const badgeLabel = IdentityClient.hasValue(certifierInfo?.name)
@@ -571,7 +571,7 @@ describe('IdentityClient (additional coverage)', () => {
571
571
  mockContactsManager.getContacts = jest.fn().mockResolvedValue([contact])
572
572
  walletMock.discoverByAttributes = jest.fn().mockResolvedValue({ certificates: [discoveredCertificate] })
573
573
 
574
- const result = await identityClient.resolveByAttributes({ attributes: { email: 'alice@example.com' } })
574
+ const result = await identityClient.resolveByAttributes({ attributes: { email: 'alice@example.com' } }, { useContacts: true })
575
575
  expect(result[0].name).toBe('Alice From Contact')
576
576
  })
577
577
 
@@ -764,4 +764,153 @@ describe('IdentityClient (additional coverage)', () => {
764
764
  expect(mockContactsManager.removeContact).toHaveBeenCalledWith('key-to-remove')
765
765
  })
766
766
  })
767
+
768
+ // ─── useContacts branches in resolveByIdentityKey / resolveByAttributes ─────
769
+
770
+ // Shared helpers — extracted to keep new tests DRY (avoid Sonar duplication gate).
771
+ const xCert = (subject: string, userName: string): any => ({
772
+ type: KNOWN_IDENTITY_TYPES.xCert,
773
+ subject,
774
+ decryptedFields: { userName, profilePhoto: '' },
775
+ certifierInfo: { name: 'CX', iconUrl: '' }
776
+ })
777
+ const emailCertOf = (subject: string, email: string): any => ({
778
+ type: KNOWN_IDENTITY_TYPES.emailCert,
779
+ subject,
780
+ decryptedFields: { email },
781
+ certifierInfo: { name: 'EC', iconUrl: '' }
782
+ })
783
+ const contactOf = (name: string, identityKey: string): any => ({
784
+ name, identityKey, avatarURL: '', abbreviatedKey: '', badgeIconURL: '', badgeLabel: '', badgeClickURL: ''
785
+ })
786
+ const stubDiscoveryByKey = (contacts: any[], certificates: any[]): void => {
787
+ identityClient['contactsManager'].getContacts = jest.fn().mockResolvedValue(contacts)
788
+ walletMock.discoverByIdentityKey = jest.fn().mockResolvedValue({ certificates })
789
+ }
790
+ const stubDiscoveryByAttr = (contacts: any[], certificates: any[]): void => {
791
+ identityClient['contactsManager'].getContacts = jest.fn().mockResolvedValue(contacts)
792
+ walletMock.discoverByAttributes = jest.fn().mockResolvedValue({ certificates })
793
+ }
794
+
795
+ describe('resolveByIdentityKey with useContacts opt-in', () => {
796
+ it('contacts miss falls through to overlay (sequential)', async () => {
797
+ stubDiscoveryByKey([], [xCert('k1', 'XUser')])
798
+ const result = await identityClient.resolveByIdentityKey({ identityKey: 'k1' }, { useContacts: true })
799
+ expect(walletMock.discoverByIdentityKey).toHaveBeenCalled()
800
+ expect(result[0].name).toBe('XUser')
801
+ })
802
+
803
+ it('parallel mode returns contact on hit even though overlay runs', async () => {
804
+ const contact = contactOf('Cached Alice', 'k2')
805
+ stubDiscoveryByKey([contact], [])
806
+ const result = await identityClient.resolveByIdentityKey({ identityKey: 'k2' }, { useContacts: true, parallel: true })
807
+ expect(walletMock.discoverByIdentityKey).toHaveBeenCalled()
808
+ expect(result).toEqual([contact])
809
+ })
810
+
811
+ it('parallel mode contacts miss returns parsed overlay results', async () => {
812
+ stubDiscoveryByKey([], [xCert('k3', 'XOnly')])
813
+ const result = await identityClient.resolveByIdentityKey({ identityKey: 'k3' }, { useContacts: true, parallel: true })
814
+ expect(result[0].name).toBe('XOnly')
815
+ })
816
+
817
+ it('legacy boolean opt-in (true) consults contacts', async () => {
818
+ stubDiscoveryByKey([contactOf('Legacy True', 'k4')], [])
819
+ const result = await identityClient.resolveByIdentityKey({ identityKey: 'k4' }, true)
820
+ expect(result[0].name).toBe('Legacy True')
821
+ expect(walletMock.discoverByIdentityKey).not.toHaveBeenCalled()
822
+ })
823
+
824
+ it('overrideWithContacts legacy alias takes precedence over useContacts', async () => {
825
+ stubDiscoveryByKey([contactOf('Override Wins', 'k5')], [])
826
+ const result = await identityClient.resolveByIdentityKey(
827
+ { identityKey: 'k5' },
828
+ { useContacts: false, overrideWithContacts: true }
829
+ )
830
+ expect(result[0].name).toBe('Override Wins')
831
+ })
832
+ })
833
+
834
+ describe('resolveByAttributes with useContacts opt-in', () => {
835
+ it('contacts no-match falls through to overlay with contact overrides applied', async () => {
836
+ stubDiscoveryByAttr([contactOf('Override Alice', 'k-over')], [emailCertOf('k-over', 'alice@example.com')])
837
+ const result = await identityClient.resolveByAttributes(
838
+ { attributes: { email: 'alice@example.com' } },
839
+ { useContacts: true }
840
+ )
841
+ expect(result[0].name).toBe('Override Alice')
842
+ })
843
+
844
+ it('contacts empty + overlay miss returns empty', async () => {
845
+ stubDiscoveryByAttr([], [])
846
+ const result = await identityClient.resolveByAttributes(
847
+ { attributes: { email: 'nobody@example.com' } },
848
+ { useContacts: true }
849
+ )
850
+ expect(result).toEqual([])
851
+ })
852
+
853
+ it('parallel mode with no contacts parses overlay only', async () => {
854
+ stubDiscoveryByAttr([], [emailCertOf('no-contact-key', 'lone@example.com')])
855
+ const result = await identityClient.resolveByAttributes(
856
+ { attributes: { email: 'lone@example.com' } },
857
+ { useContacts: true, parallel: true }
858
+ )
859
+ expect(result[0].name).toBe('lone@example.com')
860
+ })
861
+
862
+ it('parallel mode with contacts applies overrides on overlay results', async () => {
863
+ stubDiscoveryByAttr([contactOf('Parallel Contact', 'pk')], [emailCertOf('pk', 'p@example.com')])
864
+ const result = await identityClient.resolveByAttributes(
865
+ { attributes: { email: 'p@example.com' } },
866
+ { useContacts: true, parallel: true }
867
+ )
868
+ expect(result[0].name).toBe('Parallel Contact')
869
+ })
870
+
871
+ it('matchContactsByAttributes ignores non-string attribute values', async () => {
872
+ stubDiscoveryByAttr([contactOf('X', 'kkkk')], [])
873
+ const result = await identityClient.resolveByAttributes(
874
+ { attributes: { count: 5 as unknown as string } },
875
+ { useContacts: true }
876
+ )
877
+ // No string-valued attrs → matchContactsByAttributes returns [] → overlay path
878
+ expect(walletMock.discoverByAttributes).toHaveBeenCalled()
879
+ expect(result).toEqual([])
880
+ })
881
+ })
882
+
883
+ describe('parseIdentities batched path', () => {
884
+ it('yields to event loop when batch > PARSE_BATCH_SIZE', async () => {
885
+ const certs = Array.from({ length: 64 }, (_, i) => xCert(`subject-${i}`, `user-${i}`))
886
+ const result = await IdentityClient.parseIdentities(certs)
887
+ expect(result).toHaveLength(64)
888
+ expect(result[63].name).toBe('user-63')
889
+ })
890
+
891
+ it('parseIdentitiesWithOverrides batches with overrides applied', async () => {
892
+ const certs = Array.from({ length: 50 }, (_, i) => xCert(`subject-${i}`, `user-${i}`))
893
+ const overrideMap = new Map<string, any>([
894
+ ['subject-5', contactOf('Override 5', 'subject-5')],
895
+ ['subject-40', contactOf('Override 40', 'subject-40')]
896
+ ])
897
+ const result = await IdentityClient.parseIdentitiesWithOverrides(certs, overrideMap)
898
+ expect(result[5].name).toBe('Override 5')
899
+ expect(result[40].name).toBe('Override 40')
900
+ expect(result[6].name).toBe('user-6')
901
+ })
902
+ })
903
+
904
+ describe('yieldToEventLoop scheduler.yield path', () => {
905
+ const origScheduler = (globalThis as any).scheduler
906
+ afterEach(() => { (globalThis as any).scheduler = origScheduler })
907
+
908
+ it('uses scheduler.yield when available', async () => {
909
+ const yieldFn = jest.fn().mockResolvedValue(undefined)
910
+ ;(globalThis as any).scheduler = { yield: yieldFn }
911
+ const certs = Array.from({ length: 64 }, (_, i) => xCert(`s-${i}`, `u-${i}`))
912
+ await IdentityClient.parseIdentities(certs)
913
+ expect(yieldFn).toHaveBeenCalled()
914
+ })
915
+ })
767
916
  })
@@ -260,11 +260,35 @@ describe('IdentityClient', () => {
260
260
  mockContactsManager.getContacts = jest.fn().mockResolvedValue([contact])
261
261
  walletMock.discoverByIdentityKey = jest.fn().mockResolvedValue({ certificates: [discoveredCertificate] })
262
262
 
263
- const identities = await identityClient.resolveByIdentityKey({ identityKey: 'alice-identity-key' })
263
+ const identities = await identityClient.resolveByIdentityKey({ identityKey: 'alice-identity-key' }, { useContacts: true })
264
264
 
265
265
  expect(identities).toHaveLength(1)
266
266
  expect(identities[0].name).toBe('Alice Smith (Personal Contact)') // Contact should be returned, not discovered identity
267
- // Both calls fire in parallel, but contacts take priority in the result
267
+ // With useContacts opt-in, contacts hit short-circuits the overlay query entirely.
268
+ expect(walletMock.discoverByIdentityKey).not.toHaveBeenCalled()
269
+ })
270
+
271
+ it('should still call the overlay when parallel: true is passed', async () => {
272
+ const contact = {
273
+ name: 'Alice Smith (Personal Contact)',
274
+ identityKey: 'alice-identity-key',
275
+ avatarURL: 'alice-avatar.png',
276
+ abbreviatedKey: 'alice-i...',
277
+ badgeIconURL: '',
278
+ badgeLabel: '',
279
+ badgeClickURL: ''
280
+ }
281
+ const mockContactsManager = identityClient['contactsManager']
282
+ mockContactsManager.getContacts = jest.fn().mockResolvedValue([contact])
283
+ walletMock.discoverByIdentityKey = jest.fn().mockResolvedValue({ certificates: [] })
284
+
285
+ const identities = await identityClient.resolveByIdentityKey(
286
+ { identityKey: 'alice-identity-key' },
287
+ { useContacts: true, parallel: true }
288
+ )
289
+
290
+ expect(identities).toHaveLength(1)
291
+ expect(identities[0].name).toBe('Alice Smith (Personal Contact)')
268
292
  expect(walletMock.discoverByIdentityKey).toHaveBeenCalled()
269
293
  })
270
294
  })
@@ -356,7 +380,7 @@ describe('IdentityClient', () => {
356
380
  mockContactsManager.getContacts = jest.fn().mockResolvedValue([contact])
357
381
  walletMock.discoverByAttributes = jest.fn().mockResolvedValue({ certificates: [discoveredCertificate] })
358
382
 
359
- const identities = await identityClient.resolveByAttributes({ attributes: { name: 'Alice' } })
383
+ const identities = await identityClient.resolveByAttributes({ attributes: { name: 'Alice' } }, { useContacts: true })
360
384
 
361
385
  expect(identities).toHaveLength(1)
362
386
  expect(identities[0].name).toBe('Alice Smith (Personal)') // Contact should be returned, not discovered identity