@metamask/snaps-rpc-methods 15.1.0 → 16.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 (352) hide show
  1. package/CHANGELOG.md +34 -4
  2. package/dist/endowments/keyring.cjs +2 -5
  3. package/dist/endowments/keyring.cjs.map +1 -1
  4. package/dist/endowments/keyring.d.cts +0 -2
  5. package/dist/endowments/keyring.d.cts.map +1 -1
  6. package/dist/endowments/keyring.d.mts +0 -2
  7. package/dist/endowments/keyring.d.mts.map +1 -1
  8. package/dist/endowments/keyring.mjs +3 -6
  9. package/dist/endowments/keyring.mjs.map +1 -1
  10. package/dist/index.cjs +1 -4
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +1 -2
  13. package/dist/index.d.cts.map +1 -1
  14. package/dist/index.d.mts +1 -2
  15. package/dist/index.d.mts.map +1 -1
  16. package/dist/index.mjs +1 -2
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/permissions.cjs +18 -8
  19. package/dist/permissions.cjs.map +1 -1
  20. package/dist/permissions.d.cts +3 -2
  21. package/dist/permissions.d.cts.map +1 -1
  22. package/dist/permissions.d.mts +3 -2
  23. package/dist/permissions.d.mts.map +1 -1
  24. package/dist/permissions.mjs +17 -7
  25. package/dist/permissions.mjs.map +1 -1
  26. package/dist/permitted/cancelBackgroundEvent.cjs +10 -14
  27. package/dist/permitted/cancelBackgroundEvent.cjs.map +1 -1
  28. package/dist/permitted/cancelBackgroundEvent.d.cts +9 -12
  29. package/dist/permitted/cancelBackgroundEvent.d.cts.map +1 -1
  30. package/dist/permitted/cancelBackgroundEvent.d.mts +9 -12
  31. package/dist/permitted/cancelBackgroundEvent.d.mts.map +1 -1
  32. package/dist/permitted/cancelBackgroundEvent.mjs +10 -14
  33. package/dist/permitted/cancelBackgroundEvent.mjs.map +1 -1
  34. package/dist/permitted/clearState.cjs +10 -16
  35. package/dist/permitted/clearState.cjs.map +1 -1
  36. package/dist/permitted/clearState.d.cts +9 -23
  37. package/dist/permitted/clearState.d.cts.map +1 -1
  38. package/dist/permitted/clearState.d.mts +9 -23
  39. package/dist/permitted/clearState.d.mts.map +1 -1
  40. package/dist/permitted/clearState.mjs +10 -16
  41. package/dist/permitted/clearState.mjs.map +1 -1
  42. package/dist/permitted/closeWebSocket.cjs +7 -14
  43. package/dist/permitted/closeWebSocket.cjs.map +1 -1
  44. package/dist/permitted/closeWebSocket.d.cts +9 -12
  45. package/dist/permitted/closeWebSocket.d.cts.map +1 -1
  46. package/dist/permitted/closeWebSocket.d.mts +9 -12
  47. package/dist/permitted/closeWebSocket.d.mts.map +1 -1
  48. package/dist/permitted/closeWebSocket.mjs +7 -14
  49. package/dist/permitted/closeWebSocket.mjs.map +1 -1
  50. package/dist/permitted/createInterface.cjs +11 -15
  51. package/dist/permitted/createInterface.cjs.map +1 -1
  52. package/dist/permitted/createInterface.d.cts +23 -37
  53. package/dist/permitted/createInterface.d.cts.map +1 -1
  54. package/dist/permitted/createInterface.d.mts +23 -37
  55. package/dist/permitted/createInterface.d.mts.map +1 -1
  56. package/dist/permitted/createInterface.mjs +11 -15
  57. package/dist/permitted/createInterface.mjs.map +1 -1
  58. package/dist/permitted/endTrace.cjs +4 -6
  59. package/dist/permitted/endTrace.cjs.map +1 -1
  60. package/dist/permitted/endTrace.d.cts +8 -11
  61. package/dist/permitted/endTrace.d.cts.map +1 -1
  62. package/dist/permitted/endTrace.d.mts +8 -11
  63. package/dist/permitted/endTrace.d.mts.map +1 -1
  64. package/dist/permitted/endTrace.mjs +4 -6
  65. package/dist/permitted/endTrace.mjs.map +1 -1
  66. package/dist/permitted/getAllSnaps.cjs +5 -11
  67. package/dist/permitted/getAllSnaps.cjs.map +1 -1
  68. package/dist/permitted/getAllSnaps.d.cts +10 -14
  69. package/dist/permitted/getAllSnaps.d.cts.map +1 -1
  70. package/dist/permitted/getAllSnaps.d.mts +10 -14
  71. package/dist/permitted/getAllSnaps.d.mts.map +1 -1
  72. package/dist/permitted/getAllSnaps.mjs +5 -11
  73. package/dist/permitted/getAllSnaps.mjs.map +1 -1
  74. package/dist/permitted/getBackgroundEvents.cjs +8 -15
  75. package/dist/permitted/getBackgroundEvents.cjs.map +1 -1
  76. package/dist/permitted/getBackgroundEvents.d.cts +10 -13
  77. package/dist/permitted/getBackgroundEvents.d.cts.map +1 -1
  78. package/dist/permitted/getBackgroundEvents.d.mts +10 -13
  79. package/dist/permitted/getBackgroundEvents.d.mts.map +1 -1
  80. package/dist/permitted/getBackgroundEvents.mjs +8 -15
  81. package/dist/permitted/getBackgroundEvents.mjs.map +1 -1
  82. package/dist/permitted/getClientStatus.cjs +5 -6
  83. package/dist/permitted/getClientStatus.cjs.map +1 -1
  84. package/dist/permitted/getClientStatus.d.cts +17 -18
  85. package/dist/permitted/getClientStatus.d.cts.map +1 -1
  86. package/dist/permitted/getClientStatus.d.mts +17 -18
  87. package/dist/permitted/getClientStatus.d.mts.map +1 -1
  88. package/dist/permitted/getClientStatus.mjs +5 -6
  89. package/dist/permitted/getClientStatus.mjs.map +1 -1
  90. package/dist/permitted/getFile.cjs +7 -11
  91. package/dist/permitted/getFile.cjs.map +1 -1
  92. package/dist/permitted/getFile.d.cts +8 -10
  93. package/dist/permitted/getFile.d.cts.map +1 -1
  94. package/dist/permitted/getFile.d.mts +8 -10
  95. package/dist/permitted/getFile.d.mts.map +1 -1
  96. package/dist/permitted/getFile.mjs +7 -11
  97. package/dist/permitted/getFile.mjs.map +1 -1
  98. package/dist/permitted/getInterfaceContext.cjs +12 -15
  99. package/dist/permitted/getInterfaceContext.cjs.map +1 -1
  100. package/dist/permitted/getInterfaceContext.d.cts +9 -21
  101. package/dist/permitted/getInterfaceContext.d.cts.map +1 -1
  102. package/dist/permitted/getInterfaceContext.d.mts +9 -21
  103. package/dist/permitted/getInterfaceContext.d.mts.map +1 -1
  104. package/dist/permitted/getInterfaceContext.mjs +12 -15
  105. package/dist/permitted/getInterfaceContext.mjs.map +1 -1
  106. package/dist/permitted/getInterfaceState.cjs +11 -15
  107. package/dist/permitted/getInterfaceState.cjs.map +1 -1
  108. package/dist/permitted/getInterfaceState.d.cts +9 -21
  109. package/dist/permitted/getInterfaceState.d.cts.map +1 -1
  110. package/dist/permitted/getInterfaceState.d.mts +9 -21
  111. package/dist/permitted/getInterfaceState.d.mts.map +1 -1
  112. package/dist/permitted/getInterfaceState.mjs +11 -15
  113. package/dist/permitted/getInterfaceState.mjs.map +1 -1
  114. package/dist/permitted/getSnaps.cjs +6 -12
  115. package/dist/permitted/getSnaps.cjs.map +1 -1
  116. package/dist/permitted/getSnaps.d.cts +11 -14
  117. package/dist/permitted/getSnaps.d.cts.map +1 -1
  118. package/dist/permitted/getSnaps.d.mts +11 -14
  119. package/dist/permitted/getSnaps.d.mts.map +1 -1
  120. package/dist/permitted/getSnaps.mjs +6 -12
  121. package/dist/permitted/getSnaps.mjs.map +1 -1
  122. package/dist/permitted/getState.cjs +9 -11
  123. package/dist/permitted/getState.cjs.map +1 -1
  124. package/dist/permitted/getState.d.cts +17 -28
  125. package/dist/permitted/getState.d.cts.map +1 -1
  126. package/dist/permitted/getState.d.mts +17 -28
  127. package/dist/permitted/getState.d.mts.map +1 -1
  128. package/dist/permitted/getState.mjs +9 -11
  129. package/dist/permitted/getState.mjs.map +1 -1
  130. package/dist/permitted/getWebSockets.cjs +11 -14
  131. package/dist/permitted/getWebSockets.cjs.map +1 -1
  132. package/dist/permitted/getWebSockets.d.cts +10 -13
  133. package/dist/permitted/getWebSockets.d.cts.map +1 -1
  134. package/dist/permitted/getWebSockets.d.mts +10 -13
  135. package/dist/permitted/getWebSockets.d.mts.map +1 -1
  136. package/dist/permitted/getWebSockets.mjs +11 -14
  137. package/dist/permitted/getWebSockets.mjs.map +1 -1
  138. package/dist/permitted/index.cjs +0 -1
  139. package/dist/permitted/index.cjs.map +1 -1
  140. package/dist/permitted/index.d.cts +29 -25
  141. package/dist/permitted/index.d.cts.map +1 -1
  142. package/dist/permitted/index.d.mts +29 -25
  143. package/dist/permitted/index.d.mts.map +1 -1
  144. package/dist/permitted/index.mjs +0 -1
  145. package/dist/permitted/index.mjs.map +1 -1
  146. package/dist/permitted/invokeKeyring.cjs +12 -13
  147. package/dist/permitted/invokeKeyring.cjs.map +1 -1
  148. package/dist/permitted/invokeKeyring.d.cts +17 -16
  149. package/dist/permitted/invokeKeyring.d.cts.map +1 -1
  150. package/dist/permitted/invokeKeyring.d.mts +17 -16
  151. package/dist/permitted/invokeKeyring.d.mts.map +1 -1
  152. package/dist/permitted/invokeKeyring.mjs +12 -13
  153. package/dist/permitted/invokeKeyring.mjs.map +1 -1
  154. package/dist/permitted/invokeSnapSugar.cjs +6 -10
  155. package/dist/permitted/invokeSnapSugar.cjs.map +1 -1
  156. package/dist/permitted/invokeSnapSugar.d.cts +9 -12
  157. package/dist/permitted/invokeSnapSugar.d.cts.map +1 -1
  158. package/dist/permitted/invokeSnapSugar.d.mts +9 -12
  159. package/dist/permitted/invokeSnapSugar.d.mts.map +1 -1
  160. package/dist/permitted/invokeSnapSugar.mjs +6 -10
  161. package/dist/permitted/invokeSnapSugar.mjs.map +1 -1
  162. package/dist/permitted/listEntropySources.cjs +28 -12
  163. package/dist/permitted/listEntropySources.cjs.map +1 -1
  164. package/dist/permitted/listEntropySources.d.cts +12 -23
  165. package/dist/permitted/listEntropySources.d.cts.map +1 -1
  166. package/dist/permitted/listEntropySources.d.mts +12 -23
  167. package/dist/permitted/listEntropySources.d.mts.map +1 -1
  168. package/dist/permitted/listEntropySources.mjs +28 -12
  169. package/dist/permitted/listEntropySources.mjs.map +1 -1
  170. package/dist/permitted/middleware.cjs +70 -20
  171. package/dist/permitted/middleware.cjs.map +1 -1
  172. package/dist/permitted/middleware.d.cts +5 -2
  173. package/dist/permitted/middleware.d.cts.map +1 -1
  174. package/dist/permitted/middleware.d.mts +5 -2
  175. package/dist/permitted/middleware.d.mts.map +1 -1
  176. package/dist/permitted/middleware.mjs +70 -20
  177. package/dist/permitted/middleware.mjs.map +1 -1
  178. package/dist/permitted/openWebSocket.cjs +7 -14
  179. package/dist/permitted/openWebSocket.cjs.map +1 -1
  180. package/dist/permitted/openWebSocket.d.cts +9 -12
  181. package/dist/permitted/openWebSocket.d.cts.map +1 -1
  182. package/dist/permitted/openWebSocket.d.mts +9 -12
  183. package/dist/permitted/openWebSocket.d.mts.map +1 -1
  184. package/dist/permitted/openWebSocket.mjs +7 -14
  185. package/dist/permitted/openWebSocket.mjs.map +1 -1
  186. package/dist/permitted/requestSnaps.cjs +14 -19
  187. package/dist/permitted/requestSnaps.cjs.map +1 -1
  188. package/dist/permitted/requestSnaps.d.cts +9 -36
  189. package/dist/permitted/requestSnaps.d.cts.map +1 -1
  190. package/dist/permitted/requestSnaps.d.mts +9 -36
  191. package/dist/permitted/requestSnaps.d.mts.map +1 -1
  192. package/dist/permitted/requestSnaps.mjs +15 -20
  193. package/dist/permitted/requestSnaps.mjs.map +1 -1
  194. package/dist/permitted/resolveInterface.cjs +11 -15
  195. package/dist/permitted/resolveInterface.cjs.map +1 -1
  196. package/dist/permitted/resolveInterface.d.cts +12 -24
  197. package/dist/permitted/resolveInterface.d.cts.map +1 -1
  198. package/dist/permitted/resolveInterface.d.mts +12 -24
  199. package/dist/permitted/resolveInterface.d.mts.map +1 -1
  200. package/dist/permitted/resolveInterface.mjs +11 -15
  201. package/dist/permitted/resolveInterface.mjs.map +1 -1
  202. package/dist/permitted/scheduleBackgroundEvent.cjs +11 -14
  203. package/dist/permitted/scheduleBackgroundEvent.cjs.map +1 -1
  204. package/dist/permitted/scheduleBackgroundEvent.d.cts +10 -17
  205. package/dist/permitted/scheduleBackgroundEvent.d.cts.map +1 -1
  206. package/dist/permitted/scheduleBackgroundEvent.d.mts +10 -17
  207. package/dist/permitted/scheduleBackgroundEvent.d.mts.map +1 -1
  208. package/dist/permitted/scheduleBackgroundEvent.mjs +11 -14
  209. package/dist/permitted/scheduleBackgroundEvent.mjs.map +1 -1
  210. package/dist/permitted/sendWebSocketMessage.cjs +10 -14
  211. package/dist/permitted/sendWebSocketMessage.cjs.map +1 -1
  212. package/dist/permitted/sendWebSocketMessage.d.cts +9 -12
  213. package/dist/permitted/sendWebSocketMessage.d.cts.map +1 -1
  214. package/dist/permitted/sendWebSocketMessage.d.mts +9 -12
  215. package/dist/permitted/sendWebSocketMessage.d.mts.map +1 -1
  216. package/dist/permitted/sendWebSocketMessage.mjs +10 -14
  217. package/dist/permitted/sendWebSocketMessage.mjs.map +1 -1
  218. package/dist/permitted/setState.cjs +18 -21
  219. package/dist/permitted/setState.cjs.map +1 -1
  220. package/dist/permitted/setState.d.cts +18 -45
  221. package/dist/permitted/setState.d.cts.map +1 -1
  222. package/dist/permitted/setState.d.mts +18 -45
  223. package/dist/permitted/setState.d.mts.map +1 -1
  224. package/dist/permitted/setState.mjs +18 -21
  225. package/dist/permitted/setState.mjs.map +1 -1
  226. package/dist/permitted/startTrace.cjs +4 -6
  227. package/dist/permitted/startTrace.cjs.map +1 -1
  228. package/dist/permitted/startTrace.d.cts +8 -11
  229. package/dist/permitted/startTrace.d.cts.map +1 -1
  230. package/dist/permitted/startTrace.d.mts +8 -11
  231. package/dist/permitted/startTrace.d.mts.map +1 -1
  232. package/dist/permitted/startTrace.mjs +4 -6
  233. package/dist/permitted/startTrace.mjs.map +1 -1
  234. package/dist/permitted/trackError.cjs +4 -6
  235. package/dist/permitted/trackError.cjs.map +1 -1
  236. package/dist/permitted/trackError.d.cts +8 -11
  237. package/dist/permitted/trackError.d.cts.map +1 -1
  238. package/dist/permitted/trackError.d.mts +8 -11
  239. package/dist/permitted/trackError.d.mts.map +1 -1
  240. package/dist/permitted/trackError.mjs +4 -6
  241. package/dist/permitted/trackError.mjs.map +1 -1
  242. package/dist/permitted/trackEvent.cjs +4 -6
  243. package/dist/permitted/trackEvent.cjs.map +1 -1
  244. package/dist/permitted/trackEvent.d.cts +8 -11
  245. package/dist/permitted/trackEvent.d.cts.map +1 -1
  246. package/dist/permitted/trackEvent.d.mts +8 -11
  247. package/dist/permitted/trackEvent.d.mts.map +1 -1
  248. package/dist/permitted/trackEvent.mjs +4 -6
  249. package/dist/permitted/trackEvent.mjs.map +1 -1
  250. package/dist/permitted/updateInterface.cjs +11 -15
  251. package/dist/permitted/updateInterface.cjs.map +1 -1
  252. package/dist/permitted/updateInterface.d.cts +9 -22
  253. package/dist/permitted/updateInterface.d.cts.map +1 -1
  254. package/dist/permitted/updateInterface.d.mts +9 -22
  255. package/dist/permitted/updateInterface.d.mts.map +1 -1
  256. package/dist/permitted/updateInterface.mjs +11 -15
  257. package/dist/permitted/updateInterface.mjs.map +1 -1
  258. package/dist/restricted/dialog.cjs +23 -30
  259. package/dist/restricted/dialog.cjs.map +1 -1
  260. package/dist/restricted/dialog.d.cts +10 -58
  261. package/dist/restricted/dialog.d.cts.map +1 -1
  262. package/dist/restricted/dialog.d.mts +10 -58
  263. package/dist/restricted/dialog.d.mts.map +1 -1
  264. package/dist/restricted/dialog.mjs +23 -30
  265. package/dist/restricted/dialog.mjs.map +1 -1
  266. package/dist/restricted/getBip32Entropy.cjs +15 -12
  267. package/dist/restricted/getBip32Entropy.cjs.map +1 -1
  268. package/dist/restricted/getBip32Entropy.d.cts +11 -24
  269. package/dist/restricted/getBip32Entropy.d.cts.map +1 -1
  270. package/dist/restricted/getBip32Entropy.d.mts +11 -24
  271. package/dist/restricted/getBip32Entropy.d.mts.map +1 -1
  272. package/dist/restricted/getBip32Entropy.mjs +16 -13
  273. package/dist/restricted/getBip32Entropy.mjs.map +1 -1
  274. package/dist/restricted/getBip32PublicKey.cjs +15 -12
  275. package/dist/restricted/getBip32PublicKey.cjs.map +1 -1
  276. package/dist/restricted/getBip32PublicKey.d.cts +11 -24
  277. package/dist/restricted/getBip32PublicKey.d.cts.map +1 -1
  278. package/dist/restricted/getBip32PublicKey.d.mts +11 -24
  279. package/dist/restricted/getBip32PublicKey.d.mts.map +1 -1
  280. package/dist/restricted/getBip32PublicKey.mjs +16 -13
  281. package/dist/restricted/getBip32PublicKey.mjs.map +1 -1
  282. package/dist/restricted/getBip44Entropy.cjs +14 -10
  283. package/dist/restricted/getBip44Entropy.cjs.map +1 -1
  284. package/dist/restricted/getBip44Entropy.d.cts +11 -15
  285. package/dist/restricted/getBip44Entropy.d.cts.map +1 -1
  286. package/dist/restricted/getBip44Entropy.d.mts +11 -15
  287. package/dist/restricted/getBip44Entropy.d.mts.map +1 -1
  288. package/dist/restricted/getBip44Entropy.mjs +15 -11
  289. package/dist/restricted/getBip44Entropy.mjs.map +1 -1
  290. package/dist/restricted/getEntropy.cjs +10 -10
  291. package/dist/restricted/getEntropy.cjs.map +1 -1
  292. package/dist/restricted/getEntropy.d.cts +11 -15
  293. package/dist/restricted/getEntropy.d.cts.map +1 -1
  294. package/dist/restricted/getEntropy.d.mts +11 -15
  295. package/dist/restricted/getEntropy.d.mts.map +1 -1
  296. package/dist/restricted/getEntropy.mjs +11 -11
  297. package/dist/restricted/getEntropy.mjs.map +1 -1
  298. package/dist/restricted/index.cjs.map +1 -1
  299. package/dist/restricted/index.d.cts +20 -160
  300. package/dist/restricted/index.d.cts.map +1 -1
  301. package/dist/restricted/index.d.mts +20 -160
  302. package/dist/restricted/index.d.mts.map +1 -1
  303. package/dist/restricted/index.mjs.map +1 -1
  304. package/dist/restricted/invokeSnap.cjs +11 -12
  305. package/dist/restricted/invokeSnap.cjs.map +1 -1
  306. package/dist/restricted/invokeSnap.d.cts +9 -13
  307. package/dist/restricted/invokeSnap.d.cts.map +1 -1
  308. package/dist/restricted/invokeSnap.d.mts +9 -13
  309. package/dist/restricted/invokeSnap.d.mts.map +1 -1
  310. package/dist/restricted/invokeSnap.mjs +11 -12
  311. package/dist/restricted/invokeSnap.mjs.map +1 -1
  312. package/dist/restricted/manageState.cjs +21 -20
  313. package/dist/restricted/manageState.cjs.map +1 -1
  314. package/dist/restricted/manageState.d.cts +12 -34
  315. package/dist/restricted/manageState.d.cts.map +1 -1
  316. package/dist/restricted/manageState.d.mts +12 -34
  317. package/dist/restricted/manageState.d.mts.map +1 -1
  318. package/dist/restricted/manageState.mjs +21 -20
  319. package/dist/restricted/manageState.mjs.map +1 -1
  320. package/dist/restricted/notify.cjs +31 -24
  321. package/dist/restricted/notify.cjs.map +1 -1
  322. package/dist/restricted/notify.d.cts +16 -25
  323. package/dist/restricted/notify.d.cts.map +1 -1
  324. package/dist/restricted/notify.d.mts +16 -25
  325. package/dist/restricted/notify.d.mts.map +1 -1
  326. package/dist/restricted/notify.mjs +32 -25
  327. package/dist/restricted/notify.mjs.map +1 -1
  328. package/dist/types.cjs +3 -0
  329. package/dist/types.cjs.map +1 -0
  330. package/dist/types.d.cts +155 -0
  331. package/dist/types.d.cts.map +1 -0
  332. package/dist/types.d.mts +155 -0
  333. package/dist/types.d.mts.map +1 -0
  334. package/dist/types.mjs +2 -0
  335. package/dist/types.mjs.map +1 -0
  336. package/dist/utils.cjs +78 -24
  337. package/dist/utils.cjs.map +1 -1
  338. package/dist/utils.d.cts +21 -13
  339. package/dist/utils.d.cts.map +1 -1
  340. package/dist/utils.d.mts +21 -13
  341. package/dist/utils.d.mts.map +1 -1
  342. package/dist/utils.mjs +75 -22
  343. package/dist/utils.mjs.map +1 -1
  344. package/package.json +6 -6
  345. package/dist/permitted/handlers.cjs +0 -63
  346. package/dist/permitted/handlers.cjs.map +0 -1
  347. package/dist/permitted/handlers.d.cts +0 -299
  348. package/dist/permitted/handlers.d.cts.map +0 -1
  349. package/dist/permitted/handlers.d.mts +0 -299
  350. package/dist/permitted/handlers.d.mts.map +0 -1
  351. package/dist/permitted/handlers.mjs +0 -60
  352. package/dist/permitted/handlers.mjs.map +0 -1
@@ -2,11 +2,6 @@ import { providerErrors, rpcErrors } from "@metamask/rpc-errors";
2
2
  import { union } from "@metamask/snaps-sdk";
3
3
  import { create, object, number, string, array, StructError } from "@metamask/superstruct";
4
4
  import { SnapEndowments } from "../endowments/index.mjs";
5
- const methodName = 'snap_sendWebSocketMessage';
6
- const hookNames = {
7
- hasPermission: true,
8
- sendWebSocketMessage: true,
9
- };
10
5
  const SendWebSocketMessageParametersStruct = object({
11
6
  id: string(),
12
7
  message: union([string(), array(number())]),
@@ -36,9 +31,11 @@ const SendWebSocketMessageParametersStruct = object({
36
31
  * ```
37
32
  */
38
33
  export const sendWebSocketMessageHandler = {
39
- methodNames: [methodName],
40
34
  implementation: sendWebSocketMessageImplementation,
41
- hookNames,
35
+ actionNames: [
36
+ 'PermissionController:hasPermission',
37
+ 'WebSocketService:sendMessage',
38
+ ],
42
39
  };
43
40
  /**
44
41
  * The `snap_sendWebSocketMessage` method implementation.
@@ -47,19 +44,18 @@ export const sendWebSocketMessageHandler = {
47
44
  * @param res - The JSON-RPC response object.
48
45
  * @param _next - The `json-rpc-engine` "next" callback. Not used by this function.
49
46
  * @param end - The `json-rpc-engine` "end" callback.
50
- * @param hooks - The RPC method hooks.
51
- * @param hooks.hasPermission - The function to check if a snap has the `endowment:network-access` permission.
52
- * @param hooks.sendWebSocketMessage - The function to send a WebSocket message.
47
+ * @param _hooks - The RPC method hooks. Not used by this function.
48
+ * @param messenger - The messenger used to call controller actions.
53
49
  * @returns Nothing.
54
50
  */
55
- async function sendWebSocketMessageImplementation(req, res, _next, end, { hasPermission, sendWebSocketMessage }) {
56
- if (!hasPermission(SnapEndowments.NetworkAccess)) {
51
+ async function sendWebSocketMessageImplementation(req, res, _next, end, _hooks, messenger) {
52
+ const { params, origin } = req;
53
+ if (!messenger.call('PermissionController:hasPermission', origin, SnapEndowments.NetworkAccess)) {
57
54
  return end(providerErrors.unauthorized());
58
55
  }
59
- const { params } = req;
60
56
  try {
61
57
  const { id, message } = getValidatedParams(params);
62
- await sendWebSocketMessage(id, message);
58
+ await messenger.call('WebSocketService:sendMessage', origin, id, message);
63
59
  res.result = null;
64
60
  }
65
61
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"sendWebSocketMessage.mjs","sourceRoot":"","sources":["../../src/permitted/sendWebSocketMessage.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,6BAA6B;AAMjE,OAAO,EAAE,KAAK,EAAE,4BAA4B;AAE5C,OAAO,EACL,MAAM,EACN,MAAM,EACN,MAAM,EACN,MAAM,EACN,KAAK,EACL,WAAW,EACZ,8BAA8B;AAG/B,OAAO,EAAE,cAAc,EAAE,gCAAsB;AAG/C,MAAM,UAAU,GAAG,2BAA2B,CAAC;AAE/C,MAAM,SAAS,GAAuD;IACpE,aAAa,EAAE,IAAI;IACnB,oBAAoB,EAAE,IAAI;CAC3B,CAAC;AAOF,MAAM,oCAAoC,GAAG,MAAM,CAAC;IAClD,EAAE,EAAE,MAAM,EAAE;IACZ,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;CAC5C,CAAC,CAAC;AAOH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,WAAW,EAAE,CAAC,UAAU,CAAU;IAClC,cAAc,EAAE,kCAAkC;IAClD,SAAS;CAKV,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,KAAK,UAAU,kCAAkC,CAC/C,GAAmD,EACnD,GAAuD,EACvD,KAAc,EACd,GAA6B,EAC7B,EAAE,aAAa,EAAE,oBAAoB,EAAmC;IAExE,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,aAAa,CAAC,EAAE,CAAC;QACjD,OAAO,GAAG,CAAC,cAAc,CAAC,YAAY,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IAEvB,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACnD,MAAM,oBAAoB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACxC,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC;IACpB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;IACpB,CAAC;IAED,OAAO,GAAG,EAAE,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,SAAS,kBAAkB,CAAC,MAAe;IACzC,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,MAAM,EAAE,oCAAoC,CAAC,CAAC;IAC9D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;YACjC,MAAM,SAAS,CAAC,aAAa,CAAC;gBAC5B,OAAO,EAAE,mBAAmB,KAAK,CAAC,OAAO,GAAG;aAC7C,CAAC,CAAC;QACL,CAAC;QACD,0BAA0B;QAC1B,MAAM,SAAS,CAAC,QAAQ,EAAE,CAAC;IAC7B,CAAC;AACH,CAAC","sourcesContent":["import type { JsonRpcEngineEndCallback } from '@metamask/json-rpc-engine';\nimport type { PermittedHandlerExport } from '@metamask/permission-controller';\nimport { providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport type {\n JsonRpcRequest,\n SendWebSocketMessageParams,\n SendWebSocketMessageResult,\n} from '@metamask/snaps-sdk';\nimport { union } from '@metamask/snaps-sdk';\nimport type { InferMatching } from '@metamask/snaps-utils';\nimport {\n create,\n object,\n number,\n string,\n array,\n StructError,\n} from '@metamask/superstruct';\nimport type { PendingJsonRpcResponse } from '@metamask/utils';\n\nimport { SnapEndowments } from '../endowments';\nimport type { MethodHooksObject } from '../utils';\n\nconst methodName = 'snap_sendWebSocketMessage';\n\nconst hookNames: MethodHooksObject<SendWebSocketMessageMethodHooks> = {\n hasPermission: true,\n sendWebSocketMessage: true,\n};\n\nexport type SendWebSocketMessageMethodHooks = {\n hasPermission: (permissionName: string) => boolean;\n sendWebSocketMessage: (id: string, data: string | number[]) => Promise<void>;\n};\n\nconst SendWebSocketMessageParametersStruct = object({\n id: string(),\n message: union([string(), array(number())]),\n});\n\nexport type SendWebSocketMessageParameters = InferMatching<\n typeof SendWebSocketMessageParametersStruct,\n SendWebSocketMessageParams\n>;\n\n/**\n * Send a message to an open WebSocket connection. The message will be sent to\n * the WebSocket connection with the specified ID, which must have been\n * previously opened by the Snap using the [`snap_openWebSocket`](https://docs.metamask.io/snaps/reference/snaps-api/snap_openwebsocket/)\n * method.\n *\n * @example\n * ```json name=\"Manifest\"\n * {\n * \"initialPermissions\": {\n * \"endowment:network-access\": {}\n * }\n * }\n * ```\n * ```ts name=\"Usage\"\n * await wallet.request({\n * method: 'snap_sendWebSocketMessage',\n * params: {\n * id: 'websocket-connection-id',\n * message: 'Hello, WebSocket!', // or message: [1, 2, 3] for binary data\n * },\n * });\n * ```\n */\nexport const sendWebSocketMessageHandler = {\n methodNames: [methodName] as const,\n implementation: sendWebSocketMessageImplementation,\n hookNames,\n} satisfies PermittedHandlerExport<\n SendWebSocketMessageMethodHooks,\n SendWebSocketMessageParams,\n SendWebSocketMessageResult\n>;\n\n/**\n * The `snap_sendWebSocketMessage` method implementation.\n *\n * @param req - The JSON-RPC request object.\n * @param res - The JSON-RPC response object.\n * @param _next - The `json-rpc-engine` \"next\" callback. Not used by this function.\n * @param end - The `json-rpc-engine` \"end\" callback.\n * @param hooks - The RPC method hooks.\n * @param hooks.hasPermission - The function to check if a snap has the `endowment:network-access` permission.\n * @param hooks.sendWebSocketMessage - The function to send a WebSocket message.\n * @returns Nothing.\n */\nasync function sendWebSocketMessageImplementation(\n req: JsonRpcRequest<SendWebSocketMessageParameters>,\n res: PendingJsonRpcResponse<SendWebSocketMessageResult>,\n _next: unknown,\n end: JsonRpcEngineEndCallback,\n { hasPermission, sendWebSocketMessage }: SendWebSocketMessageMethodHooks,\n): Promise<void> {\n if (!hasPermission(SnapEndowments.NetworkAccess)) {\n return end(providerErrors.unauthorized());\n }\n\n const { params } = req;\n\n try {\n const { id, message } = getValidatedParams(params);\n await sendWebSocketMessage(id, message);\n res.result = null;\n } catch (error) {\n return end(error);\n }\n\n return end();\n}\n\n/**\n * Validates the parameters for the snap_sendWebSocketMessage method.\n *\n * @param params - Parameters to validate.\n * @returns Validated parameters.\n * @throws Throws RPC error if validation fails.\n */\nfunction getValidatedParams(params: unknown): SendWebSocketMessageParameters {\n try {\n return create(params, SendWebSocketMessageParametersStruct);\n } catch (error) {\n if (error instanceof StructError) {\n throw rpcErrors.invalidParams({\n message: `Invalid params: ${error.message}.`,\n });\n }\n /* istanbul ignore next */\n throw rpcErrors.internal();\n }\n}\n"]}
1
+ {"version":3,"file":"sendWebSocketMessage.mjs","sourceRoot":"","sources":["../../src/permitted/sendWebSocketMessage.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,6BAA6B;AAKjE,OAAO,EAAE,KAAK,EAAE,4BAA4B;AAE5C,OAAO,EACL,MAAM,EACN,MAAM,EACN,MAAM,EACN,MAAM,EACN,KAAK,EACL,WAAW,EACZ,8BAA8B;AAG/B,OAAO,EAAE,cAAc,EAAE,gCAAsB;AAU/C,MAAM,oCAAoC,GAAG,MAAM,CAAC;IAClD,EAAE,EAAE,MAAM,EAAE;IACZ,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;CAC5C,CAAC,CAAC;AAOH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,cAAc,EAAE,kCAAkC;IAClD,WAAW,EAAE;QACX,oCAAoC;QACpC,8BAA8B;KAC/B;CAOF,CAAC;AAEF;;;;;;;;;;GAUG;AACH,KAAK,UAAU,kCAAkC,CAC/C,GAA6D,EAC7D,GAAuD,EACvD,KAAc,EACd,GAA6B,EAC7B,MAAa,EACb,SAA+D;IAE/D,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IAE/B,IACE,CAAC,SAAS,CAAC,IAAI,CACb,oCAAoC,EACpC,MAAM,EACN,cAAc,CAAC,aAAa,CAC7B,EACD,CAAC;QACD,OAAO,GAAG,CAAC,cAAc,CAAC,YAAY,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACnD,MAAM,SAAS,CAAC,IAAI,CAAC,8BAA8B,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;QAC1E,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC;IACpB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;IACpB,CAAC;IAED,OAAO,GAAG,EAAE,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,SAAS,kBAAkB,CAAC,MAAe;IACzC,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,MAAM,EAAE,oCAAoC,CAAC,CAAC;IAC9D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;YACjC,MAAM,SAAS,CAAC,aAAa,CAAC;gBAC5B,OAAO,EAAE,mBAAmB,KAAK,CAAC,OAAO,GAAG;aAC7C,CAAC,CAAC;QACL,CAAC;QACD,0BAA0B;QAC1B,MAAM,SAAS,CAAC,QAAQ,EAAE,CAAC;IAC7B,CAAC;AACH,CAAC","sourcesContent":["import type {\n JsonRpcEngineEndCallback,\n MethodHandler,\n} from '@metamask/json-rpc-engine';\nimport type { Messenger } from '@metamask/messenger';\nimport type { PermissionControllerHasPermissionAction } from '@metamask/permission-controller';\nimport { providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport type {\n SendWebSocketMessageParams,\n SendWebSocketMessageResult,\n} from '@metamask/snaps-sdk';\nimport { union } from '@metamask/snaps-sdk';\nimport type { InferMatching } from '@metamask/snaps-utils';\nimport {\n create,\n object,\n number,\n string,\n array,\n StructError,\n} from '@metamask/superstruct';\nimport type { PendingJsonRpcResponse } from '@metamask/utils';\n\nimport { SnapEndowments } from '../endowments';\nimport type {\n JsonRpcRequestWithOrigin,\n WebSocketServiceSendMessageAction,\n} from '../types';\n\nexport type SendWebSocketMessageMethodActions =\n | PermissionControllerHasPermissionAction\n | WebSocketServiceSendMessageAction;\n\nconst SendWebSocketMessageParametersStruct = object({\n id: string(),\n message: union([string(), array(number())]),\n});\n\nexport type SendWebSocketMessageParameters = InferMatching<\n typeof SendWebSocketMessageParametersStruct,\n SendWebSocketMessageParams\n>;\n\n/**\n * Send a message to an open WebSocket connection. The message will be sent to\n * the WebSocket connection with the specified ID, which must have been\n * previously opened by the Snap using the [`snap_openWebSocket`](https://docs.metamask.io/snaps/reference/snaps-api/snap_openwebsocket/)\n * method.\n *\n * @example\n * ```json name=\"Manifest\"\n * {\n * \"initialPermissions\": {\n * \"endowment:network-access\": {}\n * }\n * }\n * ```\n * ```ts name=\"Usage\"\n * await wallet.request({\n * method: 'snap_sendWebSocketMessage',\n * params: {\n * id: 'websocket-connection-id',\n * message: 'Hello, WebSocket!', // or message: [1, 2, 3] for binary data\n * },\n * });\n * ```\n */\nexport const sendWebSocketMessageHandler = {\n implementation: sendWebSocketMessageImplementation,\n actionNames: [\n 'PermissionController:hasPermission',\n 'WebSocketService:sendMessage',\n ],\n} satisfies MethodHandler<\n never,\n SendWebSocketMessageMethodActions,\n SendWebSocketMessageParams,\n SendWebSocketMessageResult,\n { origin: string }\n>;\n\n/**\n * The `snap_sendWebSocketMessage` method implementation.\n *\n * @param req - The JSON-RPC request object.\n * @param res - The JSON-RPC response object.\n * @param _next - The `json-rpc-engine` \"next\" callback. Not used by this function.\n * @param end - The `json-rpc-engine` \"end\" callback.\n * @param _hooks - The RPC method hooks. Not used by this function.\n * @param messenger - The messenger used to call controller actions.\n * @returns Nothing.\n */\nasync function sendWebSocketMessageImplementation(\n req: JsonRpcRequestWithOrigin<SendWebSocketMessageParameters>,\n res: PendingJsonRpcResponse<SendWebSocketMessageResult>,\n _next: unknown,\n end: JsonRpcEngineEndCallback,\n _hooks: never,\n messenger: Messenger<string, SendWebSocketMessageMethodActions>,\n): Promise<void> {\n const { params, origin } = req;\n\n if (\n !messenger.call(\n 'PermissionController:hasPermission',\n origin,\n SnapEndowments.NetworkAccess,\n )\n ) {\n return end(providerErrors.unauthorized());\n }\n\n try {\n const { id, message } = getValidatedParams(params);\n await messenger.call('WebSocketService:sendMessage', origin, id, message);\n res.result = null;\n } catch (error) {\n return end(error);\n }\n\n return end();\n}\n\n/**\n * Validates the parameters for the snap_sendWebSocketMessage method.\n *\n * @param params - Parameters to validate.\n * @returns Validated parameters.\n * @throws Throws RPC error if validation fails.\n */\nfunction getValidatedParams(params: unknown): SendWebSocketMessageParameters {\n try {\n return create(params, SendWebSocketMessageParametersStruct);\n } catch (error) {\n if (error instanceof StructError) {\n throw rpcErrors.invalidParams({\n message: `Invalid params: ${error.message}.`,\n });\n }\n /* istanbul ignore next */\n throw rpcErrors.internal();\n }\n}\n"]}
@@ -8,13 +8,8 @@ const utils_1 = require("@metamask/utils");
8
8
  const async_mutex_1 = require("async-mutex");
9
9
  const manageState_1 = require("../restricted/manageState.cjs");
10
10
  const utils_2 = require("../utils.cjs");
11
- const methodName = 'snap_setState';
12
11
  const hookNames = {
13
- hasPermission: true,
14
- getSnapState: true,
15
12
  getUnlockPromise: true,
16
- updateSnapState: true,
17
- getSnap: true,
18
13
  };
19
14
  /**
20
15
  * Allow the Snap to persist up to 64 MB of data to disk and retrieve it at
@@ -65,9 +60,14 @@ const hookNames = {
65
60
  * ```
66
61
  */
67
62
  exports.setStateHandler = {
68
- methodNames: [methodName],
69
63
  implementation: setStateImplementation,
70
64
  hookNames,
65
+ actionNames: [
66
+ 'PermissionController:hasPermission',
67
+ 'SnapController:getSnapState',
68
+ 'SnapController:updateSnapState',
69
+ 'SnapController:getSnap',
70
+ ],
71
71
  };
72
72
  const mutexes = new Map();
73
73
  /**
@@ -96,17 +96,13 @@ const SetStateParametersStruct = (0, superstruct_1.object)({
96
96
  * function.
97
97
  * @param end - The `json-rpc-engine` "end" callback.
98
98
  * @param hooks - The RPC method hooks.
99
- * @param hooks.hasPermission - Check whether a given origin has a given
100
- * permission.
101
- * @param hooks.getSnapState - Get the state of the requesting Snap.
102
99
  * @param hooks.getUnlockPromise - Wait for the extension to be unlocked.
103
- * @param hooks.updateSnapState - Update the state of the requesting Snap.
104
- * @param hooks.getSnap - The hook function to get Snap metadata.
100
+ * @param messenger - The messenger used to call controller actions.
105
101
  * @returns Nothing.
106
102
  */
107
- async function setStateImplementation(request, response, _next, end, { hasPermission, getSnapState, getUnlockPromise, updateSnapState, getSnap, }) {
108
- const { params } = request;
109
- if (!hasPermission(manageState_1.manageStateBuilder.targetName)) {
103
+ async function setStateImplementation(request, response, _next, end, { getUnlockPromise }, messenger) {
104
+ const { params, origin } = request;
105
+ if (!messenger.call('PermissionController:hasPermission', origin, manageState_1.manageStateBuilder.targetName)) {
110
106
  return end(rpc_errors_1.providerErrors.unauthorized());
111
107
  }
112
108
  try {
@@ -118,14 +114,14 @@ async function setStateImplementation(request, response, _next, end, { hasPermis
118
114
  if (encrypted) {
119
115
  await getUnlockPromise(true);
120
116
  }
121
- const snapId = request.origin;
117
+ const snapId = origin;
122
118
  const mutex = getMutex(snapId);
123
119
  // The expectation when using `snap_setState` is for the operation to safe
124
120
  // to do in parallel. The mutex ensures that and prevents a bug that was
125
121
  // mostly prevalent on mobile and caused data loss.
126
122
  await mutex.runExclusive(async () => {
127
- const newState = await getNewState(key, value, encrypted, getSnapState);
128
- const snap = getSnap(snapId);
123
+ const newState = await getNewState(snapId, key, value, encrypted, messenger);
124
+ const snap = messenger.call('SnapController:getSnap', origin);
129
125
  if (!snap?.preinstalled) {
130
126
  // We know that the state is valid JSON as per previous validation.
131
127
  const size = (0, snaps_utils_1.getJsonSizeUnsafe)(newState, true);
@@ -135,7 +131,7 @@ async function setStateImplementation(request, response, _next, end, { hasPermis
135
131
  });
136
132
  }
137
133
  }
138
- await updateSnapState(newState, encrypted);
134
+ await messenger.call('SnapController:updateSnapState', origin, newState, encrypted);
139
135
  response.result = null;
140
136
  });
141
137
  }
@@ -174,18 +170,19 @@ function getValidatedParams(params) {
174
170
  * the key does not exist, it is created (and any missing intermediate keys are
175
171
  * created as well).
176
172
  *
173
+ * @param snapId - The Snap ID.
177
174
  * @param key - The key to set.
178
175
  * @param value - The value to set the key to.
179
176
  * @param encrypted - Whether the state is encrypted.
180
- * @param getSnapState - The `getSnapState` hook.
177
+ * @param messenger - The messenger used to call controller actions.
181
178
  * @returns The new state of the Snap.
182
179
  */
183
- async function getNewState(key, value, encrypted, getSnapState) {
180
+ async function getNewState(snapId, key, value, encrypted, messenger) {
184
181
  if (key === undefined) {
185
182
  (0, utils_1.assert)((0, utils_1.isObject)(value));
186
183
  return value;
187
184
  }
188
- const state = await getSnapState(encrypted);
185
+ const state = await messenger.call('SnapController:getSnapState', snapId, encrypted);
189
186
  return set(state, key, value);
190
187
  }
191
188
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"setState.cjs","sourceRoot":"","sources":["../../src/permitted/setState.ts"],"names":[],"mappings":"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","sourcesContent":["import type { JsonRpcEngineEndCallback } from '@metamask/json-rpc-engine';\nimport type { PermittedHandlerExport } from '@metamask/permission-controller';\nimport { providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport type {\n SetStateParams,\n SetStateResult,\n SnapId,\n} from '@metamask/snaps-sdk';\nimport type { JsonObject } from '@metamask/snaps-sdk/jsx';\nimport {\n getJsonSizeUnsafe,\n type InferMatching,\n type Snap,\n} from '@metamask/snaps-utils';\nimport {\n boolean,\n create,\n object as objectStruct,\n optional,\n StructError,\n} from '@metamask/superstruct';\nimport type {\n PendingJsonRpcResponse,\n Json,\n JsonRpcRequest,\n} from '@metamask/utils';\nimport { hasProperty, isObject, assert, JsonStruct } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport {\n manageStateBuilder,\n STORAGE_SIZE_LIMIT,\n} from '../restricted/manageState';\nimport type { MethodHooksObject } from '../utils';\nimport { FORBIDDEN_KEYS, StateKeyStruct } from '../utils';\n\nconst methodName = 'snap_setState';\n\nconst hookNames: MethodHooksObject<SetStateHooks> = {\n hasPermission: true,\n getSnapState: true,\n getUnlockPromise: true,\n updateSnapState: true,\n getSnap: true,\n};\n\n/**\n * Allow the Snap to persist up to 64 MB of data to disk and retrieve it at\n * will. By default, the data is automatically encrypted using a Snap-specific\n * key and automatically decrypted when retrieved. You can set `encrypted` to\n * `false` to use unencrypted storage (available when the client is locked).\n *\n * If the key is `undefined`, the value is expected to be an object. In this\n * case, the value is set as the new root state.\n *\n * If the key is not `undefined`, the value is set in the state at the key. If\n * the key does not exist, it is created (and any missing intermediate keys are\n * created as well).\n *\n * @example\n * ```json name=\"Manifest\"\n * {\n * \"initialPermissions\": {\n * \"snap_manageState\": {}\n * }\n * }\n * ```\n * ```ts name=\"Usage\"\n * // Set the entire state:\n * await snap.request({\n * method: 'snap_setState',\n * params: {\n * value: {\n * some: {\n * nested: {\n * value: 'Hello, world!',\n * },\n * },\n * },\n * encrypted: true, // Optional, defaults to `true`\n * },\n * });\n *\n * // Set a specific value within the state:\n * await snap.request({\n * method: 'snap_setState',\n * params: {\n * key: 'some.nested.value',\n * value: 'Hello, world!',\n * encrypted: true, // Optional, defaults to `true`\n * },\n * });\n * ```\n */\nexport const setStateHandler = {\n methodNames: [methodName] as const,\n implementation: setStateImplementation,\n hookNames,\n} satisfies PermittedHandlerExport<\n SetStateHooks,\n SetStateParameters,\n SetStateResult\n>;\n\nexport type SetStateHooks = {\n /**\n * Check if the requesting origin has a given permission.\n *\n * @param permissionName - The name of the permission to check.\n * @returns Whether the origin has the permission.\n */\n hasPermission: (permissionName: string) => boolean;\n\n /**\n * Get the state of the requesting Snap.\n *\n * @param encrypted - Whether the state is encrypted.\n * @returns The current state of the Snap.\n */\n getSnapState: (encrypted: boolean) => Promise<Record<string, Json>>;\n\n /**\n * Wait for the extension to be unlocked.\n *\n * @returns A promise that resolves once the extension is unlocked.\n */\n getUnlockPromise: (shouldShowUnlockRequest: boolean) => Promise<void>;\n\n /**\n * Update the state of the requesting Snap.\n *\n * @param newState - The new state of the Snap.\n * @param encrypted - Whether the state should be encrypted.\n */\n updateSnapState: (\n newState: Record<string, Json>,\n encrypted: boolean,\n ) => Promise<void>;\n\n /**\n * Get Snap metadata.\n *\n * @param snapId - The ID of a Snap.\n */\n getSnap: (snapId: string) => Snap | undefined;\n};\n\nconst mutexes = new Map();\n\n/**\n * Get the corresponding state modification mutex for a given Snap ID.\n *\n * @param snapId - The Snap ID.\n * @returns A mutex for that specific Snap.\n */\nfunction getMutex(snapId: SnapId) {\n if (!mutexes.has(snapId)) {\n mutexes.set(snapId, new Mutex());\n }\n return mutexes.get(snapId);\n}\n\nconst SetStateParametersStruct = objectStruct({\n key: optional(StateKeyStruct),\n value: JsonStruct,\n encrypted: optional(boolean()),\n});\n\nexport type SetStateParameters = InferMatching<\n typeof SetStateParametersStruct,\n SetStateParams\n>;\n\n/**\n * The `snap_setState` method implementation.\n *\n * @param request - The JSON-RPC request object.\n * @param response - The JSON-RPC response object.\n * @param _next - The `json-rpc-engine` \"next\" callback. Not used by this\n * function.\n * @param end - The `json-rpc-engine` \"end\" callback.\n * @param hooks - The RPC method hooks.\n * @param hooks.hasPermission - Check whether a given origin has a given\n * permission.\n * @param hooks.getSnapState - Get the state of the requesting Snap.\n * @param hooks.getUnlockPromise - Wait for the extension to be unlocked.\n * @param hooks.updateSnapState - Update the state of the requesting Snap.\n * @param hooks.getSnap - The hook function to get Snap metadata.\n * @returns Nothing.\n */\nasync function setStateImplementation(\n request: JsonRpcRequest<SetStateParameters>,\n response: PendingJsonRpcResponse<SetStateResult>,\n _next: unknown,\n end: JsonRpcEngineEndCallback,\n {\n hasPermission,\n getSnapState,\n getUnlockPromise,\n updateSnapState,\n getSnap,\n }: SetStateHooks,\n): Promise<void> {\n const { params } = request;\n\n if (!hasPermission(manageStateBuilder.targetName)) {\n return end(providerErrors.unauthorized());\n }\n\n try {\n const validatedParams = getValidatedParams(params);\n const { key, value, encrypted = true } = validatedParams;\n\n if (key === undefined && !isObject(value)) {\n return end(\n rpcErrors.invalidParams(\n 'Invalid params: Value must be an object if key is not provided.',\n ),\n );\n }\n\n if (encrypted) {\n await getUnlockPromise(true);\n }\n\n const snapId = (\n request as JsonRpcRequest<SetStateParams> & { origin: string }\n ).origin as SnapId;\n\n const mutex = getMutex(snapId);\n\n // The expectation when using `snap_setState` is for the operation to safe\n // to do in parallel. The mutex ensures that and prevents a bug that was\n // mostly prevalent on mobile and caused data loss.\n await mutex.runExclusive(async () => {\n const newState = await getNewState(key, value, encrypted, getSnapState);\n\n const snap = getSnap(snapId);\n\n if (!snap?.preinstalled) {\n // We know that the state is valid JSON as per previous validation.\n const size = getJsonSizeUnsafe(newState, true);\n if (size > STORAGE_SIZE_LIMIT) {\n throw rpcErrors.invalidParams({\n message: `Invalid params: The new state must not exceed ${\n STORAGE_SIZE_LIMIT / 1_000_000\n } MB in size.`,\n });\n }\n }\n\n await updateSnapState(newState, encrypted);\n response.result = null;\n });\n } catch (error) {\n return end(error);\n }\n\n return end();\n}\n\n/**\n * Validate the parameters of the `snap_setState` method.\n *\n * @param params - The parameters to validate.\n * @returns The validated parameters.\n */\nfunction getValidatedParams(params?: unknown) {\n try {\n return create(params, SetStateParametersStruct);\n } catch (error) {\n if (error instanceof StructError) {\n throw rpcErrors.invalidParams({\n message: `Invalid params: ${error.message}.`,\n });\n }\n\n /* istanbul ignore next */\n throw rpcErrors.internal();\n }\n}\n\n/**\n * Get the new state of the Snap.\n *\n * If the key is `undefined`, the value is expected to be an object. In this\n * case, the value is returned as the new state.\n *\n * If the key is not `undefined`, the value is set in the state at the key. If\n * the key does not exist, it is created (and any missing intermediate keys are\n * created as well).\n *\n * @param key - The key to set.\n * @param value - The value to set the key to.\n * @param encrypted - Whether the state is encrypted.\n * @param getSnapState - The `getSnapState` hook.\n * @returns The new state of the Snap.\n */\nasync function getNewState(\n key: string | undefined,\n value: Json,\n encrypted: boolean,\n getSnapState: SetStateHooks['getSnapState'],\n) {\n if (key === undefined) {\n assert(isObject(value));\n return value;\n }\n\n const state = await getSnapState(encrypted);\n return set(state, key, value);\n}\n\n/**\n * Set the value of a key in an object. The key may contain Lodash-style path\n * syntax, e.g., `a.b.c` (with the exception of array syntax). If the key does\n * not exist, it is created (and any missing intermediate keys are created as\n * well).\n *\n * This is a simplified version of Lodash's `set` function, but Lodash doesn't\n * seem to be maintained anymore, so we're using our own implementation.\n *\n * @param object - The object to get the key from.\n * @param key - The key to set.\n * @param value - The value to set the key to.\n * @returns The new object with the key set to the value.\n */\nexport function set(\n object: Record<string, Json> | null,\n key: string,\n value: Json,\n): JsonObject {\n const keys = key.split('.');\n const requiredObject = object ?? {};\n let currentObject: Record<string, Json> = requiredObject;\n\n for (let i = 0; i < keys.length; i++) {\n const currentKey = keys[i];\n if (FORBIDDEN_KEYS.includes(currentKey)) {\n throw rpcErrors.invalidParams(\n 'Invalid params: Key contains forbidden characters.',\n );\n }\n\n if (i === keys.length - 1) {\n currentObject[currentKey] = value;\n return requiredObject;\n }\n\n if (\n !hasProperty(currentObject, currentKey) ||\n currentObject[currentKey] === null\n ) {\n currentObject[currentKey] = {};\n } else if (!isObject(currentObject[currentKey])) {\n throw rpcErrors.invalidParams(\n 'Invalid params: Cannot overwrite non-object value.',\n );\n }\n\n currentObject = currentObject[currentKey] as Record<string, Json>;\n }\n\n // This should never be reached.\n /* istanbul ignore next */\n throw new Error('Unexpected error while setting the state.');\n}\n"]}
1
+ {"version":3,"file":"setState.cjs","sourceRoot":"","sources":["../../src/permitted/setState.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n JsonRpcEngineEndCallback,\n MethodHandler,\n} from '@metamask/json-rpc-engine';\nimport type { Messenger } from '@metamask/messenger';\nimport type { PermissionControllerHasPermissionAction } from '@metamask/permission-controller';\nimport { providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport type {\n SetStateParams,\n SetStateResult,\n SnapId,\n} from '@metamask/snaps-sdk';\nimport type { JsonObject } from '@metamask/snaps-sdk/jsx';\nimport { getJsonSizeUnsafe, type InferMatching } from '@metamask/snaps-utils';\nimport {\n boolean,\n create,\n object as objectStruct,\n optional,\n StructError,\n} from '@metamask/superstruct';\nimport type { PendingJsonRpcResponse, Json } from '@metamask/utils';\nimport { hasProperty, isObject, assert, JsonStruct } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport {\n manageStateBuilder,\n STORAGE_SIZE_LIMIT,\n} from '../restricted/manageState';\nimport type {\n JsonRpcRequestWithOrigin,\n SnapControllerGetSnapAction,\n SnapControllerGetSnapStateAction,\n SnapControllerUpdateSnapStateAction,\n} from '../types';\nimport type { MethodHooksObject } from '../utils';\nimport { FORBIDDEN_KEYS, StateKeyStruct } from '../utils';\n\nconst hookNames: MethodHooksObject<SetStateMethodHooks> = {\n getUnlockPromise: true,\n};\n\nexport type SetStateMethodHooks = {\n /**\n * Wait for the extension to be unlocked.\n *\n * @returns A promise that resolves once the extension is unlocked.\n */\n getUnlockPromise: (shouldShowUnlockRequest: boolean) => Promise<void>;\n};\n\nexport type SetStateMethodActions =\n | PermissionControllerHasPermissionAction\n | SnapControllerGetSnapStateAction\n | SnapControllerUpdateSnapStateAction\n | SnapControllerGetSnapAction;\n\n/**\n * Allow the Snap to persist up to 64 MB of data to disk and retrieve it at\n * will. By default, the data is automatically encrypted using a Snap-specific\n * key and automatically decrypted when retrieved. You can set `encrypted` to\n * `false` to use unencrypted storage (available when the client is locked).\n *\n * If the key is `undefined`, the value is expected to be an object. In this\n * case, the value is set as the new root state.\n *\n * If the key is not `undefined`, the value is set in the state at the key. If\n * the key does not exist, it is created (and any missing intermediate keys are\n * created as well).\n *\n * @example\n * ```json name=\"Manifest\"\n * {\n * \"initialPermissions\": {\n * \"snap_manageState\": {}\n * }\n * }\n * ```\n * ```ts name=\"Usage\"\n * // Set the entire state:\n * await snap.request({\n * method: 'snap_setState',\n * params: {\n * value: {\n * some: {\n * nested: {\n * value: 'Hello, world!',\n * },\n * },\n * },\n * encrypted: true, // Optional, defaults to `true`\n * },\n * });\n *\n * // Set a specific value within the state:\n * await snap.request({\n * method: 'snap_setState',\n * params: {\n * key: 'some.nested.value',\n * value: 'Hello, world!',\n * encrypted: true, // Optional, defaults to `true`\n * },\n * });\n * ```\n */\nexport const setStateHandler = {\n implementation: setStateImplementation,\n hookNames,\n actionNames: [\n 'PermissionController:hasPermission',\n 'SnapController:getSnapState',\n 'SnapController:updateSnapState',\n 'SnapController:getSnap',\n ],\n} satisfies MethodHandler<\n SetStateMethodHooks,\n SetStateMethodActions,\n SetStateParameters,\n SetStateResult,\n { origin: SnapId }\n>;\n\nconst mutexes = new Map();\n\n/**\n * Get the corresponding state modification mutex for a given Snap ID.\n *\n * @param snapId - The Snap ID.\n * @returns A mutex for that specific Snap.\n */\nfunction getMutex(snapId: SnapId) {\n if (!mutexes.has(snapId)) {\n mutexes.set(snapId, new Mutex());\n }\n return mutexes.get(snapId);\n}\n\nconst SetStateParametersStruct = objectStruct({\n key: optional(StateKeyStruct),\n value: JsonStruct,\n encrypted: optional(boolean()),\n});\n\nexport type SetStateParameters = InferMatching<\n typeof SetStateParametersStruct,\n SetStateParams\n>;\n\n/**\n * The `snap_setState` method implementation.\n *\n * @param request - The JSON-RPC request object.\n * @param response - The JSON-RPC response object.\n * @param _next - The `json-rpc-engine` \"next\" callback. Not used by this\n * function.\n * @param end - The `json-rpc-engine` \"end\" callback.\n * @param hooks - The RPC method hooks.\n * @param hooks.getUnlockPromise - Wait for the extension to be unlocked.\n * @param messenger - The messenger used to call controller actions.\n * @returns Nothing.\n */\nasync function setStateImplementation(\n request: JsonRpcRequestWithOrigin<SetStateParameters>,\n response: PendingJsonRpcResponse<SetStateResult>,\n _next: unknown,\n end: JsonRpcEngineEndCallback,\n { getUnlockPromise }: SetStateMethodHooks,\n messenger: Messenger<string, SetStateMethodActions>,\n): Promise<void> {\n const { params, origin } = request;\n\n if (\n !messenger.call(\n 'PermissionController:hasPermission',\n origin,\n manageStateBuilder.targetName,\n )\n ) {\n return end(providerErrors.unauthorized());\n }\n\n try {\n const validatedParams = getValidatedParams(params);\n const { key, value, encrypted = true } = validatedParams;\n\n if (key === undefined && !isObject(value)) {\n return end(\n rpcErrors.invalidParams(\n 'Invalid params: Value must be an object if key is not provided.',\n ),\n );\n }\n\n if (encrypted) {\n await getUnlockPromise(true);\n }\n\n const snapId = origin as SnapId;\n\n const mutex = getMutex(snapId);\n\n // The expectation when using `snap_setState` is for the operation to safe\n // to do in parallel. The mutex ensures that and prevents a bug that was\n // mostly prevalent on mobile and caused data loss.\n await mutex.runExclusive(async () => {\n const newState = await getNewState(\n snapId,\n key,\n value,\n encrypted,\n messenger,\n );\n\n const snap = messenger.call('SnapController:getSnap', origin);\n\n if (!snap?.preinstalled) {\n // We know that the state is valid JSON as per previous validation.\n const size = getJsonSizeUnsafe(newState, true);\n if (size > STORAGE_SIZE_LIMIT) {\n throw rpcErrors.invalidParams({\n message: `Invalid params: The new state must not exceed ${\n STORAGE_SIZE_LIMIT / 1_000_000\n } MB in size.`,\n });\n }\n }\n\n await messenger.call(\n 'SnapController:updateSnapState',\n origin,\n newState,\n encrypted,\n );\n response.result = null;\n });\n } catch (error) {\n return end(error);\n }\n\n return end();\n}\n\n/**\n * Validate the parameters of the `snap_setState` method.\n *\n * @param params - The parameters to validate.\n * @returns The validated parameters.\n */\nfunction getValidatedParams(params?: unknown) {\n try {\n return create(params, SetStateParametersStruct);\n } catch (error) {\n if (error instanceof StructError) {\n throw rpcErrors.invalidParams({\n message: `Invalid params: ${error.message}.`,\n });\n }\n\n /* istanbul ignore next */\n throw rpcErrors.internal();\n }\n}\n\n/**\n * Get the new state of the Snap.\n *\n * If the key is `undefined`, the value is expected to be an object. In this\n * case, the value is returned as the new state.\n *\n * If the key is not `undefined`, the value is set in the state at the key. If\n * the key does not exist, it is created (and any missing intermediate keys are\n * created as well).\n *\n * @param snapId - The Snap ID.\n * @param key - The key to set.\n * @param value - The value to set the key to.\n * @param encrypted - Whether the state is encrypted.\n * @param messenger - The messenger used to call controller actions.\n * @returns The new state of the Snap.\n */\nasync function getNewState(\n snapId: SnapId,\n key: string | undefined,\n value: Json,\n encrypted: boolean,\n messenger: Messenger<string, SetStateMethodActions>,\n): Promise<Record<string, Json>> {\n if (key === undefined) {\n assert(isObject(value));\n return value;\n }\n\n const state = await messenger.call(\n 'SnapController:getSnapState',\n snapId,\n encrypted,\n );\n return set(state, key, value);\n}\n\n/**\n * Set the value of a key in an object. The key may contain Lodash-style path\n * syntax, e.g., `a.b.c` (with the exception of array syntax). If the key does\n * not exist, it is created (and any missing intermediate keys are created as\n * well).\n *\n * This is a simplified version of Lodash's `set` function, but Lodash doesn't\n * seem to be maintained anymore, so we're using our own implementation.\n *\n * @param object - The object to get the key from.\n * @param key - The key to set.\n * @param value - The value to set the key to.\n * @returns The new object with the key set to the value.\n */\nexport function set(\n object: Record<string, Json> | null,\n key: string,\n value: Json,\n): JsonObject {\n const keys = key.split('.');\n const requiredObject = object ?? {};\n let currentObject: Record<string, Json> = requiredObject;\n\n for (let i = 0; i < keys.length; i++) {\n const currentKey = keys[i];\n if (FORBIDDEN_KEYS.includes(currentKey)) {\n throw rpcErrors.invalidParams(\n 'Invalid params: Key contains forbidden characters.',\n );\n }\n\n if (i === keys.length - 1) {\n currentObject[currentKey] = value;\n return requiredObject;\n }\n\n if (\n !hasProperty(currentObject, currentKey) ||\n currentObject[currentKey] === null\n ) {\n currentObject[currentKey] = {};\n } else if (!isObject(currentObject[currentKey])) {\n throw rpcErrors.invalidParams(\n 'Invalid params: Cannot overwrite non-object value.',\n );\n }\n\n currentObject = currentObject[currentKey] as Record<string, Json>;\n }\n\n // This should never be reached.\n /* istanbul ignore next */\n throw new Error('Unexpected error while setting the state.');\n}\n"]}
@@ -1,9 +1,21 @@
1
1
  import type { JsonRpcEngineEndCallback } from "@metamask/json-rpc-engine";
2
+ import type { Messenger } from "@metamask/messenger";
3
+ import type { PermissionControllerHasPermissionAction } from "@metamask/permission-controller";
2
4
  import type { SetStateParams, SetStateResult } from "@metamask/snaps-sdk";
3
5
  import type { JsonObject } from "@metamask/snaps-sdk/jsx";
4
- import { type InferMatching, type Snap } from "@metamask/snaps-utils";
5
- import type { PendingJsonRpcResponse, Json, JsonRpcRequest } from "@metamask/utils";
6
+ import { type InferMatching } from "@metamask/snaps-utils";
7
+ import type { PendingJsonRpcResponse, Json } from "@metamask/utils";
8
+ import type { JsonRpcRequestWithOrigin, SnapControllerGetSnapAction, SnapControllerGetSnapStateAction, SnapControllerUpdateSnapStateAction } from "../types.cjs";
6
9
  import type { MethodHooksObject } from "../utils.cjs";
10
+ export type SetStateMethodHooks = {
11
+ /**
12
+ * Wait for the extension to be unlocked.
13
+ *
14
+ * @returns A promise that resolves once the extension is unlocked.
15
+ */
16
+ getUnlockPromise: (shouldShowUnlockRequest: boolean) => Promise<void>;
17
+ };
18
+ export type SetStateMethodActions = PermissionControllerHasPermissionAction | SnapControllerGetSnapStateAction | SnapControllerUpdateSnapStateAction | SnapControllerGetSnapAction;
7
19
  /**
8
20
  * Allow the Snap to persist up to 64 MB of data to disk and retrieve it at
9
21
  * will. By default, the data is automatically encrypted using a Snap-specific
@@ -53,44 +65,9 @@ import type { MethodHooksObject } from "../utils.cjs";
53
65
  * ```
54
66
  */
55
67
  export declare const setStateHandler: {
56
- methodNames: ["snap_setState"];
57
68
  implementation: typeof setStateImplementation;
58
- hookNames: MethodHooksObject<SetStateHooks>;
59
- };
60
- export type SetStateHooks = {
61
- /**
62
- * Check if the requesting origin has a given permission.
63
- *
64
- * @param permissionName - The name of the permission to check.
65
- * @returns Whether the origin has the permission.
66
- */
67
- hasPermission: (permissionName: string) => boolean;
68
- /**
69
- * Get the state of the requesting Snap.
70
- *
71
- * @param encrypted - Whether the state is encrypted.
72
- * @returns The current state of the Snap.
73
- */
74
- getSnapState: (encrypted: boolean) => Promise<Record<string, Json>>;
75
- /**
76
- * Wait for the extension to be unlocked.
77
- *
78
- * @returns A promise that resolves once the extension is unlocked.
79
- */
80
- getUnlockPromise: (shouldShowUnlockRequest: boolean) => Promise<void>;
81
- /**
82
- * Update the state of the requesting Snap.
83
- *
84
- * @param newState - The new state of the Snap.
85
- * @param encrypted - Whether the state should be encrypted.
86
- */
87
- updateSnapState: (newState: Record<string, Json>, encrypted: boolean) => Promise<void>;
88
- /**
89
- * Get Snap metadata.
90
- *
91
- * @param snapId - The ID of a Snap.
92
- */
93
- getSnap: (snapId: string) => Snap | undefined;
69
+ hookNames: MethodHooksObject<SetStateMethodHooks>;
70
+ actionNames: ("SnapController:getSnap" | "SnapController:getSnapState" | "SnapController:updateSnapState" | "PermissionController:hasPermission")[];
94
71
  };
95
72
  declare const SetStateParametersStruct: import("@metamask/superstruct").Struct<{
96
73
  value: Json;
@@ -111,15 +88,11 @@ export type SetStateParameters = InferMatching<typeof SetStateParametersStruct,
111
88
  * function.
112
89
  * @param end - The `json-rpc-engine` "end" callback.
113
90
  * @param hooks - The RPC method hooks.
114
- * @param hooks.hasPermission - Check whether a given origin has a given
115
- * permission.
116
- * @param hooks.getSnapState - Get the state of the requesting Snap.
117
91
  * @param hooks.getUnlockPromise - Wait for the extension to be unlocked.
118
- * @param hooks.updateSnapState - Update the state of the requesting Snap.
119
- * @param hooks.getSnap - The hook function to get Snap metadata.
92
+ * @param messenger - The messenger used to call controller actions.
120
93
  * @returns Nothing.
121
94
  */
122
- declare function setStateImplementation(request: JsonRpcRequest<SetStateParameters>, response: PendingJsonRpcResponse<SetStateResult>, _next: unknown, end: JsonRpcEngineEndCallback, { hasPermission, getSnapState, getUnlockPromise, updateSnapState, getSnap, }: SetStateHooks): Promise<void>;
95
+ declare function setStateImplementation(request: JsonRpcRequestWithOrigin<SetStateParameters>, response: PendingJsonRpcResponse<SetStateResult>, _next: unknown, end: JsonRpcEngineEndCallback, { getUnlockPromise }: SetStateMethodHooks, messenger: Messenger<string, SetStateMethodActions>): Promise<void>;
123
96
  /**
124
97
  * Set the value of a key in an object. The key may contain Lodash-style path
125
98
  * syntax, e.g., `a.b.c` (with the exception of array syntax). If the key does
@@ -1 +1 @@
1
- {"version":3,"file":"setState.d.cts","sourceRoot":"","sources":["../../src/permitted/setState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,kCAAkC;AAG1E,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EAEf,4BAA4B;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,gCAAgC;AAC1D,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,IAAI,EACV,8BAA8B;AAQ/B,OAAO,KAAK,EACV,sBAAsB,EACtB,IAAI,EACJ,cAAc,EACf,wBAAwB;AAQzB,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAiB;AAalD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,eAAO,MAAM,eAAe;;;;CAQ3B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B;;;;;OAKG;IACH,aAAa,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC;IAEnD;;;;;OAKG;IACH,YAAY,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IAEpE;;;;OAIG;IACH,gBAAgB,EAAE,CAAC,uBAAuB,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtE;;;;;OAKG;IACH,eAAe,EAAE,CACf,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,EAC9B,SAAS,EAAE,OAAO,KACf,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnB;;;;OAIG;IACH,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,SAAS,CAAC;CAC/C,CAAC;AAiBF,QAAA,MAAM,wBAAwB;;;;;;;;EAI5B,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,aAAa,CAC5C,OAAO,wBAAwB,EAC/B,cAAc,CACf,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,iBAAe,sBAAsB,CACnC,OAAO,EAAE,cAAc,CAAC,kBAAkB,CAAC,EAC3C,QAAQ,EAAE,sBAAsB,CAAC,cAAc,CAAC,EAChD,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,wBAAwB,EAC7B,EACE,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,OAAO,GACR,EAAE,aAAa,GACf,OAAO,CAAC,IAAI,CAAC,CAyDf;AAsDD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,GAAG,CACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI,EACnC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,IAAI,GACV,UAAU,CAmCZ"}
1
+ {"version":3,"file":"setState.d.cts","sourceRoot":"","sources":["../../src/permitted/setState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EAEzB,kCAAkC;AACnC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EAAE,uCAAuC,EAAE,wCAAwC;AAE/F,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EAEf,4BAA4B;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,gCAAgC;AAC1D,OAAO,EAAqB,KAAK,aAAa,EAAE,8BAA8B;AAQ9E,OAAO,KAAK,EAAE,sBAAsB,EAAE,IAAI,EAAE,wBAAwB;AAQpE,OAAO,KAAK,EACV,wBAAwB,EACxB,2BAA2B,EAC3B,gCAAgC,EAChC,mCAAmC,EACpC,qBAAiB;AAClB,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAiB;AAOlD,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;;OAIG;IACH,gBAAgB,EAAE,CAAC,uBAAuB,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvE,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAC7B,uCAAuC,GACvC,gCAAgC,GAChC,mCAAmC,GACnC,2BAA2B,CAAC;AAEhC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,eAAO,MAAM,eAAe;;;;CAe3B,CAAC;AAiBF,QAAA,MAAM,wBAAwB;;;;;;;;EAI5B,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,aAAa,CAC5C,OAAO,wBAAwB,EAC/B,cAAc,CACf,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,iBAAe,sBAAsB,CACnC,OAAO,EAAE,wBAAwB,CAAC,kBAAkB,CAAC,EACrD,QAAQ,EAAE,sBAAsB,CAAC,cAAc,CAAC,EAChD,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,wBAAwB,EAC7B,EAAE,gBAAgB,EAAE,EAAE,mBAAmB,EACzC,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,qBAAqB,CAAC,GAClD,OAAO,CAAC,IAAI,CAAC,CAwEf;AA4DD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,GAAG,CACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI,EACnC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,IAAI,GACV,UAAU,CAmCZ"}
@@ -1,9 +1,21 @@
1
1
  import type { JsonRpcEngineEndCallback } from "@metamask/json-rpc-engine";
2
+ import type { Messenger } from "@metamask/messenger";
3
+ import type { PermissionControllerHasPermissionAction } from "@metamask/permission-controller";
2
4
  import type { SetStateParams, SetStateResult } from "@metamask/snaps-sdk";
3
5
  import type { JsonObject } from "@metamask/snaps-sdk/jsx";
4
- import { type InferMatching, type Snap } from "@metamask/snaps-utils";
5
- import type { PendingJsonRpcResponse, Json, JsonRpcRequest } from "@metamask/utils";
6
+ import { type InferMatching } from "@metamask/snaps-utils";
7
+ import type { PendingJsonRpcResponse, Json } from "@metamask/utils";
8
+ import type { JsonRpcRequestWithOrigin, SnapControllerGetSnapAction, SnapControllerGetSnapStateAction, SnapControllerUpdateSnapStateAction } from "../types.mjs";
6
9
  import type { MethodHooksObject } from "../utils.mjs";
10
+ export type SetStateMethodHooks = {
11
+ /**
12
+ * Wait for the extension to be unlocked.
13
+ *
14
+ * @returns A promise that resolves once the extension is unlocked.
15
+ */
16
+ getUnlockPromise: (shouldShowUnlockRequest: boolean) => Promise<void>;
17
+ };
18
+ export type SetStateMethodActions = PermissionControllerHasPermissionAction | SnapControllerGetSnapStateAction | SnapControllerUpdateSnapStateAction | SnapControllerGetSnapAction;
7
19
  /**
8
20
  * Allow the Snap to persist up to 64 MB of data to disk and retrieve it at
9
21
  * will. By default, the data is automatically encrypted using a Snap-specific
@@ -53,44 +65,9 @@ import type { MethodHooksObject } from "../utils.mjs";
53
65
  * ```
54
66
  */
55
67
  export declare const setStateHandler: {
56
- methodNames: ["snap_setState"];
57
68
  implementation: typeof setStateImplementation;
58
- hookNames: MethodHooksObject<SetStateHooks>;
59
- };
60
- export type SetStateHooks = {
61
- /**
62
- * Check if the requesting origin has a given permission.
63
- *
64
- * @param permissionName - The name of the permission to check.
65
- * @returns Whether the origin has the permission.
66
- */
67
- hasPermission: (permissionName: string) => boolean;
68
- /**
69
- * Get the state of the requesting Snap.
70
- *
71
- * @param encrypted - Whether the state is encrypted.
72
- * @returns The current state of the Snap.
73
- */
74
- getSnapState: (encrypted: boolean) => Promise<Record<string, Json>>;
75
- /**
76
- * Wait for the extension to be unlocked.
77
- *
78
- * @returns A promise that resolves once the extension is unlocked.
79
- */
80
- getUnlockPromise: (shouldShowUnlockRequest: boolean) => Promise<void>;
81
- /**
82
- * Update the state of the requesting Snap.
83
- *
84
- * @param newState - The new state of the Snap.
85
- * @param encrypted - Whether the state should be encrypted.
86
- */
87
- updateSnapState: (newState: Record<string, Json>, encrypted: boolean) => Promise<void>;
88
- /**
89
- * Get Snap metadata.
90
- *
91
- * @param snapId - The ID of a Snap.
92
- */
93
- getSnap: (snapId: string) => Snap | undefined;
69
+ hookNames: MethodHooksObject<SetStateMethodHooks>;
70
+ actionNames: ("SnapController:getSnap" | "SnapController:getSnapState" | "SnapController:updateSnapState" | "PermissionController:hasPermission")[];
94
71
  };
95
72
  declare const SetStateParametersStruct: import("@metamask/superstruct").Struct<{
96
73
  value: Json;
@@ -111,15 +88,11 @@ export type SetStateParameters = InferMatching<typeof SetStateParametersStruct,
111
88
  * function.
112
89
  * @param end - The `json-rpc-engine` "end" callback.
113
90
  * @param hooks - The RPC method hooks.
114
- * @param hooks.hasPermission - Check whether a given origin has a given
115
- * permission.
116
- * @param hooks.getSnapState - Get the state of the requesting Snap.
117
91
  * @param hooks.getUnlockPromise - Wait for the extension to be unlocked.
118
- * @param hooks.updateSnapState - Update the state of the requesting Snap.
119
- * @param hooks.getSnap - The hook function to get Snap metadata.
92
+ * @param messenger - The messenger used to call controller actions.
120
93
  * @returns Nothing.
121
94
  */
122
- declare function setStateImplementation(request: JsonRpcRequest<SetStateParameters>, response: PendingJsonRpcResponse<SetStateResult>, _next: unknown, end: JsonRpcEngineEndCallback, { hasPermission, getSnapState, getUnlockPromise, updateSnapState, getSnap, }: SetStateHooks): Promise<void>;
95
+ declare function setStateImplementation(request: JsonRpcRequestWithOrigin<SetStateParameters>, response: PendingJsonRpcResponse<SetStateResult>, _next: unknown, end: JsonRpcEngineEndCallback, { getUnlockPromise }: SetStateMethodHooks, messenger: Messenger<string, SetStateMethodActions>): Promise<void>;
123
96
  /**
124
97
  * Set the value of a key in an object. The key may contain Lodash-style path
125
98
  * syntax, e.g., `a.b.c` (with the exception of array syntax). If the key does
@@ -1 +1 @@
1
- {"version":3,"file":"setState.d.mts","sourceRoot":"","sources":["../../src/permitted/setState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,kCAAkC;AAG1E,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EAEf,4BAA4B;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,gCAAgC;AAC1D,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,IAAI,EACV,8BAA8B;AAQ/B,OAAO,KAAK,EACV,sBAAsB,EACtB,IAAI,EACJ,cAAc,EACf,wBAAwB;AAQzB,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAiB;AAalD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,eAAO,MAAM,eAAe;;;;CAQ3B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B;;;;;OAKG;IACH,aAAa,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC;IAEnD;;;;;OAKG;IACH,YAAY,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IAEpE;;;;OAIG;IACH,gBAAgB,EAAE,CAAC,uBAAuB,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtE;;;;;OAKG;IACH,eAAe,EAAE,CACf,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,EAC9B,SAAS,EAAE,OAAO,KACf,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnB;;;;OAIG;IACH,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,SAAS,CAAC;CAC/C,CAAC;AAiBF,QAAA,MAAM,wBAAwB;;;;;;;;EAI5B,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,aAAa,CAC5C,OAAO,wBAAwB,EAC/B,cAAc,CACf,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,iBAAe,sBAAsB,CACnC,OAAO,EAAE,cAAc,CAAC,kBAAkB,CAAC,EAC3C,QAAQ,EAAE,sBAAsB,CAAC,cAAc,CAAC,EAChD,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,wBAAwB,EAC7B,EACE,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,OAAO,GACR,EAAE,aAAa,GACf,OAAO,CAAC,IAAI,CAAC,CAyDf;AAsDD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,GAAG,CACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI,EACnC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,IAAI,GACV,UAAU,CAmCZ"}
1
+ {"version":3,"file":"setState.d.mts","sourceRoot":"","sources":["../../src/permitted/setState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EAEzB,kCAAkC;AACnC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EAAE,uCAAuC,EAAE,wCAAwC;AAE/F,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EAEf,4BAA4B;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,gCAAgC;AAC1D,OAAO,EAAqB,KAAK,aAAa,EAAE,8BAA8B;AAQ9E,OAAO,KAAK,EAAE,sBAAsB,EAAE,IAAI,EAAE,wBAAwB;AAQpE,OAAO,KAAK,EACV,wBAAwB,EACxB,2BAA2B,EAC3B,gCAAgC,EAChC,mCAAmC,EACpC,qBAAiB;AAClB,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAiB;AAOlD,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;;OAIG;IACH,gBAAgB,EAAE,CAAC,uBAAuB,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvE,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAC7B,uCAAuC,GACvC,gCAAgC,GAChC,mCAAmC,GACnC,2BAA2B,CAAC;AAEhC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,eAAO,MAAM,eAAe;;;;CAe3B,CAAC;AAiBF,QAAA,MAAM,wBAAwB;;;;;;;;EAI5B,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,aAAa,CAC5C,OAAO,wBAAwB,EAC/B,cAAc,CACf,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,iBAAe,sBAAsB,CACnC,OAAO,EAAE,wBAAwB,CAAC,kBAAkB,CAAC,EACrD,QAAQ,EAAE,sBAAsB,CAAC,cAAc,CAAC,EAChD,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,wBAAwB,EAC7B,EAAE,gBAAgB,EAAE,EAAE,mBAAmB,EACzC,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,qBAAqB,CAAC,GAClD,OAAO,CAAC,IAAI,CAAC,CAwEf;AA4DD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,GAAG,CACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI,EACnC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,IAAI,GACV,UAAU,CAmCZ"}
@@ -5,13 +5,8 @@ import { hasProperty, isObject, assert, JsonStruct } from "@metamask/utils";
5
5
  import { Mutex } from "async-mutex";
6
6
  import { manageStateBuilder, STORAGE_SIZE_LIMIT } from "../restricted/manageState.mjs";
7
7
  import { FORBIDDEN_KEYS, StateKeyStruct } from "../utils.mjs";
8
- const methodName = 'snap_setState';
9
8
  const hookNames = {
10
- hasPermission: true,
11
- getSnapState: true,
12
9
  getUnlockPromise: true,
13
- updateSnapState: true,
14
- getSnap: true,
15
10
  };
16
11
  /**
17
12
  * Allow the Snap to persist up to 64 MB of data to disk and retrieve it at
@@ -62,9 +57,14 @@ const hookNames = {
62
57
  * ```
63
58
  */
64
59
  export const setStateHandler = {
65
- methodNames: [methodName],
66
60
  implementation: setStateImplementation,
67
61
  hookNames,
62
+ actionNames: [
63
+ 'PermissionController:hasPermission',
64
+ 'SnapController:getSnapState',
65
+ 'SnapController:updateSnapState',
66
+ 'SnapController:getSnap',
67
+ ],
68
68
  };
69
69
  const mutexes = new Map();
70
70
  /**
@@ -93,17 +93,13 @@ const SetStateParametersStruct = objectStruct({
93
93
  * function.
94
94
  * @param end - The `json-rpc-engine` "end" callback.
95
95
  * @param hooks - The RPC method hooks.
96
- * @param hooks.hasPermission - Check whether a given origin has a given
97
- * permission.
98
- * @param hooks.getSnapState - Get the state of the requesting Snap.
99
96
  * @param hooks.getUnlockPromise - Wait for the extension to be unlocked.
100
- * @param hooks.updateSnapState - Update the state of the requesting Snap.
101
- * @param hooks.getSnap - The hook function to get Snap metadata.
97
+ * @param messenger - The messenger used to call controller actions.
102
98
  * @returns Nothing.
103
99
  */
104
- async function setStateImplementation(request, response, _next, end, { hasPermission, getSnapState, getUnlockPromise, updateSnapState, getSnap, }) {
105
- const { params } = request;
106
- if (!hasPermission(manageStateBuilder.targetName)) {
100
+ async function setStateImplementation(request, response, _next, end, { getUnlockPromise }, messenger) {
101
+ const { params, origin } = request;
102
+ if (!messenger.call('PermissionController:hasPermission', origin, manageStateBuilder.targetName)) {
107
103
  return end(providerErrors.unauthorized());
108
104
  }
109
105
  try {
@@ -115,14 +111,14 @@ async function setStateImplementation(request, response, _next, end, { hasPermis
115
111
  if (encrypted) {
116
112
  await getUnlockPromise(true);
117
113
  }
118
- const snapId = request.origin;
114
+ const snapId = origin;
119
115
  const mutex = getMutex(snapId);
120
116
  // The expectation when using `snap_setState` is for the operation to safe
121
117
  // to do in parallel. The mutex ensures that and prevents a bug that was
122
118
  // mostly prevalent on mobile and caused data loss.
123
119
  await mutex.runExclusive(async () => {
124
- const newState = await getNewState(key, value, encrypted, getSnapState);
125
- const snap = getSnap(snapId);
120
+ const newState = await getNewState(snapId, key, value, encrypted, messenger);
121
+ const snap = messenger.call('SnapController:getSnap', origin);
126
122
  if (!snap?.preinstalled) {
127
123
  // We know that the state is valid JSON as per previous validation.
128
124
  const size = getJsonSizeUnsafe(newState, true);
@@ -132,7 +128,7 @@ async function setStateImplementation(request, response, _next, end, { hasPermis
132
128
  });
133
129
  }
134
130
  }
135
- await updateSnapState(newState, encrypted);
131
+ await messenger.call('SnapController:updateSnapState', origin, newState, encrypted);
136
132
  response.result = null;
137
133
  });
138
134
  }
@@ -171,18 +167,19 @@ function getValidatedParams(params) {
171
167
  * the key does not exist, it is created (and any missing intermediate keys are
172
168
  * created as well).
173
169
  *
170
+ * @param snapId - The Snap ID.
174
171
  * @param key - The key to set.
175
172
  * @param value - The value to set the key to.
176
173
  * @param encrypted - Whether the state is encrypted.
177
- * @param getSnapState - The `getSnapState` hook.
174
+ * @param messenger - The messenger used to call controller actions.
178
175
  * @returns The new state of the Snap.
179
176
  */
180
- async function getNewState(key, value, encrypted, getSnapState) {
177
+ async function getNewState(snapId, key, value, encrypted, messenger) {
181
178
  if (key === undefined) {
182
179
  assert(isObject(value));
183
180
  return value;
184
181
  }
185
- const state = await getSnapState(encrypted);
182
+ const state = await messenger.call('SnapController:getSnapState', snapId, encrypted);
186
183
  return set(state, key, value);
187
184
  }
188
185
  /**